Merge commit 'cb41b9c565d4eec9e1f06e24d429696f59f2f07d'
[unleashed.git] / usr / src / uts / common / io / drm / drm_sunmod.c
blobc8ff29010a6eb9577c8fe3cb29f6dc31dacbd33d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Common misc module interfaces of DRM under Solaris
32 * This module calls into gfx and agpmaster misc modules respectively
33 * for generic graphics operations and AGP master device support.
36 #include "drm_sunmod.h"
37 #include <sys/modctl.h>
38 #include <sys/kmem.h>
39 #include <vm/seg_kmem.h>
41 static struct modlmisc modlmisc = {
42 &mod_miscops, "DRM common interfaces"
45 static struct modlinkage modlinkage = {
46 MODREV_1, (void *)&modlmisc, NULL
49 static drm_inst_list_t *drm_inst_head;
50 static kmutex_t drm_inst_list_lock;
52 static int drm_sun_open(dev_t *, int, int, cred_t *);
53 static int drm_sun_close(dev_t, int, int, cred_t *);
54 static int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
55 static int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
56 size_t *, uint_t);
59 * devmap callbacks for AGP and PCI GART
61 static int drm_devmap_map(devmap_cookie_t, dev_t,
62 uint_t, offset_t, size_t, void **);
63 static int drm_devmap_dup(devmap_cookie_t, void *,
64 devmap_cookie_t, void **);
65 static void drm_devmap_unmap(devmap_cookie_t, void *,
66 offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **);
68 static drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *);
69 static drm_inst_state_t *drm_sup_devt_to_state(dev_t);
70 static void drm_supp_free_drv_entry(dev_info_t *);
72 static struct devmap_callback_ctl drm_devmap_callbacks = {
73 DEVMAP_OPS_REV, /* devmap_rev */
74 drm_devmap_map, /* devmap_map */
75 NULL, /* devmap_access */
76 drm_devmap_dup, /* devmap_dup */
77 drm_devmap_unmap /* devmap_unmap */
81 * Common device operations structure for all DRM drivers
83 struct cb_ops drm_cb_ops = {
84 drm_sun_open, /* cb_open */
85 drm_sun_close, /* cb_close */
86 nodev, /* cb_strategy */
87 nodev, /* cb_print */
88 nodev, /* cb_dump */
89 nodev, /* cb_read */
90 nodev, /* cb_write */
91 drm_sun_ioctl, /* cb_ioctl */
92 drm_sun_devmap, /* cb_devmap */
93 nodev, /* cb_mmap */
94 NULL, /* cb_segmap */
95 nochpoll, /* cb_chpoll */
96 ddi_prop_op, /* cb_prop_op */
97 0, /* cb_stream */
98 D_NEW | D_MTSAFE |D_DEVMAP /* cb_flag */
102 _init(void)
104 int error;
106 if ((error = mod_install(&modlinkage)) != 0) {
107 return (error);
110 /* initialize the instance list lock */
111 mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
112 return (0);
116 _fini(void)
118 int err;
120 if ((err = mod_remove(&modlinkage)) != 0)
121 return (err);
123 mutex_destroy(&drm_inst_list_lock);
124 return (0);
128 _info(struct modinfo *modinfop)
130 return (mod_info(&modlinkage, modinfop));
133 void *
134 drm_supp_register(dev_info_t *dip, drm_device_t *dp)
136 int error;
137 char buf[80];
138 int instance = ddi_get_instance(dip);
139 ddi_acc_handle_t pci_cfg_handle;
140 agp_master_softc_t *agpm;
141 drm_inst_state_t *mstate;
142 drm_inst_list_t *entry;
143 gfxp_vgatext_softc_ptr_t gfxp;
144 struct dev_ops *devop;
146 ASSERT(dip != NULL);
148 entry = drm_supp_alloc_drv_entry(dip);
149 if (entry == NULL) {
150 cmn_err(CE_WARN, "drm_supp_register: failed to get softstate");
151 return (NULL);
153 mstate = &entry->disl_state;
156 * DRM drivers are required to use common cb_ops
158 devop = ddi_get_driver(dip);
159 if (devop->devo_cb_ops != &drm_cb_ops) {
160 devop->devo_cb_ops = &drm_cb_ops;
163 /* Generic graphics initialization */
164 gfxp = gfxp_vgatext_softc_alloc();
165 error = gfxp_vgatext_attach(dip, DDI_ATTACH, gfxp);
166 if (error != DDI_SUCCESS) {
167 DRM_ERROR("drm_supp_regiter: failed to init gfx");
168 goto exit1;
171 /* create a minor node for common graphics ops */
172 (void) sprintf(buf, "%s%d", GFX_NAME, instance);
173 error = ddi_create_minor_node(dip, buf, S_IFCHR,
174 INST2NODE0(instance), DDI_NT_DISPLAY, 0);
175 if (error != DDI_SUCCESS) {
176 DRM_ERROR("drm_supp_regiter: "
177 "failed to create minor node for gfx");
178 goto exit2;
181 /* setup mapping for later PCI config space access */
182 error = pci_config_setup(dip, &pci_cfg_handle);
183 if (error != DDI_SUCCESS) {
184 DRM_ERROR("drm_supp_regiter: "
185 "PCI configuration space setup failed");
186 goto exit2;
189 /* AGP master attach */
190 agpm = NULL;
191 if (dp->driver->use_agp) {
192 DRM_DEBUG("drm_supp_regiter: driver use AGP\n");
193 error = agpmaster_attach(dip, &agpm,
194 pci_cfg_handle, INST2NODE1(instance));
195 if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) {
196 DRM_ERROR("drm_supp_regiter: "
197 "AGP master support not available");
198 goto exit3;
202 mutex_enter(&mstate->mis_lock);
203 mstate->mis_major = ddi_driver_major(dip);
204 mstate->mis_dip = dip;
205 mstate->mis_gfxp = gfxp;
206 mstate->mis_agpm = agpm;
207 mstate->mis_cfg_hdl = pci_cfg_handle;
208 mstate->mis_devp = dp;
209 mutex_exit(&mstate->mis_lock);
211 /* create minor node for DRM access */
212 (void) sprintf(buf, "%s%d", DRM_DEVNODE, instance);
213 if (ddi_create_minor_node(dip, buf, S_IFCHR,
214 INST2NODE2(instance), DDI_NT_DISPLAY_DRM, 0)) {
215 DRM_ERROR("supp_regiter: faled to create minor node for drm");
216 goto exit4;
219 return ((void *)mstate);
221 exit4:
222 if ((dp->driver->use_agp) && agpm)
223 agpmaster_detach(&agpm);
224 exit3:
225 pci_config_teardown(&pci_cfg_handle);
226 exit2:
227 (void) gfxp_vgatext_detach(dip, DDI_DETACH, gfxp);
228 exit1:
229 gfxp_vgatext_softc_free(gfxp);
230 drm_supp_free_drv_entry(dip);
231 ddi_remove_minor_node(dip, NULL);
233 return (NULL);
238 drm_supp_unregister(void *handle)
240 drm_inst_list_t *list;
241 drm_inst_state_t *mstate;
243 list = (drm_inst_list_t *)handle;
244 mstate = &list->disl_state;
245 mutex_enter(&mstate->mis_lock);
247 /* AGP master detach */
248 if (mstate->mis_agpm != NULL)
249 agpmaster_detach(&mstate->mis_agpm);
251 /* free PCI config access handle */
252 if (mstate->mis_cfg_hdl)
253 pci_config_teardown(&mstate->mis_cfg_hdl);
255 /* graphics misc module detach */
256 if (mstate->mis_gfxp) {
257 (void) gfxp_vgatext_detach(mstate->mis_dip, DDI_DETACH,
258 mstate->mis_gfxp);
259 gfxp_vgatext_softc_free(mstate->mis_gfxp);
262 mstate->mis_devp = NULL;
264 /* remove all minor nodes */
265 ddi_remove_minor_node(mstate->mis_dip, NULL);
266 mutex_exit(&mstate->mis_lock);
267 drm_supp_free_drv_entry(mstate->mis_dip);
269 return (DDI_SUCCESS);
273 /*ARGSUSED*/
274 static int
275 drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
277 drm_inst_state_t *mstate;
278 drm_cminor_t *mp, *newp;
279 drm_device_t *dp;
280 minor_t minor;
281 int newminor;
282 int instance;
283 int err;
285 mstate = drm_sup_devt_to_state(*devp);
287 * return ENXIO for deferred attach so that system can
288 * attach us again.
290 if (mstate == NULL)
291 return (ENXIO);
294 * The lest significant 15 bits are used for minor_number, and
295 * the mid 3 bits are used for instance number. All minor numbers
296 * are used as follows:
297 * 0 -- gfx
298 * 1 -- agpmaster
299 * 2 -- drm
300 * (3, MAX_CLONE_MINOR) -- drm minor node for clone open.
302 minor = DEV2MINOR(*devp);
303 instance = DEV2INST(*devp);
304 ASSERT(minor <= MAX_CLONE_MINOR);
307 * No operations for VGA & AGP mater devices, always return OK.
309 if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
310 return (0);
313 * From here, we start to process drm
316 dp = mstate->mis_devp;
317 if (!dp)
318 return (ENXIO);
321 * Drm driver implements a software lock to serialize access
322 * to graphics hardware based on per-process granulation. Before
323 * operating graphics hardware, all clients, including kernel
324 * and applications, must acquire this lock via DRM_IOCTL_LOCK
325 * ioctl, and release it via DRM_IOCTL_UNLOCK after finishing
326 * operations. Drm driver will grant r/w permission to the
327 * process which acquires this lock (Kernel is assumed to have
328 * process ID 0).
330 * A process might be terminated without releasing drm lock, in
331 * this case, drm driver is responsible for clearing the holding.
332 * To be informed of process exiting, drm driver uses clone open
333 * to guarantee that each call to open(9e) have one corresponding
334 * call to close(9e). In most cases, a process will close drm
335 * during process termination, so that drm driver could have a
336 * chance to release drm lock.
338 * In fact, a driver cannot know exactly when a process exits.
339 * Clone open doesn't address this issue completely: Because of
340 * inheritance, child processes inherit file descriptors from
341 * their parent. As a result, if the parent exits before its
342 * children, drm close(9e) entrypoint won't be called until all
343 * of its children terminate.
345 * Another issue brought up by inhertance is the process PID
346 * that calls the drm close() entry point may not be the same
347 * as the one who called open(). Per-process struct is allocated
348 * when a process first open() drm, and released when the process
349 * last close() drm. Since open()/close() may be not the same
350 * process, PID cannot be used for key to lookup per-process
351 * struct. So, we associate minor number with per-process struct
352 * during open()'ing, and find corresponding process struct
353 * via minor number when close() is called.
355 newp = kmem_zalloc(sizeof (drm_cminor_t), KM_SLEEP);
356 mutex_enter(&dp->dev_lock);
357 for (newminor = DRM_MIN_CLONEMINOR; newminor < MAX_CLONE_MINOR;
358 newminor ++) {
359 TAILQ_FOREACH(mp, &dp->minordevs, link) {
360 if (mp->minor == newminor)
361 break;
363 if (mp == NULL)
364 goto gotminor;
367 mutex_exit(&dp->dev_lock);
368 (void) kmem_free(newp, sizeof (drm_cminor_t));
369 return (EMFILE);
371 gotminor:
372 TAILQ_INSERT_TAIL(&dp->minordevs, newp, link);
373 newp->minor = newminor;
374 mutex_exit(&dp->dev_lock);
375 err = drm_open(dp, newp, flag, otyp, credp);
376 if (err) {
377 mutex_enter(&dp->dev_lock);
378 TAILQ_REMOVE(&dp->minordevs, newp, link);
379 (void) kmem_free(newp, sizeof (drm_cminor_t));
380 mutex_exit(&dp->dev_lock);
382 return (err);
385 /* return a clone minor */
386 newminor = newminor | (instance << NBITSMNODE);
387 *devp = makedevice(getmajor(*devp), newminor);
388 return (err);
391 /*ARGSUSED*/
392 static int
393 drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
395 drm_inst_state_t *mstate;
396 drm_device_t *dp;
397 minor_t minor;
398 int ret;
400 mstate = drm_sup_devt_to_state(dev);
401 if (mstate == NULL)
402 return (EBADF);
404 minor = DEV2MINOR(dev);
405 ASSERT(minor <= MAX_CLONE_MINOR);
406 if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
407 return (0);
409 dp = mstate->mis_devp;
410 if (dp == NULL) {
411 DRM_ERROR("drm_sun_close: NULL soft state");
412 return (ENXIO);
415 ret = drm_close(dp, minor, flag, otyp, credp);
417 return (ret);
420 /*ARGSUSED*/
421 static int
422 drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
423 cred_t *credp, int *rvalp)
425 extern drm_ioctl_desc_t drm_ioctls[];
427 drm_inst_state_t *mstate;
428 drm_device_t *dp;
429 drm_ioctl_desc_t *ioctl;
430 drm_ioctl_t *func;
431 drm_file_t *fpriv;
432 minor_t minor;
433 int retval;
434 int nr;
436 if (cmd == VIS_GETIDENTIFIER) {
437 if (ddi_copyout(&text_ident, (void *)arg,
438 sizeof (struct vis_identifier), mode))
439 return (EFAULT);
442 mstate = drm_sup_devt_to_state(dev);
443 if (mstate == NULL) {
444 return (EIO);
447 minor = DEV2MINOR(dev);
448 ASSERT(minor <= MAX_CLONE_MINOR);
449 switch (minor) {
450 case GFX_MINOR:
451 retval = gfxp_vgatext_ioctl(dev, cmd, arg,
452 mode, credp, rvalp, mstate->mis_gfxp);
453 return (retval);
455 case AGPMASTER_MINOR:
456 retval = agpmaster_ioctl(dev, cmd, arg, mode,
457 credp, rvalp, mstate->mis_agpm);
458 return (retval);
460 case DRM_MINOR:
461 default: /* DRM cloning minor nodes */
462 break;
465 dp = mstate->mis_devp;
466 ASSERT(dp != NULL);
468 nr = DRM_IOCTL_NR(cmd);
469 ioctl = &drm_ioctls[nr];
470 atomic_inc_32(&dp->counts[_DRM_STAT_IOCTLS]);
472 /* It's not a core DRM ioctl, try driver-specific. */
473 if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
474 /* The array entries begin at DRM_COMMAND_BASE ioctl nr */
475 nr -= DRM_COMMAND_BASE;
476 if (nr > dp->driver->max_driver_ioctl) {
477 DRM_ERROR("Bad driver ioctl number, 0x%x (of 0x%x)",
478 nr, dp->driver->max_driver_ioctl);
479 return (EINVAL);
481 ioctl = &dp->driver->driver_ioctls[nr];
484 func = ioctl->func;
485 if (func == NULL) {
486 return (ENOTSUP);
489 mutex_enter(&dp->dev_lock);
490 fpriv = drm_find_file_by_proc(dp, credp);
491 mutex_exit(&dp->dev_lock);
492 if (fpriv == NULL) {
493 DRM_ERROR("drm_sun_ioctl : can't find authenticator");
494 return (EACCES);
497 if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) ||
498 ((ioctl->flags & DRM_AUTH) && !fpriv->authenticated) ||
499 ((ioctl->flags & DRM_MASTER) && !fpriv->master))
500 return (EACCES);
502 fpriv->dev = dev;
503 fpriv->credp = credp;
505 retval = func(dp, arg, fpriv, mode);
507 return (retval);
510 /*ARGSUSED*/
511 static int
512 drm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset,
513 size_t len, size_t *maplen, uint_t model)
515 extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
517 drm_inst_state_t *mstate;
518 drm_device_t *dp;
519 ddi_umem_cookie_t cookie;
520 drm_local_map_t *map = NULL;
521 unsigned long aperbase;
522 uoff_t handle;
523 offset_t koff;
524 caddr_t kva;
525 minor_t minor;
526 size_t length;
527 int ret;
529 static ddi_device_acc_attr_t dev_attr = {
530 DDI_DEVICE_ATTR_V0,
531 DDI_NEVERSWAP_ACC,
532 DDI_STRICTORDER_ACC,
534 static ddi_device_acc_attr_t gem_dev_attr = {
535 DDI_DEVICE_ATTR_V0,
536 DDI_NEVERSWAP_ACC,
537 DDI_MERGING_OK_ACC
540 mstate = drm_sup_devt_to_state(dev);
541 if (mstate == NULL)
542 return (ENXIO);
544 minor = DEV2MINOR(dev);
545 switch (minor) {
546 case GFX_MINOR:
547 ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model,
548 mstate->mis_gfxp);
549 return (ret);
551 case AGPMASTER_MINOR:
552 return (ENOTSUP);
554 case DRM_MINOR:
555 break;
557 default:
558 /* DRM cloning nodes */
559 if (minor > MAX_CLONE_MINOR)
560 return (EBADF);
561 break;
565 dp = mstate->mis_devp;
566 if (dp == NULL) {
567 DRM_ERROR("drm_sun_devmap: NULL soft state");
568 return (EINVAL);
571 mutex_enter(&dp->dev_lock);
573 if (dp->driver->use_gem == 1) {
574 struct idr_list *entry;
575 drm_cminor_t *mp;
577 mp = drm_find_file_by_minor(dp, minor);
578 if (!mp) {
579 mutex_exit(&dp->dev_lock);
580 DRM_ERROR("drm_sun_devmap: can't find authenticator");
581 return (EACCES);
584 spin_lock(&dp->struct_mutex);
585 idr_list_for_each(entry, &(mp->fpriv->object_idr)) {
586 if ((uintptr_t)entry->obj == (uoff_t)offset) {
587 map = entry->obj->map;
588 goto goon;
591 goon:
592 spin_unlock(&dp->struct_mutex);
595 if (map == NULL) {
597 * We will solve 32-bit application on 64-bit kernel
598 * issue later, now, we just use low 32-bit
600 handle = (uoff_t)offset;
601 handle &= 0xffffffff;
603 TAILQ_FOREACH(map, &dp->maplist, link) {
604 if (handle ==
605 ((uoff_t)((uintptr_t)map->handle) & 0xffffffff))
606 break;
610 * Temporarily, because offset is phys_addr for register
611 * and framebuffer, is kernel virtual_addr for others
612 * Maybe we will use hash table to solve this issue later.
614 if (map == NULL) {
615 TAILQ_FOREACH(map, &dp->maplist, link) {
616 if (handle == (map->offset & 0xffffffff))
617 break;
622 if (map == NULL) {
623 uoff_t tmp;
625 mutex_exit(&dp->dev_lock);
626 cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n",
627 offset, (int)len);
628 cmn_err(CE_WARN, "Current mapping:\n");
629 TAILQ_FOREACH(map, &dp->maplist, link) {
630 tmp = (uoff_t)((uintptr_t)map->handle) & 0xffffffff;
631 cmn_err(CE_WARN, "map(handle=0x%p, size=0x%lx,type=%d,"
632 "offset=0x%lx), handle=%llx, tmp=%lld", map->handle,
633 map->size, map->type, map->offset, handle, tmp);
635 return (-1);
637 if (map->flags & _DRM_RESTRICTED) {
638 mutex_exit(&dp->dev_lock);
639 cmn_err(CE_WARN, "restricted map\n");
640 return (-1);
643 mutex_exit(&dp->dev_lock);
644 switch (map->type) {
645 case _DRM_FRAME_BUFFER:
646 case _DRM_REGISTERS:
648 int regno;
649 off_t regoff;
651 regno = drm_get_pci_index_reg(dp->dip,
652 map->offset, (uint_t)len, &regoff);
653 if (regno < 0) {
654 DRM_ERROR("devmap: failed to get register"
655 " offset=0x%llx, len=0x%x", handle, len);
656 return (EINVAL);
659 ret = devmap_devmem_setup(dhp, dp->dip, NULL,
660 regno, (offset_t)regoff, len, PROT_ALL,
661 0, &dev_attr);
662 if (ret != 0) {
663 *maplen = 0;
664 DRM_ERROR("devmap: failed, regno=%d,type=%d,"
665 " handle=0x%x, offset=0x%llx, len=0x%x",
666 regno, map->type, handle, offset, len);
667 return (ret);
669 *maplen = len;
670 return (ret);
673 case _DRM_SHM:
674 if (map->drm_umem_cookie == NULL)
675 return (EINVAL);
676 length = ptob(btopr(map->size));
677 ret = devmap_umem_setup(dhp, dp->dip, NULL,
678 map->drm_umem_cookie, 0, length,
679 PROT_ALL, IOMEM_DATA_CACHED, NULL);
680 if (ret != 0) {
681 *maplen = 0;
682 return (ret);
684 *maplen = length;
686 return (DDI_SUCCESS);
688 case _DRM_AGP:
689 if (dp->agp == NULL) {
690 cmn_err(CE_WARN, "drm_sun_devmap: attempted to mmap AGP"
691 "memory before AGP support is enabled");
692 return (DDI_FAILURE);
695 aperbase = dp->agp->base;
696 koff = map->offset - aperbase;
697 length = ptob(btopr(len));
698 kva = map->dev_addr;
699 cookie = gfxp_umem_cookie_init(kva, length);
700 if (cookie == NULL) {
701 cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
702 return (DDI_FAILURE);
705 if ((ret = devmap_umem_setup(dhp, dp->dip,
706 &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
707 IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) {
708 gfxp_umem_cookie_destroy(cookie);
709 cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
710 return (DDI_FAILURE);
712 *maplen = length;
713 break;
715 case _DRM_SCATTER_GATHER:
716 koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual;
717 kva = map->dev_addr + koff;
718 length = ptob(btopr(len));
719 if (length > map->size) {
720 cmn_err(CE_WARN, "offset=0x%lx, virtual=0x%p,"
721 "mapsize=0x%lx,len=0x%lx", map->offset,
722 dp->sg->virtual, map->size, len);
723 return (DDI_FAILURE);
725 cookie = gfxp_umem_cookie_init(kva, length);
726 if (cookie == NULL) {
727 cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
728 return (DDI_FAILURE);
730 ret = devmap_umem_setup(dhp, dp->dip,
731 &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
732 IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
733 if (ret != 0) {
734 cmn_err(CE_WARN, "sun_devmap: umem_setup fail");
735 gfxp_umem_cookie_destroy(cookie);
736 return (DDI_FAILURE);
738 *maplen = length;
739 break;
741 case _DRM_TTM:
742 if (map->drm_umem_cookie == NULL)
743 return (EINVAL);
745 if (gfxp_devmap_umem_setup(dhp, dp->dip,
746 NULL, map->drm_umem_cookie, 0, map->size, PROT_ALL,
747 IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP,
748 &gem_dev_attr)) {
749 cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
750 return (DDI_FAILURE);
752 *maplen = map->size;
753 return (DDI_SUCCESS);
755 default:
756 return (DDI_FAILURE);
758 return (DDI_SUCCESS);
762 /*ARGSUSED*/
763 static int
764 drm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags,
765 offset_t offset, size_t len, void **new_priv)
767 devmap_handle_t *dhp;
768 drm_inst_state_t *statep;
769 struct ddi_umem_cookie *cp;
771 statep = drm_sup_devt_to_state(dev);
772 ASSERT(statep != NULL);
775 * This driver only supports MAP_SHARED,
776 * and doesn't support MAP_PRIVATE
778 if (flags & MAP_PRIVATE) {
779 cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
780 return (EINVAL);
783 mutex_enter(&statep->dis_ctxlock);
784 dhp = (devmap_handle_t *)dhc;
785 cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
786 cp->cook_refcnt = 1;
787 mutex_exit(&statep->dis_ctxlock);
788 *new_priv = statep;
790 return (0);
793 /*ARGSUSED*/
794 static void
795 drm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
796 devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
797 void **new_pvtp2)
799 devmap_handle_t *dhp;
800 devmap_handle_t *ndhp;
801 drm_inst_state_t *statep;
802 struct ddi_umem_cookie *cp;
803 struct ddi_umem_cookie *ncp;
805 dhp = (devmap_handle_t *)dhc;
806 statep = (drm_inst_state_t *)pvtp;
808 mutex_enter(&statep->dis_ctxlock);
809 cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
810 if (new_dhp1 != NULL) {
811 ndhp = (devmap_handle_t *)new_dhp1;
812 ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
813 ncp->cook_refcnt ++;
814 *new_pvtp1 = statep;
815 ASSERT(ncp == cp);
818 if (new_dhp2 != NULL) {
819 ndhp = (devmap_handle_t *)new_dhp2;
820 ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
821 ncp->cook_refcnt ++;
822 *new_pvtp2 = statep;
823 ASSERT(ncp == cp);
826 cp->cook_refcnt --;
827 if (cp->cook_refcnt == 0) {
828 gfxp_umem_cookie_destroy(dhp->dh_cookie);
829 dhp->dh_cookie = NULL;
831 mutex_exit(&statep->dis_ctxlock);
835 /*ARGSUSED*/
836 static int
837 drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
838 void **new_pvtp)
840 devmap_handle_t *dhp;
841 drm_inst_state_t *statep;
842 struct ddi_umem_cookie *cp;
844 statep = (drm_inst_state_t *)pvtp;
845 mutex_enter(&statep->dis_ctxlock);
846 dhp = (devmap_handle_t *)dhc;
847 cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
848 cp->cook_refcnt ++;
849 mutex_exit(&statep->dis_ctxlock);
850 *new_pvtp = statep;
852 return (0);
856 drm_dev_to_instance(dev_t dev)
858 return (DEV2INST(dev));
862 * drm_supp_alloc_drv_entry()
864 * Description:
865 * Create a DRM entry and add it into the instance list (drm_inst_head).
866 * Note that we don't allow a duplicated entry
868 static drm_inst_list_t *
869 drm_supp_alloc_drv_entry(dev_info_t *dip)
871 drm_inst_list_t **plist;
872 drm_inst_list_t *list;
873 drm_inst_list_t *entry;
875 /* protect the driver list */
876 mutex_enter(&drm_inst_list_lock);
877 plist = &drm_inst_head;
878 list = *plist;
879 while (list) {
880 if (list->disl_state.mis_dip == dip) {
881 mutex_exit(&drm_inst_list_lock);
882 cmn_err(CE_WARN, "%s%d already registered",
883 ddi_driver_name(dip), ddi_get_instance(dip));
884 return (NULL);
886 plist = &list->disl_next;
887 list = list->disl_next;
890 /* "dip" is not registered, create new one and add to list */
891 entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
892 *plist = entry;
893 entry->disl_state.mis_dip = dip;
894 mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL);
895 mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL);
896 mutex_exit(&drm_inst_list_lock);
898 return (entry);
900 } /* drm_supp_alloc_drv_entry */
903 * drm_supp_free_drv_entry()
905 static void
906 drm_supp_free_drv_entry(dev_info_t *dip)
908 drm_inst_list_t *list;
909 drm_inst_list_t **plist;
910 drm_inst_state_t *mstate;
912 /* protect the driver list */
913 mutex_enter(&drm_inst_list_lock);
914 plist = &drm_inst_head;
915 list = *plist;
916 while (list) {
917 if (list->disl_state.mis_dip == dip) {
918 *plist = list->disl_next;
919 mstate = &list->disl_state;
920 mutex_destroy(&mstate->mis_lock);
921 mutex_destroy(&mstate->dis_ctxlock);
922 kmem_free(list, sizeof (*list));
923 mutex_exit(&drm_inst_list_lock);
924 return;
926 plist = &list->disl_next;
927 list = list->disl_next;
929 mutex_exit(&drm_inst_list_lock);
931 } /* drm_supp_free_drv_entry() */
934 * drm_sup_devt_to_state()
936 * description:
937 * Get the soft state of DRM instance by device number
939 static drm_inst_state_t *
940 drm_sup_devt_to_state(dev_t dev)
942 drm_inst_list_t *list;
943 drm_inst_state_t *mstate;
944 major_t major = getmajor(dev);
945 int instance = DEV2INST(dev);
947 mutex_enter(&drm_inst_list_lock);
948 list = drm_inst_head;
949 while (list) {
950 mstate = &list->disl_state;
951 mutex_enter(&mstate->mis_lock);
953 if ((mstate->mis_major == major) &&
954 (ddi_get_instance(mstate->mis_dip) == instance)) {
955 mutex_exit(&mstate->mis_lock);
956 mutex_exit(&drm_inst_list_lock);
957 return (mstate);
960 list = list->disl_next;
961 mutex_exit(&mstate->mis_lock);
964 mutex_exit(&drm_inst_list_lock);
965 return (NULL);
967 } /* drm_sup_devt_to_state() */
970 drm_supp_get_irq(void *handle)
972 drm_inst_list_t *list;
973 drm_inst_state_t *mstate;
974 int irq;
976 list = (drm_inst_list_t *)handle;
977 mstate = &list->disl_state;
978 ASSERT(mstate != NULL);
979 irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE);
980 return (irq);
984 drm_supp_device_capability(void *handle, int capid)
986 drm_inst_list_t *list;
987 drm_inst_state_t *mstate;
988 uint8_t cap = 0;
989 uint16_t caps_ptr;
991 list = (drm_inst_list_t *)handle;
992 mstate = &list->disl_state;
993 ASSERT(mstate != NULL);
995 /* has capabilities list ? */
996 if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) &
997 PCI_CONF_CAP_MASK) == 0)
998 return (0);
1000 caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR);
1001 while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
1002 cap = pci_config_get32(mstate->mis_cfg_hdl, caps_ptr);
1003 if ((cap & PCI_CONF_CAPID_MASK) == capid)
1004 return (cap);
1005 caps_ptr = pci_config_get8(mstate->mis_cfg_hdl,
1006 caps_ptr + PCI_CAP_NEXT_PTR);
1009 return (0);