xref: /gfx-drm/usr/src/uts/common/io/drm/drm_stub.c (revision ba92f03d)
1 /*
2  * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * Copyright (c) 2012, 2013 Intel Corporation.  All rights reserved.
7  */
8 
9 /**
10  * \file drm_stub.h
11  * Stub support
12  *
13  * \author Rickard E. (Rik) Faith <faith@valinux.com>
14  */
15 
16 /*
17  * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
18  *
19  * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
20  * All Rights Reserved.
21  *
22  * Permission is hereby granted, free of charge, to any person obtaining a
23  * copy of this software and associated documentation files (the "Software"),
24  * to deal in the Software without restriction, including without limitation
25  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
26  * and/or sell copies of the Software, and to permit persons to whom the
27  * Software is furnished to do so, subject to the following conditions:
28  *
29  * The above copyright notice and this permission notice (including the next
30  * paragraph) shall be included in all copies or substantial portions of the
31  * Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
36  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
37  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
38  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
39  * DEALINGS IN THE SOFTWARE.
40  */
41 
42 #include "drmP.h"
43 #include "drm_core.h"
44 #include "drm_linux_list.h"
45 
46 unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
47 unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
48 
49 struct idr drm_minors_idr;
50 
drm_minor_get_id(struct drm_device * dev,int type)51 static int drm_minor_get_id(struct drm_device *dev, int type)
52 {
53 	int new_id;
54 	int ret;
55 	int base, limit;
56 
57 	switch (type) {
58 	case DRM_MINOR_LEGACY:
59 		base = DRM_MINOR_ID_BASE_LEGACY;
60 		limit = DRM_MINOR_ID_LIMIT_LEGACY;
61 		break;
62 	case DRM_MINOR_CONTROL:
63 		base = DRM_MINOR_ID_BASE_CONTROL;
64 		limit = DRM_MINOR_ID_LIMIT_CONTROL;
65 		break;
66 	case DRM_MINOR_RENDER:
67 		base = DRM_MINOR_ID_BASE_RENDER;
68 		limit = DRM_MINOR_ID_LIMIT_RENDER;
69 		break;
70 	case DRM_MINOR_VGATEXT:
71 		base = DRM_MINOR_ID_BASE_VGATEXT;
72 		limit = DRM_MINOR_ID_LIMIT_VGATEXT;
73 		break;
74 	case DRM_MINOR_AGPMASTER:
75 		base = DRM_MINOR_ID_BASE_AGPMASTER;
76 		limit = DRM_MINOR_ID_LIMIT_AGPMASTER;
77 		break;
78 	default:
79 		return -EINVAL;
80 	}
81 
82 	mutex_lock(&dev->struct_mutex);
83 	ret = idr_get_new_above(&drm_minors_idr, NULL,
84 				base, &new_id);
85 	mutex_unlock(&dev->struct_mutex);
86 
87 	if (ret) {
88 		return ret;
89 	}
90 
91 	if (new_id > limit) {
92 		(void) idr_remove(&drm_minors_idr, new_id);
93 		return -EINVAL;
94 	}
95 	return new_id;
96 }
97 
drm_master_create(struct drm_minor * minor)98 struct drm_master *drm_master_create(struct drm_minor *minor)
99 {
100 	struct drm_master *master;
101 	int i;
102 
103 	master = kzalloc(sizeof(*master), GFP_KERNEL);
104 	if (!master)
105 		return NULL;
106 
107 	kref_init(&master->refcount);
108 	mutex_init(&master->lock.lock_mutex, NULL, MUTEX_DRIVER, (void *)minor->dev->pdev->intr_block);
109 	cv_init(&master->lock.lock_cv, NULL, CV_DRIVER, NULL);
110 
111 	for (i = 0; i < DRM_HASH_SIZE; i++) {
112 		master->magiclist[i].head = NULL;
113 		master->magiclist[i].tail = NULL;
114 	}
115 
116 	master->minor = minor;
117 
118 	list_add_tail(&master->head, &minor->master_list, (caddr_t)master);
119 
120 	return master;
121 }
122 
drm_master_get(struct drm_master * master)123 struct drm_master *drm_master_get(struct drm_master *master)
124 {
125 	kref_get(&master->refcount);
126 	return master;
127 }
128 
drm_master_destroy(struct kref * kref)129 void drm_master_destroy(struct kref *kref)
130 {
131 	struct drm_master *master = container_of(kref, struct drm_master, refcount);
132 	struct drm_magic_entry *pt, *next;
133 	struct drm_device *dev = master->minor->dev;
134 	struct drm_map_list *r_list, *list_temp;
135 	int i;
136 
137 	list_del(&master->head);
138 
139 	if (dev->driver->master_destroy)
140 		dev->driver->master_destroy(dev, master);
141 
142 	list_for_each_entry_safe(r_list, list_temp, struct drm_map_list, &dev->maplist, head) {
143 		if (r_list->master == master) {
144 			(void) drm_rmmap_locked(dev, r_list->map);
145 			r_list = NULL;
146 		}
147 	}
148 
149 	if (master->unique) {
150 		kfree(master->unique, master->unique_size);
151 		master->unique = NULL;
152 		master->unique_len = 0;
153 
154 	}
155 
156 	for (i = 0; i < DRM_HASH_SIZE; i++) {
157 		for (pt = master->magiclist[i].head; pt; pt = next) {
158 			next = pt->next;
159 			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
160 		}
161 		master->magiclist[i].head = master->magiclist[i].tail = NULL;
162 	}
163 
164 	cv_destroy(&master->lock.lock_cv);
165 	mutex_destroy(&master->lock.lock_mutex);
166 
167 	kfree(master, sizeof (struct drm_master));
168 }
169 
drm_master_put(struct drm_master ** master)170 void drm_master_put(struct drm_master **master)
171 {
172 	kref_put(&(*master)->refcount, drm_master_destroy);
173 	*master = NULL;
174 }
175 
176 /* LINTED */
drm_setmaster_ioctl(DRM_IOCTL_ARGS)177 int drm_setmaster_ioctl(DRM_IOCTL_ARGS)
178 {
179 	int ret = 0;
180 
181 	if (dev->driver->entervt)
182 		dev->driver->entervt(dev);
183 
184 	if (file->is_master)
185 		return 0;
186 
187 	if (file->minor->master && file->minor->master != file->master)
188 		return -EINVAL;
189 
190 	if (!file->master)
191 		return -EINVAL;
192 
193 	if (!file->minor->master &&
194 	    file->minor->master != file->master) {
195 		mutex_lock(&dev->struct_mutex);
196 		file->minor->master = drm_master_get(file->master);
197 		file->is_master = 1;
198 		if (dev->driver->master_set) {
199 			ret = dev->driver->master_set(dev, file, false);
200 			if (unlikely(ret != 0)) {
201 				file->is_master = 0;
202 				drm_master_put(&file->minor->master);
203 			}
204 		}
205 		mutex_unlock(&dev->struct_mutex);
206 	}
207 
208 	return 0;
209 }
210 
211 /* LINTED */
drm_dropmaster_ioctl(DRM_IOCTL_ARGS)212 int drm_dropmaster_ioctl(DRM_IOCTL_ARGS)
213 {
214 	if (!file->is_master)
215 		return -EINVAL;
216 
217 	if (!file->minor->master)
218 		return -EINVAL;
219 
220 	if (dev->driver->leavevt)
221 		dev->driver->leavevt(dev);
222 
223 	mutex_lock(&dev->struct_mutex);
224 	if (dev->driver->master_drop)
225 		dev->driver->master_drop(dev, file, false);
226 	drm_master_put(&file->minor->master);
227 	file->is_master = 0;
228 	mutex_unlock(&dev->struct_mutex);
229 	return 0;
230 }
231 
drm_fill_in_dev(struct drm_device * dev,struct pci_dev * pdev,struct drm_driver * driver)232 static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
233 			   struct drm_driver *driver)
234 {
235 	int retcode;
236 
237 	INIT_LIST_HEAD(&dev->filelist);
238 	INIT_LIST_HEAD(&dev->ctxlist);
239 	INIT_LIST_HEAD(&dev->maplist);
240 	INIT_LIST_HEAD(&dev->vblank_event_list);
241 	INIT_LIST_HEAD(&dev->gem_objects_list);
242 
243 	mutex_init(&dev->count_lock, NULL, MUTEX_DRIVER, (void *)pdev->intr_block);
244 	mutex_init(&dev->event_lock, NULL, MUTEX_DRIVER, (void *)pdev->intr_block);
245 	mutex_init(&dev->struct_mutex, NULL, MUTEX_DRIVER, NULL);	//adaptive locks
246 	mutex_init(&dev->ctxlist_mutex, NULL, MUTEX_DRIVER, NULL);
247 	mutex_init(&dev->irq_lock, NULL, MUTEX_DRIVER, (void *)pdev->intr_block);
248 	mutex_init(&dev->track_lock, NULL, MUTEX_DRIVER, (void *)pdev->intr_block);
249 	mutex_init(&dev->page_fault_lock, NULL, MUTEX_DRIVER, NULL);
250 
251 	dev->pdev = pdev;
252 	dev->pci_device = pdev->device;
253 	dev->pci_vendor = pdev->vendor;
254 
255 	idr_init(&dev->map_idr);
256 
257 	/* the DRM has 6 basic counters */
258 	dev->counters = 6;
259 	dev->types[0] = _DRM_STAT_LOCK;
260 	dev->types[1] = _DRM_STAT_OPENS;
261 	dev->types[2] = _DRM_STAT_CLOSES;
262 	dev->types[3] = _DRM_STAT_IOCTLS;
263 	dev->types[4] = _DRM_STAT_LOCKS;
264 	dev->types[5] = _DRM_STAT_UNLOCKS;
265 
266 	dev->driver = driver;
267 
268 	retcode = drm_ctxbitmap_init(dev);
269 	if (retcode) {
270 		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
271 		goto error_out_unreg;
272 	}
273 
274 	if (driver->driver_features & DRIVER_GEM) {
275 		retcode = drm_gem_init(dev);
276 		if (retcode) {
277 			DRM_ERROR("Cannot initialize graphics execution "
278 				  "manager (GEM)\n");
279 			goto error_out_unreg;
280 		}
281 	}
282 
283 	dev->drm_wq = create_workqueue(dev->devinfo, "drm");
284 	if (dev->drm_wq == NULL) {
285 		DRM_ERROR("Failed to create drm workqueue.\n");
286 		goto error_out_unreg;
287 	}
288 
289 	return 0;
290 
291       error_out_unreg:
292 	(void)drm_lastclose(dev);
293 	return retcode;
294 }
295 
296 
297 /**
298  * Get a secondary minor number.
299  *
300  * \param dev device data structure
301  * \param sec-minor structure to hold the assigned minor
302  * \return negative number on failure.
303  *
304  * Search an empty entry and initialize it to the given parameters, and
305  * create the proc init entry via proc_init(). This routines assigns
306  * minor numbers to secondary heads of multi-headed cards
307  */
drm_get_minor(struct drm_device * dev,struct drm_minor ** minor,int type)308 static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
309 {
310 	struct drm_minor *new_minor;
311 	int ret;
312 	int minor_id;
313 	int minor_unit;
314 
315 	DRM_DEBUG("\n");
316 
317 	minor_id = drm_minor_get_id(dev, type);
318 	if (minor_id < 0)
319 		return minor_id;
320 
321 	new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
322 	if (!new_minor) {
323 		ret = -ENOMEM;
324 		goto err_idr;
325 	}
326 
327 	new_minor->type = type;
328 	new_minor->dev = dev;
329 	new_minor->index = minor_id;
330 	INIT_LIST_HEAD(&new_minor->master_list);
331 
332 	(void) idr_replace(&drm_minors_idr, new_minor, minor_id);
333 
334 	minor_unit = minor_id & DRM_MINOR_ID_LIMIT_LEGACY; /* 63 */
335 	if (type == DRM_MINOR_LEGACY)
336 		(void) sprintf(new_minor->name, "drm%d", minor_unit);
337 	else if (type == DRM_MINOR_CONTROL)
338 		(void) sprintf(new_minor->name, "controlD%d", minor_unit);
339 	else if (type == DRM_MINOR_RENDER)
340 		(void) sprintf(new_minor->name, "renderD%d", minor_unit);
341 	else if (type == DRM_MINOR_VGATEXT)
342 		(void) sprintf(new_minor->name, "gfx%d", minor_unit);
343 	else if (type == DRM_MINOR_AGPMASTER)
344 		(void) sprintf(new_minor->name, "agpmaster%d", minor_unit);
345 
346 	idr_init(&new_minor->clone_idr);
347 
348 	ret = drm_sysfs_device_add(new_minor);
349 	if (ret)
350 		goto err_g2;
351 	*minor = new_minor;
352 
353 	DRM_DEBUG("new minor assigned %d\n", minor_id);
354 	return 0;
355 
356 
357 err_g2:
358 	kfree(new_minor, sizeof (*new_minor));
359 err_idr:
360 	(void) idr_remove(&drm_minors_idr, minor_id);
361 	*minor = NULL;
362 	return ret;
363 }
364 
365 /**
366  * Register.
367  *
368  * \return zero on success or a negative number on failure.
369  *
370  * Attempt to gets inter module "drm" information. If we are first
371  * then register the character device and inter module information.
372  * Try and register, if we fail to register, backout previous work.
373  */
drm_get_dev(struct drm_device * dev,struct pci_dev * pdev,struct drm_driver * driver,unsigned long driver_data)374 int drm_get_dev(struct drm_device *dev, struct pci_dev *pdev,
375 		struct drm_driver *driver, unsigned long driver_data)
376 {
377 	int ret;
378 
379 	DRM_DEBUG("\n");
380 
381 	if ((ret = drm_fill_in_dev(dev, pdev, driver))) {
382 		DRM_ERROR("DRM: Fill_in_dev failed");
383 		goto err_g1;
384 	}
385 
386 	if ((ret = drm_get_minor(dev, &dev->vgatext, DRM_MINOR_VGATEXT))) {
387 		goto err_g2;
388 	}
389 
390 	if (dev->driver->agp_support_detect)
391 		dev->driver->agp_support_detect(dev, driver_data);
392 
393 	if (drm_core_has_AGP(dev)) {
394 		if ((ret = drm_get_minor(dev, &dev->agpmaster, DRM_MINOR_AGPMASTER)))
395 			goto err_g1;
396 	}
397 
398 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
399 		ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
400 		if (ret)
401 			goto err_g3;
402 	}
403 
404 	if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
405 		goto err_g4;
406 
407 	if (dev->driver->load) {
408 		ret = dev->driver->load(dev, driver_data);
409 		if (ret)
410 			goto err_g5;
411 	}
412 
413 	if (drm_init_kstats(dev)) {
414 		DRM_ERROR("init kstats error");
415 		ret = EFAULT;
416 		goto err_g5;
417 	}
418 
419 	cmn_err(CE_CONT, "!Initialized %s v%d.%d.%d Modified date %s",
420 		 driver->name, driver->major, driver->minor, driver->patchlevel,
421 		 driver->date);
422 
423 	return 0;
424 
425 err_g5:
426 	(void) drm_put_minor(&dev->primary);
427 err_g4:
428 	if (drm_core_check_feature(dev, DRIVER_MODESET))
429 		(void) drm_put_minor(&dev->control);
430 err_g3:
431 	(void) drm_put_minor(&dev->vgatext);
432 err_g2:
433 	if (drm_core_has_AGP(dev))
434 		(void) drm_put_minor(&dev->agpmaster);
435 err_g1:
436 	return ret;
437 }
438 
439 /**
440  * Put a secondary minor number.
441  *
442  * \param sec_minor - structure to be released
443  * \return always zero
444  *
445  * Cleans up the proc resources. Not legal for this to be the
446  * last minor released.
447  *
448  */
drm_put_minor(struct drm_minor ** minor_p)449 int drm_put_minor(struct drm_minor **minor_p)
450 {
451 	struct drm_minor *minor = *minor_p;
452 
453 	DRM_DEBUG("release secondary minor %d\n", minor->index);
454 
455 	drm_sysfs_device_remove(minor);
456 
457 	(void) idr_remove(&drm_minors_idr, minor->index);
458 
459 	idr_destroy(&minor->clone_idr);
460 
461 	kfree(minor, sizeof (*minor));
462 	*minor_p = NULL;
463 	return 0;
464 }
465 
466 /**
467  * Called via drm_exit() at module unload time or when pci device is
468  * unplugged.
469  *
470  * Cleans up all DRM device, calling drm_lastclose().
471  *
472  * \sa drm_init
473  */
drm_put_dev(struct drm_device * dev)474 void drm_put_dev(struct drm_device *dev)
475 {
476 	struct drm_driver *driver;
477 	struct drm_map_list *r_list, *list_temp;
478 
479 	DRM_DEBUG("\n");
480 
481 	if (!dev) {
482 		DRM_ERROR("cleanup called no dev\n");
483 		return;
484 	}
485 	driver = dev->driver;
486 
487 	(void) drm_lastclose(dev);
488 
489 	(void) destroy_workqueue(dev->drm_wq);
490 
491 	if (dev->driver->unload)
492 		dev->driver->unload(dev);
493 
494 	gfxp_mempool_destroy();
495 
496 	if (drm_core_has_AGP(dev) && dev->agp) {
497 		drm_agp_cleanup(dev);
498 		kfree(dev->agp, sizeof(*dev->agp));
499 		dev->agp = NULL;
500 	}
501 
502 	drm_vblank_cleanup(dev);
503 
504 	list_for_each_entry_safe(r_list, list_temp, struct drm_map_list, &dev->maplist, head)
505 		(void) drm_rmmap(dev, r_list->map);
506 	idr_destroy(&dev->map_idr);
507 
508 	drm_ctxbitmap_cleanup(dev);
509 
510 	(void) drm_put_minor(&dev->vgatext);
511 
512 	if (drm_core_has_AGP(dev))
513 		(void) drm_put_minor(&dev->agpmaster);
514 
515 	if (drm_core_check_feature(dev, DRIVER_MODESET))
516 		(void) drm_put_minor(&dev->control);
517 
518 	if (driver->driver_features & DRIVER_GEM)
519 		drm_gem_destroy(dev);
520 
521 	(void) drm_put_minor(&dev->primary);
522 
523 	mutex_destroy(&dev->irq_lock);
524 	mutex_destroy(&dev->ctxlist_mutex);
525 	mutex_destroy(&dev->struct_mutex);
526 	mutex_destroy(&dev->event_lock);
527 	mutex_destroy(&dev->count_lock);
528 
529 	drm_fini_kstats(dev);
530 }
531