xref: /freebsd/sys/dev/drm2/drm_stub.c (revision 685dc743)
1592ffb21SWarner Losh /**
2592ffb21SWarner Losh  * \file drm_stub.h
3592ffb21SWarner Losh  * Stub support
4592ffb21SWarner Losh  *
5592ffb21SWarner Losh  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6592ffb21SWarner Losh  */
7592ffb21SWarner Losh 
8592ffb21SWarner Losh /*
9592ffb21SWarner Losh  * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
10592ffb21SWarner Losh  *
11592ffb21SWarner Losh  * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
12592ffb21SWarner Losh  * All Rights Reserved.
13592ffb21SWarner Losh  *
14592ffb21SWarner Losh  * Permission is hereby granted, free of charge, to any person obtaining a
15592ffb21SWarner Losh  * copy of this software and associated documentation files (the "Software"),
16592ffb21SWarner Losh  * to deal in the Software without restriction, including without limitation
17592ffb21SWarner Losh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18592ffb21SWarner Losh  * and/or sell copies of the Software, and to permit persons to whom the
19592ffb21SWarner Losh  * Software is furnished to do so, subject to the following conditions:
20592ffb21SWarner Losh  *
21592ffb21SWarner Losh  * The above copyright notice and this permission notice (including the next
22592ffb21SWarner Losh  * paragraph) shall be included in all copies or substantial portions of the
23592ffb21SWarner Losh  * Software.
24592ffb21SWarner Losh  *
25592ffb21SWarner Losh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26592ffb21SWarner Losh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27592ffb21SWarner Losh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28592ffb21SWarner Losh  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29592ffb21SWarner Losh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30592ffb21SWarner Losh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31592ffb21SWarner Losh  * DEALINGS IN THE SOFTWARE.
32592ffb21SWarner Losh  */
33592ffb21SWarner Losh 
34592ffb21SWarner Losh #include <sys/cdefs.h>
35592ffb21SWarner Losh #include <dev/drm2/drmP.h>
36592ffb21SWarner Losh #include <dev/drm2/drm_core.h>
37592ffb21SWarner Losh 
38592ffb21SWarner Losh #ifdef DRM_DEBUG_DEFAULT_ON
39592ffb21SWarner Losh unsigned int drm_debug = (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS |
40592ffb21SWarner Losh     DRM_DEBUGBITS_FAILED_IOCTL);
41592ffb21SWarner Losh #else
42592ffb21SWarner Losh unsigned int drm_debug = 0;	/* 1 to enable debug output */
43592ffb21SWarner Losh #endif
44592ffb21SWarner Losh EXPORT_SYMBOL(drm_debug);
45592ffb21SWarner Losh 
46592ffb21SWarner Losh unsigned int drm_notyet = 0;
47592ffb21SWarner Losh 
48592ffb21SWarner Losh unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
49592ffb21SWarner Losh EXPORT_SYMBOL(drm_vblank_offdelay);
50592ffb21SWarner Losh 
51592ffb21SWarner Losh unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
52592ffb21SWarner Losh EXPORT_SYMBOL(drm_timestamp_precision);
53592ffb21SWarner Losh 
54592ffb21SWarner Losh /*
55592ffb21SWarner Losh  * Default to use monotonic timestamps for wait-for-vblank and page-flip
56592ffb21SWarner Losh  * complete events.
57592ffb21SWarner Losh  */
58592ffb21SWarner Losh unsigned int drm_timestamp_monotonic = 1;
59592ffb21SWarner Losh 
60592ffb21SWarner Losh MODULE_AUTHOR(CORE_AUTHOR);
61592ffb21SWarner Losh MODULE_DESCRIPTION(CORE_DESC);
62592ffb21SWarner Losh MODULE_LICENSE("GPL and additional rights");
63592ffb21SWarner Losh MODULE_PARM_DESC(debug, "Enable debug output");
64592ffb21SWarner Losh MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
65592ffb21SWarner Losh MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
66592ffb21SWarner Losh MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
67592ffb21SWarner Losh 
68592ffb21SWarner Losh module_param_named(debug, drm_debug, int, 0600);
69592ffb21SWarner Losh module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
70592ffb21SWarner Losh module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
71592ffb21SWarner Losh module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
72592ffb21SWarner Losh 
73592ffb21SWarner Losh static struct cdevsw drm_cdevsw = {
74592ffb21SWarner Losh 	.d_version =	D_VERSION,
75592ffb21SWarner Losh 	.d_open =	drm_open,
76592ffb21SWarner Losh 	.d_read =	drm_read,
77592ffb21SWarner Losh 	.d_ioctl =	drm_ioctl,
78592ffb21SWarner Losh 	.d_poll =	drm_poll,
79592ffb21SWarner Losh 	.d_mmap_single = drm_mmap_single,
80592ffb21SWarner Losh 	.d_name =	"drm",
81592ffb21SWarner Losh 	.d_flags =	D_TRACKCLOSE
82592ffb21SWarner Losh };
83592ffb21SWarner Losh 
drm_minor_get_id(struct drm_device * dev,int type)84592ffb21SWarner Losh static int drm_minor_get_id(struct drm_device *dev, int type)
85592ffb21SWarner Losh {
86592ffb21SWarner Losh 	int new_id;
87592ffb21SWarner Losh 
88592ffb21SWarner Losh 	new_id = device_get_unit(dev->dev);
89592ffb21SWarner Losh 
90592ffb21SWarner Losh 	if (new_id >= 64)
91592ffb21SWarner Losh 		return -EINVAL;
92592ffb21SWarner Losh 
93592ffb21SWarner Losh 	if (type == DRM_MINOR_CONTROL) {
94592ffb21SWarner Losh 		new_id += 64;
95592ffb21SWarner Losh 	} else if (type == DRM_MINOR_RENDER) {
96592ffb21SWarner Losh 		new_id += 128;
97592ffb21SWarner Losh 	}
98592ffb21SWarner Losh 
99592ffb21SWarner Losh 	return new_id;
100592ffb21SWarner Losh }
101592ffb21SWarner Losh 
drm_master_create(struct drm_minor * minor)102592ffb21SWarner Losh struct drm_master *drm_master_create(struct drm_minor *minor)
103592ffb21SWarner Losh {
104592ffb21SWarner Losh 	struct drm_master *master;
105592ffb21SWarner Losh 
106592ffb21SWarner Losh 	master = malloc(sizeof(*master), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
107592ffb21SWarner Losh 	if (!master)
108592ffb21SWarner Losh 		return NULL;
109592ffb21SWarner Losh 
110592ffb21SWarner Losh 	refcount_init(&master->refcount, 1);
111592ffb21SWarner Losh 	mtx_init(&master->lock.spinlock, "drm_master__lock__spinlock",
112592ffb21SWarner Losh 	    NULL, MTX_DEF);
113592ffb21SWarner Losh 	DRM_INIT_WAITQUEUE(&master->lock.lock_queue);
114592ffb21SWarner Losh 	drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
115592ffb21SWarner Losh 	INIT_LIST_HEAD(&master->magicfree);
116592ffb21SWarner Losh 	master->minor = minor;
117592ffb21SWarner Losh 
118592ffb21SWarner Losh 	list_add_tail(&master->head, &minor->master_list);
119592ffb21SWarner Losh 
120592ffb21SWarner Losh 	return master;
121592ffb21SWarner Losh }
122592ffb21SWarner Losh 
drm_master_get(struct drm_master * master)123592ffb21SWarner Losh struct drm_master *drm_master_get(struct drm_master *master)
124592ffb21SWarner Losh {
125592ffb21SWarner Losh 	refcount_acquire(&master->refcount);
126592ffb21SWarner Losh 	return master;
127592ffb21SWarner Losh }
128592ffb21SWarner Losh EXPORT_SYMBOL(drm_master_get);
129592ffb21SWarner Losh 
drm_master_destroy(struct drm_master * master)130592ffb21SWarner Losh static void drm_master_destroy(struct drm_master *master)
131592ffb21SWarner Losh {
132592ffb21SWarner Losh 	struct drm_magic_entry *pt, *next;
133592ffb21SWarner Losh 	struct drm_device *dev = master->minor->dev;
134592ffb21SWarner Losh 	struct drm_map_list *r_list, *list_temp;
135592ffb21SWarner Losh 
136592ffb21SWarner Losh 	list_del(&master->head);
137592ffb21SWarner Losh 
138592ffb21SWarner Losh 	if (dev->driver->master_destroy)
139592ffb21SWarner Losh 		dev->driver->master_destroy(dev, master);
140592ffb21SWarner Losh 
141592ffb21SWarner Losh 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) {
142592ffb21SWarner Losh 		if (r_list->master == master) {
143592ffb21SWarner Losh 			drm_rmmap_locked(dev, r_list->map);
144592ffb21SWarner Losh 			r_list = NULL;
145592ffb21SWarner Losh 		}
146592ffb21SWarner Losh 	}
147592ffb21SWarner Losh 
148592ffb21SWarner Losh 	if (master->unique) {
149592ffb21SWarner Losh 		free(master->unique, DRM_MEM_DRIVER);
150592ffb21SWarner Losh 		master->unique = NULL;
151592ffb21SWarner Losh 		master->unique_len = 0;
152592ffb21SWarner Losh 	}
153592ffb21SWarner Losh 
154592ffb21SWarner Losh 	list_for_each_entry_safe(pt, next, &master->magicfree, head) {
155592ffb21SWarner Losh 		list_del(&pt->head);
156592ffb21SWarner Losh 		drm_ht_remove_item(&master->magiclist, &pt->hash_item);
157592ffb21SWarner Losh 		free(pt, DRM_MEM_MAGIC);
158592ffb21SWarner Losh 	}
159592ffb21SWarner Losh 
160592ffb21SWarner Losh 	drm_ht_remove(&master->magiclist);
161592ffb21SWarner Losh 
162592ffb21SWarner Losh 	free(master, DRM_MEM_KMS);
163592ffb21SWarner Losh }
164592ffb21SWarner Losh 
drm_master_put(struct drm_master ** master)165592ffb21SWarner Losh void drm_master_put(struct drm_master **master)
166592ffb21SWarner Losh {
167592ffb21SWarner Losh 	if (refcount_release(&(*master)->refcount))
168592ffb21SWarner Losh 		drm_master_destroy(*master);
169592ffb21SWarner Losh 	*master = NULL;
170592ffb21SWarner Losh }
171592ffb21SWarner Losh EXPORT_SYMBOL(drm_master_put);
172592ffb21SWarner Losh 
drm_setmaster_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)173592ffb21SWarner Losh int drm_setmaster_ioctl(struct drm_device *dev, void *data,
174592ffb21SWarner Losh 			struct drm_file *file_priv)
175592ffb21SWarner Losh {
176592ffb21SWarner Losh 	int ret;
177592ffb21SWarner Losh 
178592ffb21SWarner Losh 	if (file_priv->is_master)
179592ffb21SWarner Losh 		return 0;
180592ffb21SWarner Losh 
181592ffb21SWarner Losh 	if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
182592ffb21SWarner Losh 		return -EINVAL;
183592ffb21SWarner Losh 
184592ffb21SWarner Losh 	if (!file_priv->master)
185592ffb21SWarner Losh 		return -EINVAL;
186592ffb21SWarner Losh 
187592ffb21SWarner Losh 	if (file_priv->minor->master)
188592ffb21SWarner Losh 		return -EINVAL;
189592ffb21SWarner Losh 
190592ffb21SWarner Losh 	DRM_LOCK(dev);
191592ffb21SWarner Losh 	file_priv->minor->master = drm_master_get(file_priv->master);
192592ffb21SWarner Losh 	file_priv->is_master = 1;
193592ffb21SWarner Losh 	if (dev->driver->master_set) {
194592ffb21SWarner Losh 		ret = dev->driver->master_set(dev, file_priv, false);
195592ffb21SWarner Losh 		if (unlikely(ret != 0)) {
196592ffb21SWarner Losh 			file_priv->is_master = 0;
197592ffb21SWarner Losh 			drm_master_put(&file_priv->minor->master);
198592ffb21SWarner Losh 		}
199592ffb21SWarner Losh 	}
200592ffb21SWarner Losh 	DRM_UNLOCK(dev);
201592ffb21SWarner Losh 
202592ffb21SWarner Losh 	return 0;
203592ffb21SWarner Losh }
204592ffb21SWarner Losh 
drm_dropmaster_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)205592ffb21SWarner Losh int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
206592ffb21SWarner Losh 			 struct drm_file *file_priv)
207592ffb21SWarner Losh {
208592ffb21SWarner Losh 	if (!file_priv->is_master)
209592ffb21SWarner Losh 		return -EINVAL;
210592ffb21SWarner Losh 
211592ffb21SWarner Losh 	if (!file_priv->minor->master)
212592ffb21SWarner Losh 		return -EINVAL;
213592ffb21SWarner Losh 
214592ffb21SWarner Losh 	DRM_LOCK(dev);
215592ffb21SWarner Losh 	if (dev->driver->master_drop)
216592ffb21SWarner Losh 		dev->driver->master_drop(dev, file_priv, false);
217592ffb21SWarner Losh 	drm_master_put(&file_priv->minor->master);
218592ffb21SWarner Losh 	file_priv->is_master = 0;
219592ffb21SWarner Losh 	DRM_UNLOCK(dev);
220592ffb21SWarner Losh 	return 0;
221592ffb21SWarner Losh }
222592ffb21SWarner Losh 
drm_fill_in_dev(struct drm_device * dev,struct drm_driver * driver)223592ffb21SWarner Losh int drm_fill_in_dev(struct drm_device *dev,
224592ffb21SWarner Losh 			   struct drm_driver *driver)
225592ffb21SWarner Losh {
226592ffb21SWarner Losh 	int retcode, i;
227592ffb21SWarner Losh 
228592ffb21SWarner Losh 	INIT_LIST_HEAD(&dev->filelist);
229592ffb21SWarner Losh 	INIT_LIST_HEAD(&dev->ctxlist);
230592ffb21SWarner Losh 	INIT_LIST_HEAD(&dev->maplist);
231592ffb21SWarner Losh 	INIT_LIST_HEAD(&dev->vblank_event_list);
232592ffb21SWarner Losh 
233592ffb21SWarner Losh 	mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF);
234592ffb21SWarner Losh 	mtx_init(&dev->count_lock, "drmcount", NULL, MTX_DEF);
235592ffb21SWarner Losh 	mtx_init(&dev->event_lock, "drmev", NULL, MTX_DEF);
236592ffb21SWarner Losh 	sx_init(&dev->dev_struct_lock, "drmslk");
237592ffb21SWarner Losh 	mtx_init(&dev->ctxlist_mutex, "drmctxlist", NULL, MTX_DEF);
238592ffb21SWarner Losh 	mtx_init(&dev->pcir_lock, "drmpcir", NULL, MTX_DEF);
239592ffb21SWarner Losh 
240592ffb21SWarner Losh 	if (drm_ht_create(&dev->map_hash, 12)) {
241592ffb21SWarner Losh 		return -ENOMEM;
242592ffb21SWarner Losh 	}
243592ffb21SWarner Losh 
244592ffb21SWarner Losh 	/* the DRM has 6 basic counters */
245592ffb21SWarner Losh 	dev->counters = 6;
246592ffb21SWarner Losh 	dev->types[0] = _DRM_STAT_LOCK;
247592ffb21SWarner Losh 	dev->types[1] = _DRM_STAT_OPENS;
248592ffb21SWarner Losh 	dev->types[2] = _DRM_STAT_CLOSES;
249592ffb21SWarner Losh 	dev->types[3] = _DRM_STAT_IOCTLS;
250592ffb21SWarner Losh 	dev->types[4] = _DRM_STAT_LOCKS;
251592ffb21SWarner Losh 	dev->types[5] = _DRM_STAT_UNLOCKS;
252592ffb21SWarner Losh 
253592ffb21SWarner Losh 	/*
254592ffb21SWarner Losh 	 * FIXME Linux<->FreeBSD: this is done in drm_setup() on Linux.
255592ffb21SWarner Losh 	 */
256592ffb21SWarner Losh 	for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
257592ffb21SWarner Losh 		atomic_set(&dev->counts[i], 0);
258592ffb21SWarner Losh 
259592ffb21SWarner Losh 	dev->driver = driver;
260592ffb21SWarner Losh 
261592ffb21SWarner Losh 	retcode = drm_pci_agp_init(dev);
262592ffb21SWarner Losh 	if (retcode)
263592ffb21SWarner Losh 		goto error_out_unreg;
264592ffb21SWarner Losh 
265592ffb21SWarner Losh 
266592ffb21SWarner Losh 
267592ffb21SWarner Losh 	retcode = drm_ctxbitmap_init(dev);
268592ffb21SWarner Losh 	if (retcode) {
269592ffb21SWarner Losh 		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
270592ffb21SWarner Losh 		goto error_out_unreg;
271592ffb21SWarner Losh 	}
272592ffb21SWarner Losh 
273592ffb21SWarner Losh 	if (driver->driver_features & DRIVER_GEM) {
274592ffb21SWarner Losh 		retcode = drm_gem_init(dev);
275592ffb21SWarner Losh 		if (retcode) {
276592ffb21SWarner Losh 			DRM_ERROR("Cannot initialize graphics execution "
277592ffb21SWarner Losh 				  "manager (GEM)\n");
278592ffb21SWarner Losh 			goto error_out_unreg;
279592ffb21SWarner Losh 		}
280592ffb21SWarner Losh 	}
281592ffb21SWarner Losh 
282592ffb21SWarner Losh 	retcode = drm_sysctl_init(dev);
283592ffb21SWarner Losh 	if (retcode != 0) {
284592ffb21SWarner Losh 		DRM_ERROR("Failed to create hw.dri sysctl entry: %d\n",
285592ffb21SWarner Losh 		    retcode);
286592ffb21SWarner Losh 	}
287592ffb21SWarner Losh 
288592ffb21SWarner Losh 	return 0;
289592ffb21SWarner Losh 
290592ffb21SWarner Losh       error_out_unreg:
291592ffb21SWarner Losh 	drm_cancel_fill_in_dev(dev);
292592ffb21SWarner Losh 	return retcode;
293592ffb21SWarner Losh }
294592ffb21SWarner Losh EXPORT_SYMBOL(drm_fill_in_dev);
295592ffb21SWarner Losh 
drm_cancel_fill_in_dev(struct drm_device * dev)296592ffb21SWarner Losh void drm_cancel_fill_in_dev(struct drm_device *dev)
297592ffb21SWarner Losh {
298592ffb21SWarner Losh 	struct drm_driver *driver;
299592ffb21SWarner Losh 
300592ffb21SWarner Losh 	driver = dev->driver;
301592ffb21SWarner Losh 
302592ffb21SWarner Losh 	drm_sysctl_cleanup(dev);
303592ffb21SWarner Losh 	if (driver->driver_features & DRIVER_GEM)
304592ffb21SWarner Losh 		drm_gem_destroy(dev);
305592ffb21SWarner Losh 	drm_ctxbitmap_cleanup(dev);
306592ffb21SWarner Losh 
307592ffb21SWarner Losh 	if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
308592ffb21SWarner Losh 	    dev->agp && dev->agp->agp_mtrr >= 0) {
309592ffb21SWarner Losh 		int retval;
310592ffb21SWarner Losh 		retval = drm_mtrr_del(dev->agp->agp_mtrr,
311592ffb21SWarner Losh 				  dev->agp->agp_info.ai_aperture_base,
312592ffb21SWarner Losh 				  dev->agp->agp_info.ai_aperture_size,
313592ffb21SWarner Losh 				  DRM_MTRR_WC);
314592ffb21SWarner Losh 		DRM_DEBUG("mtrr_del=%d\n", retval);
315592ffb21SWarner Losh 	}
316592ffb21SWarner Losh 	free(dev->agp, DRM_MEM_AGPLISTS);
317592ffb21SWarner Losh 	dev->agp = NULL;
318592ffb21SWarner Losh 
319592ffb21SWarner Losh 	drm_ht_remove(&dev->map_hash);
320592ffb21SWarner Losh 
321592ffb21SWarner Losh 	mtx_destroy(&dev->irq_lock);
322592ffb21SWarner Losh 	mtx_destroy(&dev->count_lock);
323592ffb21SWarner Losh 	mtx_destroy(&dev->event_lock);
324592ffb21SWarner Losh 	sx_destroy(&dev->dev_struct_lock);
325592ffb21SWarner Losh 	mtx_destroy(&dev->ctxlist_mutex);
326592ffb21SWarner Losh 	mtx_destroy(&dev->pcir_lock);
327592ffb21SWarner Losh }
328592ffb21SWarner Losh 
329592ffb21SWarner Losh /**
330592ffb21SWarner Losh  * Get a secondary minor number.
331592ffb21SWarner Losh  *
332592ffb21SWarner Losh  * \param dev device data structure
333592ffb21SWarner Losh  * \param sec-minor structure to hold the assigned minor
334592ffb21SWarner Losh  * \return negative number on failure.
335592ffb21SWarner Losh  *
336592ffb21SWarner Losh  * Search an empty entry and initialize it to the given parameters, and
337592ffb21SWarner Losh  * create the proc init entry via proc_init(). This routines assigns
338592ffb21SWarner Losh  * minor numbers to secondary heads of multi-headed cards
339592ffb21SWarner Losh  */
drm_get_minor(struct drm_device * dev,struct drm_minor ** minor,int type)340592ffb21SWarner Losh int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
341592ffb21SWarner Losh {
342592ffb21SWarner Losh 	struct drm_minor *new_minor;
343592ffb21SWarner Losh 	int ret;
344592ffb21SWarner Losh 	int minor_id;
345592ffb21SWarner Losh 	const char *minor_devname;
346592ffb21SWarner Losh 
347592ffb21SWarner Losh 	DRM_DEBUG("\n");
348592ffb21SWarner Losh 
349592ffb21SWarner Losh 	minor_id = drm_minor_get_id(dev, type);
350592ffb21SWarner Losh 	if (minor_id < 0)
351592ffb21SWarner Losh 		return minor_id;
352592ffb21SWarner Losh 
353592ffb21SWarner Losh 	new_minor = malloc(sizeof(struct drm_minor), DRM_MEM_MINOR,
354592ffb21SWarner Losh 	    M_NOWAIT | M_ZERO);
355592ffb21SWarner Losh 	if (!new_minor) {
356592ffb21SWarner Losh 		ret = -ENOMEM;
357592ffb21SWarner Losh 		goto err_idr;
358592ffb21SWarner Losh 	}
359592ffb21SWarner Losh 
360592ffb21SWarner Losh 	new_minor->type = type;
361592ffb21SWarner Losh 	new_minor->dev = dev;
362592ffb21SWarner Losh 	new_minor->index = minor_id;
363592ffb21SWarner Losh 	INIT_LIST_HEAD(&new_minor->master_list);
364592ffb21SWarner Losh 
365592ffb21SWarner Losh 	new_minor->buf_sigio = NULL;
366592ffb21SWarner Losh 
367592ffb21SWarner Losh 	switch (type) {
368592ffb21SWarner Losh 	case DRM_MINOR_CONTROL:
369592ffb21SWarner Losh 		minor_devname = "dri/controlD%d";
370592ffb21SWarner Losh 		break;
371592ffb21SWarner Losh 	case DRM_MINOR_RENDER:
372592ffb21SWarner Losh 		minor_devname = "dri/renderD%d";
373592ffb21SWarner Losh 		break;
374592ffb21SWarner Losh 	default:
375592ffb21SWarner Losh 		minor_devname = "dri/card%d";
376592ffb21SWarner Losh 		break;
377592ffb21SWarner Losh 	}
378592ffb21SWarner Losh 
379592ffb21SWarner Losh 	ret = make_dev_p(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME, &new_minor->device,
380592ffb21SWarner Losh 	    &drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID,
381592ffb21SWarner Losh 	    DRM_DEV_MODE, minor_devname, minor_id);
382592ffb21SWarner Losh 	if (ret) {
383592ffb21SWarner Losh 		DRM_ERROR("Failed to create cdev: %d\n", ret);
384592ffb21SWarner Losh 		goto err_mem;
385592ffb21SWarner Losh 	}
386592ffb21SWarner Losh 	new_minor->device->si_drv1 = new_minor;
387592ffb21SWarner Losh 	*minor = new_minor;
388592ffb21SWarner Losh 
389592ffb21SWarner Losh 	DRM_DEBUG("new minor assigned %d\n", minor_id);
390592ffb21SWarner Losh 	return 0;
391592ffb21SWarner Losh 
392592ffb21SWarner Losh 
393592ffb21SWarner Losh err_mem:
394592ffb21SWarner Losh 	free(new_minor, DRM_MEM_MINOR);
395592ffb21SWarner Losh err_idr:
396592ffb21SWarner Losh 	*minor = NULL;
397592ffb21SWarner Losh 	return ret;
398592ffb21SWarner Losh }
399592ffb21SWarner Losh EXPORT_SYMBOL(drm_get_minor);
400592ffb21SWarner Losh 
401592ffb21SWarner Losh /**
402592ffb21SWarner Losh  * Put a secondary minor number.
403592ffb21SWarner Losh  *
404592ffb21SWarner Losh  * \param sec_minor - structure to be released
405592ffb21SWarner Losh  * \return always zero
406592ffb21SWarner Losh  *
407592ffb21SWarner Losh  * Cleans up the proc resources. Not legal for this to be the
408592ffb21SWarner Losh  * last minor released.
409592ffb21SWarner Losh  *
410592ffb21SWarner Losh  */
drm_put_minor(struct drm_minor ** minor_p)411592ffb21SWarner Losh int drm_put_minor(struct drm_minor **minor_p)
412592ffb21SWarner Losh {
413592ffb21SWarner Losh 	struct drm_minor *minor = *minor_p;
414592ffb21SWarner Losh 
415592ffb21SWarner Losh 	DRM_DEBUG("release secondary minor %d\n", minor->index);
416592ffb21SWarner Losh 
417592ffb21SWarner Losh 	funsetown(&minor->buf_sigio);
418592ffb21SWarner Losh 
419592ffb21SWarner Losh 	destroy_dev(minor->device);
420592ffb21SWarner Losh 
421592ffb21SWarner Losh 	free(minor, DRM_MEM_MINOR);
422592ffb21SWarner Losh 	*minor_p = NULL;
423592ffb21SWarner Losh 	return 0;
424592ffb21SWarner Losh }
425592ffb21SWarner Losh EXPORT_SYMBOL(drm_put_minor);
426592ffb21SWarner Losh 
427592ffb21SWarner Losh /**
428592ffb21SWarner Losh  * Called via drm_exit() at module unload time or when pci device is
429592ffb21SWarner Losh  * unplugged.
430592ffb21SWarner Losh  *
431592ffb21SWarner Losh  * Cleans up all DRM device, calling drm_lastclose().
432592ffb21SWarner Losh  *
433592ffb21SWarner Losh  */
drm_put_dev(struct drm_device * dev)434592ffb21SWarner Losh void drm_put_dev(struct drm_device *dev)
435592ffb21SWarner Losh {
436592ffb21SWarner Losh 	struct drm_driver *driver;
437592ffb21SWarner Losh 	struct drm_map_list *r_list, *list_temp;
438592ffb21SWarner Losh 
439592ffb21SWarner Losh 	DRM_DEBUG("\n");
440592ffb21SWarner Losh 
441592ffb21SWarner Losh 	if (!dev) {
442592ffb21SWarner Losh 		DRM_ERROR("cleanup called no dev\n");
443592ffb21SWarner Losh 		return;
444592ffb21SWarner Losh 	}
445592ffb21SWarner Losh 	driver = dev->driver;
446592ffb21SWarner Losh 
447592ffb21SWarner Losh 	drm_lastclose(dev);
448592ffb21SWarner Losh 
449592ffb21SWarner Losh 	if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
450592ffb21SWarner Losh 	    dev->agp && dev->agp->agp_mtrr >= 0) {
451592ffb21SWarner Losh 		int retval;
452592ffb21SWarner Losh 		retval = drm_mtrr_del(dev->agp->agp_mtrr,
453592ffb21SWarner Losh 				  dev->agp->agp_info.ai_aperture_base,
454592ffb21SWarner Losh 				  dev->agp->agp_info.ai_aperture_size,
455592ffb21SWarner Losh 				  DRM_MTRR_WC);
456592ffb21SWarner Losh 		DRM_DEBUG("mtrr_del=%d\n", retval);
457592ffb21SWarner Losh 	}
458592ffb21SWarner Losh 
459592ffb21SWarner Losh 	if (drm_core_check_feature(dev, DRIVER_MODESET))
460592ffb21SWarner Losh 		drm_mode_group_free(&dev->primary->mode_group);
461592ffb21SWarner Losh 
462592ffb21SWarner Losh 	if (dev->driver->unload)
463592ffb21SWarner Losh 		dev->driver->unload(dev);
464592ffb21SWarner Losh 
465592ffb21SWarner Losh 	drm_sysctl_cleanup(dev);
466592ffb21SWarner Losh 
467592ffb21SWarner Losh 	if (drm_core_has_AGP(dev) && dev->agp) {
468592ffb21SWarner Losh 		free(dev->agp, DRM_MEM_AGPLISTS);
469592ffb21SWarner Losh 		dev->agp = NULL;
470592ffb21SWarner Losh 	}
471592ffb21SWarner Losh 
472592ffb21SWarner Losh 	drm_vblank_cleanup(dev);
473592ffb21SWarner Losh 
474592ffb21SWarner Losh 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
475592ffb21SWarner Losh 		drm_rmmap(dev, r_list->map);
476592ffb21SWarner Losh 	drm_ht_remove(&dev->map_hash);
477592ffb21SWarner Losh 
478592ffb21SWarner Losh 	drm_ctxbitmap_cleanup(dev);
479592ffb21SWarner Losh 
480592ffb21SWarner Losh 	if (drm_core_check_feature(dev, DRIVER_MODESET))
481592ffb21SWarner Losh 		drm_put_minor(&dev->control);
482592ffb21SWarner Losh 
483592ffb21SWarner Losh 	if (driver->driver_features & DRIVER_GEM)
484592ffb21SWarner Losh 		drm_gem_destroy(dev);
485592ffb21SWarner Losh 
486592ffb21SWarner Losh 	drm_put_minor(&dev->primary);
487592ffb21SWarner Losh 
488592ffb21SWarner Losh 	mtx_destroy(&dev->irq_lock);
489592ffb21SWarner Losh 	mtx_destroy(&dev->count_lock);
490592ffb21SWarner Losh 	mtx_destroy(&dev->event_lock);
491592ffb21SWarner Losh 	sx_destroy(&dev->dev_struct_lock);
492592ffb21SWarner Losh 	mtx_destroy(&dev->ctxlist_mutex);
493592ffb21SWarner Losh 	mtx_destroy(&dev->pcir_lock);
494592ffb21SWarner Losh 
495592ffb21SWarner Losh #ifdef FREEBSD_NOTYET
496592ffb21SWarner Losh 	list_del(&dev->driver_item);
497592ffb21SWarner Losh #endif /* FREEBSD_NOTYET */
498592ffb21SWarner Losh }
499592ffb21SWarner Losh EXPORT_SYMBOL(drm_put_dev);
500