18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Legacy: Generic DRM Contexts 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 58c2ecf20Sopenharmony_ci * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 68c2ecf20Sopenharmony_ci * All Rights Reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Rickard E. (Rik) Faith <faith@valinux.com> 98c2ecf20Sopenharmony_ci * Author: Gareth Hughes <gareth@valinux.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 128c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 138c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 148c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 158c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 168c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 198c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 208c2ecf20Sopenharmony_ci * Software. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 238c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 248c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 258c2ecf20Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 268c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 278c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 288c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 358c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 368c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "drm_legacy.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct drm_ctx_list { 418c2ecf20Sopenharmony_ci struct list_head head; 428c2ecf20Sopenharmony_ci drm_context_t handle; 438c2ecf20Sopenharmony_ci struct drm_file *tag; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/******************************************************************/ 478c2ecf20Sopenharmony_ci/** \name Context bitmap support */ 488c2ecf20Sopenharmony_ci/*@{*/ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Free a handle from the context bitmap. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * \param dev DRM device. 548c2ecf20Sopenharmony_ci * \param ctx_handle context handle. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry 578c2ecf20Sopenharmony_ci * in drm_device::ctx_idr, while holding the drm_device::struct_mutex 588c2ecf20Sopenharmony_ci * lock. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_civoid drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 638c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 648c2ecf20Sopenharmony_ci return; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 678c2ecf20Sopenharmony_ci idr_remove(&dev->ctx_idr, ctx_handle); 688c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * Context bitmap allocation. 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * \param dev DRM device. 758c2ecf20Sopenharmony_ci * \return (non-negative) context handle on success or a negative number on failure. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Allocate a new idr from drm_device::ctx_idr while holding the 788c2ecf20Sopenharmony_ci * drm_device::struct_mutex lock. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic int drm_legacy_ctxbitmap_next(struct drm_device * dev) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci int ret; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 858c2ecf20Sopenharmony_ci ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0, 868c2ecf20Sopenharmony_ci GFP_KERNEL); 878c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 888c2ecf20Sopenharmony_ci return ret; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* 928c2ecf20Sopenharmony_ci * Context bitmap initialization. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * \param dev DRM device. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Initialise the drm_device::ctx_idr 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_civoid drm_legacy_ctxbitmap_init(struct drm_device * dev) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 1018c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci idr_init(&dev->ctx_idr); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * Context bitmap cleanup. 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * \param dev DRM device. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Free all idr members using drm_ctx_sarea_free helper function 1138c2ecf20Sopenharmony_ci * while holding the drm_device::struct_mutex lock. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_civoid drm_legacy_ctxbitmap_cleanup(struct drm_device * dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 1188c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 1198c2ecf20Sopenharmony_ci return; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 1228c2ecf20Sopenharmony_ci idr_destroy(&dev->ctx_idr); 1238c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/** 1278c2ecf20Sopenharmony_ci * drm_ctxbitmap_flush() - Flush all contexts owned by a file 1288c2ecf20Sopenharmony_ci * @dev: DRM device to operate on 1298c2ecf20Sopenharmony_ci * @file: Open file to flush contexts for 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * This iterates over all contexts on @dev and drops them if they're owned by 1328c2ecf20Sopenharmony_ci * @file. Note that after this call returns, new contexts might be added if 1338c2ecf20Sopenharmony_ci * the file is still alive. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_civoid drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct drm_ctx_list *pos, *tmp; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 1408c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci mutex_lock(&dev->ctxlist_mutex); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) { 1468c2ecf20Sopenharmony_ci if (pos->tag == file && 1478c2ecf20Sopenharmony_ci pos->handle != DRM_KERNEL_CONTEXT) { 1488c2ecf20Sopenharmony_ci if (dev->driver->context_dtor) 1498c2ecf20Sopenharmony_ci dev->driver->context_dtor(dev, pos->handle); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci drm_legacy_ctxbitmap_free(dev, pos->handle); 1528c2ecf20Sopenharmony_ci list_del(&pos->head); 1538c2ecf20Sopenharmony_ci kfree(pos); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci mutex_unlock(&dev->ctxlist_mutex); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/*@}*/ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/******************************************************************/ 1638c2ecf20Sopenharmony_ci/** \name Per Context SAREA Support */ 1648c2ecf20Sopenharmony_ci/*@{*/ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* 1678c2ecf20Sopenharmony_ci * Get per-context SAREA. 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * \param inode device inode. 1708c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 1718c2ecf20Sopenharmony_ci * \param cmd command. 1728c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx_priv_map structure. 1738c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * Gets the map from drm_device::ctx_idr with the handle specified and 1768c2ecf20Sopenharmony_ci * returns its handle. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ciint drm_legacy_getsareactx(struct drm_device *dev, void *data, 1798c2ecf20Sopenharmony_ci struct drm_file *file_priv) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct drm_ctx_priv_map *request = data; 1828c2ecf20Sopenharmony_ci struct drm_local_map *map; 1838c2ecf20Sopenharmony_ci struct drm_map_list *_entry; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 1868c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 1878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci map = idr_find(&dev->ctx_idr, request->ctx_id); 1928c2ecf20Sopenharmony_ci if (!map) { 1938c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 1948c2ecf20Sopenharmony_ci return -EINVAL; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci request->handle = NULL; 1988c2ecf20Sopenharmony_ci list_for_each_entry(_entry, &dev->maplist, head) { 1998c2ecf20Sopenharmony_ci if (_entry->map == map) { 2008c2ecf20Sopenharmony_ci request->handle = 2018c2ecf20Sopenharmony_ci (void *)(unsigned long)_entry->user_token; 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (request->handle == NULL) 2098c2ecf20Sopenharmony_ci return -EINVAL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* 2158c2ecf20Sopenharmony_ci * Set per-context SAREA. 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * \param inode device inode. 2188c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 2198c2ecf20Sopenharmony_ci * \param cmd command. 2208c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx_priv_map structure. 2218c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * Searches the mapping specified in \p arg and update the entry in 2248c2ecf20Sopenharmony_ci * drm_device::ctx_idr with it. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ciint drm_legacy_setsareactx(struct drm_device *dev, void *data, 2278c2ecf20Sopenharmony_ci struct drm_file *file_priv) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct drm_ctx_priv_map *request = data; 2308c2ecf20Sopenharmony_ci struct drm_local_map *map = NULL; 2318c2ecf20Sopenharmony_ci struct drm_map_list *r_list = NULL; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 2348c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 2358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 2388c2ecf20Sopenharmony_ci list_for_each_entry(r_list, &dev->maplist, head) { 2398c2ecf20Sopenharmony_ci if (r_list->map 2408c2ecf20Sopenharmony_ci && r_list->user_token == (unsigned long) request->handle) 2418c2ecf20Sopenharmony_ci goto found; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci bad: 2448c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci found: 2488c2ecf20Sopenharmony_ci map = r_list->map; 2498c2ecf20Sopenharmony_ci if (!map) 2508c2ecf20Sopenharmony_ci goto bad; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id))) 2538c2ecf20Sopenharmony_ci goto bad; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/*@}*/ 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/******************************************************************/ 2638c2ecf20Sopenharmony_ci/** \name The actual DRM context handling routines */ 2648c2ecf20Sopenharmony_ci/*@{*/ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* 2678c2ecf20Sopenharmony_ci * Switch context. 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * \param dev DRM device. 2708c2ecf20Sopenharmony_ci * \param old old context handle. 2718c2ecf20Sopenharmony_ci * \param new new context handle. 2728c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * Attempt to set drm_device::context_flag. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic int drm_context_switch(struct drm_device * dev, int old, int new) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci if (test_and_set_bit(0, &dev->context_flag)) { 2798c2ecf20Sopenharmony_ci DRM_ERROR("Reentering -- FIXME\n"); 2808c2ecf20Sopenharmony_ci return -EBUSY; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci DRM_DEBUG("Context switch from %d to %d\n", old, new); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (new == dev->last_context) { 2868c2ecf20Sopenharmony_ci clear_bit(0, &dev->context_flag); 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * Complete context switch. 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * \param dev DRM device. 2978c2ecf20Sopenharmony_ci * \param new new context handle. 2988c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Updates drm_device::last_context and drm_device::last_switch. Verifies the 3018c2ecf20Sopenharmony_ci * hardware lock is held, clears the drm_device::context_flag and wakes up 3028c2ecf20Sopenharmony_ci * drm_device::context_wait. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cistatic int drm_context_switch_complete(struct drm_device *dev, 3058c2ecf20Sopenharmony_ci struct drm_file *file_priv, int new) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) { 3108c2ecf20Sopenharmony_ci DRM_ERROR("Lock isn't held after context switch\n"); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* If a context switch is ever initiated 3148c2ecf20Sopenharmony_ci when the kernel holds the lock, release 3158c2ecf20Sopenharmony_ci that lock here. */ 3168c2ecf20Sopenharmony_ci clear_bit(0, &dev->context_flag); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* 3228c2ecf20Sopenharmony_ci * Reserve contexts. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * \param inode device inode. 3258c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 3268c2ecf20Sopenharmony_ci * \param cmd command. 3278c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx_res structure. 3288c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ciint drm_legacy_resctx(struct drm_device *dev, void *data, 3318c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct drm_ctx_res *res = data; 3348c2ecf20Sopenharmony_ci struct drm_ctx ctx; 3358c2ecf20Sopenharmony_ci int i; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 3388c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 3398c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (res->count >= DRM_RESERVED_CONTEXTS) { 3428c2ecf20Sopenharmony_ci memset(&ctx, 0, sizeof(ctx)); 3438c2ecf20Sopenharmony_ci for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 3448c2ecf20Sopenharmony_ci ctx.handle = i; 3458c2ecf20Sopenharmony_ci if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx))) 3468c2ecf20Sopenharmony_ci return -EFAULT; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci res->count = DRM_RESERVED_CONTEXTS; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* 3558c2ecf20Sopenharmony_ci * Add context. 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * \param inode device inode. 3588c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 3598c2ecf20Sopenharmony_ci * \param cmd command. 3608c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx structure. 3618c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * Get a new handle for the context and copy to userspace. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ciint drm_legacy_addctx(struct drm_device *dev, void *data, 3668c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct drm_ctx_list *ctx_entry; 3698c2ecf20Sopenharmony_ci struct drm_ctx *ctx = data; 3708c2ecf20Sopenharmony_ci int tmp_handle; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 3738c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 3748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci tmp_handle = drm_legacy_ctxbitmap_next(dev); 3778c2ecf20Sopenharmony_ci if (tmp_handle == DRM_KERNEL_CONTEXT) { 3788c2ecf20Sopenharmony_ci /* Skip kernel's context and get a new one. */ 3798c2ecf20Sopenharmony_ci tmp_handle = drm_legacy_ctxbitmap_next(dev); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci DRM_DEBUG("%d\n", tmp_handle); 3828c2ecf20Sopenharmony_ci if (tmp_handle < 0) { 3838c2ecf20Sopenharmony_ci DRM_DEBUG("Not enough free contexts.\n"); 3848c2ecf20Sopenharmony_ci /* Should this return -EBUSY instead? */ 3858c2ecf20Sopenharmony_ci return tmp_handle; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ctx->handle = tmp_handle; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL); 3918c2ecf20Sopenharmony_ci if (!ctx_entry) { 3928c2ecf20Sopenharmony_ci DRM_DEBUG("out of memory\n"); 3938c2ecf20Sopenharmony_ci return -ENOMEM; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctx_entry->head); 3978c2ecf20Sopenharmony_ci ctx_entry->handle = ctx->handle; 3988c2ecf20Sopenharmony_ci ctx_entry->tag = file_priv; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci mutex_lock(&dev->ctxlist_mutex); 4018c2ecf20Sopenharmony_ci list_add(&ctx_entry->head, &dev->ctxlist); 4028c2ecf20Sopenharmony_ci mutex_unlock(&dev->ctxlist_mutex); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/* 4088c2ecf20Sopenharmony_ci * Get context. 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * \param inode device inode. 4118c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 4128c2ecf20Sopenharmony_ci * \param cmd command. 4138c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx structure. 4148c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_ciint drm_legacy_getctx(struct drm_device *dev, void *data, 4178c2ecf20Sopenharmony_ci struct drm_file *file_priv) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct drm_ctx *ctx = data; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 4228c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 4238c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* This is 0, because we don't handle any context flags */ 4268c2ecf20Sopenharmony_ci ctx->flags = 0; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* 4328c2ecf20Sopenharmony_ci * Switch context. 4338c2ecf20Sopenharmony_ci * 4348c2ecf20Sopenharmony_ci * \param inode device inode. 4358c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 4368c2ecf20Sopenharmony_ci * \param cmd command. 4378c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx structure. 4388c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * Calls context_switch(). 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ciint drm_legacy_switchctx(struct drm_device *dev, void *data, 4438c2ecf20Sopenharmony_ci struct drm_file *file_priv) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct drm_ctx *ctx = data; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 4488c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 4498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci DRM_DEBUG("%d\n", ctx->handle); 4528c2ecf20Sopenharmony_ci return drm_context_switch(dev, dev->last_context, ctx->handle); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/* 4568c2ecf20Sopenharmony_ci * New context. 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci * \param inode device inode. 4598c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 4608c2ecf20Sopenharmony_ci * \param cmd command. 4618c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx structure. 4628c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 4638c2ecf20Sopenharmony_ci * 4648c2ecf20Sopenharmony_ci * Calls context_switch_complete(). 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ciint drm_legacy_newctx(struct drm_device *dev, void *data, 4678c2ecf20Sopenharmony_ci struct drm_file *file_priv) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct drm_ctx *ctx = data; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 4728c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 4738c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci DRM_DEBUG("%d\n", ctx->handle); 4768c2ecf20Sopenharmony_ci drm_context_switch_complete(dev, file_priv, ctx->handle); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* 4828c2ecf20Sopenharmony_ci * Remove context. 4838c2ecf20Sopenharmony_ci * 4848c2ecf20Sopenharmony_ci * \param inode device inode. 4858c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 4868c2ecf20Sopenharmony_ci * \param cmd command. 4878c2ecf20Sopenharmony_ci * \param arg user argument pointing to a drm_ctx structure. 4888c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 4898c2ecf20Sopenharmony_ci * 4908c2ecf20Sopenharmony_ci * If not the special kernel context, calls ctxbitmap_free() to free the specified context. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ciint drm_legacy_rmctx(struct drm_device *dev, void *data, 4938c2ecf20Sopenharmony_ci struct drm_file *file_priv) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct drm_ctx *ctx = data; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && 4988c2ecf20Sopenharmony_ci !drm_core_check_feature(dev, DRIVER_LEGACY)) 4998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci DRM_DEBUG("%d\n", ctx->handle); 5028c2ecf20Sopenharmony_ci if (ctx->handle != DRM_KERNEL_CONTEXT) { 5038c2ecf20Sopenharmony_ci if (dev->driver->context_dtor) 5048c2ecf20Sopenharmony_ci dev->driver->context_dtor(dev, ctx->handle); 5058c2ecf20Sopenharmony_ci drm_legacy_ctxbitmap_free(dev, ctx->handle); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci mutex_lock(&dev->ctxlist_mutex); 5098c2ecf20Sopenharmony_ci if (!list_empty(&dev->ctxlist)) { 5108c2ecf20Sopenharmony_ci struct drm_ctx_list *pos, *n; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { 5138c2ecf20Sopenharmony_ci if (pos->handle == ctx->handle) { 5148c2ecf20Sopenharmony_ci list_del(&pos->head); 5158c2ecf20Sopenharmony_ci kfree(pos); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci mutex_unlock(&dev->ctxlist_mutex); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/*@}*/ 525