drm_drv.c revision 184213
1193323Sed/*-
2193323Sed * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
3193323Sed * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4193323Sed * All Rights Reserved.
5193323Sed *
6193323Sed * Permission is hereby granted, free of charge, to any person obtaining a
7193323Sed * copy of this software and associated documentation files (the "Software"),
8193323Sed * to deal in the Software without restriction, including without limitation
9193323Sed * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10193323Sed * and/or sell copies of the Software, and to permit persons to whom the
11193323Sed * Software is furnished to do so, subject to the following conditions:
12193323Sed *
13193323Sed * The above copyright notice and this permission notice (including the next
14193323Sed * paragraph) shall be included in all copies or substantial portions of the
15193323Sed * Software.
16193323Sed *
17193323Sed * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18193323Sed * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19193323Sed * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20193323Sed * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21207618Srdivacky * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22203954Srdivacky * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23249423Sdim * OTHER DEALINGS IN THE SOFTWARE.
24207618Srdivacky *
25218893Sdim * Authors:
26193323Sed *    Rickard E. (Rik) Faith <faith@valinux.com>
27193323Sed *    Gareth Hughes <gareth@valinux.com>
28193323Sed *
29193323Sed */
30193323Sed
31199481Srdivacky#include <sys/cdefs.h>
32193323Sed__FBSDID("$FreeBSD: head/sys/dev/drm/drm_drv.c 184213 2008-10-23 20:23:03Z rnoland $");
33193323Sed
34193323Sed/** @file drm_drv.c
35193323Sed * The catch-all file for DRM device support, including module setup/teardown,
36193323Sed * open/close, and ioctl dispatch.
37193323Sed */
38193323Sed
39193323Sed
40193323Sed#include <sys/limits.h>
41193323Sed#include "dev/drm/drmP.h"
42243830Sdim#include "dev/drm/drm.h"
43198090Srdivacky#include "dev/drm/drm_sarea.h"
44193323Sed
45198090Srdivacky#ifdef DRM_DEBUG_DEFAULT_ON
46193323Sedint drm_debug_flag = 1;
47193323Sed#else
48193323Sedint drm_debug_flag = 0;
49193323Sed#endif
50218893Sdim
51193323Sedstatic int drm_load(struct drm_device *dev);
52193323Sedstatic void drm_unload(struct drm_device *dev);
53193323Sedstatic drm_pci_id_list_t *drm_find_description(int vendor, int device,
54193323Sed    drm_pci_id_list_t *idlist);
55193323Sed
56193323Sed#define DRIVER_SOFTC(unit) \
57193323Sed	((struct drm_device *)devclass_get_softc(drm_devclass, unit))
58193323Sed
59193323SedMODULE_VERSION(drm, 1);
60193323SedMODULE_DEPEND(drm, agp, 1, 1, 1);
61193323SedMODULE_DEPEND(drm, pci, 1, 1, 1);
62193323SedMODULE_DEPEND(drm, mem, 1, 1, 1);
63193323Sed
64193323Sedstatic drm_ioctl_desc_t		  drm_ioctls[256] = {
65234353Sdim	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
66193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
67193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
68193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
69193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
70193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
71193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
72193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
73193323Sed
74193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
75193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
76193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
77193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
78193323Sed
79193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
80193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
81193323Sed
82193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
83193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
84193323Sed
85210299Sed	DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
86193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
87193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
88193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
89193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
90193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
91193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
92193323Sed
93193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
94193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
95193323Sed
96193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
97193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
98218893Sdim	DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
99203954Srdivacky
100193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
101193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER),
102193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
103193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
104210299Sed	DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
105210299Sed	DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma, DRM_AUTH),
106210299Sed
107193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
108193323Sed
109193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
110193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
111212904Sdim	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
112212904Sdim	DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
113212904Sdim	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
114193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
115218893Sdim	DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
116212904Sdim	DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
117193323Sed
118193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
119193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
120212904Sdim
121193323Sed	DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
122234353Sdim	DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
123234353Sdim	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
124193323Sed};
125212904Sdim
126212904Sdimstatic struct cdevsw drm_cdevsw = {
127212904Sdim	.d_version =	D_VERSION,
128193323Sed	.d_open =	drm_open,
129218893Sdim	.d_read =	drm_read,
130212904Sdim	.d_ioctl =	drm_ioctl,
131198090Srdivacky	.d_poll =	drm_poll,
132193323Sed	.d_mmap =	drm_mmap,
133234353Sdim	.d_name =	"drm",
134263508Sdim	.d_flags =	D_TRACKCLOSE | D_NEEDGIANT
135263508Sdim};
136193323Sed
137193323Sedint drm_probe(device_t dev, drm_pci_id_list_t *idlist)
138193323Sed{
139193323Sed	drm_pci_id_list_t *id_entry;
140193323Sed	int vendor, device;
141193323Sed#if __FreeBSD_version < 700010
142193323Sed	device_t realdev;
143193323Sed
144212904Sdim	if (!strcmp(device_get_name(dev), "drmsub"))
145212904Sdim		realdev = device_get_parent(dev);
146212904Sdim	else
147212904Sdim		realdev = dev;
148193323Sed	vendor = pci_get_vendor(realdev);
149218893Sdim	device = pci_get_device(realdev);
150212904Sdim#else
151198090Srdivacky	vendor = pci_get_vendor(dev);
152193323Sed	device = pci_get_device(dev);
153193323Sed#endif
154243830Sdim
155199481Srdivacky	id_entry = drm_find_description(vendor, device, idlist);
156193323Sed	if (id_entry != NULL) {
157207618Srdivacky		device_set_desc(dev, id_entry->name);
158207618Srdivacky		return 0;
159207618Srdivacky	}
160207618Srdivacky
161207618Srdivacky	return ENXIO;
162243830Sdim}
163207618Srdivacky
164207618Srdivackyint drm_attach(device_t nbdev, drm_pci_id_list_t *idlist)
165207618Srdivacky{
166207618Srdivacky	struct drm_device *dev;
167207618Srdivacky	drm_pci_id_list_t *id_entry;
168243830Sdim	int unit;
169207618Srdivacky
170207618Srdivacky	unit = device_get_unit(nbdev);
171207618Srdivacky	dev = device_get_softc(nbdev);
172207618Srdivacky
173207618Srdivacky#if __FreeBSD_version < 700010
174207618Srdivacky	if (!strcmp(device_get_name(nbdev), "drmsub"))
175207618Srdivacky		dev->device = device_get_parent(nbdev);
176207618Srdivacky	else
177207618Srdivacky		dev->device = nbdev;
178207618Srdivacky#else
179207618Srdivacky	dev->device = nbdev;
180207618Srdivacky#endif
181207618Srdivacky	dev->devnode = make_dev(&drm_cdevsw,
182207618Srdivacky			unit,
183207618Srdivacky			DRM_DEV_UID,
184193323Sed			DRM_DEV_GID,
185193323Sed			DRM_DEV_MODE,
186193323Sed			"dri/card%d", unit);
187193323Sed
188193323Sed	mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF);
189193323Sed	mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF);
190193323Sed	mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF);
191221345Sdim	mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF);
192193323Sed	mtx_init(&dev->tsk_lock, "drmtsk", NULL, MTX_DEF);
193193323Sed
194234353Sdim	id_entry = drm_find_description(pci_get_vendor(dev->device),
195234353Sdim	    pci_get_device(dev->device), idlist);
196234353Sdim	dev->id_entry = id_entry;
197193323Sed
198193323Sed	return drm_load(dev);
199193323Sed}
200193323Sed
201int drm_detach(device_t dev)
202{
203	drm_unload(device_get_softc(dev));
204	return 0;
205}
206
207#ifndef DRM_DEV_NAME
208#define DRM_DEV_NAME "drm"
209#endif
210
211devclass_t drm_devclass;
212
213drm_pci_id_list_t *drm_find_description(int vendor, int device,
214    drm_pci_id_list_t *idlist)
215{
216	int i = 0;
217
218	for (i = 0; idlist[i].vendor != 0; i++) {
219		if ((idlist[i].vendor == vendor) &&
220		    (idlist[i].device == device)) {
221			return &idlist[i];
222		}
223	}
224	return NULL;
225}
226
227static int drm_firstopen(struct drm_device *dev)
228{
229	drm_local_map_t *map;
230	int i;
231
232	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
233
234	/* prebuild the SAREA */
235	i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
236	    _DRM_CONTAINS_LOCK, &map);
237	if (i != 0)
238		return i;
239
240	if (dev->driver->firstopen)
241		dev->driver->firstopen(dev);
242
243	dev->buf_use = 0;
244
245	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
246		i = drm_dma_setup(dev);
247		if (i != 0)
248			return i;
249	}
250
251	for (i = 0; i < DRM_HASH_SIZE; i++) {
252		dev->magiclist[i].head = NULL;
253		dev->magiclist[i].tail = NULL;
254	}
255
256	dev->lock.lock_queue = 0;
257	dev->irq_enabled = 0;
258	dev->context_flag = 0;
259	dev->last_context = 0;
260	dev->if_version = 0;
261
262	dev->buf_sigio = NULL;
263
264	DRM_DEBUG("\n");
265
266	return 0;
267}
268
269static int drm_lastclose(struct drm_device *dev)
270{
271	drm_magic_entry_t *pt, *next;
272	drm_local_map_t *map, *mapsave;
273	int i;
274
275	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
276
277	DRM_DEBUG("\n");
278
279	if (dev->driver->lastclose != NULL)
280		dev->driver->lastclose(dev);
281
282	if (dev->irq_enabled)
283		drm_irq_uninstall(dev);
284
285	if (dev->unique) {
286		free(dev->unique, DRM_MEM_DRIVER);
287		dev->unique = NULL;
288		dev->unique_len = 0;
289	}
290	/* Clear pid list */
291	for (i = 0; i < DRM_HASH_SIZE; i++) {
292		for (pt = dev->magiclist[i].head; pt; pt = next) {
293			next = pt->next;
294			free(pt, DRM_MEM_MAGIC);
295		}
296		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
297	}
298
299	DRM_UNLOCK();
300	drm_drawable_free_all(dev);
301	DRM_LOCK();
302
303	/* Clear AGP information */
304	if (dev->agp) {
305		drm_agp_mem_t *entry;
306		drm_agp_mem_t *nexte;
307
308		/* Remove AGP resources, but leave dev->agp intact until
309		 * drm_unload is called.
310		 */
311		for (entry = dev->agp->memory; entry; entry = nexte) {
312			nexte = entry->next;
313			if (entry->bound)
314				drm_agp_unbind_memory(entry->handle);
315			drm_agp_free_memory(entry->handle);
316			free(entry, DRM_MEM_AGPLISTS);
317		}
318		dev->agp->memory = NULL;
319
320		if (dev->agp->acquired)
321			drm_agp_release(dev);
322
323		dev->agp->acquired = 0;
324		dev->agp->enabled  = 0;
325	}
326	if (dev->sg != NULL) {
327		drm_sg_cleanup(dev->sg);
328		dev->sg = NULL;
329	}
330
331	TAILQ_FOREACH_SAFE(map, &dev->maplist, link, mapsave) {
332		if (!(map->flags & _DRM_DRIVER))
333			drm_rmmap(dev, map);
334	}
335
336	drm_dma_takedown(dev);
337	if (dev->lock.hw_lock) {
338		dev->lock.hw_lock = NULL; /* SHM removed */
339		dev->lock.file_priv = NULL;
340		DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
341	}
342
343	return 0;
344}
345
346static int drm_load(struct drm_device *dev)
347{
348	int i, retcode;
349
350	DRM_DEBUG("\n");
351
352	dev->irq = pci_get_irq(dev->device);
353#if __FreeBSD_version >= 700053
354	dev->pci_domain = pci_get_domain(dev->device);
355#else
356	dev->pci_domain = 0;
357#endif
358	dev->pci_bus = pci_get_bus(dev->device);
359	dev->pci_slot = pci_get_slot(dev->device);
360	dev->pci_func = pci_get_function(dev->device);
361
362	dev->pci_vendor = pci_get_vendor(dev->device);
363	dev->pci_device = pci_get_device(dev->device);
364
365	TAILQ_INIT(&dev->maplist);
366
367	drm_mem_init();
368	drm_sysctl_init(dev);
369	TAILQ_INIT(&dev->files);
370
371	dev->counters  = 6;
372	dev->types[0]  = _DRM_STAT_LOCK;
373	dev->types[1]  = _DRM_STAT_OPENS;
374	dev->types[2]  = _DRM_STAT_CLOSES;
375	dev->types[3]  = _DRM_STAT_IOCTLS;
376	dev->types[4]  = _DRM_STAT_LOCKS;
377	dev->types[5]  = _DRM_STAT_UNLOCKS;
378
379	for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
380		atomic_set(&dev->counts[i], 0);
381
382	if (dev->driver->load != NULL) {
383		DRM_LOCK();
384		/* Shared code returns -errno. */
385		retcode = -dev->driver->load(dev,
386		    dev->id_entry->driver_private);
387		if (pci_enable_busmaster(dev->device))
388			DRM_ERROR("Request to enable bus-master failed.\n");
389		DRM_UNLOCK();
390		if (retcode != 0)
391			goto error;
392	}
393
394	if (drm_core_has_AGP(dev)) {
395		if (drm_device_is_agp(dev))
396			dev->agp = drm_agp_init();
397		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) &&
398		    dev->agp == NULL) {
399			DRM_ERROR("Card isn't AGP, or couldn't initialize "
400			    "AGP.\n");
401			retcode = ENOMEM;
402			goto error;
403		}
404		if (dev->agp != NULL) {
405			if (drm_mtrr_add(dev->agp->info.ai_aperture_base,
406			    dev->agp->info.ai_aperture_size, DRM_MTRR_WC) == 0)
407				dev->agp->mtrr = 1;
408		}
409	}
410
411	retcode = drm_ctxbitmap_init(dev);
412	if (retcode != 0) {
413		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
414		goto error;
415	}
416
417	dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL);
418	if (dev->drw_unrhdr == NULL) {
419		DRM_ERROR("Couldn't allocate drawable number allocator\n");
420		goto error;
421	}
422
423	DRM_INFO("Initialized %s %d.%d.%d %s\n",
424	    dev->driver->name,
425	    dev->driver->major,
426	    dev->driver->minor,
427	    dev->driver->patchlevel,
428	    dev->driver->date);
429
430	return 0;
431
432error:
433	drm_sysctl_cleanup(dev);
434	DRM_LOCK();
435	drm_lastclose(dev);
436	DRM_UNLOCK();
437	destroy_dev(dev->devnode);
438
439	mtx_destroy(&dev->tsk_lock);
440	mtx_destroy(&dev->drw_lock);
441	mtx_destroy(&dev->vbl_lock);
442	mtx_destroy(&dev->irq_lock);
443	mtx_destroy(&dev->dev_lock);
444
445	return retcode;
446}
447
448static void drm_unload(struct drm_device *dev)
449{
450	int i;
451
452	DRM_DEBUG("\n");
453
454	drm_sysctl_cleanup(dev);
455	destroy_dev(dev->devnode);
456
457	drm_ctxbitmap_cleanup(dev);
458
459	if (dev->agp && dev->agp->mtrr) {
460		int __unused retcode;
461
462		retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base,
463		    dev->agp->info.ai_aperture_size, DRM_MTRR_WC);
464		DRM_DEBUG("mtrr_del = %d", retcode);
465	}
466
467	DRM_LOCK();
468	drm_lastclose(dev);
469	DRM_UNLOCK();
470
471	/* Clean up PCI resources allocated by drm_bufs.c.  We're not really
472	 * worried about resource consumption while the DRM is inactive (between
473	 * lastclose and firstopen or unload) because these aren't actually
474	 * taking up KVA, just keeping the PCI resource allocated.
475	 */
476	for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
477		if (dev->pcir[i] == NULL)
478			continue;
479		bus_release_resource(dev->device, SYS_RES_MEMORY,
480		    dev->pcirid[i], dev->pcir[i]);
481		dev->pcir[i] = NULL;
482	}
483
484	if (dev->agp) {
485		free(dev->agp, DRM_MEM_AGPLISTS);
486		dev->agp = NULL;
487	}
488
489	if (dev->driver->unload != NULL) {
490		DRM_LOCK();
491		dev->driver->unload(dev);
492		DRM_UNLOCK();
493	}
494
495	delete_unrhdr(dev->drw_unrhdr);
496
497	drm_mem_uninit();
498
499	if (pci_disable_busmaster(dev->device))
500		DRM_ERROR("Request to disable bus-master failed.\n");
501
502	mtx_destroy(&dev->tsk_lock);
503	mtx_destroy(&dev->drw_lock);
504	mtx_destroy(&dev->vbl_lock);
505	mtx_destroy(&dev->irq_lock);
506	mtx_destroy(&dev->dev_lock);
507}
508
509
510int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
511{
512	struct drm_version *version = data;
513	int len;
514
515#define DRM_COPY( name, value )						\
516	len = strlen( value );						\
517	if ( len > name##_len ) len = name##_len;			\
518	name##_len = strlen( value );					\
519	if ( len && name ) {						\
520		if ( DRM_COPY_TO_USER( name, value, len ) )		\
521			return EFAULT;				\
522	}
523
524	version->version_major		= dev->driver->major;
525	version->version_minor		= dev->driver->minor;
526	version->version_patchlevel	= dev->driver->patchlevel;
527
528	DRM_COPY(version->name, dev->driver->name);
529	DRM_COPY(version->date, dev->driver->date);
530	DRM_COPY(version->desc, dev->driver->desc);
531
532	return 0;
533}
534
535int drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p)
536{
537	struct drm_device *dev = NULL;
538	int retcode = 0;
539
540	dev = DRIVER_SOFTC(dev2unit(kdev));
541
542	DRM_DEBUG("open_count = %d\n", dev->open_count);
543
544	retcode = drm_open_helper(kdev, flags, fmt, p, dev);
545
546	if (!retcode) {
547		atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
548		DRM_LOCK();
549		device_busy(dev->device);
550		if (!dev->open_count++)
551			retcode = drm_firstopen(dev);
552		DRM_UNLOCK();
553	}
554
555	return retcode;
556}
557
558void drm_close(void *data)
559{
560	struct drm_file *file_priv = data;
561	struct drm_device *dev = file_priv->dev;
562	int retcode = 0;
563
564	DRM_DEBUG("open_count = %d\n", dev->open_count);
565
566	DRM_LOCK();
567
568	if (dev->driver->preclose != NULL)
569		dev->driver->preclose(dev, file_priv);
570
571	/* ========================================================
572	 * Begin inline drm_release
573	 */
574
575	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
576	    DRM_CURRENTPID, (long)dev->device, dev->open_count);
577
578	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
579	    && dev->lock.file_priv == file_priv) {
580		DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
581			  DRM_CURRENTPID,
582			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
583		if (dev->driver->reclaim_buffers_locked != NULL)
584			dev->driver->reclaim_buffers_locked(dev, file_priv);
585
586		drm_lock_free(&dev->lock,
587		    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
588
589				/* FIXME: may require heavy-handed reset of
590                                   hardware at this point, possibly
591                                   processed via a callback to the X
592                                   server. */
593	} else if (dev->driver->reclaim_buffers_locked != NULL &&
594	    dev->lock.hw_lock != NULL) {
595		/* The lock is required to reclaim buffers */
596		for (;;) {
597			if (!dev->lock.hw_lock) {
598				/* Device has been unregistered */
599				retcode = EINTR;
600				break;
601			}
602			if (drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT)) {
603				dev->lock.file_priv = file_priv;
604				dev->lock.lock_time = jiffies;
605				atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
606				break;	/* Got lock */
607			}
608			/* Contention */
609			retcode = mtx_sleep((void *)&dev->lock.lock_queue,
610			    &dev->dev_lock, PZERO | PCATCH, "drmlk2", 0);
611			if (retcode)
612				break;
613		}
614		if (retcode == 0) {
615			dev->driver->reclaim_buffers_locked(dev, file_priv);
616			drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT);
617		}
618	}
619
620	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
621	    !dev->driver->reclaim_buffers_locked)
622		drm_reclaim_buffers(dev, file_priv);
623
624	funsetown(&dev->buf_sigio);
625
626	if (dev->driver->postclose != NULL)
627		dev->driver->postclose(dev, file_priv);
628	TAILQ_REMOVE(&dev->files, file_priv, link);
629	free(file_priv, DRM_MEM_FILES);
630
631	/* ========================================================
632	 * End inline drm_release
633	 */
634
635	atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
636	device_unbusy(dev->device);
637	if (--dev->open_count == 0) {
638		retcode = drm_lastclose(dev);
639	}
640
641	DRM_UNLOCK();
642}
643
644/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm.
645 */
646int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags,
647    DRM_STRUCTPROC *p)
648{
649	struct drm_device *dev = drm_get_device_from_kdev(kdev);
650	int retcode = 0;
651	drm_ioctl_desc_t *ioctl;
652	int (*func)(struct drm_device *dev, void *data, struct drm_file *file_priv);
653	int nr = DRM_IOCTL_NR(cmd);
654	int is_driver_ioctl = 0;
655	struct drm_file *file_priv;
656
657	DRM_LOCK();
658	retcode = devfs_get_cdevpriv((void **)&file_priv);
659	DRM_UNLOCK();
660	if (retcode != 0) {
661		DRM_ERROR("can't find authenticator\n");
662		return EINVAL;
663	}
664
665	atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
666	++file_priv->ioctl_count;
667
668	DRM_DEBUG("pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
669	    DRM_CURRENTPID, cmd, nr, (long)dev->device,
670	    file_priv->authenticated);
671
672	switch (cmd) {
673	case FIONBIO:
674	case FIOASYNC:
675		return 0;
676
677	case FIOSETOWN:
678		return fsetown(*(int *)data, &dev->buf_sigio);
679
680	case FIOGETOWN:
681		*(int *) data = fgetown(&dev->buf_sigio);
682		return 0;
683	}
684
685	if (IOCGROUP(cmd) != DRM_IOCTL_BASE) {
686		DRM_DEBUG("Bad ioctl group 0x%x\n", (int)IOCGROUP(cmd));
687		return EINVAL;
688	}
689
690	ioctl = &drm_ioctls[nr];
691	/* It's not a core DRM ioctl, try driver-specific. */
692	if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
693		/* The array entries begin at DRM_COMMAND_BASE ioctl nr */
694		nr -= DRM_COMMAND_BASE;
695		if (nr > dev->driver->max_ioctl) {
696			DRM_DEBUG("Bad driver ioctl number, 0x%x (of 0x%x)\n",
697			    nr, dev->driver->max_ioctl);
698			return EINVAL;
699		}
700		ioctl = &dev->driver->ioctls[nr];
701		is_driver_ioctl = 1;
702	}
703	func = ioctl->func;
704
705	if (func == NULL) {
706		DRM_DEBUG("no function\n");
707		return EINVAL;
708	}
709
710	if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(p)) ||
711	    ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
712	    ((ioctl->flags & DRM_MASTER) && !file_priv->master))
713		return EACCES;
714
715	if (is_driver_ioctl) {
716		DRM_LOCK();
717		/* shared code returns -errno */
718		retcode = -func(dev, data, file_priv);
719		DRM_UNLOCK();
720	} else {
721		retcode = func(dev, data, file_priv);
722	}
723
724	if (retcode != 0)
725		DRM_DEBUG("    returning %d\n", retcode);
726
727	return retcode;
728}
729
730drm_local_map_t *drm_getsarea(struct drm_device *dev)
731{
732	drm_local_map_t *map;
733
734	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
735	TAILQ_FOREACH(map, &dev->maplist, link) {
736		if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
737			return map;
738	}
739
740	return NULL;
741}
742
743#if DRM_LINUX
744
745#include <sys/sysproto.h>
746
747MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
748
749#define LINUX_IOCTL_DRM_MIN		0x6400
750#define LINUX_IOCTL_DRM_MAX		0x64ff
751
752static linux_ioctl_function_t drm_linux_ioctl;
753static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl,
754    LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
755
756SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
757    linux_ioctl_register_handler, &drm_handler);
758SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
759    linux_ioctl_unregister_handler, &drm_handler);
760
761/* The bits for in/out are switched on Linux */
762#define LINUX_IOC_IN	IOC_OUT
763#define LINUX_IOC_OUT	IOC_IN
764
765static int
766drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)
767{
768	int error;
769	int cmd = args->cmd;
770
771	args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT);
772	if (cmd & LINUX_IOC_IN)
773		args->cmd |= IOC_IN;
774	if (cmd & LINUX_IOC_OUT)
775		args->cmd |= IOC_OUT;
776
777	error = ioctl(p, (struct ioctl_args *)args);
778
779	return error;
780}
781#endif /* DRM_LINUX */
782