xref: /titanic_44/usr/src/uts/common/io/drm/drm_sunmod.c (revision 98157a7002f4f2cf7978f3084ca5577f0a1d72b2)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Common misc module interfaces of DRM under Solaris
31  */
32 
33 /*
34  * This module calls into gfx and agpmaster misc modules respectively
35  * for generic graphics operations and AGP master device support.
36  */
37 
38 #include "drm_sunmod.h"
39 #include <sys/modctl.h>
40 #include <sys/kmem.h>
41 #include <vm/seg_kmem.h>
42 
43 static struct modlmisc modlmisc = {
44 	&mod_miscops, "DRM common interfaces %I%"
45 };
46 
47 static struct modlinkage modlinkage = {
48 	MODREV_1, (void *)&modlmisc, NULL
49 };
50 
51 static drm_inst_list_t	*drm_inst_head;
52 static kmutex_t	drm_inst_list_lock;
53 
54 static int drm_sun_open(dev_t *, int, int, cred_t *);
55 static int drm_sun_close(dev_t, int, int, cred_t *);
56 static int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
57 static int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
58     size_t *, uint_t);
59 
60 /*
61  * devmap callbacks for AGP and PCI GART
62  */
63 static int drm_devmap_map(devmap_cookie_t, dev_t,
64     uint_t, offset_t, size_t, void **);
65 static int drm_devmap_dup(devmap_cookie_t, void *,
66     devmap_cookie_t, void **);
67 static void drm_devmap_unmap(devmap_cookie_t, void *,
68     offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **);
69 
70 static drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *);
71 static drm_inst_state_t *drm_sup_devt_to_state(dev_t);
72 static void drm_supp_free_drv_entry(dev_info_t *);
73 
74 static struct devmap_callback_ctl drm_devmap_callbacks = {
75 		DEVMAP_OPS_REV, 		/* devmap_rev */
76 		drm_devmap_map,				/* devmap_map */
77 		NULL,			/* devmap_access */
78 		drm_devmap_dup,			/* devmap_dup */
79 		drm_devmap_unmap 		/* devmap_unmap */
80 };
81 
82 /*
83  * Common device operations structure for all DRM drivers
84  */
85 struct cb_ops drm_cb_ops = {
86 	drm_sun_open,			/* cb_open */
87 	drm_sun_close,			/* cb_close */
88 	nodev,					/* cb_strategy */
89 	nodev,					/* cb_print */
90 	nodev,					/* cb_dump */
91 	nodev,					/* cb_read */
92 	nodev,					/* cb_write */
93 	drm_sun_ioctl,		/* cb_ioctl */
94 	drm_sun_devmap,		/* cb_devmap */
95 	nodev,					/* cb_mmap */
96 	NULL,			/* cb_segmap */
97 	nochpoll,				/* cb_chpoll */
98 	ddi_prop_op,		/* cb_prop_op */
99 	0,					/* cb_stream */
100 	D_NEW | D_MTSAFE |D_DEVMAP	/* cb_flag */
101 };
102 
103 
104 int
105 _init(void)
106 {
107 	int	error;
108 
109 	if ((error = mod_install(&modlinkage)) != 0) {
110 		return (error);
111 	}
112 
113 	/* initialize the instance list lock */
114 	mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
115 	return (0);
116 }
117 
118 int
119 _fini(void)
120 {
121 	int	err;
122 
123 	if ((err = mod_remove(&modlinkage)) != 0)
124 		return (err);
125 
126 	mutex_destroy(&drm_inst_list_lock);
127 	return (0);
128 }
129 
130 int
131 _info(struct modinfo *modinfop)
132 {
133 	return (mod_info(&modlinkage, modinfop));
134 }
135 
136 void *
137 drm_supp_register(dev_info_t *dip, drm_device_t *dp)
138 {
139 	int		error;
140 	char	buf[80];
141 	int		instance = ddi_get_instance(dip);
142 	ddi_acc_handle_t	pci_cfg_handle;
143 	agp_master_softc_t	*agpm;
144 	drm_inst_state_t	*mstate;
145 	drm_inst_list_t		*entry;
146 	gfxp_vgatext_softc_ptr_t gfxp;
147 	struct dev_ops	*devop;
148 
149 	ASSERT(dip != NULL);
150 
151 	entry = drm_supp_alloc_drv_entry(dip);
152 	if (entry == NULL) {
153 		cmn_err(CE_WARN, "drm_supp_register: failed to get softstate");
154 		return (NULL);
155 	}
156 	mstate = &entry->disl_state;
157 
158 	/*
159 	 * DRM drivers are required to use common cb_ops
160 	 */
161 	devop = ddi_get_driver(dip);
162 	if (devop->devo_cb_ops != &drm_cb_ops) {
163 		devop->devo_cb_ops = &drm_cb_ops;
164 	}
165 
166 	/* Generic graphics initialization */
167 	gfxp = gfxp_vgatext_softc_alloc();
168 	error = gfxp_vgatext_attach(dip, DDI_ATTACH, gfxp);
169 	if (error != DDI_SUCCESS) {
170 		DRM_ERROR("drm_supp_regiter: failed to init gfx");
171 		goto exit1;
172 	}
173 
174 	/* create a minor node for common graphics ops */
175 	(void) sprintf(buf, "%s%d", GFX_NAME, instance);
176 	error = ddi_create_minor_node(dip, buf, S_IFCHR,
177 	    INST2NODE0(instance), DDI_NT_DISPLAY, NULL);
178 	if (error != DDI_SUCCESS) {
179 		DRM_ERROR("drm_supp_regiter: "
180 		    "failed to create minor node for gfx");
181 		goto exit2;
182 	}
183 
184 	/* setup mapping for later PCI config space access */
185 	error = pci_config_setup(dip, &pci_cfg_handle);
186 	if (error != DDI_SUCCESS) {
187 		DRM_ERROR("drm_supp_regiter: "
188 		    "PCI configuration space setup failed");
189 		goto exit2;
190 	}
191 
192 	/* AGP master attach */
193 	agpm = NULL;
194 	if (dp->driver->use_agp) {
195 		DRM_DEBUG("drm_supp_regiter: driver use AGP\n");
196 		error = agpmaster_attach(dip, &agpm,
197 		    pci_cfg_handle, INST2NODE1(instance));
198 		if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) {
199 			DRM_ERROR("drm_supp_regiter: "
200 			    "AGP master support not available");
201 			goto exit3;
202 		}
203 	}
204 
205 	mutex_enter(&mstate->mis_lock);
206 	mstate->mis_major = ddi_driver_major(dip);
207 	mstate->mis_dip = dip;
208 	mstate->mis_gfxp = gfxp;
209 	mstate->mis_agpm = agpm;
210 	mstate->mis_cfg_hdl = pci_cfg_handle;
211 	mstate->mis_devp = dp;
212 	mutex_exit(&mstate->mis_lock);
213 
214 	/* create minor node for DRM access */
215 	(void) sprintf(buf, "%s%d", DRM_DEVNODE, instance);
216 	if (ddi_create_minor_node(dip, buf, S_IFCHR,
217 	    INST2NODE2(instance), DDI_NT_DISPLAY_DRM, 0)) {
218 		DRM_ERROR("supp_regiter: faled to create minor node for drm");
219 		goto exit4;
220 	}
221 
222 	return ((void *)mstate);
223 
224 exit4:
225 	if ((dp->driver->use_agp) && agpm)
226 		agpmaster_detach(&agpm);
227 exit3:
228 	pci_config_teardown(&pci_cfg_handle);
229 exit2:
230 	gfxp_vgatext_detach(dip, DDI_DETACH, gfxp);
231 exit1:
232 	gfxp_vgatext_softc_free(gfxp);
233 	drm_supp_free_drv_entry(dip);
234 	ddi_remove_minor_node(dip, NULL);
235 
236 	return (NULL);
237 }
238 
239 
240 int
241 drm_supp_unregister(void *handle)
242 {
243 	drm_inst_list_t		*list;
244 	drm_inst_state_t	*mstate;
245 
246 	list = (drm_inst_list_t *)handle;
247 	mstate = &list->disl_state;
248 	mutex_enter(&mstate->mis_lock);
249 
250 	/* AGP master detach */
251 	if (mstate->mis_agpm != NULL)
252 		agpmaster_detach(&mstate->mis_agpm);
253 
254 	/* free PCI config access handle */
255 	if (mstate->mis_cfg_hdl)
256 		pci_config_teardown(&mstate->mis_cfg_hdl);
257 
258 	/* graphics misc module detach */
259 	if (mstate->mis_gfxp) {
260 		(void) gfxp_vgatext_detach(mstate->mis_dip, DDI_DETACH,
261 		    mstate->mis_gfxp);
262 		gfxp_vgatext_softc_free(mstate->mis_gfxp);
263 	}
264 
265 	mstate->mis_devp = NULL;
266 
267 	/* remove all minor nodes */
268 	ddi_remove_minor_node(mstate->mis_dip, NULL);
269 	mutex_exit(&mstate->mis_lock);
270 	drm_supp_free_drv_entry(mstate->mis_dip);
271 
272 	return (DDI_SUCCESS);
273 }
274 
275 
276 /*ARGSUSED*/
277 static int
278 drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
279 {
280 	drm_inst_state_t	*mstate;
281 	drm_device_t	*dp;
282 	struct minordev *mp, *newp;
283 	int cloneminor;
284 	minor_t		minor;
285 	int			err;
286 
287 	mstate = drm_sup_devt_to_state(*devp);
288 	/*
289 	 * return ENXIO for deferred attach so that system can
290 	 * attach us again.
291 	 */
292 	if (mstate == NULL)
293 		return (ENXIO);
294 
295 	minor = DEV2MINOR(*devp);
296 	ASSERT(minor <= MAX_CLONE_MINOR);
297 	if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
298 		return (0);
299 
300 	/*
301 	 * From here, we start to process drm
302 	 */
303 
304 	dp = mstate->mis_devp;
305 	if (!dp)
306 		return (ENXIO);
307 
308 	/*
309 	 * Here, minor consists of minor_number and instance number
310 	 * the first 3 bits is for instance number.
311 	 */
312 	minor = getminor(*devp);
313 
314 	newp = kmem_zalloc(sizeof (struct minordev), KM_SLEEP);
315 	mutex_enter(&dp->dev_lock);
316 	for (cloneminor = minor; cloneminor < MAX_CLONE_MINOR;
317 	    cloneminor += 1) {
318 		for (mp = dp->minordevs; mp != NULL; mp = mp->next) {
319 			if (mp->cloneminor == cloneminor) {
320 				break;
321 			}
322 		}
323 		if (mp == NULL)
324 			goto gotminor;
325 	}
326 
327 	mutex_exit(&dp->dev_lock);
328 	return (EMFILE);
329 
330 gotminor:
331 	newp->next = dp->minordevs;
332 	newp->cloneminor = cloneminor;
333 	dp->minordevs = newp;
334 	dp->cloneopens++;
335 	mutex_exit(&dp->dev_lock);
336 	err = drm_open(dp, devp, flag, otyp, credp);
337 	*devp = makedevice(getmajor(*devp), cloneminor);
338 	return (err);
339 }
340 
341 /*ARGSUSED*/
342 static int
343 drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
344 {
345 	drm_inst_state_t	*mstate;
346 	drm_device_t		*dp;
347 	struct minordev		*lastp, *mp;
348 	minor_t minor;
349 
350 	mstate = drm_sup_devt_to_state(dev);
351 	if (mstate == NULL)
352 		return (EBADF);
353 
354 	minor = DEV2MINOR(dev);
355 	ASSERT(minor <= MAX_CLONE_MINOR);
356 	if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
357 		return (0);
358 
359 	dp = mstate->mis_devp;
360 	if (dp == NULL) {
361 		DRM_ERROR("drm_sun_close: NULL soft state");
362 		return (ENXIO);
363 	}
364 
365 	lastp = NULL;
366 	mutex_enter(&dp->dev_lock);
367 	for (mp = dp->minordevs; mp != NULL; mp = mp->next) {
368 		if (mp->cloneminor == minor) {
369 			if (lastp == NULL)
370 				dp->minordevs = mp->next;
371 			else
372 				lastp->next = mp->next;
373 			dp->cloneopens--;
374 			(void) kmem_free(mp, sizeof (struct minordev));
375 			break;
376 		} else
377 			lastp = mp;
378 	}
379 	mutex_exit(&dp->dev_lock);
380 
381 	return (drm_close(dp, dev, flag, otyp, credp));
382 }
383 
384 /*ARGSUSED*/
385 static int
386 drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
387     cred_t *credp, int *rvalp)
388 {
389 	extern drm_ioctl_desc_t drm_ioctls[];
390 
391 	drm_inst_state_t	*mstate;
392 	drm_device_t		*dp;
393 	drm_ioctl_desc_t	*ioctl;
394 	drm_ioctl_t		*func;
395 	drm_file_t		*fpriv;
396 	minor_t		minor;
397 	int		retval;
398 	int		nr;
399 
400 	if (cmd == VIS_GETIDENTIFIER) {
401 		if (ddi_copyout(&text_ident, (void *)arg,
402 		    sizeof (struct vis_identifier), mode))
403 			return (EFAULT);
404 	}
405 
406 	mstate = drm_sup_devt_to_state(dev);
407 	if (mstate == NULL) {
408 		return (EIO);
409 	}
410 
411 	minor = DEV2MINOR(dev);
412 	ASSERT(minor <= MAX_CLONE_MINOR);
413 	switch (minor) {
414 	case GFX_MINOR:
415 		retval = gfxp_vgatext_ioctl(dev, cmd, arg,
416 		    mode, credp, rvalp, mstate->mis_gfxp);
417 		return (retval);
418 
419 	case AGPMASTER_MINOR:
420 		retval = agpmaster_ioctl(dev, cmd, arg, mode,
421 		    credp, rvalp, mstate->mis_agpm);
422 		return (retval);
423 
424 	case DRM_MINOR:
425 	default:	/* DRM cloning minor nodes */
426 		break;
427 	}
428 
429 	dp = mstate->mis_devp;
430 	ASSERT(dp != NULL);
431 
432 	nr = DRM_IOCTL_NR(cmd);
433 	ioctl = &drm_ioctls[nr];
434 	atomic_inc_32(&dp->counts[_DRM_STAT_IOCTLS]);
435 
436 	/* It's not a core DRM ioctl, try driver-specific. */
437 	if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
438 		/* The array entries begin at DRM_COMMAND_BASE ioctl nr */
439 		nr -= DRM_COMMAND_BASE;
440 		if (nr > dp->driver->max_driver_ioctl) {
441 			DRM_ERROR("Bad driver ioctl number, 0x%x (of 0x%x)",
442 			    nr, dp->driver->max_driver_ioctl);
443 			return (EINVAL);
444 		}
445 		ioctl = &dp->driver->driver_ioctls[nr];
446 	}
447 
448 	func = ioctl->func;
449 	if (func == NULL) {
450 		return (ENOTSUP);
451 	}
452 
453 	mutex_enter(&dp->dev_lock);
454 	fpriv = drm_find_file_by_proc(dp, credp);
455 	mutex_exit(&dp->dev_lock);
456 	if (fpriv == NULL) {
457 		DRM_ERROR("drm_sun_ioctl : can't find authenticator");
458 		return (EACCES);
459 	}
460 
461 	if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) ||
462 	    ((ioctl->flags & DRM_AUTH) && !fpriv->authenticated) ||
463 	    ((ioctl->flags & DRM_MASTER) && !fpriv->master))
464 		return (EACCES);
465 
466 	retval = func(dp, arg, fpriv, mode);
467 
468 	return (retval);
469 }
470 
471 /*ARGSUSED*/
472 static int
473 drm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset,
474     size_t len, size_t *maplen, uint_t model)
475 {
476 	extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
477 
478 	drm_inst_state_t	*mstate;
479 	drm_device_t		*dp;
480 	ddi_umem_cookie_t	cookie;
481 	drm_local_map_t		*map;
482 	unsigned long	aperbase;
483 	u_offset_t		handle;
484 	offset_t		koff;
485 	caddr_t			kva;
486 	minor_t			minor;
487 	size_t			length;
488 	int			ret;
489 
490 	static ddi_device_acc_attr_t dev_attr = {
491 		DDI_DEVICE_ATTR_V0,
492 		DDI_NEVERSWAP_ACC,
493 		DDI_STRICTORDER_ACC,
494 	};
495 
496 	mstate = drm_sup_devt_to_state(dev);
497 	if (mstate == NULL)
498 		return (ENXIO);
499 
500 	minor = DEV2MINOR(dev);
501 	switch (minor) {
502 	case GFX_MINOR:
503 		ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model,
504 		    mstate->mis_gfxp);
505 		return (ret);
506 
507 	case AGPMASTER_MINOR:
508 		return (ENOTSUP);
509 
510 	case DRM_MINOR:
511 		break;
512 
513 	default:
514 		/* DRM cloning nodes */
515 		if (minor > MAX_CLONE_MINOR)
516 			return (EBADF);
517 		break;
518 	}
519 
520 
521 	dp = mstate->mis_devp;
522 	if (dp == NULL) {
523 		DRM_ERROR("drm_sun_devmap: NULL soft state");
524 		return (EINVAL);
525 	}
526 
527 	/*
528 	 * We will solve 32-bit application on 64-bit kernel
529 	 * issue later, now, we just use low 32-bit
530 	 */
531 	handle = (u_offset_t)offset;
532 	handle &= 0xffffffff;
533 	mutex_enter(&dp->dev_lock);
534 	TAILQ_FOREACH(map, &dp->maplist, link) {
535 		if (handle ==
536 		    ((u_offset_t)((uintptr_t)map->handle) & 0xffffffff))
537 			break;
538 	}
539 
540 	/*
541 	 * Temporarily, because offset is phys_addr for register
542 	 * and framebuffer, is kernel virtual_addr for others
543 	 * Maybe we will use hash table to solve this issue later.
544 	 */
545 	if (map == NULL) {
546 		TAILQ_FOREACH(map, &dp->maplist, link) {
547 			if (handle == (map->offset & 0xffffffff))
548 				break;
549 		}
550 	}
551 
552 	if (map == NULL) {
553 		u_offset_t	tmp;
554 
555 		mutex_exit(&dp->dev_lock);
556 		cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n",
557 		    offset, (int)len);
558 		cmn_err(CE_WARN, "Current mapping:\n");
559 		TAILQ_FOREACH(map, &dp->maplist, link) {
560 		tmp = (u_offset_t)((uintptr_t)map->handle) & 0xffffffff;
561 		cmn_err(CE_WARN, "map(handle=0x%p, size=0x%lx,type=%d,"
562 		    "offset=0x%lx), handle=%llx, tmp=%lld", map->handle,
563 		    map->size, map->type, map->offset, handle, tmp);
564 		}
565 		return (-1);
566 	}
567 	if (map->flags & _DRM_RESTRICTED) {
568 		mutex_exit(&dp->dev_lock);
569 		cmn_err(CE_WARN, "restricted map\n");
570 		return (-1);
571 	}
572 
573 	mutex_exit(&dp->dev_lock);
574 	switch (map->type) {
575 	case _DRM_FRAME_BUFFER:
576 	case _DRM_REGISTERS:
577 		{
578 			int	regno;
579 			off_t	regoff;
580 
581 			regno = drm_get_pci_index_reg(dp->dip,
582 			    map->offset, (uint_t)len, &regoff);
583 			if (regno < 0) {
584 				DRM_ERROR("devmap: failed to get register"
585 				    " offset=0x%llx, len=0x%x", handle, len);
586 				return (EINVAL);
587 			}
588 
589 			ret = devmap_devmem_setup(dhp, dp->dip, NULL,
590 			    regno, (offset_t)regoff, len, PROT_ALL,
591 			    0, &dev_attr);
592 			if (ret != 0) {
593 				*maplen = 0;
594 				DRM_ERROR("devmap: failed, regno=%d,type=%d,"
595 				    " handle=0x%x, offset=0x%llx, len=0x%x",
596 				    regno, map->type, handle, offset, len);
597 				return (ret);
598 			}
599 			*maplen = len;
600 			return (ret);
601 		}
602 
603 	case _DRM_SHM:
604 		if (map->drm_umem_cookie == NULL)
605 			return (EINVAL);
606 		length = ptob(btopr(map->size));
607 		ret = devmap_umem_setup(dhp, dp->dip, NULL,
608 		    map->drm_umem_cookie, 0, length,
609 		    PROT_ALL, IOMEM_DATA_CACHED, NULL);
610 		if (ret != 0) {
611 			*maplen = 0;
612 			return (ret);
613 		}
614 		*maplen = length;
615 
616 		return (DDI_SUCCESS);
617 
618 	case _DRM_AGP:
619 		if (dp->agp == NULL) {
620 			cmn_err(CE_WARN, "drm_sun_devmap: attempted to mmap AGP"
621 			    "memory before AGP support is enabled");
622 			return (DDI_FAILURE);
623 		}
624 
625 		aperbase = dp->agp->base;
626 		koff = map->offset - aperbase;
627 		length = ptob(btopr(len));
628 		kva = map->dev_addr;
629 		cookie = gfxp_umem_cookie_init(kva, length);
630 		if (cookie == NULL) {
631 			cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
632 			return (DDI_FAILURE);
633 		}
634 
635 		if ((ret = devmap_umem_setup(dhp, dp->dip,
636 		    &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
637 		    IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) {
638 			gfxp_umem_cookie_destroy(cookie);
639 			cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
640 			return (DDI_FAILURE);
641 		}
642 		*maplen = length;
643 		break;
644 
645 	case _DRM_SCATTER_GATHER:
646 		koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual;
647 		kva = map->dev_addr + koff;
648 		length = ptob(btopr(len));
649 		if (length > map->size) {
650 			cmn_err(CE_WARN, "offset=0x%lx, virtual=0x%p,"
651 			    "mapsize=0x%lx,len=0x%lx", map->offset,
652 			    dp->sg->virtual, map->size, len);
653 			return (DDI_FAILURE);
654 		}
655 		cookie = gfxp_umem_cookie_init(kva, length);
656 		if (cookie == NULL) {
657 			cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
658 			return (DDI_FAILURE);
659 		}
660 		ret = devmap_umem_setup(dhp, dp->dip,
661 		    &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
662 		    IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
663 		if (ret != 0) {
664 			cmn_err(CE_WARN, "sun_devmap: umem_setup fail");
665 			gfxp_umem_cookie_destroy(cookie);
666 			return (DDI_FAILURE);
667 		}
668 		*maplen = length;
669 		break;
670 
671 	default:
672 		return (DDI_FAILURE);
673 	}
674 	return (DDI_SUCCESS);
675 
676 }
677 
678 /*ARGSUSED*/
679 static int
680 drm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags,
681     offset_t offset, size_t len, void **new_priv)
682 {
683 	devmap_handle_t			*dhp;
684 	drm_inst_state_t		*statep;
685 	struct ddi_umem_cookie 	*cp;
686 
687 	statep = drm_sup_devt_to_state(dev);
688 	ASSERT(statep != NULL);
689 
690 	/*
691 	 * This driver only supports MAP_SHARED,
692 	 * and doesn't support MAP_PRIVATE
693 	 */
694 	if (flags & MAP_PRIVATE) {
695 		cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
696 		return (EINVAL);
697 	}
698 
699 	mutex_enter(&statep->dis_ctxlock);
700 	dhp = (devmap_handle_t *)dhc;
701 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
702 	cp->cook_refcnt = 1;
703 	mutex_exit(&statep->dis_ctxlock);
704 	*new_priv = statep;
705 
706 	return (0);
707 }
708 
709 /*ARGSUSED*/
710 static void
711 drm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
712     devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
713     void **new_pvtp2)
714 {
715 	devmap_handle_t		*dhp;
716 	devmap_handle_t		*ndhp;
717 	drm_inst_state_t		*statep;
718 	struct ddi_umem_cookie	*cp;
719 	struct ddi_umem_cookie	*ncp;
720 
721 	dhp = (devmap_handle_t *)dhc;
722 	statep = (drm_inst_state_t *)pvtp;
723 
724 	mutex_enter(&statep->dis_ctxlock);
725 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
726 	if (new_dhp1 != NULL) {
727 		ndhp = (devmap_handle_t *)new_dhp1;
728 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
729 		ncp->cook_refcnt ++;
730 		*new_pvtp1 = statep;
731 		ASSERT(ncp == cp);
732 	}
733 
734 	if (new_dhp2 != NULL) {
735 		ndhp = (devmap_handle_t *)new_dhp2;
736 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
737 		ncp->cook_refcnt ++;
738 		*new_pvtp2 = statep;
739 		ASSERT(ncp == cp);
740 	}
741 
742 	cp->cook_refcnt --;
743 	if (cp->cook_refcnt == 0) {
744 		gfxp_umem_cookie_destroy(dhp->dh_cookie);
745 		dhp->dh_cookie = NULL;
746 	}
747 	mutex_exit(&statep->dis_ctxlock);
748 }
749 
750 
751 /*ARGSUSED*/
752 static int
753 drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
754     void **new_pvtp)
755 {
756 	devmap_handle_t			*dhp;
757 	drm_inst_state_t    *statep;
758 	struct ddi_umem_cookie *cp;
759 
760 	statep = (drm_inst_state_t *)pvtp;
761 	mutex_enter(&statep->dis_ctxlock);
762 	dhp = (devmap_handle_t *)dhc;
763 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
764 	cp->cook_refcnt ++;
765 	mutex_exit(&statep->dis_ctxlock);
766 	*new_pvtp = statep;
767 
768 	return (0);
769 }
770 
771 int
772 drm_dev_to_instance(dev_t dev)
773 {
774 	return (DEV2INST(dev));
775 }
776 
777 /*
778  * drm_supp_alloc_drv_entry()
779  *
780  * Description:
781  *	Create a DRM entry and add it into the instance list (drm_inst_head).
782  *	Note that we don't allow a duplicated entry
783  */
784 static drm_inst_list_t *
785 drm_supp_alloc_drv_entry(dev_info_t *dip)
786 {
787 	drm_inst_list_t	**plist;
788 	drm_inst_list_t	*list;
789 	drm_inst_list_t	*entry;
790 
791 	/* protect the driver list */
792 	mutex_enter(&drm_inst_list_lock);
793 	plist = &drm_inst_head;
794 	list = *plist;
795 	while (list) {
796 		if (list->disl_state.mis_dip == dip) {
797 			mutex_exit(&drm_inst_list_lock);
798 			cmn_err(CE_WARN, "%s%d already registered",
799 			    ddi_driver_name(dip), ddi_get_instance(dip));
800 			return (NULL);
801 		}
802 		plist = &list->disl_next;
803 		list = list->disl_next;
804 	}
805 
806 	/* "dip" is not registered, create new one and add to list */
807 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
808 	*plist = entry;
809 	entry->disl_state.mis_dip = dip;
810 	mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL);
811 	mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL);
812 	mutex_exit(&drm_inst_list_lock);
813 
814 	return (entry);
815 
816 }	/* drm_supp_alloc_drv_entry */
817 
818 /*
819  * drm_supp_free_drv_entry()
820  */
821 static void
822 drm_supp_free_drv_entry(dev_info_t *dip)
823 {
824 	drm_inst_list_t		*list;
825 	drm_inst_list_t		**plist;
826 	drm_inst_state_t	*mstate;
827 
828 	/* protect the driver list */
829 	mutex_enter(&drm_inst_list_lock);
830 	plist = &drm_inst_head;
831 	list = *plist;
832 	while (list) {
833 		if (list->disl_state.mis_dip == dip) {
834 			*plist = list->disl_next;
835 			mstate = &list->disl_state;
836 			mutex_destroy(&mstate->mis_lock);
837 			mutex_destroy(&mstate->dis_ctxlock);
838 			kmem_free(list, sizeof (*list));
839 			mutex_exit(&drm_inst_list_lock);
840 			return;
841 		}
842 		plist = &list->disl_next;
843 		list = list->disl_next;
844 	}
845 	mutex_exit(&drm_inst_list_lock);
846 
847 }	/* drm_supp_free_drv_entry() */
848 
849 /*
850  * drm_sup_devt_to_state()
851  *
852  * description:
853  *	Get the soft state of DRM instance by device number
854  */
855 static drm_inst_state_t *
856 drm_sup_devt_to_state(dev_t dev)
857 {
858 	drm_inst_list_t	*list;
859 	drm_inst_state_t	*mstate;
860 	major_t	major = getmajor(dev);
861 	int		instance = DEV2INST(dev);
862 
863 	mutex_enter(&drm_inst_list_lock);
864 	list = drm_inst_head;
865 	while (list) {
866 		mstate = &list->disl_state;
867 		mutex_enter(&mstate->mis_lock);
868 
869 		if ((mstate->mis_major == major) &&
870 		    (ddi_get_instance(mstate->mis_dip) == instance)) {
871 			mutex_exit(&mstate->mis_lock);
872 			mutex_exit(&drm_inst_list_lock);
873 			return (mstate);
874 		}
875 
876 		list = list->disl_next;
877 		mutex_exit(&mstate->mis_lock);
878 	}
879 
880 	mutex_exit(&drm_inst_list_lock);
881 	return (NULL);
882 
883 }	/* drm_sup_devt_to_state() */
884 
885 int
886 drm_supp_get_irq(void *handle)
887 {
888 	drm_inst_list_t *list;
889 	drm_inst_state_t    *mstate;
890 	int		irq;
891 
892 	list = (drm_inst_list_t *)handle;
893 	mstate = &list->disl_state;
894 	ASSERT(mstate != NULL);
895 	irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE);
896 	return (irq);
897 }
898 
899 int
900 drm_supp_device_capability(void *handle, int capid)
901 {
902 	drm_inst_list_t *list;
903 	drm_inst_state_t    *mstate;
904 	uint8_t		cap = 0;
905 	uint16_t	caps_ptr;
906 
907 	list = (drm_inst_list_t *)handle;
908 	mstate = &list->disl_state;
909 	ASSERT(mstate != NULL);
910 
911 	/* has capabilities list ? */
912 	if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) &
913 	    PCI_CONF_CAP_MASK) == 0)
914 		return (NULL);
915 
916 	caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR);
917 	while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
918 		cap = pci_config_get32(mstate->mis_cfg_hdl, caps_ptr);
919 		if ((cap & PCI_CONF_CAPID_MASK) == capid)
920 			return (cap);
921 		caps_ptr = pci_config_get8(mstate->mis_cfg_hdl,
922 		    caps_ptr + PCI_CAP_NEXT_PTR);
923 	}
924 
925 	return (0);
926 }
927