xref: /dragonfly/sys/dev/drm/drm_context.c (revision 3f2dd94a)
18b59d098SFrançois Tigeot /*
224edb884SFrançois Tigeot  * Legacy: Generic DRM Contexts
38b59d098SFrançois Tigeot  *
47f3c3d6fSHasso Tepper  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
57f3c3d6fSHasso Tepper  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
67f3c3d6fSHasso Tepper  * All Rights Reserved.
77f3c3d6fSHasso Tepper  *
824edb884SFrançois Tigeot  * Author: Rickard E. (Rik) Faith <faith@valinux.com>
924edb884SFrançois Tigeot  * Author: Gareth Hughes <gareth@valinux.com>
1024edb884SFrançois Tigeot  *
117f3c3d6fSHasso Tepper  * Permission is hereby granted, free of charge, to any person obtaining a
127f3c3d6fSHasso Tepper  * copy of this software and associated documentation files (the "Software"),
137f3c3d6fSHasso Tepper  * to deal in the Software without restriction, including without limitation
147f3c3d6fSHasso Tepper  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
157f3c3d6fSHasso Tepper  * and/or sell copies of the Software, and to permit persons to whom the
167f3c3d6fSHasso Tepper  * Software is furnished to do so, subject to the following conditions:
177f3c3d6fSHasso Tepper  *
187f3c3d6fSHasso Tepper  * The above copyright notice and this permission notice (including the next
197f3c3d6fSHasso Tepper  * paragraph) shall be included in all copies or substantial portions of the
207f3c3d6fSHasso Tepper  * Software.
217f3c3d6fSHasso Tepper  *
227f3c3d6fSHasso Tepper  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
237f3c3d6fSHasso Tepper  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
247f3c3d6fSHasso Tepper  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
257f3c3d6fSHasso Tepper  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
267f3c3d6fSHasso Tepper  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
277f3c3d6fSHasso Tepper  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
287f3c3d6fSHasso Tepper  * OTHER DEALINGS IN THE SOFTWARE.
297f3c3d6fSHasso Tepper  */
307f3c3d6fSHasso Tepper 
3118e26a6dSFrançois Tigeot #include <drm/drmP.h>
3224edb884SFrançois Tigeot #include "drm_legacy.h"
3324edb884SFrançois Tigeot 
3424edb884SFrançois Tigeot struct drm_ctx_list {
3524edb884SFrançois Tigeot 	struct list_head head;
3624edb884SFrançois Tigeot 	drm_context_t handle;
3724edb884SFrançois Tigeot 	struct drm_file *tag;
3824edb884SFrançois Tigeot };
397f3c3d6fSHasso Tepper 
408b59d098SFrançois Tigeot /******************************************************************/
418b59d098SFrançois Tigeot /** \name Context bitmap support */
428b59d098SFrançois Tigeot /*@{*/
4379f713b0SFrançois Tigeot 
448b59d098SFrançois Tigeot /**
458b59d098SFrançois Tigeot  * Free a handle from the context bitmap.
468b59d098SFrançois Tigeot  *
478b59d098SFrançois Tigeot  * \param dev DRM device.
488b59d098SFrançois Tigeot  * \param ctx_handle context handle.
498b59d098SFrançois Tigeot  *
508b59d098SFrançois Tigeot  * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
518b59d098SFrançois Tigeot  * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
528b59d098SFrançois Tigeot  * lock.
538b59d098SFrançois Tigeot  */
drm_legacy_ctxbitmap_free(struct drm_device * dev,int ctx_handle)5424edb884SFrançois Tigeot void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
557f3c3d6fSHasso Tepper {
56a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
571dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
58a05eeebfSFrançois Tigeot 		return;
59a05eeebfSFrançois Tigeot 
608b59d098SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
618b59d098SFrançois Tigeot 	idr_remove(&dev->ctx_idr, ctx_handle);
628b59d098SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
637f3c3d6fSHasso Tepper }
647f3c3d6fSHasso Tepper 
658b59d098SFrançois Tigeot /**
668b59d098SFrançois Tigeot  * Context bitmap allocation.
678b59d098SFrançois Tigeot  *
688b59d098SFrançois Tigeot  * \param dev DRM device.
698b59d098SFrançois Tigeot  * \return (non-negative) context handle on success or a negative number on failure.
708b59d098SFrançois Tigeot  *
718b59d098SFrançois Tigeot  * Allocate a new idr from drm_device::ctx_idr while holding the
728b59d098SFrançois Tigeot  * drm_device::struct_mutex lock.
738b59d098SFrançois Tigeot  */
drm_legacy_ctxbitmap_next(struct drm_device * dev)7424edb884SFrançois Tigeot static int drm_legacy_ctxbitmap_next(struct drm_device * dev)
757f3c3d6fSHasso Tepper {
768b59d098SFrançois Tigeot 	int ret;
777f3c3d6fSHasso Tepper 
788b59d098SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
798b59d098SFrançois Tigeot 	ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0,
808b59d098SFrançois Tigeot 			GFP_KERNEL);
818b59d098SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
828b59d098SFrançois Tigeot 	return ret;
837f3c3d6fSHasso Tepper }
847f3c3d6fSHasso Tepper 
858b59d098SFrançois Tigeot /**
868b59d098SFrançois Tigeot  * Context bitmap initialization.
878b59d098SFrançois Tigeot  *
888b59d098SFrançois Tigeot  * \param dev DRM device.
898b59d098SFrançois Tigeot  *
908b59d098SFrançois Tigeot  * Initialise the drm_device::ctx_idr
918b59d098SFrançois Tigeot  */
drm_legacy_ctxbitmap_init(struct drm_device * dev)92a05eeebfSFrançois Tigeot void drm_legacy_ctxbitmap_init(struct drm_device * dev)
937f3c3d6fSHasso Tepper {
94a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
951dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
96a05eeebfSFrançois Tigeot 		return;
97a05eeebfSFrançois Tigeot 
988b59d098SFrançois Tigeot 	idr_init(&dev->ctx_idr);
997f3c3d6fSHasso Tepper }
1007f3c3d6fSHasso Tepper 
1018b59d098SFrançois Tigeot /**
1028b59d098SFrançois Tigeot  * Context bitmap cleanup.
1038b59d098SFrançois Tigeot  *
1048b59d098SFrançois Tigeot  * \param dev DRM device.
1058b59d098SFrançois Tigeot  *
1068b59d098SFrançois Tigeot  * Free all idr members using drm_ctx_sarea_free helper function
1078b59d098SFrançois Tigeot  * while holding the drm_device::struct_mutex lock.
1088b59d098SFrançois Tigeot  */
drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)10924edb884SFrançois Tigeot void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
1107f3c3d6fSHasso Tepper {
111a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
1121dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
113a05eeebfSFrançois Tigeot 		return;
114a05eeebfSFrançois Tigeot 
1158b59d098SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1168b59d098SFrançois Tigeot 	idr_destroy(&dev->ctx_idr);
1178b59d098SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1187f3c3d6fSHasso Tepper }
1197f3c3d6fSHasso Tepper 
12024edb884SFrançois Tigeot /**
12124edb884SFrançois Tigeot  * drm_ctxbitmap_flush() - Flush all contexts owned by a file
12224edb884SFrançois Tigeot  * @dev: DRM device to operate on
12324edb884SFrançois Tigeot  * @file: Open file to flush contexts for
12424edb884SFrançois Tigeot  *
12524edb884SFrançois Tigeot  * This iterates over all contexts on @dev and drops them if they're owned by
12624edb884SFrançois Tigeot  * @file. Note that after this call returns, new contexts might be added if
12724edb884SFrançois Tigeot  * the file is still alive.
12824edb884SFrançois Tigeot  */
drm_legacy_ctxbitmap_flush(struct drm_device * dev,struct drm_file * file)12924edb884SFrançois Tigeot void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file)
13024edb884SFrançois Tigeot {
13124edb884SFrançois Tigeot 	struct drm_ctx_list *pos, *tmp;
13224edb884SFrançois Tigeot 
133a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
1341dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
135a05eeebfSFrançois Tigeot 		return;
136a05eeebfSFrançois Tigeot 
13724edb884SFrançois Tigeot 	mutex_lock(&dev->ctxlist_mutex);
13824edb884SFrançois Tigeot 
13924edb884SFrançois Tigeot 	list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) {
14024edb884SFrançois Tigeot 		if (pos->tag == file &&
14124edb884SFrançois Tigeot 		    pos->handle != DRM_KERNEL_CONTEXT) {
14224edb884SFrançois Tigeot 			if (dev->driver->context_dtor)
14324edb884SFrançois Tigeot 				dev->driver->context_dtor(dev, pos->handle);
14424edb884SFrançois Tigeot 
14524edb884SFrançois Tigeot 			drm_legacy_ctxbitmap_free(dev, pos->handle);
14624edb884SFrançois Tigeot 			list_del(&pos->head);
14724edb884SFrançois Tigeot 			kfree(pos);
14824edb884SFrançois Tigeot 		}
14924edb884SFrançois Tigeot 	}
15024edb884SFrançois Tigeot 
15124edb884SFrançois Tigeot 	mutex_unlock(&dev->ctxlist_mutex);
15224edb884SFrançois Tigeot }
15324edb884SFrançois Tigeot 
1548b59d098SFrançois Tigeot /*@}*/
15579f713b0SFrançois Tigeot 
1568b59d098SFrançois Tigeot /******************************************************************/
1578b59d098SFrançois Tigeot /** \name Per Context SAREA Support */
1588b59d098SFrançois Tigeot /*@{*/
1598b59d098SFrançois Tigeot 
1608b59d098SFrançois Tigeot /**
1618b59d098SFrançois Tigeot  * Get per-context SAREA.
1628b59d098SFrançois Tigeot  *
1638b59d098SFrançois Tigeot  * \param inode device inode.
1648b59d098SFrançois Tigeot  * \param file_priv DRM file private.
1658b59d098SFrançois Tigeot  * \param cmd command.
1668b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx_priv_map structure.
1678b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
1688b59d098SFrançois Tigeot  *
1698b59d098SFrançois Tigeot  * Gets the map from drm_device::ctx_idr with the handle specified and
1708b59d098SFrançois Tigeot  * returns its handle.
1718b59d098SFrançois Tigeot  */
drm_legacy_getsareactx(struct drm_device * dev,void * data,struct drm_file * file_priv)17224edb884SFrançois Tigeot int drm_legacy_getsareactx(struct drm_device *dev, void *data,
173b3705d71SHasso Tepper 			   struct drm_file *file_priv)
1747f3c3d6fSHasso Tepper {
175b3705d71SHasso Tepper 	struct drm_ctx_priv_map *request = data;
1768b59d098SFrançois Tigeot 	struct drm_local_map *map;
1778b59d098SFrançois Tigeot 	struct drm_map_list *_entry;
1787f3c3d6fSHasso Tepper 
179a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
1801dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
181a05eeebfSFrançois Tigeot 		return -EINVAL;
182a05eeebfSFrançois Tigeot 
1838b59d098SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1848b59d098SFrançois Tigeot 
1858b59d098SFrançois Tigeot 	map = idr_find(&dev->ctx_idr, request->ctx_id);
1868b59d098SFrançois Tigeot 	if (!map) {
1878b59d098SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
1888b59d098SFrançois Tigeot 		return -EINVAL;
1897f3c3d6fSHasso Tepper 	}
1907f3c3d6fSHasso Tepper 
1918b59d098SFrançois Tigeot 	request->handle = NULL;
1928b59d098SFrançois Tigeot 	list_for_each_entry(_entry, &dev->maplist, head) {
1938b59d098SFrançois Tigeot 		if (_entry->map == map) {
1948b59d098SFrançois Tigeot 			request->handle =
1958b59d098SFrançois Tigeot 			    (void *)(unsigned long)_entry->user_token;
1968b59d098SFrançois Tigeot 			break;
1978b59d098SFrançois Tigeot 		}
1988b59d098SFrançois Tigeot 	}
1997f3c3d6fSHasso Tepper 
2008b59d098SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
2018b59d098SFrançois Tigeot 
2028b59d098SFrançois Tigeot 	if (request->handle == NULL)
2038b59d098SFrançois Tigeot 		return -EINVAL;
2047f3c3d6fSHasso Tepper 
2057f3c3d6fSHasso Tepper 	return 0;
2067f3c3d6fSHasso Tepper }
2077f3c3d6fSHasso Tepper 
208f599cd46SFrançois Tigeot /**
209f599cd46SFrançois Tigeot  * Set per-context SAREA.
210f599cd46SFrançois Tigeot  *
211f599cd46SFrançois Tigeot  * \param inode device inode.
212f599cd46SFrançois Tigeot  * \param file_priv DRM file private.
213f599cd46SFrançois Tigeot  * \param cmd command.
214f599cd46SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx_priv_map structure.
215f599cd46SFrançois Tigeot  * \return zero on success or a negative number on failure.
216f599cd46SFrançois Tigeot  *
217f599cd46SFrançois Tigeot  * Searches the mapping specified in \p arg and update the entry in
218f599cd46SFrançois Tigeot  * drm_device::ctx_idr with it.
219f599cd46SFrançois Tigeot  */
drm_legacy_setsareactx(struct drm_device * dev,void * data,struct drm_file * file_priv)22024edb884SFrançois Tigeot int drm_legacy_setsareactx(struct drm_device *dev, void *data,
221b3705d71SHasso Tepper 			   struct drm_file *file_priv)
2227f3c3d6fSHasso Tepper {
223b3705d71SHasso Tepper 	struct drm_ctx_priv_map *request = data;
224f599cd46SFrançois Tigeot 	struct drm_local_map *map = NULL;
225f599cd46SFrançois Tigeot 	struct drm_map_list *r_list = NULL;
2267f3c3d6fSHasso Tepper 
227a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
2281dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
229a05eeebfSFrançois Tigeot 		return -EINVAL;
230a05eeebfSFrançois Tigeot 
2318b59d098SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
232f599cd46SFrançois Tigeot 	list_for_each_entry(r_list, &dev->maplist, head) {
233f599cd46SFrançois Tigeot 		if (r_list->map
2348b59d098SFrançois Tigeot 		    && r_list->user_token == (unsigned long) request->handle)
2358b59d098SFrançois Tigeot 			goto found;
2367f3c3d6fSHasso Tepper 	}
23779f713b0SFrançois Tigeot       bad:
2388b59d098SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
2398b59d098SFrançois Tigeot 	return -EINVAL;
2408b59d098SFrançois Tigeot 
2418b59d098SFrançois Tigeot       found:
2428b59d098SFrançois Tigeot 	map = r_list->map;
2438b59d098SFrançois Tigeot 	if (!map)
2448b59d098SFrançois Tigeot 		goto bad;
2458b59d098SFrançois Tigeot 
2468b59d098SFrançois Tigeot 	if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
2478b59d098SFrançois Tigeot 		goto bad;
2488b59d098SFrançois Tigeot 
2498b59d098SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
2508b59d098SFrançois Tigeot 
2518b59d098SFrançois Tigeot 	return 0;
25279f713b0SFrançois Tigeot }
2537f3c3d6fSHasso Tepper 
254e3b244c9SFrançois Tigeot /*@}*/
2557f3c3d6fSHasso Tepper 
256e3b244c9SFrançois Tigeot /******************************************************************/
257e3b244c9SFrançois Tigeot /** \name The actual DRM context handling routines */
258e3b244c9SFrançois Tigeot /*@{*/
259e3b244c9SFrançois Tigeot 
260e3b244c9SFrançois Tigeot /**
261e3b244c9SFrançois Tigeot  * Switch context.
262e3b244c9SFrançois Tigeot  *
263e3b244c9SFrançois Tigeot  * \param dev DRM device.
264e3b244c9SFrançois Tigeot  * \param old old context handle.
265e3b244c9SFrançois Tigeot  * \param new new context handle.
266e3b244c9SFrançois Tigeot  * \return zero on success or a negative number on failure.
267e3b244c9SFrançois Tigeot  *
268e3b244c9SFrançois Tigeot  * Attempt to set drm_device::context_flag.
269e3b244c9SFrançois Tigeot  */
drm_context_switch(struct drm_device * dev,int old,int new)270e3b244c9SFrançois Tigeot static int drm_context_switch(struct drm_device * dev, int old, int new)
2717f3c3d6fSHasso Tepper {
272e3b244c9SFrançois Tigeot 	if (test_and_set_bit(0, &dev->context_flag)) {
2737f3c3d6fSHasso Tepper 		DRM_ERROR("Reentering -- FIXME\n");
274e3b244c9SFrançois Tigeot 		return -EBUSY;
2757f3c3d6fSHasso Tepper 	}
2767f3c3d6fSHasso Tepper 
2777f3c3d6fSHasso Tepper 	DRM_DEBUG("Context switch from %d to %d\n", old, new);
2787f3c3d6fSHasso Tepper 
2797f3c3d6fSHasso Tepper 	if (new == dev->last_context) {
280e3b244c9SFrançois Tigeot 		clear_bit(0, &dev->context_flag);
2817f3c3d6fSHasso Tepper 		return 0;
2827f3c3d6fSHasso Tepper 	}
2837f3c3d6fSHasso Tepper 
2847f3c3d6fSHasso Tepper 	return 0;
2857f3c3d6fSHasso Tepper }
2867f3c3d6fSHasso Tepper 
287e3b244c9SFrançois Tigeot /**
288e3b244c9SFrançois Tigeot  * Complete context switch.
289e3b244c9SFrançois Tigeot  *
290e3b244c9SFrançois Tigeot  * \param dev DRM device.
291e3b244c9SFrançois Tigeot  * \param new new context handle.
292e3b244c9SFrançois Tigeot  * \return zero on success or a negative number on failure.
293e3b244c9SFrançois Tigeot  *
294e3b244c9SFrançois Tigeot  * Updates drm_device::last_context and drm_device::last_switch. Verifies the
295e3b244c9SFrançois Tigeot  * hardware lock is held, clears the drm_device::context_flag and wakes up
296e3b244c9SFrançois Tigeot  * drm_device::context_wait.
297e3b244c9SFrançois Tigeot  */
drm_context_switch_complete(struct drm_device * dev,struct drm_file * file_priv,int new)2988b59d098SFrançois Tigeot static int drm_context_switch_complete(struct drm_device *dev,
2998b59d098SFrançois Tigeot 				       struct drm_file *file_priv, int new)
3007f3c3d6fSHasso Tepper {
3017f3c3d6fSHasso Tepper 	dev->last_context = new;	/* PRE/POST: This is the _only_ writer. */
3027f3c3d6fSHasso Tepper 
303*3f2dd94aSFrançois Tigeot 	if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
3047f3c3d6fSHasso Tepper 		DRM_ERROR("Lock isn't held after context switch\n");
3057f3c3d6fSHasso Tepper 	}
3067f3c3d6fSHasso Tepper 
3077f3c3d6fSHasso Tepper 	/* If a context switch is ever initiated
3087f3c3d6fSHasso Tepper 	   when the kernel holds the lock, release
3097f3c3d6fSHasso Tepper 	   that lock here. */
310e3b244c9SFrançois Tigeot 	clear_bit(0, &dev->context_flag);
3117f3c3d6fSHasso Tepper 
3127f3c3d6fSHasso Tepper 	return 0;
3137f3c3d6fSHasso Tepper }
3147f3c3d6fSHasso Tepper 
3158b59d098SFrançois Tigeot /**
3168b59d098SFrançois Tigeot  * Reserve contexts.
3178b59d098SFrançois Tigeot  *
3188b59d098SFrançois Tigeot  * \param inode device inode.
3198b59d098SFrançois Tigeot  * \param file_priv DRM file private.
3208b59d098SFrançois Tigeot  * \param cmd command.
3218b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx_res structure.
3228b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
3238b59d098SFrançois Tigeot  */
drm_legacy_resctx(struct drm_device * dev,void * data,struct drm_file * file_priv)32424edb884SFrançois Tigeot int drm_legacy_resctx(struct drm_device *dev, void *data,
3258b59d098SFrançois Tigeot 		      struct drm_file *file_priv)
3267f3c3d6fSHasso Tepper {
327b3705d71SHasso Tepper 	struct drm_ctx_res *res = data;
328b3705d71SHasso Tepper 	struct drm_ctx ctx;
3297f3c3d6fSHasso Tepper 	int i;
3307f3c3d6fSHasso Tepper 
331a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
3321dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
333a05eeebfSFrançois Tigeot 		return -EINVAL;
334a05eeebfSFrançois Tigeot 
3357f3c3d6fSHasso Tepper 	if (res->count >= DRM_RESERVED_CONTEXTS) {
3368b59d098SFrançois Tigeot 		memset(&ctx, 0, sizeof(ctx));
3377f3c3d6fSHasso Tepper 		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
3387f3c3d6fSHasso Tepper 			ctx.handle = i;
3398b59d098SFrançois Tigeot 			if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
3408b59d098SFrançois Tigeot 				return -EFAULT;
3417f3c3d6fSHasso Tepper 		}
3427f3c3d6fSHasso Tepper 	}
3437f3c3d6fSHasso Tepper 	res->count = DRM_RESERVED_CONTEXTS;
3447f3c3d6fSHasso Tepper 
3457f3c3d6fSHasso Tepper 	return 0;
3467f3c3d6fSHasso Tepper }
3477f3c3d6fSHasso Tepper 
3488b59d098SFrançois Tigeot /**
3498b59d098SFrançois Tigeot  * Add context.
3508b59d098SFrançois Tigeot  *
3518b59d098SFrançois Tigeot  * \param inode device inode.
3528b59d098SFrançois Tigeot  * \param file_priv DRM file private.
3538b59d098SFrançois Tigeot  * \param cmd command.
3548b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx structure.
3558b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
3568b59d098SFrançois Tigeot  *
3578b59d098SFrançois Tigeot  * Get a new handle for the context and copy to userspace.
3588b59d098SFrançois Tigeot  */
drm_legacy_addctx(struct drm_device * dev,void * data,struct drm_file * file_priv)35924edb884SFrançois Tigeot int drm_legacy_addctx(struct drm_device *dev, void *data,
3608b59d098SFrançois Tigeot 		      struct drm_file *file_priv)
3617f3c3d6fSHasso Tepper {
3628b59d098SFrançois Tigeot 	struct drm_ctx_list *ctx_entry;
363b3705d71SHasso Tepper 	struct drm_ctx *ctx = data;
3647f3c3d6fSHasso Tepper 
365a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
3661dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
367a05eeebfSFrançois Tigeot 		return -EINVAL;
368a05eeebfSFrançois Tigeot 
36924edb884SFrançois Tigeot 	ctx->handle = drm_legacy_ctxbitmap_next(dev);
3707f3c3d6fSHasso Tepper 	if (ctx->handle == DRM_KERNEL_CONTEXT) {
3717f3c3d6fSHasso Tepper 		/* Skip kernel's context and get a new one. */
37224edb884SFrançois Tigeot 		ctx->handle = drm_legacy_ctxbitmap_next(dev);
3737f3c3d6fSHasso Tepper 	}
3747f3c3d6fSHasso Tepper 	DRM_DEBUG("%d\n", ctx->handle);
3757f3c3d6fSHasso Tepper 	if (ctx->handle == -1) {
3767f3c3d6fSHasso Tepper 		DRM_DEBUG("Not enough free contexts.\n");
3777f3c3d6fSHasso Tepper 		/* Should this return -EBUSY instead? */
3788b59d098SFrançois Tigeot 		return -ENOMEM;
3797f3c3d6fSHasso Tepper 	}
3807f3c3d6fSHasso Tepper 
381*3f2dd94aSFrançois Tigeot 	ctx_entry = kmalloc(sizeof(*ctx_entry), M_DRM, GFP_KERNEL);
3828b59d098SFrançois Tigeot 	if (!ctx_entry) {
3838b59d098SFrançois Tigeot 		DRM_DEBUG("out of memory\n");
3848b59d098SFrançois Tigeot 		return -ENOMEM;
3857f3c3d6fSHasso Tepper 	}
3867f3c3d6fSHasso Tepper 
3878b59d098SFrançois Tigeot 	INIT_LIST_HEAD(&ctx_entry->head);
3888b59d098SFrançois Tigeot 	ctx_entry->handle = ctx->handle;
3898b59d098SFrançois Tigeot 	ctx_entry->tag = file_priv;
3908b59d098SFrançois Tigeot 
3918b59d098SFrançois Tigeot 	mutex_lock(&dev->ctxlist_mutex);
3928b59d098SFrançois Tigeot 	list_add(&ctx_entry->head, &dev->ctxlist);
3938b59d098SFrançois Tigeot 	mutex_unlock(&dev->ctxlist_mutex);
3948b59d098SFrançois Tigeot 
3957f3c3d6fSHasso Tepper 	return 0;
3967f3c3d6fSHasso Tepper }
3977f3c3d6fSHasso Tepper 
3988b59d098SFrançois Tigeot /**
3998b59d098SFrançois Tigeot  * Get context.
4008b59d098SFrançois Tigeot  *
4018b59d098SFrançois Tigeot  * \param inode device inode.
4028b59d098SFrançois Tigeot  * \param file_priv DRM file private.
4038b59d098SFrançois Tigeot  * \param cmd command.
4048b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx structure.
4058b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
4068b59d098SFrançois Tigeot  */
drm_legacy_getctx(struct drm_device * dev,void * data,struct drm_file * file_priv)40724edb884SFrançois Tigeot int drm_legacy_getctx(struct drm_device *dev, void *data,
40824edb884SFrançois Tigeot 		      struct drm_file *file_priv)
4097f3c3d6fSHasso Tepper {
410b3705d71SHasso Tepper 	struct drm_ctx *ctx = data;
4117f3c3d6fSHasso Tepper 
412a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
4131dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
414a05eeebfSFrançois Tigeot 		return -EINVAL;
415a05eeebfSFrançois Tigeot 
4167f3c3d6fSHasso Tepper 	/* This is 0, because we don't handle any context flags */
4177f3c3d6fSHasso Tepper 	ctx->flags = 0;
4187f3c3d6fSHasso Tepper 
4197f3c3d6fSHasso Tepper 	return 0;
4207f3c3d6fSHasso Tepper }
4217f3c3d6fSHasso Tepper 
4228b59d098SFrançois Tigeot /**
4238b59d098SFrançois Tigeot  * Switch context.
4248b59d098SFrançois Tigeot  *
4258b59d098SFrançois Tigeot  * \param inode device inode.
4268b59d098SFrançois Tigeot  * \param file_priv DRM file private.
4278b59d098SFrançois Tigeot  * \param cmd command.
4288b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx structure.
4298b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
4308b59d098SFrançois Tigeot  *
4318b59d098SFrançois Tigeot  * Calls context_switch().
4328b59d098SFrançois Tigeot  */
drm_legacy_switchctx(struct drm_device * dev,void * data,struct drm_file * file_priv)43324edb884SFrançois Tigeot int drm_legacy_switchctx(struct drm_device *dev, void *data,
434b3705d71SHasso Tepper 			 struct drm_file *file_priv)
4357f3c3d6fSHasso Tepper {
436b3705d71SHasso Tepper 	struct drm_ctx *ctx = data;
4377f3c3d6fSHasso Tepper 
438a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
4391dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
440a05eeebfSFrançois Tigeot 		return -EINVAL;
441a05eeebfSFrançois Tigeot 
4427f3c3d6fSHasso Tepper 	DRM_DEBUG("%d\n", ctx->handle);
4437f3c3d6fSHasso Tepper 	return drm_context_switch(dev, dev->last_context, ctx->handle);
4447f3c3d6fSHasso Tepper }
4457f3c3d6fSHasso Tepper 
4468b59d098SFrançois Tigeot /**
4478b59d098SFrançois Tigeot  * New context.
4488b59d098SFrançois Tigeot  *
4498b59d098SFrançois Tigeot  * \param inode device inode.
4508b59d098SFrançois Tigeot  * \param file_priv DRM file private.
4518b59d098SFrançois Tigeot  * \param cmd command.
4528b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx structure.
4538b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
4548b59d098SFrançois Tigeot  *
4558b59d098SFrançois Tigeot  * Calls context_switch_complete().
4568b59d098SFrançois Tigeot  */
drm_legacy_newctx(struct drm_device * dev,void * data,struct drm_file * file_priv)45724edb884SFrançois Tigeot int drm_legacy_newctx(struct drm_device *dev, void *data,
4588b59d098SFrançois Tigeot 		      struct drm_file *file_priv)
4597f3c3d6fSHasso Tepper {
460b3705d71SHasso Tepper 	struct drm_ctx *ctx = data;
4617f3c3d6fSHasso Tepper 
462a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
4631dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
464a05eeebfSFrançois Tigeot 		return -EINVAL;
465a05eeebfSFrançois Tigeot 
4667f3c3d6fSHasso Tepper 	DRM_DEBUG("%d\n", ctx->handle);
4678b59d098SFrançois Tigeot 	drm_context_switch_complete(dev, file_priv, ctx->handle);
4687f3c3d6fSHasso Tepper 
4697f3c3d6fSHasso Tepper 	return 0;
4707f3c3d6fSHasso Tepper }
4717f3c3d6fSHasso Tepper 
4728b59d098SFrançois Tigeot /**
4738b59d098SFrançois Tigeot  * Remove context.
4748b59d098SFrançois Tigeot  *
4758b59d098SFrançois Tigeot  * \param inode device inode.
4768b59d098SFrançois Tigeot  * \param file_priv DRM file private.
4778b59d098SFrançois Tigeot  * \param cmd command.
4788b59d098SFrançois Tigeot  * \param arg user argument pointing to a drm_ctx structure.
4798b59d098SFrançois Tigeot  * \return zero on success or a negative number on failure.
4808b59d098SFrançois Tigeot  *
4818b59d098SFrançois Tigeot  * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
4828b59d098SFrançois Tigeot  */
drm_legacy_rmctx(struct drm_device * dev,void * data,struct drm_file * file_priv)48324edb884SFrançois Tigeot int drm_legacy_rmctx(struct drm_device *dev, void *data,
4848b59d098SFrançois Tigeot 		     struct drm_file *file_priv)
4857f3c3d6fSHasso Tepper {
486b3705d71SHasso Tepper 	struct drm_ctx *ctx = data;
4877f3c3d6fSHasso Tepper 
488a05eeebfSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
4891dedbd3bSFrançois Tigeot 	    !drm_core_check_feature(dev, DRIVER_LEGACY))
490a05eeebfSFrançois Tigeot 		return -EINVAL;
491a05eeebfSFrançois Tigeot 
4927f3c3d6fSHasso Tepper 	DRM_DEBUG("%d\n", ctx->handle);
4937f3c3d6fSHasso Tepper 	if (ctx->handle != DRM_KERNEL_CONTEXT) {
4948b59d098SFrançois Tigeot 		if (dev->driver->context_dtor)
495b3705d71SHasso Tepper 			dev->driver->context_dtor(dev, ctx->handle);
49624edb884SFrançois Tigeot 		drm_legacy_ctxbitmap_free(dev, ctx->handle);
4977f3c3d6fSHasso Tepper 	}
4987f3c3d6fSHasso Tepper 
4998b59d098SFrançois Tigeot 	mutex_lock(&dev->ctxlist_mutex);
5008b59d098SFrançois Tigeot 	if (!list_empty(&dev->ctxlist)) {
5018b59d098SFrançois Tigeot 		struct drm_ctx_list *pos, *n;
5028b59d098SFrançois Tigeot 
5038b59d098SFrançois Tigeot 		list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
5048b59d098SFrançois Tigeot 			if (pos->handle == ctx->handle) {
5058b59d098SFrançois Tigeot 				list_del(&pos->head);
5068b59d098SFrançois Tigeot 				kfree(pos);
5078b59d098SFrançois Tigeot 			}
5088b59d098SFrançois Tigeot 		}
5098b59d098SFrançois Tigeot 	}
5108b59d098SFrançois Tigeot 	mutex_unlock(&dev->ctxlist_mutex);
5118b59d098SFrançois Tigeot 
5127f3c3d6fSHasso Tepper 	return 0;
5137f3c3d6fSHasso Tepper }
5148b59d098SFrançois Tigeot 
5158b59d098SFrançois Tigeot /*@}*/
516