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