xref: /onnv-gate/usr/src/uts/common/io/drm/drm_sunmod.c (revision 11387:0072514d53c7)
12820Skz151634 /*
22820Skz151634  * CDDL HEADER START
32820Skz151634  *
42820Skz151634  * The contents of this file are subject to the terms of the
52820Skz151634  * Common Development and Distribution License (the "License").
62820Skz151634  * You may not use this file except in compliance with the License.
72820Skz151634  *
82820Skz151634  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92820Skz151634  * or http://www.opensolaris.org/os/licensing.
102820Skz151634  * See the License for the specific language governing permissions
112820Skz151634  * and limitations under the License.
122820Skz151634  *
132820Skz151634  * When distributing Covered Code, include this CDDL HEADER in each
142820Skz151634  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152820Skz151634  * If applicable, add the following below this CDDL HEADER, with the
162820Skz151634  * fields enclosed by brackets "[]" replaced with your own identifying
172820Skz151634  * information: Portions Copyright [yyyy] [name of copyright owner]
182820Skz151634  *
192820Skz151634  * CDDL HEADER END
202820Skz151634  */
212820Skz151634 
222820Skz151634 /*
2311260SMiao.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242820Skz151634  * Use is subject to license terms.
252820Skz151634  */
262820Skz151634 
272820Skz151634 /*
282820Skz151634  * Common misc module interfaces of DRM under Solaris
292820Skz151634  */
302820Skz151634 
315804Scg149915 /*
325804Scg149915  * This module calls into gfx and agpmaster misc modules respectively
335804Scg149915  * for generic graphics operations and AGP master device support.
345804Scg149915  */
355804Scg149915 
365804Scg149915 #include "drm_sunmod.h"
372820Skz151634 #include <sys/modctl.h>
385804Scg149915 #include <sys/kmem.h>
395804Scg149915 #include <vm/seg_kmem.h>
402820Skz151634 
412820Skz151634 static struct modlmisc modlmisc = {
427862SRichard.Bean@Sun.COM 	&mod_miscops, "DRM common interfaces"
432820Skz151634 };
442820Skz151634 
452820Skz151634 static struct modlinkage modlinkage = {
462820Skz151634 	MODREV_1, (void *)&modlmisc, NULL
472820Skz151634 };
482820Skz151634 
495804Scg149915 static drm_inst_list_t	*drm_inst_head;
505804Scg149915 static kmutex_t	drm_inst_list_lock;
515804Scg149915 
525804Scg149915 static int drm_sun_open(dev_t *, int, int, cred_t *);
535804Scg149915 static int drm_sun_close(dev_t, int, int, cred_t *);
545804Scg149915 static int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
555804Scg149915 static int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
565804Scg149915     size_t *, uint_t);
575804Scg149915 
585804Scg149915 /*
595804Scg149915  * devmap callbacks for AGP and PCI GART
605804Scg149915  */
615804Scg149915 static int drm_devmap_map(devmap_cookie_t, dev_t,
625804Scg149915     uint_t, offset_t, size_t, void **);
635804Scg149915 static int drm_devmap_dup(devmap_cookie_t, void *,
645804Scg149915     devmap_cookie_t, void **);
655804Scg149915 static void drm_devmap_unmap(devmap_cookie_t, void *,
665804Scg149915     offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **);
675804Scg149915 
685804Scg149915 static drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *);
695804Scg149915 static drm_inst_state_t *drm_sup_devt_to_state(dev_t);
705804Scg149915 static void drm_supp_free_drv_entry(dev_info_t *);
715804Scg149915 
725804Scg149915 static struct devmap_callback_ctl drm_devmap_callbacks = {
735804Scg149915 		DEVMAP_OPS_REV, 		/* devmap_rev */
745804Scg149915 		drm_devmap_map,				/* devmap_map */
755804Scg149915 		NULL,			/* devmap_access */
765804Scg149915 		drm_devmap_dup,			/* devmap_dup */
775804Scg149915 		drm_devmap_unmap 		/* devmap_unmap */
785804Scg149915 };
795804Scg149915 
805804Scg149915 /*
815804Scg149915  * Common device operations structure for all DRM drivers
825804Scg149915  */
835804Scg149915 struct cb_ops drm_cb_ops = {
845804Scg149915 	drm_sun_open,			/* cb_open */
855804Scg149915 	drm_sun_close,			/* cb_close */
865804Scg149915 	nodev,					/* cb_strategy */
875804Scg149915 	nodev,					/* cb_print */
885804Scg149915 	nodev,					/* cb_dump */
895804Scg149915 	nodev,					/* cb_read */
905804Scg149915 	nodev,					/* cb_write */
915804Scg149915 	drm_sun_ioctl,		/* cb_ioctl */
925804Scg149915 	drm_sun_devmap,		/* cb_devmap */
935804Scg149915 	nodev,					/* cb_mmap */
945804Scg149915 	NULL,			/* cb_segmap */
955804Scg149915 	nochpoll,				/* cb_chpoll */
965804Scg149915 	ddi_prop_op,		/* cb_prop_op */
975804Scg149915 	0,					/* cb_stream */
985804Scg149915 	D_NEW | D_MTSAFE |D_DEVMAP	/* cb_flag */
995804Scg149915 };
1005804Scg149915 
1012820Skz151634 int
_init(void)1022820Skz151634 _init(void)
1032820Skz151634 {
1045804Scg149915 	int	error;
1052820Skz151634 
1065804Scg149915 	if ((error = mod_install(&modlinkage)) != 0) {
1075804Scg149915 		return (error);
1085804Scg149915 	}
1092820Skz151634 
1105804Scg149915 	/* initialize the instance list lock */
1115804Scg149915 	mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
1122820Skz151634 	return (0);
1132820Skz151634 }
1142820Skz151634 
1152820Skz151634 int
_fini(void)1162820Skz151634 _fini(void)
1172820Skz151634 {
1182820Skz151634 	int	err;
1192820Skz151634 
1202820Skz151634 	if ((err = mod_remove(&modlinkage)) != 0)
1212820Skz151634 		return (err);
1222820Skz151634 
1235804Scg149915 	mutex_destroy(&drm_inst_list_lock);
1242820Skz151634 	return (0);
1252820Skz151634 }
1262820Skz151634 
1272820Skz151634 int
_info(struct modinfo * modinfop)1282820Skz151634 _info(struct modinfo *modinfop)
1292820Skz151634 {
1302820Skz151634 	return (mod_info(&modlinkage, modinfop));
1312820Skz151634 }
1325804Scg149915 
1335804Scg149915 void *
drm_supp_register(dev_info_t * dip,drm_device_t * dp)1345804Scg149915 drm_supp_register(dev_info_t *dip, drm_device_t *dp)
1355804Scg149915 {
1365804Scg149915 	int		error;
1375804Scg149915 	char	buf[80];
1385804Scg149915 	int		instance = ddi_get_instance(dip);
1395804Scg149915 	ddi_acc_handle_t	pci_cfg_handle;
1405804Scg149915 	agp_master_softc_t	*agpm;
1415804Scg149915 	drm_inst_state_t	*mstate;
1425804Scg149915 	drm_inst_list_t		*entry;
1435804Scg149915 	gfxp_vgatext_softc_ptr_t gfxp;
1445804Scg149915 	struct dev_ops	*devop;
1455804Scg149915 
1465804Scg149915 	ASSERT(dip != NULL);
1475804Scg149915 
1485804Scg149915 	entry = drm_supp_alloc_drv_entry(dip);
1495804Scg149915 	if (entry == NULL) {
1505804Scg149915 		cmn_err(CE_WARN, "drm_supp_register: failed to get softstate");
1515804Scg149915 		return (NULL);
1525804Scg149915 	}
1535804Scg149915 	mstate = &entry->disl_state;
1545804Scg149915 
1555804Scg149915 	/*
1565804Scg149915 	 * DRM drivers are required to use common cb_ops
1575804Scg149915 	 */
1585804Scg149915 	devop = ddi_get_driver(dip);
1595804Scg149915 	if (devop->devo_cb_ops != &drm_cb_ops) {
1605804Scg149915 		devop->devo_cb_ops = &drm_cb_ops;
1615804Scg149915 	}
1625804Scg149915 
1635804Scg149915 	/* Generic graphics initialization */
1645804Scg149915 	gfxp = gfxp_vgatext_softc_alloc();
1655804Scg149915 	error = gfxp_vgatext_attach(dip, DDI_ATTACH, gfxp);
1665804Scg149915 	if (error != DDI_SUCCESS) {
1675804Scg149915 		DRM_ERROR("drm_supp_regiter: failed to init gfx");
1685804Scg149915 		goto exit1;
1695804Scg149915 	}
1705804Scg149915 
1715804Scg149915 	/* create a minor node for common graphics ops */
1725804Scg149915 	(void) sprintf(buf, "%s%d", GFX_NAME, instance);
1735804Scg149915 	error = ddi_create_minor_node(dip, buf, S_IFCHR,
1745804Scg149915 	    INST2NODE0(instance), DDI_NT_DISPLAY, NULL);
1755804Scg149915 	if (error != DDI_SUCCESS) {
1765804Scg149915 		DRM_ERROR("drm_supp_regiter: "
1775804Scg149915 		    "failed to create minor node for gfx");
1785804Scg149915 		goto exit2;
1795804Scg149915 	}
1805804Scg149915 
1815804Scg149915 	/* setup mapping for later PCI config space access */
1825804Scg149915 	error = pci_config_setup(dip, &pci_cfg_handle);
1835804Scg149915 	if (error != DDI_SUCCESS) {
1845804Scg149915 		DRM_ERROR("drm_supp_regiter: "
1855804Scg149915 		    "PCI configuration space setup failed");
1865804Scg149915 		goto exit2;
1875804Scg149915 	}
1885804Scg149915 
1895804Scg149915 	/* AGP master attach */
1905804Scg149915 	agpm = NULL;
1915804Scg149915 	if (dp->driver->use_agp) {
1925804Scg149915 		DRM_DEBUG("drm_supp_regiter: driver use AGP\n");
1935804Scg149915 		error = agpmaster_attach(dip, &agpm,
1945804Scg149915 		    pci_cfg_handle, INST2NODE1(instance));
1955804Scg149915 		if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) {
1965804Scg149915 			DRM_ERROR("drm_supp_regiter: "
1975804Scg149915 			    "AGP master support not available");
1985804Scg149915 			goto exit3;
1995804Scg149915 		}
2005804Scg149915 	}
2015804Scg149915 
2025804Scg149915 	mutex_enter(&mstate->mis_lock);
2035804Scg149915 	mstate->mis_major = ddi_driver_major(dip);
2045804Scg149915 	mstate->mis_dip = dip;
2055804Scg149915 	mstate->mis_gfxp = gfxp;
2065804Scg149915 	mstate->mis_agpm = agpm;
2075804Scg149915 	mstate->mis_cfg_hdl = pci_cfg_handle;
2085804Scg149915 	mstate->mis_devp = dp;
2095804Scg149915 	mutex_exit(&mstate->mis_lock);
2105804Scg149915 
2115804Scg149915 	/* create minor node for DRM access */
2125804Scg149915 	(void) sprintf(buf, "%s%d", DRM_DEVNODE, instance);
2135804Scg149915 	if (ddi_create_minor_node(dip, buf, S_IFCHR,
2145804Scg149915 	    INST2NODE2(instance), DDI_NT_DISPLAY_DRM, 0)) {
2155804Scg149915 		DRM_ERROR("supp_regiter: faled to create minor node for drm");
2165804Scg149915 		goto exit4;
2175804Scg149915 	}
2185804Scg149915 
2195804Scg149915 	return ((void *)mstate);
2205804Scg149915 
2215804Scg149915 exit4:
2225804Scg149915 	if ((dp->driver->use_agp) && agpm)
2235804Scg149915 		agpmaster_detach(&agpm);
2245804Scg149915 exit3:
2255804Scg149915 	pci_config_teardown(&pci_cfg_handle);
2265804Scg149915 exit2:
227*11387SSurya.Prakki@Sun.COM 	(void) gfxp_vgatext_detach(dip, DDI_DETACH, gfxp);
2285804Scg149915 exit1:
2295804Scg149915 	gfxp_vgatext_softc_free(gfxp);
2305804Scg149915 	drm_supp_free_drv_entry(dip);
2315804Scg149915 	ddi_remove_minor_node(dip, NULL);
2325804Scg149915 
2335804Scg149915 	return (NULL);
2345804Scg149915 }
2355804Scg149915 
2365804Scg149915 
2375804Scg149915 int
drm_supp_unregister(void * handle)2385804Scg149915 drm_supp_unregister(void *handle)
2395804Scg149915 {
2405804Scg149915 	drm_inst_list_t		*list;
2415804Scg149915 	drm_inst_state_t	*mstate;
2425804Scg149915 
2435804Scg149915 	list = (drm_inst_list_t *)handle;
2445804Scg149915 	mstate = &list->disl_state;
2455804Scg149915 	mutex_enter(&mstate->mis_lock);
2465804Scg149915 
2475804Scg149915 	/* AGP master detach */
2485804Scg149915 	if (mstate->mis_agpm != NULL)
2495804Scg149915 		agpmaster_detach(&mstate->mis_agpm);
2505804Scg149915 
2515804Scg149915 	/* free PCI config access handle */
2525804Scg149915 	if (mstate->mis_cfg_hdl)
2535804Scg149915 		pci_config_teardown(&mstate->mis_cfg_hdl);
2545804Scg149915 
2555804Scg149915 	/* graphics misc module detach */
2565804Scg149915 	if (mstate->mis_gfxp) {
2575804Scg149915 		(void) gfxp_vgatext_detach(mstate->mis_dip, DDI_DETACH,
2585804Scg149915 		    mstate->mis_gfxp);
2595804Scg149915 		gfxp_vgatext_softc_free(mstate->mis_gfxp);
2605804Scg149915 	}
2615804Scg149915 
2625804Scg149915 	mstate->mis_devp = NULL;
2635804Scg149915 
2645804Scg149915 	/* remove all minor nodes */
2655804Scg149915 	ddi_remove_minor_node(mstate->mis_dip, NULL);
2665804Scg149915 	mutex_exit(&mstate->mis_lock);
2675804Scg149915 	drm_supp_free_drv_entry(mstate->mis_dip);
2685804Scg149915 
2695804Scg149915 	return (DDI_SUCCESS);
2705804Scg149915 }
2715804Scg149915 
2725804Scg149915 
2735804Scg149915 /*ARGSUSED*/
2745804Scg149915 static int
drm_sun_open(dev_t * devp,int flag,int otyp,cred_t * credp)2755804Scg149915 drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
2765804Scg149915 {
2775804Scg149915 	drm_inst_state_t	*mstate;
2786114Scg149915 	drm_cminor_t	*mp, *newp;
2795804Scg149915 	drm_device_t	*dp;
2805804Scg149915 	minor_t		minor;
2816114Scg149915 	int		newminor;
2826114Scg149915 	int		instance;
2836114Scg149915 	int		err;
2845804Scg149915 
2855804Scg149915 	mstate = drm_sup_devt_to_state(*devp);
2865804Scg149915 	/*
2875804Scg149915 	 * return ENXIO for deferred attach so that system can
2885804Scg149915 	 * attach us again.
2895804Scg149915 	 */
2905804Scg149915 	if (mstate == NULL)
2915804Scg149915 		return (ENXIO);
2925804Scg149915 
2936114Scg149915 	/*
2946114Scg149915 	 * The lest significant 15 bits are used for minor_number, and
2956114Scg149915 	 * the mid 3 bits are used for instance number. All minor numbers
2966114Scg149915 	 * are used as follows:
2976114Scg149915 	 * 0 -- gfx
2986114Scg149915 	 * 1 -- agpmaster
2996114Scg149915 	 * 2 -- drm
3006114Scg149915 	 * (3, MAX_CLONE_MINOR) -- drm minor node for clone open.
3016114Scg149915 	 */
3025804Scg149915 	minor = DEV2MINOR(*devp);
3036114Scg149915 	instance = DEV2INST(*devp);
3045804Scg149915 	ASSERT(minor <= MAX_CLONE_MINOR);
3056114Scg149915 
3066114Scg149915 	/*
3076114Scg149915 	 * No operations for VGA & AGP mater devices, always return OK.
3086114Scg149915 	 */
3095804Scg149915 	if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
3105804Scg149915 		return (0);
3115804Scg149915 
3125804Scg149915 	/*
3135804Scg149915 	 * From here, we start to process drm
3145804Scg149915 	 */
3155804Scg149915 
3165804Scg149915 	dp = mstate->mis_devp;
3175804Scg149915 	if (!dp)
3185804Scg149915 		return (ENXIO);
3195804Scg149915 
3205804Scg149915 	/*
3216114Scg149915 	 * Drm driver implements a software lock to serialize access
3226114Scg149915 	 * to graphics hardware based on per-process granulation. Before
3236114Scg149915 	 * operating graphics hardware, all clients, including kernel
3246114Scg149915 	 * and applications, must acquire this lock via DRM_IOCTL_LOCK
3256114Scg149915 	 * ioctl, and release it via DRM_IOCTL_UNLOCK after finishing
3266114Scg149915 	 * operations. Drm driver will grant r/w permission to the
3276114Scg149915 	 * process which acquires this lock (Kernel is assumed to have
3286114Scg149915 	 * process ID 0).
3296114Scg149915 	 *
3306114Scg149915 	 * A process might be terminated without releasing drm lock, in
3316114Scg149915 	 * this case, drm driver is responsible for clearing the holding.
3326114Scg149915 	 * To be informed of process exiting, drm driver uses clone open
3336114Scg149915 	 * to guarantee that each call to open(9e) have one corresponding
3346114Scg149915 	 * call to close(9e). In most cases, a process will close drm
3356114Scg149915 	 * during process termination, so that drm driver could have a
3366114Scg149915 	 * chance to release drm lock.
3376114Scg149915 	 *
3386114Scg149915 	 * In fact, a driver cannot know exactly when a process exits.
3396114Scg149915 	 * Clone open doesn't address this issue completely: Because of
3406114Scg149915 	 * inheritance, child processes inherit file descriptors from
3416114Scg149915 	 * their parent. As a result, if the parent exits before its
3426114Scg149915 	 * children, drm close(9e) entrypoint won't be called until all
3436114Scg149915 	 * of its children terminate.
3446114Scg149915 	 *
3456114Scg149915 	 * Another issue brought up by inhertance is the process PID
3466114Scg149915 	 * that calls the drm close() entry point may not be the same
3476114Scg149915 	 * as the one who called open(). Per-process struct is allocated
3486114Scg149915 	 * when a process first open() drm, and released when the process
3496114Scg149915 	 * last close() drm. Since open()/close() may be not the same
3506114Scg149915 	 * process, PID cannot be used for key to lookup per-process
3516114Scg149915 	 * struct. So, we associate minor number with per-process struct
3526114Scg149915 	 * during open()'ing, and find corresponding process struct
3536114Scg149915 	 * via minor number when close() is called.
3545804Scg149915 	 */
3556114Scg149915 	newp = kmem_zalloc(sizeof (drm_cminor_t), KM_SLEEP);
3565804Scg149915 	mutex_enter(&dp->dev_lock);
3576114Scg149915 	for (newminor = DRM_MIN_CLONEMINOR; newminor < MAX_CLONE_MINOR;
3586114Scg149915 	    newminor ++) {
3596114Scg149915 		TAILQ_FOREACH(mp, &dp->minordevs, link) {
3606114Scg149915 			if (mp->minor == newminor)
3615804Scg149915 				break;
3625804Scg149915 		}
3635804Scg149915 		if (mp == NULL)
3645804Scg149915 			goto gotminor;
3655804Scg149915 	}
3665804Scg149915 
3675804Scg149915 	mutex_exit(&dp->dev_lock);
36811346STao.Chen@Sun.COM 	(void) kmem_free(newp, sizeof (drm_cminor_t));
3695804Scg149915 	return (EMFILE);
3705804Scg149915 
3715804Scg149915 gotminor:
3726114Scg149915 	TAILQ_INSERT_TAIL(&dp->minordevs, newp, link);
3736114Scg149915 	newp->minor = newminor;
3745804Scg149915 	mutex_exit(&dp->dev_lock);
3756114Scg149915 	err = drm_open(dp, newp, flag, otyp, credp);
3766114Scg149915 	if (err) {
3776114Scg149915 		mutex_enter(&dp->dev_lock);
3786114Scg149915 		TAILQ_REMOVE(&dp->minordevs, newp, link);
37911346STao.Chen@Sun.COM 		(void) kmem_free(newp, sizeof (drm_cminor_t));
3806114Scg149915 		mutex_exit(&dp->dev_lock);
3816114Scg149915 
3826114Scg149915 		return (err);
3836114Scg149915 	}
3846114Scg149915 
3856114Scg149915 	/* return a clone minor */
3866114Scg149915 	newminor = newminor | (instance << NBITSMNODE);
3876114Scg149915 	*devp = makedevice(getmajor(*devp), newminor);
3885804Scg149915 	return (err);
3895804Scg149915 }
3905804Scg149915 
3915804Scg149915 /*ARGSUSED*/
3925804Scg149915 static int
drm_sun_close(dev_t dev,int flag,int otyp,cred_t * credp)3935804Scg149915 drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
3945804Scg149915 {
3955804Scg149915 	drm_inst_state_t	*mstate;
3965804Scg149915 	drm_device_t		*dp;
3976114Scg149915 	minor_t		minor;
3986114Scg149915 	int		ret;
3995804Scg149915 
4005804Scg149915 	mstate = drm_sup_devt_to_state(dev);
4015804Scg149915 	if (mstate == NULL)
4025804Scg149915 		return (EBADF);
4035804Scg149915 
4045804Scg149915 	minor = DEV2MINOR(dev);
4055804Scg149915 	ASSERT(minor <= MAX_CLONE_MINOR);
4065804Scg149915 	if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
4075804Scg149915 		return (0);
4085804Scg149915 
4095804Scg149915 	dp = mstate->mis_devp;
4105804Scg149915 	if (dp == NULL) {
4115804Scg149915 		DRM_ERROR("drm_sun_close: NULL soft state");
4125804Scg149915 		return (ENXIO);
4135804Scg149915 	}
4145804Scg149915 
4156114Scg149915 	ret = drm_close(dp, minor, flag, otyp, credp);
4165804Scg149915 
4176114Scg149915 	return (ret);
4185804Scg149915 }
4195804Scg149915 
4205804Scg149915 /*ARGSUSED*/
4215804Scg149915 static int
drm_sun_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)4225804Scg149915 drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
4235804Scg149915     cred_t *credp, int *rvalp)
4245804Scg149915 {
4255804Scg149915 	extern drm_ioctl_desc_t drm_ioctls[];
4265804Scg149915 
4275804Scg149915 	drm_inst_state_t	*mstate;
4285804Scg149915 	drm_device_t		*dp;
4295804Scg149915 	drm_ioctl_desc_t	*ioctl;
4305804Scg149915 	drm_ioctl_t		*func;
4315804Scg149915 	drm_file_t		*fpriv;
4325804Scg149915 	minor_t		minor;
4335804Scg149915 	int		retval;
4345804Scg149915 	int		nr;
4355804Scg149915 
4365804Scg149915 	if (cmd == VIS_GETIDENTIFIER) {
4375804Scg149915 		if (ddi_copyout(&text_ident, (void *)arg,
4385804Scg149915 		    sizeof (struct vis_identifier), mode))
4395804Scg149915 			return (EFAULT);
4405804Scg149915 	}
4415804Scg149915 
4425804Scg149915 	mstate = drm_sup_devt_to_state(dev);
4435804Scg149915 	if (mstate == NULL) {
4445804Scg149915 		return (EIO);
4455804Scg149915 	}
4465804Scg149915 
4475804Scg149915 	minor = DEV2MINOR(dev);
4485804Scg149915 	ASSERT(minor <= MAX_CLONE_MINOR);
4495804Scg149915 	switch (minor) {
4505804Scg149915 	case GFX_MINOR:
4515804Scg149915 		retval = gfxp_vgatext_ioctl(dev, cmd, arg,
4525804Scg149915 		    mode, credp, rvalp, mstate->mis_gfxp);
4535804Scg149915 		return (retval);
4545804Scg149915 
4555804Scg149915 	case AGPMASTER_MINOR:
4565804Scg149915 		retval = agpmaster_ioctl(dev, cmd, arg, mode,
4575804Scg149915 		    credp, rvalp, mstate->mis_agpm);
4585804Scg149915 		return (retval);
4595804Scg149915 
4605804Scg149915 	case DRM_MINOR:
4615804Scg149915 	default:	/* DRM cloning minor nodes */
4625804Scg149915 		break;
4635804Scg149915 	}
4645804Scg149915 
4655804Scg149915 	dp = mstate->mis_devp;
4665804Scg149915 	ASSERT(dp != NULL);
4675804Scg149915 
4685804Scg149915 	nr = DRM_IOCTL_NR(cmd);
4695804Scg149915 	ioctl = &drm_ioctls[nr];
4705804Scg149915 	atomic_inc_32(&dp->counts[_DRM_STAT_IOCTLS]);
4715804Scg149915 
4725804Scg149915 	/* It's not a core DRM ioctl, try driver-specific. */
4735804Scg149915 	if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
4745804Scg149915 		/* The array entries begin at DRM_COMMAND_BASE ioctl nr */
4755804Scg149915 		nr -= DRM_COMMAND_BASE;
4765804Scg149915 		if (nr > dp->driver->max_driver_ioctl) {
4775804Scg149915 			DRM_ERROR("Bad driver ioctl number, 0x%x (of 0x%x)",
4785804Scg149915 			    nr, dp->driver->max_driver_ioctl);
4795804Scg149915 			return (EINVAL);
4805804Scg149915 		}
4815804Scg149915 		ioctl = &dp->driver->driver_ioctls[nr];
4825804Scg149915 	}
4835804Scg149915 
4845804Scg149915 	func = ioctl->func;
4855804Scg149915 	if (func == NULL) {
4865804Scg149915 		return (ENOTSUP);
4875804Scg149915 	}
4885804Scg149915 
4895804Scg149915 	mutex_enter(&dp->dev_lock);
4905804Scg149915 	fpriv = drm_find_file_by_proc(dp, credp);
4915804Scg149915 	mutex_exit(&dp->dev_lock);
4925804Scg149915 	if (fpriv == NULL) {
4935804Scg149915 		DRM_ERROR("drm_sun_ioctl : can't find authenticator");
4945804Scg149915 		return (EACCES);
4955804Scg149915 	}
4965804Scg149915 
4975804Scg149915 	if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) ||
4985804Scg149915 	    ((ioctl->flags & DRM_AUTH) && !fpriv->authenticated) ||
4995804Scg149915 	    ((ioctl->flags & DRM_MASTER) && !fpriv->master))
5005804Scg149915 		return (EACCES);
5015804Scg149915 
50211260SMiao.Chen@Sun.COM 	fpriv->dev = dev;
50311260SMiao.Chen@Sun.COM 	fpriv->credp = credp;
50411260SMiao.Chen@Sun.COM 
5055804Scg149915 	retval = func(dp, arg, fpriv, mode);
5065804Scg149915 
5075804Scg149915 	return (retval);
5085804Scg149915 }
5095804Scg149915 
5105804Scg149915 /*ARGSUSED*/
5115804Scg149915 static int
drm_sun_devmap(dev_t dev,devmap_cookie_t dhp,offset_t offset,size_t len,size_t * maplen,uint_t model)5125804Scg149915 drm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset,
5135804Scg149915     size_t len, size_t *maplen, uint_t model)
5145804Scg149915 {
5155804Scg149915 	extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
5165804Scg149915 
5175804Scg149915 	drm_inst_state_t	*mstate;
5185804Scg149915 	drm_device_t		*dp;
5195804Scg149915 	ddi_umem_cookie_t	cookie;
52011260SMiao.Chen@Sun.COM 	drm_local_map_t		*map = NULL;
5215804Scg149915 	unsigned long	aperbase;
5225804Scg149915 	u_offset_t		handle;
5235804Scg149915 	offset_t		koff;
5245804Scg149915 	caddr_t			kva;
5255804Scg149915 	minor_t			minor;
5265804Scg149915 	size_t			length;
5275804Scg149915 	int			ret;
5285804Scg149915 
5295804Scg149915 	static ddi_device_acc_attr_t dev_attr = {
5305804Scg149915 		DDI_DEVICE_ATTR_V0,
5315804Scg149915 		DDI_NEVERSWAP_ACC,
5325804Scg149915 		DDI_STRICTORDER_ACC,
5335804Scg149915 	};
53411260SMiao.Chen@Sun.COM 	static ddi_device_acc_attr_t gem_dev_attr = {
53511260SMiao.Chen@Sun.COM 		DDI_DEVICE_ATTR_V0,
53611260SMiao.Chen@Sun.COM 		DDI_NEVERSWAP_ACC,
53711260SMiao.Chen@Sun.COM 		DDI_MERGING_OK_ACC
53811260SMiao.Chen@Sun.COM 	};
5395804Scg149915 
5405804Scg149915 	mstate = drm_sup_devt_to_state(dev);
5415804Scg149915 	if (mstate == NULL)
5425804Scg149915 		return (ENXIO);
5435804Scg149915 
5445804Scg149915 	minor = DEV2MINOR(dev);
5455804Scg149915 	switch (minor) {
5465804Scg149915 	case GFX_MINOR:
5475804Scg149915 		ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model,
5485804Scg149915 		    mstate->mis_gfxp);
5495804Scg149915 		return (ret);
5505804Scg149915 
5515804Scg149915 	case AGPMASTER_MINOR:
5525804Scg149915 		return (ENOTSUP);
5535804Scg149915 
5545804Scg149915 	case DRM_MINOR:
5555804Scg149915 		break;
5565804Scg149915 
5575804Scg149915 	default:
5585804Scg149915 		/* DRM cloning nodes */
5595804Scg149915 		if (minor > MAX_CLONE_MINOR)
5605804Scg149915 			return (EBADF);
5615804Scg149915 		break;
5625804Scg149915 	}
5635804Scg149915 
5645804Scg149915 
5655804Scg149915 	dp = mstate->mis_devp;
5665804Scg149915 	if (dp == NULL) {
5675804Scg149915 		DRM_ERROR("drm_sun_devmap: NULL soft state");
5685804Scg149915 		return (EINVAL);
5695804Scg149915 	}
5705804Scg149915 
5715804Scg149915 	mutex_enter(&dp->dev_lock);
57211260SMiao.Chen@Sun.COM 
57311260SMiao.Chen@Sun.COM 	if (dp->driver->use_gem == 1) {
57411260SMiao.Chen@Sun.COM 		struct idr_list *entry;
57511260SMiao.Chen@Sun.COM 		drm_cminor_t *mp;
57611260SMiao.Chen@Sun.COM 
57711260SMiao.Chen@Sun.COM 		mp = drm_find_file_by_minor(dp, minor);
57811260SMiao.Chen@Sun.COM 		if (!mp) {
57911260SMiao.Chen@Sun.COM 			mutex_exit(&dp->dev_lock);
58011260SMiao.Chen@Sun.COM 			DRM_ERROR("drm_sun_devmap: can't find authenticator");
58111260SMiao.Chen@Sun.COM 			return (EACCES);
58211260SMiao.Chen@Sun.COM 		}
58311260SMiao.Chen@Sun.COM 
58411260SMiao.Chen@Sun.COM 		spin_lock(&dp->struct_mutex);
58511260SMiao.Chen@Sun.COM 		idr_list_for_each(entry, &(mp->fpriv->object_idr)) {
58611260SMiao.Chen@Sun.COM 			if ((uintptr_t)entry->obj == (u_offset_t)offset) {
58711260SMiao.Chen@Sun.COM 				map = entry->obj->map;
58811260SMiao.Chen@Sun.COM 				goto goon;
58911260SMiao.Chen@Sun.COM 			}
59011260SMiao.Chen@Sun.COM 		}
59111260SMiao.Chen@Sun.COM goon:
59211260SMiao.Chen@Sun.COM 		spin_unlock(&dp->struct_mutex);
5935804Scg149915 	}
5945804Scg149915 
5955804Scg149915 	if (map == NULL) {
59611260SMiao.Chen@Sun.COM 		/*
59711260SMiao.Chen@Sun.COM 		 * We will solve 32-bit application on 64-bit kernel
59811260SMiao.Chen@Sun.COM 		 * issue later, now, we just use low 32-bit
59911260SMiao.Chen@Sun.COM 		 */
60011260SMiao.Chen@Sun.COM 		handle = (u_offset_t)offset;
60111260SMiao.Chen@Sun.COM 		handle &= 0xffffffff;
60211260SMiao.Chen@Sun.COM 
6035804Scg149915 		TAILQ_FOREACH(map, &dp->maplist, link) {
60411260SMiao.Chen@Sun.COM 			if (handle ==
60511260SMiao.Chen@Sun.COM 			    ((u_offset_t)((uintptr_t)map->handle) & 0xffffffff))
6065804Scg149915 				break;
6075804Scg149915 		}
60811260SMiao.Chen@Sun.COM 
60911260SMiao.Chen@Sun.COM 		/*
61011260SMiao.Chen@Sun.COM 		 * Temporarily, because offset is phys_addr for register
61111260SMiao.Chen@Sun.COM 		 * and framebuffer, is kernel virtual_addr for others
61211260SMiao.Chen@Sun.COM 		 * Maybe we will use hash table to solve this issue later.
61311260SMiao.Chen@Sun.COM 		 */
61411260SMiao.Chen@Sun.COM 		if (map == NULL) {
61511260SMiao.Chen@Sun.COM 			TAILQ_FOREACH(map, &dp->maplist, link) {
61611260SMiao.Chen@Sun.COM 				if (handle == (map->offset & 0xffffffff))
61711260SMiao.Chen@Sun.COM 					break;
61811260SMiao.Chen@Sun.COM 			}
61911260SMiao.Chen@Sun.COM 		}
6205804Scg149915 	}
6215804Scg149915 
6225804Scg149915 	if (map == NULL) {
6235804Scg149915 		u_offset_t	tmp;
6245804Scg149915 
6255804Scg149915 		mutex_exit(&dp->dev_lock);
6265804Scg149915 		cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n",
6275804Scg149915 		    offset, (int)len);
6285804Scg149915 		cmn_err(CE_WARN, "Current mapping:\n");
6295804Scg149915 		TAILQ_FOREACH(map, &dp->maplist, link) {
6305804Scg149915 		tmp = (u_offset_t)((uintptr_t)map->handle) & 0xffffffff;
6315804Scg149915 		cmn_err(CE_WARN, "map(handle=0x%p, size=0x%lx,type=%d,"
6325804Scg149915 		    "offset=0x%lx), handle=%llx, tmp=%lld", map->handle,
6335804Scg149915 		    map->size, map->type, map->offset, handle, tmp);
6345804Scg149915 		}
6355804Scg149915 		return (-1);
6365804Scg149915 	}
6375804Scg149915 	if (map->flags & _DRM_RESTRICTED) {
6385804Scg149915 		mutex_exit(&dp->dev_lock);
6395804Scg149915 		cmn_err(CE_WARN, "restricted map\n");
6405804Scg149915 		return (-1);
6415804Scg149915 	}
6425804Scg149915 
6435804Scg149915 	mutex_exit(&dp->dev_lock);
6445804Scg149915 	switch (map->type) {
6455804Scg149915 	case _DRM_FRAME_BUFFER:
6465804Scg149915 	case _DRM_REGISTERS:
6475804Scg149915 		{
6485804Scg149915 			int	regno;
6495804Scg149915 			off_t	regoff;
6505804Scg149915 
6515804Scg149915 			regno = drm_get_pci_index_reg(dp->dip,
6525804Scg149915 			    map->offset, (uint_t)len, &regoff);
6535804Scg149915 			if (regno < 0) {
6545804Scg149915 				DRM_ERROR("devmap: failed to get register"
6555804Scg149915 				    " offset=0x%llx, len=0x%x", handle, len);
6565804Scg149915 				return (EINVAL);
6575804Scg149915 			}
6585804Scg149915 
6595804Scg149915 			ret = devmap_devmem_setup(dhp, dp->dip, NULL,
6605804Scg149915 			    regno, (offset_t)regoff, len, PROT_ALL,
6615804Scg149915 			    0, &dev_attr);
6625804Scg149915 			if (ret != 0) {
6635804Scg149915 				*maplen = 0;
6645804Scg149915 				DRM_ERROR("devmap: failed, regno=%d,type=%d,"
6655804Scg149915 				    " handle=0x%x, offset=0x%llx, len=0x%x",
6665804Scg149915 				    regno, map->type, handle, offset, len);
6675804Scg149915 				return (ret);
6685804Scg149915 			}
6695804Scg149915 			*maplen = len;
6705804Scg149915 			return (ret);
6715804Scg149915 		}
6725804Scg149915 
6735804Scg149915 	case _DRM_SHM:
6745804Scg149915 		if (map->drm_umem_cookie == NULL)
6755804Scg149915 			return (EINVAL);
6765804Scg149915 		length = ptob(btopr(map->size));
6775804Scg149915 		ret = devmap_umem_setup(dhp, dp->dip, NULL,
6785804Scg149915 		    map->drm_umem_cookie, 0, length,
6795804Scg149915 		    PROT_ALL, IOMEM_DATA_CACHED, NULL);
6805804Scg149915 		if (ret != 0) {
6815804Scg149915 			*maplen = 0;
6825804Scg149915 			return (ret);
6835804Scg149915 		}
6845804Scg149915 		*maplen = length;
6855804Scg149915 
6865804Scg149915 		return (DDI_SUCCESS);
6875804Scg149915 
6885804Scg149915 	case _DRM_AGP:
6895804Scg149915 		if (dp->agp == NULL) {
6905804Scg149915 			cmn_err(CE_WARN, "drm_sun_devmap: attempted to mmap AGP"
6915804Scg149915 			    "memory before AGP support is enabled");
6925804Scg149915 			return (DDI_FAILURE);
6935804Scg149915 		}
6945804Scg149915 
6955804Scg149915 		aperbase = dp->agp->base;
6965804Scg149915 		koff = map->offset - aperbase;
6975804Scg149915 		length = ptob(btopr(len));
6985804Scg149915 		kva = map->dev_addr;
6995804Scg149915 		cookie = gfxp_umem_cookie_init(kva, length);
7005804Scg149915 		if (cookie == NULL) {
7015804Scg149915 			cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
7025804Scg149915 			return (DDI_FAILURE);
7035804Scg149915 		}
7045804Scg149915 
7055804Scg149915 		if ((ret = devmap_umem_setup(dhp, dp->dip,
7065804Scg149915 		    &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
7075804Scg149915 		    IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) {
7085804Scg149915 			gfxp_umem_cookie_destroy(cookie);
7095804Scg149915 			cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
7105804Scg149915 			return (DDI_FAILURE);
7115804Scg149915 		}
7125804Scg149915 		*maplen = length;
7135804Scg149915 		break;
7145804Scg149915 
7155804Scg149915 	case _DRM_SCATTER_GATHER:
7165804Scg149915 		koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual;
7175804Scg149915 		kva = map->dev_addr + koff;
7185804Scg149915 		length = ptob(btopr(len));
7195804Scg149915 		if (length > map->size) {
7205804Scg149915 			cmn_err(CE_WARN, "offset=0x%lx, virtual=0x%p,"
7215804Scg149915 			    "mapsize=0x%lx,len=0x%lx", map->offset,
7225804Scg149915 			    dp->sg->virtual, map->size, len);
7235804Scg149915 			return (DDI_FAILURE);
7245804Scg149915 		}
7255804Scg149915 		cookie = gfxp_umem_cookie_init(kva, length);
7265804Scg149915 		if (cookie == NULL) {
7275804Scg149915 			cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
7285804Scg149915 			return (DDI_FAILURE);
7295804Scg149915 		}
7305804Scg149915 		ret = devmap_umem_setup(dhp, dp->dip,
7315804Scg149915 		    &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
7325804Scg149915 		    IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
7335804Scg149915 		if (ret != 0) {
7345804Scg149915 			cmn_err(CE_WARN, "sun_devmap: umem_setup fail");
7355804Scg149915 			gfxp_umem_cookie_destroy(cookie);
7365804Scg149915 			return (DDI_FAILURE);
7375804Scg149915 		}
7385804Scg149915 		*maplen = length;
7395804Scg149915 		break;
7405804Scg149915 
74111260SMiao.Chen@Sun.COM 	case _DRM_TTM:
74211260SMiao.Chen@Sun.COM 		if (map->drm_umem_cookie == NULL)
74311260SMiao.Chen@Sun.COM 			return (EINVAL);
74411260SMiao.Chen@Sun.COM 
74511260SMiao.Chen@Sun.COM 		if (gfxp_devmap_umem_setup(dhp, dp->dip,
74611260SMiao.Chen@Sun.COM 		    NULL, map->drm_umem_cookie, 0, map->size, PROT_ALL,
74711260SMiao.Chen@Sun.COM 		    IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP,
74811260SMiao.Chen@Sun.COM 		    &gem_dev_attr)) {
74911260SMiao.Chen@Sun.COM 			cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
75011260SMiao.Chen@Sun.COM 			return (DDI_FAILURE);
75111260SMiao.Chen@Sun.COM 		}
75211260SMiao.Chen@Sun.COM 		*maplen = map->size;
75311260SMiao.Chen@Sun.COM 		return (DDI_SUCCESS);
75411260SMiao.Chen@Sun.COM 
7555804Scg149915 	default:
7565804Scg149915 		return (DDI_FAILURE);
7575804Scg149915 	}
7585804Scg149915 	return (DDI_SUCCESS);
7595804Scg149915 
7605804Scg149915 }
7615804Scg149915 
7625804Scg149915 /*ARGSUSED*/
7635804Scg149915 static int
drm_devmap_map(devmap_cookie_t dhc,dev_t dev,uint_t flags,offset_t offset,size_t len,void ** new_priv)7645804Scg149915 drm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags,
7655804Scg149915     offset_t offset, size_t len, void **new_priv)
7665804Scg149915 {
7675804Scg149915 	devmap_handle_t			*dhp;
7685804Scg149915 	drm_inst_state_t		*statep;
7695804Scg149915 	struct ddi_umem_cookie 	*cp;
7705804Scg149915 
7715804Scg149915 	statep = drm_sup_devt_to_state(dev);
7725804Scg149915 	ASSERT(statep != NULL);
7735804Scg149915 
7745804Scg149915 	/*
7755804Scg149915 	 * This driver only supports MAP_SHARED,
7765804Scg149915 	 * and doesn't support MAP_PRIVATE
7775804Scg149915 	 */
7785804Scg149915 	if (flags & MAP_PRIVATE) {
7795804Scg149915 		cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
7805804Scg149915 		return (EINVAL);
7815804Scg149915 	}
7825804Scg149915 
7835804Scg149915 	mutex_enter(&statep->dis_ctxlock);
7845804Scg149915 	dhp = (devmap_handle_t *)dhc;
7855804Scg149915 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
7865804Scg149915 	cp->cook_refcnt = 1;
7875804Scg149915 	mutex_exit(&statep->dis_ctxlock);
7885804Scg149915 	*new_priv = statep;
7895804Scg149915 
7905804Scg149915 	return (0);
7915804Scg149915 }
7925804Scg149915 
7935804Scg149915 /*ARGSUSED*/
7945804Scg149915 static void
drm_devmap_unmap(devmap_cookie_t dhc,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** new_pvtp1,devmap_cookie_t new_dhp2,void ** new_pvtp2)7955804Scg149915 drm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
7965804Scg149915     devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
7975804Scg149915     void **new_pvtp2)
7985804Scg149915 {
7995804Scg149915 	devmap_handle_t		*dhp;
8005804Scg149915 	devmap_handle_t		*ndhp;
8015804Scg149915 	drm_inst_state_t		*statep;
8025804Scg149915 	struct ddi_umem_cookie	*cp;
8035804Scg149915 	struct ddi_umem_cookie	*ncp;
8045804Scg149915 
8055804Scg149915 	dhp = (devmap_handle_t *)dhc;
8065804Scg149915 	statep = (drm_inst_state_t *)pvtp;
8075804Scg149915 
8085804Scg149915 	mutex_enter(&statep->dis_ctxlock);
8095804Scg149915 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
8105804Scg149915 	if (new_dhp1 != NULL) {
8115804Scg149915 		ndhp = (devmap_handle_t *)new_dhp1;
8125804Scg149915 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
8135804Scg149915 		ncp->cook_refcnt ++;
8145804Scg149915 		*new_pvtp1 = statep;
8155804Scg149915 		ASSERT(ncp == cp);
8165804Scg149915 	}
8175804Scg149915 
8185804Scg149915 	if (new_dhp2 != NULL) {
8195804Scg149915 		ndhp = (devmap_handle_t *)new_dhp2;
8205804Scg149915 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
8215804Scg149915 		ncp->cook_refcnt ++;
8225804Scg149915 		*new_pvtp2 = statep;
8235804Scg149915 		ASSERT(ncp == cp);
8245804Scg149915 	}
8255804Scg149915 
8265804Scg149915 	cp->cook_refcnt --;
8275804Scg149915 	if (cp->cook_refcnt == 0) {
8285804Scg149915 		gfxp_umem_cookie_destroy(dhp->dh_cookie);
8295804Scg149915 		dhp->dh_cookie = NULL;
8305804Scg149915 	}
8315804Scg149915 	mutex_exit(&statep->dis_ctxlock);
8325804Scg149915 }
8335804Scg149915 
8345804Scg149915 
8355804Scg149915 /*ARGSUSED*/
8365804Scg149915 static int
drm_devmap_dup(devmap_cookie_t dhc,void * pvtp,devmap_cookie_t new_dhc,void ** new_pvtp)8375804Scg149915 drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
8385804Scg149915     void **new_pvtp)
8395804Scg149915 {
8405804Scg149915 	devmap_handle_t			*dhp;
8415804Scg149915 	drm_inst_state_t    *statep;
8425804Scg149915 	struct ddi_umem_cookie *cp;
8435804Scg149915 
8445804Scg149915 	statep = (drm_inst_state_t *)pvtp;
8455804Scg149915 	mutex_enter(&statep->dis_ctxlock);
8465804Scg149915 	dhp = (devmap_handle_t *)dhc;
8475804Scg149915 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
8485804Scg149915 	cp->cook_refcnt ++;
8495804Scg149915 	mutex_exit(&statep->dis_ctxlock);
8505804Scg149915 	*new_pvtp = statep;
8515804Scg149915 
8525804Scg149915 	return (0);
8535804Scg149915 }
8545804Scg149915 
8555804Scg149915 int
drm_dev_to_instance(dev_t dev)8565804Scg149915 drm_dev_to_instance(dev_t dev)
8575804Scg149915 {
8585804Scg149915 	return (DEV2INST(dev));
8595804Scg149915 }
8605804Scg149915 
8615804Scg149915 /*
8625804Scg149915  * drm_supp_alloc_drv_entry()
8635804Scg149915  *
8645804Scg149915  * Description:
8655804Scg149915  *	Create a DRM entry and add it into the instance list (drm_inst_head).
8665804Scg149915  *	Note that we don't allow a duplicated entry
8675804Scg149915  */
8685804Scg149915 static drm_inst_list_t *
drm_supp_alloc_drv_entry(dev_info_t * dip)8695804Scg149915 drm_supp_alloc_drv_entry(dev_info_t *dip)
8705804Scg149915 {
8715804Scg149915 	drm_inst_list_t	**plist;
8725804Scg149915 	drm_inst_list_t	*list;
8735804Scg149915 	drm_inst_list_t	*entry;
8745804Scg149915 
8755804Scg149915 	/* protect the driver list */
8765804Scg149915 	mutex_enter(&drm_inst_list_lock);
8775804Scg149915 	plist = &drm_inst_head;
8785804Scg149915 	list = *plist;
8795804Scg149915 	while (list) {
8805804Scg149915 		if (list->disl_state.mis_dip == dip) {
8815804Scg149915 			mutex_exit(&drm_inst_list_lock);
8825804Scg149915 			cmn_err(CE_WARN, "%s%d already registered",
8835804Scg149915 			    ddi_driver_name(dip), ddi_get_instance(dip));
8845804Scg149915 			return (NULL);
8855804Scg149915 		}
8865804Scg149915 		plist = &list->disl_next;
8875804Scg149915 		list = list->disl_next;
8885804Scg149915 	}
8895804Scg149915 
8905804Scg149915 	/* "dip" is not registered, create new one and add to list */
8915804Scg149915 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
8925804Scg149915 	*plist = entry;
8935804Scg149915 	entry->disl_state.mis_dip = dip;
8945804Scg149915 	mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL);
8955804Scg149915 	mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL);
8965804Scg149915 	mutex_exit(&drm_inst_list_lock);
8975804Scg149915 
8985804Scg149915 	return (entry);
8995804Scg149915 
9005804Scg149915 }	/* drm_supp_alloc_drv_entry */
9015804Scg149915 
9025804Scg149915 /*
9035804Scg149915  * drm_supp_free_drv_entry()
9045804Scg149915  */
9055804Scg149915 static void
drm_supp_free_drv_entry(dev_info_t * dip)9065804Scg149915 drm_supp_free_drv_entry(dev_info_t *dip)
9075804Scg149915 {
9085804Scg149915 	drm_inst_list_t		*list;
9095804Scg149915 	drm_inst_list_t		**plist;
9105804Scg149915 	drm_inst_state_t	*mstate;
9115804Scg149915 
9125804Scg149915 	/* protect the driver list */
9135804Scg149915 	mutex_enter(&drm_inst_list_lock);
9145804Scg149915 	plist = &drm_inst_head;
9155804Scg149915 	list = *plist;
9165804Scg149915 	while (list) {
9175804Scg149915 		if (list->disl_state.mis_dip == dip) {
9185804Scg149915 			*plist = list->disl_next;
9195804Scg149915 			mstate = &list->disl_state;
9205804Scg149915 			mutex_destroy(&mstate->mis_lock);
9215804Scg149915 			mutex_destroy(&mstate->dis_ctxlock);
9225804Scg149915 			kmem_free(list, sizeof (*list));
9235804Scg149915 			mutex_exit(&drm_inst_list_lock);
9245804Scg149915 			return;
9255804Scg149915 		}
9265804Scg149915 		plist = &list->disl_next;
9275804Scg149915 		list = list->disl_next;
9285804Scg149915 	}
9295804Scg149915 	mutex_exit(&drm_inst_list_lock);
9305804Scg149915 
9315804Scg149915 }	/* drm_supp_free_drv_entry() */
9325804Scg149915 
9335804Scg149915 /*
9345804Scg149915  * drm_sup_devt_to_state()
9355804Scg149915  *
9365804Scg149915  * description:
9375804Scg149915  *	Get the soft state of DRM instance by device number
9385804Scg149915  */
9395804Scg149915 static drm_inst_state_t *
drm_sup_devt_to_state(dev_t dev)9405804Scg149915 drm_sup_devt_to_state(dev_t dev)
9415804Scg149915 {
9425804Scg149915 	drm_inst_list_t	*list;
9435804Scg149915 	drm_inst_state_t	*mstate;
9445804Scg149915 	major_t	major = getmajor(dev);
9455804Scg149915 	int		instance = DEV2INST(dev);
9465804Scg149915 
9475804Scg149915 	mutex_enter(&drm_inst_list_lock);
9485804Scg149915 	list = drm_inst_head;
9495804Scg149915 	while (list) {
9505804Scg149915 		mstate = &list->disl_state;
9515804Scg149915 		mutex_enter(&mstate->mis_lock);
9525804Scg149915 
9535804Scg149915 		if ((mstate->mis_major == major) &&
9545804Scg149915 		    (ddi_get_instance(mstate->mis_dip) == instance)) {
9555804Scg149915 			mutex_exit(&mstate->mis_lock);
9565804Scg149915 			mutex_exit(&drm_inst_list_lock);
9575804Scg149915 			return (mstate);
9585804Scg149915 		}
9595804Scg149915 
9605804Scg149915 		list = list->disl_next;
9615804Scg149915 		mutex_exit(&mstate->mis_lock);
9625804Scg149915 	}
9635804Scg149915 
9645804Scg149915 	mutex_exit(&drm_inst_list_lock);
9655804Scg149915 	return (NULL);
9665804Scg149915 
9675804Scg149915 }	/* drm_sup_devt_to_state() */
9685804Scg149915 
9695804Scg149915 int
drm_supp_get_irq(void * handle)9705804Scg149915 drm_supp_get_irq(void *handle)
9715804Scg149915 {
9725804Scg149915 	drm_inst_list_t *list;
9735804Scg149915 	drm_inst_state_t    *mstate;
9745804Scg149915 	int		irq;
9755804Scg149915 
9765804Scg149915 	list = (drm_inst_list_t *)handle;
9775804Scg149915 	mstate = &list->disl_state;
9785804Scg149915 	ASSERT(mstate != NULL);
9795804Scg149915 	irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE);
9805804Scg149915 	return (irq);
9815804Scg149915 }
9825804Scg149915 
9835804Scg149915 int
drm_supp_device_capability(void * handle,int capid)9845804Scg149915 drm_supp_device_capability(void *handle, int capid)
9855804Scg149915 {
9865804Scg149915 	drm_inst_list_t *list;
9875804Scg149915 	drm_inst_state_t    *mstate;
9885804Scg149915 	uint8_t		cap = 0;
9895804Scg149915 	uint16_t	caps_ptr;
9905804Scg149915 
9915804Scg149915 	list = (drm_inst_list_t *)handle;
9925804Scg149915 	mstate = &list->disl_state;
9935804Scg149915 	ASSERT(mstate != NULL);
9945804Scg149915 
9955804Scg149915 	/* has capabilities list ? */
9965804Scg149915 	if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) &
9975804Scg149915 	    PCI_CONF_CAP_MASK) == 0)
9985804Scg149915 		return (NULL);
9995804Scg149915 
10005804Scg149915 	caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR);
10015804Scg149915 	while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
10025804Scg149915 		cap = pci_config_get32(mstate->mis_cfg_hdl, caps_ptr);
10035804Scg149915 		if ((cap & PCI_CONF_CAPID_MASK) == capid)
10045804Scg149915 			return (cap);
10055804Scg149915 		caps_ptr = pci_config_get8(mstate->mis_cfg_hdl,
10065804Scg149915 		    caps_ptr + PCI_CAP_NEXT_PTR);
10075804Scg149915 	}
10085804Scg149915 
10095804Scg149915 	return (0);
10105804Scg149915 }
1011