diff options
Diffstat (limited to 'usr/src/uts/common/io/drm/drm_sunmod.c')
-rw-r--r-- | usr/src/uts/common/io/drm/drm_sunmod.c | 1372 |
1 files changed, 578 insertions, 794 deletions
diff --git a/usr/src/uts/common/io/drm/drm_sunmod.c b/usr/src/uts/common/io/drm/drm_sunmod.c index 2f69229..24971ba 100644 --- a/usr/src/uts/common/io/drm/drm_sunmod.c +++ b/usr/src/uts/common/io/drm/drm_sunmod.c @@ -1,27 +1,28 @@ /* - * CDDL HEADER START + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved. */ /* @@ -34,288 +35,427 @@ */ #include "drm_sunmod.h" +#include "drm_sun_idr.h" #include <sys/modctl.h> #include <sys/kmem.h> #include <vm/seg_kmem.h> -static struct modlmisc modlmisc = { - &mod_miscops, "DRM common interfaces" +int drm_debug_flag = 0; +int mdb_track_enable = B_FALSE; + +/* Identifier of this driver */ +static struct vis_identifier text_ident = { "SUNWdrm" }; + +static ddi_device_acc_attr_t dev_attr = { + DDI_DEVICE_ATTR_V0, + DDI_NEVERSWAP_ACC, + DDI_STRICTORDER_ACC, + DDI_FLAGERR_ACC }; -static struct modlinkage modlinkage = { - MODREV_1, (void *)&modlmisc, NULL +static ddi_device_acc_attr_t gem_dev_attr = { + DDI_DEVICE_ATTR_V0, + DDI_NEVERSWAP_ACC, + DDI_MERGING_OK_ACC, + DDI_FLAGERR_ACC }; -static drm_inst_list_t *drm_inst_head; -static kmutex_t drm_inst_list_lock; +extern int __init drm_core_init(void); +extern void __exit drm_core_exit(void); +extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *); -static int drm_sun_open(dev_t *, int, int, cred_t *); -static int drm_sun_close(dev_t, int, int, cred_t *); -static int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); -static int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t, - size_t *, uint_t); +struct find_gem_object { + offset_t offset; + struct drm_gem_object *obj; +}; -/* - * devmap callbacks for AGP and PCI GART - */ -static int drm_devmap_map(devmap_cookie_t, dev_t, - uint_t, offset_t, size_t, void **); -static int drm_devmap_dup(devmap_cookie_t, void *, - devmap_cookie_t, void **); -static void drm_devmap_unmap(devmap_cookie_t, void *, - offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **); +static int +drm_devmap_map(devmap_cookie_t dhc, dev_t dev_id, uint_t flags, + offset_t offset, size_t len, void **new_priv) +{ + _NOTE(ARGUNUSED(offset, len)) -static drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *); -static drm_inst_state_t *drm_sup_devt_to_state(dev_t); -static void drm_supp_free_drv_entry(dev_info_t *); + devmap_handle_t *dhp; + struct ddi_umem_cookie *cp; + struct drm_minor *minor; + struct drm_device *dev; + int minor_id; -static struct devmap_callback_ctl drm_devmap_callbacks = { - DEVMAP_OPS_REV, /* devmap_rev */ - drm_devmap_map, /* devmap_map */ - NULL, /* devmap_access */ - drm_devmap_dup, /* devmap_dup */ - drm_devmap_unmap /* devmap_unmap */ -}; + minor_id = DRM_DEV2MINOR(dev_id); + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + dev = minor->dev; -/* - * Common device operations structure for all DRM drivers - */ -struct cb_ops drm_cb_ops = { - drm_sun_open, /* cb_open */ - drm_sun_close, /* cb_close */ - nodev, /* cb_strategy */ - nodev, /* cb_print */ - nodev, /* cb_dump */ - nodev, /* cb_read */ - nodev, /* cb_write */ - drm_sun_ioctl, /* cb_ioctl */ - drm_sun_devmap, /* cb_devmap */ - nodev, /* cb_mmap */ - NULL, /* cb_segmap */ - nochpoll, /* cb_chpoll */ - ddi_prop_op, /* cb_prop_op */ - 0, /* cb_stream */ - D_NEW | D_MTSAFE |D_DEVMAP /* cb_flag */ -}; + /* + * This driver only supports MAP_SHARED, + * and doesn't support MAP_PRIVATE + */ + if (flags & MAP_PRIVATE) { + DRM_ERROR("Not support MAP_PRIVATE"); + return (EINVAL); + } -int -_init(void) + mutex_enter(&dev->struct_mutex); + dhp = (devmap_handle_t *)dhc; + cp = (struct ddi_umem_cookie *)dhp->dh_cookie; + cp->cook_refcnt = 1; + mutex_exit(&dev->struct_mutex); + + *new_priv = dev; + return (0); +} + +static int +drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc, + void **new_pvtp) { - int error; + _NOTE(ARGUNUSED(new_dhc)) - if ((error = mod_install(&modlinkage)) != 0) { - return (error); - } + struct drm_device *dev = (struct drm_device *)pvtp; + devmap_handle_t *dhp; + struct ddi_umem_cookie *cp; + + mutex_enter(&dev->struct_mutex); + dhp = (devmap_handle_t *)dhc; + cp = (struct ddi_umem_cookie *)dhp->dh_cookie; + cp->cook_refcnt++; + mutex_exit(&dev->struct_mutex); - /* initialize the instance list lock */ - mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL); + *new_pvtp = dev; return (0); } -int -_fini(void) +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) { - int err; + _NOTE(ARGUNUSED(off, len)) - if ((err = mod_remove(&modlinkage)) != 0) - return (err); + struct drm_device *dev; + devmap_handle_t *dhp; + devmap_handle_t *ndhp; + struct ddi_umem_cookie *cp; + struct ddi_umem_cookie *ncp; - mutex_destroy(&drm_inst_list_lock); - return (0); + dhp = (devmap_handle_t *)dhc; + dev = (struct drm_device *)pvtp; + + mutex_enter(&dev->struct_mutex); + + cp = (struct ddi_umem_cookie *)dhp->dh_cookie; + if (new_dhp1 != NULL) { + ndhp = (devmap_handle_t *)new_dhp1; + ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie; + ncp->cook_refcnt++; + *new_pvtp1 = dev; + ASSERT(ncp == cp); + } + + if (new_dhp2 != NULL) { + ndhp = (devmap_handle_t *)new_dhp2; + ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie; + ncp->cook_refcnt++; + *new_pvtp2 = dev; + ASSERT(ncp == cp); + } + + /* FIXME: dh_cookie should not be released here. */ +#if 0 + cp->cook_refcnt--; + if (cp->cook_refcnt == 0) { + gfxp_umem_cookie_destroy(dhp->dh_cookie); + dhp->dh_cookie = NULL; + } +#endif + + mutex_exit(&dev->struct_mutex); } -int -_info(struct modinfo *modinfop) +static struct devmap_callback_ctl drm_devmap_callbacks = { + DEVMAP_OPS_REV, /* devmap_rev */ + drm_devmap_map, /* devmap_map */ + NULL, /* devmap_access */ + drm_devmap_dup, /* devmap_dup */ + drm_devmap_unmap /* devmap_unmap */ +}; + +static struct drm_local_map * +__find_local_map(struct drm_device *dev, offset_t offset) { - return (mod_info(&modlinkage, modinfop)); + struct drm_map_list *entry; + + entry = idr_find(&dev->map_idr, offset >> PAGE_SHIFT); + if (entry) + return (entry->map); + + return (NULL); } -void * -drm_supp_register(dev_info_t *dip, drm_device_t *dp) +static int +drm_gem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags, offset_t off, + size_t len, void **pvtp) { - int error; - char buf[80]; - int instance = ddi_get_instance(dip); - ddi_acc_handle_t pci_cfg_handle; - agp_master_softc_t *agpm; - drm_inst_state_t *mstate; - drm_inst_list_t *entry; - gfxp_vgatext_softc_ptr_t gfxp; - struct dev_ops *devop; - - ASSERT(dip != NULL); - - entry = drm_supp_alloc_drv_entry(dip); - if (entry == NULL) { - cmn_err(CE_WARN, "drm_supp_register: failed to get softstate"); - return (NULL); + _NOTE(ARGUNUSED(dhp, flags, len)) + + struct drm_device *drm_dev; + struct drm_minor *minor; + int minor_id = DRM_DEV2MINOR(dev); + drm_local_map_t *map = NULL; + + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); + + drm_dev = minor->dev; + + mutex_enter(&drm_dev->struct_mutex); + map = __find_local_map(drm_dev, off); + if (!map) { + mutex_exit(&drm_dev->struct_mutex); + *pvtp = NULL; + return (DDI_EINVAL); } - mstate = &entry->disl_state; - /* - * DRM drivers are required to use common cb_ops - */ - devop = ddi_get_driver(dip); - if (devop->devo_cb_ops != &drm_cb_ops) { - devop->devo_cb_ops = &drm_cb_ops; + mutex_exit(&drm_dev->struct_mutex); + + *pvtp = map->handle; + + return (DDI_SUCCESS); +} + +static int +drm_gem_map_access(devmap_cookie_t dhp, void *pvt, offset_t offset, size_t len, + uint_t type, uint_t rw) +{ + struct drm_device *dev; + struct drm_gem_object *obj; + struct gem_map_list *seg; + + obj = (struct drm_gem_object *)pvt; + if (obj == NULL) { + goto next; } - /* Generic graphics initialization */ - gfxp = gfxp_vgatext_softc_alloc(); - error = gfxp_vgatext_attach(dip, DDI_ATTACH, gfxp); - if (error != DDI_SUCCESS) { - DRM_ERROR("drm_supp_regiter: failed to init gfx"); - goto exit1; + dev = obj->dev; + if (dev->driver->gem_fault != NULL) + dev->driver->gem_fault(obj); + +next: + if (devmap_load(dhp, offset, len, type, rw)) { + return (DDI_FAILURE); + } + if (obj != NULL) { + seg = drm_alloc(sizeof (struct gem_map_list), DRM_MEM_MAPS); + if (seg != NULL) { + mutex_lock(&dev->page_fault_lock); + seg->dhp = dhp; + seg->mapoffset = offset; + seg->maplen = len; + list_add_tail(&seg->head, &obj->seg_list, (caddr_t)seg); + mutex_unlock(&dev->page_fault_lock); + } } + return (DDI_SUCCESS); +} + +static void +drm_gem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, size_t len, + devmap_cookie_t new_dhp1, void **newpvtp1, + devmap_cookie_t new_dhp2, void **newpvtp2) +{ + struct drm_device *dev; + struct drm_gem_object *obj; + struct gem_map_list *entry, *temp; - /* create a minor node for common graphics ops */ - (void) sprintf(buf, "%s%d", GFX_NAME, instance); - error = ddi_create_minor_node(dip, buf, S_IFCHR, - INST2NODE0(instance), DDI_NT_DISPLAY, NULL); - if (error != DDI_SUCCESS) { - DRM_ERROR("drm_supp_regiter: " - "failed to create minor node for gfx"); - goto exit2; + _NOTE(ARGUNUSED(dhp, pvtp, off, len, new_dhp1, newpvtp1)) + _NOTE(ARGUNUSED(new_dhp2, newpvtp2)) + + obj = (struct drm_gem_object *)pvtp; + if (obj == NULL) + return; + + dev = obj->dev; + + mutex_lock(&dev->page_fault_lock); + if (list_empty(&obj->seg_list)) { + mutex_unlock(&dev->page_fault_lock); + return; } - /* setup mapping for later PCI config space access */ - error = pci_config_setup(dip, &pci_cfg_handle); - if (error != DDI_SUCCESS) { - DRM_ERROR("drm_supp_regiter: " - "PCI configuration space setup failed"); - goto exit2; + list_for_each_entry_safe(entry, temp, struct gem_map_list, + &obj->seg_list, head) { + (void) devmap_unload(entry->dhp, entry->mapoffset, + entry->maplen); + list_del(&entry->head); + drm_free(entry, sizeof (struct gem_map_list), DRM_MEM_MAPS); } - /* AGP master attach */ - agpm = NULL; - if (dp->driver->use_agp) { - DRM_DEBUG("drm_supp_regiter: driver use AGP\n"); - error = agpmaster_attach(dip, &agpm, - pci_cfg_handle, INST2NODE1(instance)); - if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) { - DRM_ERROR("drm_supp_regiter: " - "AGP master support not available"); - goto exit3; - } + mutex_unlock(&dev->page_fault_lock); +} + +static struct devmap_callback_ctl drm_gem_map_ops = { + DEVMAP_OPS_REV, /* devmap_ops version number */ + drm_gem_map, /* devmap_ops map routine */ + drm_gem_map_access, /* devmap_ops access routine */ + NULL, /* devmap_ops dup routine */ + drm_gem_unmap, /* devmap_ops unmap routine */ +}; + +static int +__devmap_general(struct drm_device *dev, devmap_cookie_t dhp, + struct drm_local_map *map, size_t len, size_t *maplen) +{ + off_t regoff; + int regno, ret; + + regno = drm_get_pci_index_reg(dev->devinfo, + map->offset, (uint_t)len, ®off); + if (regno < 0) { + DRM_ERROR("drm_get_pci_index_reg() failed"); + return (-EINVAL); } - mutex_enter(&mstate->mis_lock); - mstate->mis_major = ddi_driver_major(dip); - mstate->mis_dip = dip; - mstate->mis_gfxp = gfxp; - mstate->mis_agpm = agpm; - mstate->mis_cfg_hdl = pci_cfg_handle; - mstate->mis_devp = dp; - mutex_exit(&mstate->mis_lock); - - /* create minor node for DRM access */ - (void) sprintf(buf, "%s%d", DRM_DEVNODE, instance); - if (ddi_create_minor_node(dip, buf, S_IFCHR, - INST2NODE2(instance), DDI_NT_DISPLAY_DRM, 0)) { - DRM_ERROR("supp_regiter: faled to create minor node for drm"); - goto exit4; + ret = devmap_devmem_setup(dhp, dev->devinfo, NULL, + regno, (offset_t)regoff, len, PROT_ALL, + 0, &dev_attr); + if (ret != DDI_SUCCESS) { + DRM_ERROR("devmap_devmem_setup failed, ret=%d", ret); + return (-EFAULT); } - return ((void *)mstate); + *maplen = len; + return (0); +} -exit4: - if ((dp->driver->use_agp) && agpm) - agpmaster_detach(&agpm); -exit3: - pci_config_teardown(&pci_cfg_handle); -exit2: - (void) gfxp_vgatext_detach(dip, DDI_DETACH, gfxp); -exit1: - gfxp_vgatext_softc_free(gfxp); - drm_supp_free_drv_entry(dip); - ddi_remove_minor_node(dip, NULL); +static int +__devmap_shm(struct drm_device *dev, devmap_cookie_t dhp, + struct drm_local_map *map, size_t len, size_t *maplen) +{ + int ret; - return (NULL); -} + if (!map->umem_cookie) + return (-EINVAL); + len = ptob(btopr(map->size)); -int -drm_supp_unregister(void *handle) + ret = devmap_umem_setup(dhp, dev->devinfo, + NULL, map->umem_cookie, 0, len, PROT_ALL, + IOMEM_DATA_CACHED, NULL); + if (ret != DDI_SUCCESS) { + DRM_ERROR("devmap_umem_setup failed, ret=%d", ret); + return (-EFAULT); + } + + *maplen = len; + return (0); +} + +static int +__devmap_agp(struct drm_device *dev, devmap_cookie_t dhp, + struct drm_local_map *map, size_t len, size_t *maplen) { - drm_inst_list_t *list; - drm_inst_state_t *mstate; - - list = (drm_inst_list_t *)handle; - mstate = &list->disl_state; - mutex_enter(&mstate->mis_lock); - - /* AGP master detach */ - if (mstate->mis_agpm != NULL) - agpmaster_detach(&mstate->mis_agpm); - - /* free PCI config access handle */ - if (mstate->mis_cfg_hdl) - pci_config_teardown(&mstate->mis_cfg_hdl); - - /* graphics misc module detach */ - if (mstate->mis_gfxp) { - (void) gfxp_vgatext_detach(mstate->mis_dip, DDI_DETACH, - mstate->mis_gfxp); - gfxp_vgatext_softc_free(mstate->mis_gfxp); + int ret; + + if (dev->agp == NULL) { + DRM_ERROR("attempted to mmap AGP" + "memory before AGP support is enabled"); + return (-ENODEV); } - mstate->mis_devp = NULL; + len = ptob(btopr(len)); - /* remove all minor nodes */ - ddi_remove_minor_node(mstate->mis_dip, NULL); - mutex_exit(&mstate->mis_lock); - drm_supp_free_drv_entry(mstate->mis_dip); + ret = devmap_umem_setup(dhp, dev->devinfo, + &drm_devmap_callbacks, map->umem_cookie, 0, len, PROT_ALL, + IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr); + if (ret != DDI_SUCCESS) { + DRM_ERROR("devmap_umem_setup() failed, ret=%d", ret); + return (-EFAULT); + } - return (DDI_SUCCESS); + *maplen = len; + return (0); } +static int +__devmap_sg(struct drm_device *dev, devmap_cookie_t dhp, + struct drm_local_map *map, size_t len, size_t *maplen) +{ + int ret; + + len = ptob(btopr(len)); + if (len > map->size) { + DRM_ERROR("offset=0x%lx, virtual=0x%p, " + "mapsize=0x%lx, len=0x%lx", + map->offset, dev->sg->virtual, map->size, len); + return (-EINVAL); + } + + ret = devmap_umem_setup(dhp, dev->devinfo, + &drm_devmap_callbacks, map->umem_cookie, 0, len, PROT_ALL, + IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr); + if (ret != DDI_SUCCESS) { + DRM_ERROR("devmap_umem_setup() fail"); + return (-EFAULT); + } + + *maplen = len; + return (0); +} -/*ARGSUSED*/ static int -drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp) +__devmap_gem(struct drm_device *dev, devmap_cookie_t dhp, + struct drm_local_map *map, size_t *maplen) { - drm_inst_state_t *mstate; - drm_cminor_t *mp, *newp; - drm_device_t *dp; - minor_t minor; - int newminor; - int instance; - int err; - - mstate = drm_sup_devt_to_state(*devp); - /* - * return ENXIO for deferred attach so that system can - * attach us again. - */ - if (mstate == NULL) - return (ENXIO); + struct devmap_callback_ctl *callbackops = NULL; + int ret; - /* - * The lest significant 15 bits are used for minor_number, and - * the mid 3 bits are used for instance number. All minor numbers - * are used as follows: - * 0 -- gfx - * 1 -- agpmaster - * 2 -- drm - * (3, MAX_CLONE_MINOR) -- drm minor node for clone open. - */ - minor = DEV2MINOR(*devp); - instance = DEV2INST(*devp); - ASSERT(minor <= MAX_CLONE_MINOR); + if (map->callback == 1) { + callbackops = &drm_gem_map_ops; + } + + if (!map->umem_cookie) + return (-EINVAL); + + ret = gfxp_devmap_umem_setup(dhp, dev->devinfo, callbackops, + map->umem_cookie, 0, map->size, PROT_ALL, + IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP, &gem_dev_attr); + if (ret != DDI_SUCCESS) { + DRM_ERROR("gfxp_devmap_umem_setup failed, ret=%d", ret); + return (-EFAULT); + } + + *maplen = map->size; + return (0); +} + +static int +drm_sun_open(dev_t *dev_id, int flag, int otyp, cred_t *credp) +{ + _NOTE(ARGUNUSED(otyp)) + + int minor_id = DRM_DEV2MINOR(*dev_id); + struct drm_minor *minor; + int clone_id; + int ret; + + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); /* * No operations for VGA & AGP mater devices, always return OK. */ - if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR)) + if (DRM_MINOR_IS_VGATEXT(minor_id)) return (0); - /* - * From here, we start to process drm - */ - - dp = mstate->mis_devp; - if (!dp) - return (ENXIO); + if (DRM_MINOR_IS_AGPMASTER(minor_id)) + return (0); /* * Drm driver implements a software lock to serialize access @@ -352,86 +492,79 @@ drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp) * during open()'ing, and find corresponding process struct * via minor number when close() is called. */ - newp = kmem_zalloc(sizeof (drm_cminor_t), KM_SLEEP); - mutex_enter(&dp->dev_lock); - for (newminor = DRM_MIN_CLONEMINOR; newminor < MAX_CLONE_MINOR; - newminor ++) { - TAILQ_FOREACH(mp, &dp->minordevs, link) { - if (mp->minor == newminor) - break; - } - if (mp == NULL) - goto gotminor; + ret = idr_get_new_above(&minor->clone_idr, NULL, 0, &clone_id); + if (ret) + return (EMFILE); + + if (clone_id > DRM_CLONEID_MAX) { + (void) idr_remove(&minor->clone_idr, clone_id); + return (EMFILE); } - mutex_exit(&dp->dev_lock); - (void) kmem_free(newp, sizeof (drm_cminor_t)); - return (EMFILE); - -gotminor: - TAILQ_INSERT_TAIL(&dp->minordevs, newp, link); - newp->minor = newminor; - mutex_exit(&dp->dev_lock); - err = drm_open(dp, newp, flag, otyp, credp); - if (err) { - mutex_enter(&dp->dev_lock); - TAILQ_REMOVE(&dp->minordevs, newp, link); - (void) kmem_free(newp, sizeof (drm_cminor_t)); - mutex_exit(&dp->dev_lock); - - return (err); + ret = drm_open(minor, clone_id, flag, credp); + if (ret) { + (void) idr_remove(&minor->clone_idr, clone_id); + return (-ret); } - /* return a clone minor */ - newminor = newminor | (instance << NBITSMNODE); - *devp = makedevice(getmajor(*devp), newminor); - return (err); + *dev_id = DRM_MAKEDEV(getmajor(*dev_id), minor_id, clone_id); + + return (-ret); } -/*ARGSUSED*/ static int -drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp) +drm_sun_close(dev_t dev_id, int flag, int otyp, cred_t *credp) { - drm_inst_state_t *mstate; - drm_device_t *dp; - minor_t minor; - int ret; + _NOTE(ARGUNUSED(flag, otyp, credp)) - mstate = drm_sup_devt_to_state(dev); - if (mstate == NULL) - return (EBADF); + struct drm_minor *minor; + struct drm_file *file_priv; + int minor_id = DRM_DEV2MINOR(dev_id); + int clone_id = DRM_DEV2CLONEID(dev_id); + int ret = 0; + + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); - minor = DEV2MINOR(dev); - ASSERT(minor <= MAX_CLONE_MINOR); - if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR)) + /* + * No operations for VGA & AGP mater devices, always return OK. + */ + if (DRM_MINOR_IS_VGATEXT(minor_id)) return (0); - dp = mstate->mis_devp; - if (dp == NULL) { - DRM_ERROR("drm_sun_close: NULL soft state"); - return (ENXIO); - } + if (DRM_MINOR_IS_AGPMASTER(minor_id)) + return (0); - ret = drm_close(dp, minor, flag, otyp, credp); + file_priv = idr_find(&minor->clone_idr, clone_id); + if (!file_priv) + return (EBADF); + + ret = drm_release(file_priv); + if (ret) + return (-ret); + + (void) idr_remove(&minor->clone_idr, clone_id); - return (ret); + return (0); } -/*ARGSUSED*/ static int -drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, - cred_t *credp, int *rvalp) +drm_sun_ioctl(dev_t dev_id, int cmd, intptr_t arg, int mode, cred_t *credp, + int *rvalp) { - extern drm_ioctl_desc_t drm_ioctls[]; + struct drm_minor *minor; + struct drm_file *file_priv; + int minor_id = DRM_DEV2MINOR(dev_id); + int clone_id = DRM_DEV2CLONEID(dev_id); - drm_inst_state_t *mstate; - drm_device_t *dp; - drm_ioctl_desc_t *ioctl; - drm_ioctl_t *func; - drm_file_t *fpriv; - minor_t minor; - int retval; - int nr; + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); if (cmd == VIS_GETIDENTIFIER) { if (ddi_copyout(&text_ident, (void *)arg, @@ -439,572 +572,223 @@ drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, return (EFAULT); } - mstate = drm_sup_devt_to_state(dev); - if (mstate == NULL) { - return (EIO); - } - - minor = DEV2MINOR(dev); - ASSERT(minor <= MAX_CLONE_MINOR); - switch (minor) { - case GFX_MINOR: - retval = gfxp_vgatext_ioctl(dev, cmd, arg, - mode, credp, rvalp, mstate->mis_gfxp); - return (retval); - - case AGPMASTER_MINOR: - retval = agpmaster_ioctl(dev, cmd, arg, mode, - credp, rvalp, mstate->mis_agpm); - return (retval); - - case DRM_MINOR: - default: /* DRM cloning minor nodes */ - break; - } - - dp = mstate->mis_devp; - ASSERT(dp != NULL); - - nr = DRM_IOCTL_NR(cmd); - ioctl = &drm_ioctls[nr]; - atomic_inc_32(&dp->counts[_DRM_STAT_IOCTLS]); - - /* It's not a core DRM ioctl, try driver-specific. */ - if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) { - /* The array entries begin at DRM_COMMAND_BASE ioctl nr */ - nr -= DRM_COMMAND_BASE; - if (nr > dp->driver->max_driver_ioctl) { - DRM_ERROR("Bad driver ioctl number, 0x%x (of 0x%x)", - nr, dp->driver->max_driver_ioctl); - return (EINVAL); - } - ioctl = &dp->driver->driver_ioctls[nr]; - } - - func = ioctl->func; - if (func == NULL) { - return (ENOTSUP); - } - - mutex_enter(&dp->dev_lock); - fpriv = drm_find_file_by_proc(dp, credp); - mutex_exit(&dp->dev_lock); - if (fpriv == NULL) { - DRM_ERROR("drm_sun_ioctl : can't find authenticator"); - return (EACCES); - } - - if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) || - ((ioctl->flags & DRM_AUTH) && !fpriv->authenticated) || - ((ioctl->flags & DRM_MASTER) && !fpriv->master)) - return (EACCES); + if (DRM_MINOR_IS_VGATEXT(minor_id)) + return (gfxp_vgatext_ioctl(dev_id, cmd, arg, mode, credp, + rvalp, minor->private)); - fpriv->dev = dev; - fpriv->credp = credp; + if (DRM_MINOR_IS_AGPMASTER(minor_id)) + return (agpmaster_ioctl(dev_id, cmd, arg, mode, credp, + rvalp, minor->private)); - retval = func(dp, arg, fpriv, mode); + file_priv = idr_find(&minor->clone_idr, clone_id); + if (!file_priv) + return (EBADF); - return (retval); + return (-(drm_ioctl(dev_id, file_priv, cmd, arg, mode, credp))); } -/*ARGSUSED*/ static int -drm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset, +drm_sun_devmap(dev_t dev_id, devmap_cookie_t dhp, offset_t offset, size_t len, size_t *maplen, uint_t model) { - extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *); - - drm_inst_state_t *mstate; - drm_device_t *dp; - ddi_umem_cookie_t cookie; - drm_local_map_t *map = NULL; - unsigned long aperbase; - u_offset_t handle; - offset_t koff; - caddr_t kva; - minor_t minor; - size_t length; - int ret; - - static ddi_device_acc_attr_t dev_attr = { - DDI_DEVICE_ATTR_V0, - DDI_NEVERSWAP_ACC, - DDI_STRICTORDER_ACC, - }; - static ddi_device_acc_attr_t gem_dev_attr = { - DDI_DEVICE_ATTR_V0, - DDI_NEVERSWAP_ACC, - DDI_MERGING_OK_ACC - }; - - mstate = drm_sup_devt_to_state(dev); - if (mstate == NULL) - return (ENXIO); - - minor = DEV2MINOR(dev); - switch (minor) { - case GFX_MINOR: - ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model, - mstate->mis_gfxp); - return (ret); - - case AGPMASTER_MINOR: + struct drm_device *dev; + struct drm_minor *minor; + struct drm_file *file_priv; + int minor_id = DRM_DEV2MINOR(dev_id); + int clone_id = DRM_DEV2CLONEID(dev_id); + drm_local_map_t *map = NULL; + + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); + + dev = minor->dev; + + if (DRM_MINOR_IS_VGATEXT(minor_id)) + return (gfxp_vgatext_devmap(dev_id, dhp, offset, len, + maplen, model, minor->private)); + + if (DRM_MINOR_IS_AGPMASTER(minor_id)) return (ENOTSUP); - case DRM_MINOR: - break; - - default: - /* DRM cloning nodes */ - if (minor > MAX_CLONE_MINOR) - return (EBADF); - break; - } - - - dp = mstate->mis_devp; - if (dp == NULL) { - DRM_ERROR("drm_sun_devmap: NULL soft state"); - return (EINVAL); - } - - mutex_enter(&dp->dev_lock); - - if (dp->driver->use_gem == 1) { - struct idr_list *entry; - drm_cminor_t *mp; - - mp = drm_find_file_by_minor(dp, minor); - if (!mp) { - mutex_exit(&dp->dev_lock); - DRM_ERROR("drm_sun_devmap: can't find authenticator"); - return (EACCES); - } - - spin_lock(&dp->struct_mutex); - idr_list_for_each(entry, &(mp->fpriv->object_idr)) { - if ((uintptr_t)entry->obj == (u_offset_t)offset) { - map = entry->obj->map; - goto goon; - } - } -goon: - spin_unlock(&dp->struct_mutex); - } - - if (map == NULL) { - /* - * We will solve 32-bit application on 64-bit kernel - * issue later, now, we just use low 32-bit - */ - handle = (u_offset_t)offset; - handle &= 0xffffffff; - - TAILQ_FOREACH(map, &dp->maplist, link) { - if (handle == - ((u_offset_t)((uintptr_t)map->handle) & 0xffffffff)) - break; - } - - /* - * Temporarily, because offset is phys_addr for register - * and framebuffer, is kernel virtual_addr for others - * Maybe we will use hash table to solve this issue later. - */ - if (map == NULL) { - TAILQ_FOREACH(map, &dp->maplist, link) { - if (handle == (map->offset & 0xffffffff)) - break; - } - } - } + file_priv = idr_find(&minor->clone_idr, clone_id); + if (!file_priv) + return (EBADF); - if (map == NULL) { - u_offset_t tmp; - - mutex_exit(&dp->dev_lock); - cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n", - offset, (int)len); - cmn_err(CE_WARN, "Current mapping:\n"); - TAILQ_FOREACH(map, &dp->maplist, link) { - tmp = (u_offset_t)((uintptr_t)map->handle) & 0xffffffff; - cmn_err(CE_WARN, "map(handle=0x%p, size=0x%lx,type=%d," - "offset=0x%lx), handle=%llx, tmp=%lld", map->handle, - map->size, map->type, map->offset, handle, tmp); - } - return (-1); + mutex_enter(&dev->struct_mutex); + map = __find_local_map(dev, offset); + if (!map) { + mutex_exit(&dev->struct_mutex); + return (EFAULT); } if (map->flags & _DRM_RESTRICTED) { - mutex_exit(&dp->dev_lock); - cmn_err(CE_WARN, "restricted map\n"); - return (-1); + mutex_exit(&dev->struct_mutex); + return (ENOTSUP); } + mutex_exit(&dev->struct_mutex); - mutex_exit(&dp->dev_lock); switch (map->type) { case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - { - int regno; - off_t regoff; - - regno = drm_get_pci_index_reg(dp->dip, - map->offset, (uint_t)len, ®off); - if (regno < 0) { - DRM_ERROR("devmap: failed to get register" - " offset=0x%llx, len=0x%x", handle, len); - return (EINVAL); - } - - ret = devmap_devmem_setup(dhp, dp->dip, NULL, - regno, (offset_t)regoff, len, PROT_ALL, - 0, &dev_attr); - if (ret != 0) { - *maplen = 0; - DRM_ERROR("devmap: failed, regno=%d,type=%d," - " handle=0x%x, offset=0x%llx, len=0x%x", - regno, map->type, handle, offset, len); - return (ret); - } - *maplen = len; - return (ret); - } + return (__devmap_general(dev, dhp, map, len, maplen)); case _DRM_SHM: - if (map->drm_umem_cookie == NULL) - return (EINVAL); - length = ptob(btopr(map->size)); - ret = devmap_umem_setup(dhp, dp->dip, NULL, - map->drm_umem_cookie, 0, length, - PROT_ALL, IOMEM_DATA_CACHED, NULL); - if (ret != 0) { - *maplen = 0; - return (ret); - } - *maplen = length; - - return (DDI_SUCCESS); + return (__devmap_shm(dev, dhp, map, len, maplen)); case _DRM_AGP: - if (dp->agp == NULL) { - cmn_err(CE_WARN, "drm_sun_devmap: attempted to mmap AGP" - "memory before AGP support is enabled"); - return (DDI_FAILURE); - } - - aperbase = dp->agp->base; - koff = map->offset - aperbase; - length = ptob(btopr(len)); - kva = map->dev_addr; - cookie = gfxp_umem_cookie_init(kva, length); - if (cookie == NULL) { - cmn_err(CE_WARN, "devmap:failed to get umem_cookie"); - return (DDI_FAILURE); - } - - if ((ret = devmap_umem_setup(dhp, dp->dip, - &drm_devmap_callbacks, cookie, 0, length, PROT_ALL, - IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) { - gfxp_umem_cookie_destroy(cookie); - cmn_err(CE_WARN, "devmap:failed, retval=%d", ret); - return (DDI_FAILURE); - } - *maplen = length; - break; + return (__devmap_agp(dev, dhp, map, len, maplen)); case _DRM_SCATTER_GATHER: - koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual; - kva = map->dev_addr + koff; - length = ptob(btopr(len)); - if (length > map->size) { - cmn_err(CE_WARN, "offset=0x%lx, virtual=0x%p," - "mapsize=0x%lx,len=0x%lx", map->offset, - dp->sg->virtual, map->size, len); - return (DDI_FAILURE); - } - cookie = gfxp_umem_cookie_init(kva, length); - if (cookie == NULL) { - cmn_err(CE_WARN, "devmap:failed to get umem_cookie"); - return (DDI_FAILURE); - } - ret = devmap_umem_setup(dhp, dp->dip, - &drm_devmap_callbacks, cookie, 0, length, PROT_ALL, - IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr); - if (ret != 0) { - cmn_err(CE_WARN, "sun_devmap: umem_setup fail"); - gfxp_umem_cookie_destroy(cookie); - return (DDI_FAILURE); - } - *maplen = length; - break; - - case _DRM_TTM: - if (map->drm_umem_cookie == NULL) - return (EINVAL); - - if (gfxp_devmap_umem_setup(dhp, dp->dip, - NULL, map->drm_umem_cookie, 0, map->size, PROT_ALL, - IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP, - &gem_dev_attr)) { - cmn_err(CE_WARN, "devmap:failed, retval=%d", ret); - return (DDI_FAILURE); - } - *maplen = map->size; - return (DDI_SUCCESS); + return (__devmap_sg(dev, dhp, map, len, maplen)); - default: - return (DDI_FAILURE); + case _DRM_GEM: + return (__devmap_gem(dev, dhp, map, maplen)); } - return (DDI_SUCCESS); + return (ENOTSUP); } -/*ARGSUSED*/ static int -drm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags, - offset_t offset, size_t len, void **new_priv) +drm_sun_read(dev_t dev_id, struct uio *uiop, cred_t *credp) { - devmap_handle_t *dhp; - drm_inst_state_t *statep; - struct ddi_umem_cookie *cp; + _NOTE(ARGUNUSED(credp)) + + struct drm_minor *minor; + struct drm_file *file_priv; + int minor_id = DRM_DEV2MINOR(dev_id); + int clone_id = DRM_DEV2CLONEID(dev_id); - statep = drm_sup_devt_to_state(dev); - ASSERT(statep != NULL); + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); /* - * This driver only supports MAP_SHARED, - * and doesn't support MAP_PRIVATE + * No operations for VGA & AGP master devices, always return OK. */ - if (flags & MAP_PRIVATE) { - cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE"); - return (EINVAL); - } + if (DRM_MINOR_IS_VGATEXT(minor_id)) + return (0); - mutex_enter(&statep->dis_ctxlock); - dhp = (devmap_handle_t *)dhc; - cp = (struct ddi_umem_cookie *)dhp->dh_cookie; - cp->cook_refcnt = 1; - mutex_exit(&statep->dis_ctxlock); - *new_priv = statep; + if (DRM_MINOR_IS_AGPMASTER(minor_id)) + return (0); + file_priv = idr_find(&minor->clone_idr, clone_id); + if (!file_priv) + return (EBADF); + + (void) drm_read(file_priv, uiop); return (0); } -/*ARGSUSED*/ -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) +static int +drm_sun_chpoll(dev_t dev_id, short events, int anyyet, short *reventsp, + struct pollhead **phpp) { - devmap_handle_t *dhp; - devmap_handle_t *ndhp; - drm_inst_state_t *statep; - struct ddi_umem_cookie *cp; - struct ddi_umem_cookie *ncp; + struct drm_minor *minor; + struct drm_file *file_priv; + int minor_id = DRM_DEV2MINOR(dev_id); + int clone_id = DRM_DEV2CLONEID(dev_id); - dhp = (devmap_handle_t *)dhc; - statep = (drm_inst_state_t *)pvtp; + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return (ENODEV); + if (!minor->dev) + return (ENODEV); - mutex_enter(&statep->dis_ctxlock); - cp = (struct ddi_umem_cookie *)dhp->dh_cookie; - if (new_dhp1 != NULL) { - ndhp = (devmap_handle_t *)new_dhp1; - ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie; - ncp->cook_refcnt ++; - *new_pvtp1 = statep; - ASSERT(ncp == cp); - } - - if (new_dhp2 != NULL) { - ndhp = (devmap_handle_t *)new_dhp2; - ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie; - ncp->cook_refcnt ++; - *new_pvtp2 = statep; - ASSERT(ncp == cp); - } - - cp->cook_refcnt --; - if (cp->cook_refcnt == 0) { - gfxp_umem_cookie_destroy(dhp->dh_cookie); - dhp->dh_cookie = NULL; - } - mutex_exit(&statep->dis_ctxlock); -} + /* + * No operations for VGA & AGP master devices, always return OK. + */ + if (DRM_MINOR_IS_VGATEXT(minor_id)) + return (0); + if (DRM_MINOR_IS_AGPMASTER(minor_id)) + return (0); -/*ARGSUSED*/ -static int -drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc, - void **new_pvtp) -{ - devmap_handle_t *dhp; - drm_inst_state_t *statep; - struct ddi_umem_cookie *cp; + file_priv = idr_find(&minor->clone_idr, clone_id); + if (!file_priv) + return (EBADF); - statep = (drm_inst_state_t *)pvtp; - mutex_enter(&statep->dis_ctxlock); - dhp = (devmap_handle_t *)dhc; - cp = (struct ddi_umem_cookie *)dhp->dh_cookie; - cp->cook_refcnt ++; - mutex_exit(&statep->dis_ctxlock); - *new_pvtp = statep; + if (!anyyet) { + *phpp = &file_priv->drm_pollhead; + } + *reventsp = drm_poll(file_priv, events); return (0); } -int -drm_dev_to_instance(dev_t dev) -{ - return (DEV2INST(dev)); -} - /* - * drm_supp_alloc_drv_entry() - * - * Description: - * Create a DRM entry and add it into the instance list (drm_inst_head). - * Note that we don't allow a duplicated entry + * Common device operations structure for all DRM drivers */ -static drm_inst_list_t * -drm_supp_alloc_drv_entry(dev_info_t *dip) -{ - drm_inst_list_t **plist; - drm_inst_list_t *list; - drm_inst_list_t *entry; - - /* protect the driver list */ - mutex_enter(&drm_inst_list_lock); - plist = &drm_inst_head; - list = *plist; - while (list) { - if (list->disl_state.mis_dip == dip) { - mutex_exit(&drm_inst_list_lock); - cmn_err(CE_WARN, "%s%d already registered", - ddi_driver_name(dip), ddi_get_instance(dip)); - return (NULL); - } - plist = &list->disl_next; - list = list->disl_next; - } - - /* "dip" is not registered, create new one and add to list */ - entry = kmem_zalloc(sizeof (*entry), KM_SLEEP); - *plist = entry; - entry->disl_state.mis_dip = dip; - mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL); - mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL); - mutex_exit(&drm_inst_list_lock); +struct cb_ops drm_cb_ops = { + drm_sun_open, /* cb_open */ + drm_sun_close, /* cb_close */ + nodev, /* cb_strategy */ + nodev, /* cb_print */ + nodev, /* cb_dump */ + drm_sun_read, /* cb_read */ + nodev, /* cb_write */ + drm_sun_ioctl, /* cb_ioctl */ + drm_sun_devmap, /* cb_devmap */ + nodev, /* cb_mmap */ + NULL, /* cb_segmap */ + drm_sun_chpoll, /* cb_chpoll */ + ddi_prop_op, /* cb_prop_op */ + 0, /* cb_stream */ + D_NEW | D_MTSAFE | D_DEVMAP /* cb_flag */ +}; - return (entry); +static struct modlmisc modlmisc = { + &mod_miscops, "DRM common interfaces" +}; -} /* drm_supp_alloc_drv_entry */ +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modlmisc, NULL +}; -/* - * drm_supp_free_drv_entry() - */ -static void -drm_supp_free_drv_entry(dev_info_t *dip) +int +_init(void) { - drm_inst_list_t *list; - drm_inst_list_t **plist; - drm_inst_state_t *mstate; - - /* protect the driver list */ - mutex_enter(&drm_inst_list_lock); - plist = &drm_inst_head; - list = *plist; - while (list) { - if (list->disl_state.mis_dip == dip) { - *plist = list->disl_next; - mstate = &list->disl_state; - mutex_destroy(&mstate->mis_lock); - mutex_destroy(&mstate->dis_ctxlock); - kmem_free(list, sizeof (*list)); - mutex_exit(&drm_inst_list_lock); - return; - } - plist = &list->disl_next; - list = list->disl_next; - } - mutex_exit(&drm_inst_list_lock); + int ret; -} /* drm_supp_free_drv_entry() */ + ret = mod_install(&modlinkage); + if (ret) + return (ret); -/* - * drm_sup_devt_to_state() - * - * description: - * Get the soft state of DRM instance by device number - */ -static drm_inst_state_t * -drm_sup_devt_to_state(dev_t dev) + return (drm_core_init()); +} + +int +_fini(void) { - drm_inst_list_t *list; - drm_inst_state_t *mstate; - major_t major = getmajor(dev); - int instance = DEV2INST(dev); - - mutex_enter(&drm_inst_list_lock); - list = drm_inst_head; - while (list) { - mstate = &list->disl_state; - mutex_enter(&mstate->mis_lock); - - if ((mstate->mis_major == major) && - (ddi_get_instance(mstate->mis_dip) == instance)) { - mutex_exit(&mstate->mis_lock); - mutex_exit(&drm_inst_list_lock); - return (mstate); - } + int ret; - list = list->disl_next; - mutex_exit(&mstate->mis_lock); - } + ret = mod_remove(&modlinkage); + if (ret) + return (ret); - mutex_exit(&drm_inst_list_lock); - return (NULL); + drm_core_exit(); -} /* drm_sup_devt_to_state() */ + return (0); +} int -drm_supp_get_irq(void *handle) +_info(struct modinfo *modinfop) { - drm_inst_list_t *list; - drm_inst_state_t *mstate; - int irq; - - list = (drm_inst_list_t *)handle; - mstate = &list->disl_state; - ASSERT(mstate != NULL); - irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE); - return (irq); + return (mod_info(&modlinkage, modinfop)); } -int -drm_supp_device_capability(void *handle, int capid) +struct drm_local_map * +drm_core_findmap(struct drm_device *dev, unsigned int token) { - drm_inst_list_t *list; - drm_inst_state_t *mstate; - uint8_t cap = 0; - uint16_t caps_ptr; - - list = (drm_inst_list_t *)handle; - mstate = &list->disl_state; - ASSERT(mstate != NULL); - - /* has capabilities list ? */ - if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) & - PCI_CONF_CAP_MASK) == 0) - return (NULL); - - caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR); - while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) { - cap = pci_config_get32(mstate->mis_cfg_hdl, caps_ptr); - if ((cap & PCI_CONF_CAPID_MASK) == capid) - return (cap); - caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, - caps_ptr + PCI_CAP_NEXT_PTR); + struct drm_map_list *_entry; + + list_for_each_entry(_entry, struct drm_map_list, &dev->maplist, head) { + if (_entry->user_token == token) + return (_entry->map); } - return (0); + return (NULL); } |