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, ®off);
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