summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/drm/drm_sunmod.c
diff options
context:
space:
mode:
authorcg149915 <none@none>2008-01-09 19:45:15 -0800
committercg149915 <none@none>2008-01-09 19:45:15 -0800
commitd0538f66491267879b7418b21ad78e3dcc2dcc83 (patch)
tree273cc76b66df1e78697b0647a3cfe6c5527ae273 /usr/src/uts/common/io/drm/drm_sunmod.c
parentcbd166e3c04cfcc0c8bbfef3d285e141db181017 (diff)
downloadillumos-gate-d0538f66491267879b7418b21ad78e3dcc2dcc83.tar.gz
6641254 upgrading drm module for i915 3D driver
6638035 panic in mutex_vector_exit from i915_wait_irq 6635888 panic in drm_getsareactx 6637576 panic in drm_addmap 6643083 missing interrupts in i915_driver_irq_handler() --HG-- rename : usr/src/uts/common/io/drm/create_sunos_pci_lists.sh => deleted_files/usr/src/uts/common/io/drm/create_sunos_pci_lists.sh rename : usr/src/uts/common/io/drm/drm_pciids.txt => deleted_files/usr/src/uts/common/io/drm/drm_pciids.txt rename : usr/src/uts/intel/io/drm/i915_sundrv.c => deleted_files/usr/src/uts/intel/io/drm/i915_sundrv.c
Diffstat (limited to 'usr/src/uts/common/io/drm/drm_sunmod.c')
-rw-r--r--usr/src/uts/common/io/drm/drm_sunmod.c865
1 files changed, 861 insertions, 4 deletions
diff --git a/usr/src/uts/common/io/drm/drm_sunmod.c b/usr/src/uts/common/io/drm/drm_sunmod.c
index b8c45f596a..e1298ddf95 100644
--- a/usr/src/uts/common/io/drm/drm_sunmod.c
+++ b/usr/src/uts/common/io/drm/drm_sunmod.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,7 +30,15 @@
* Common misc module interfaces of DRM under Solaris
*/
+/*
+ * This module calls into gfx and agpmaster misc modules respectively
+ * for generic graphics operations and AGP master device support.
+ */
+
+#include "drm_sunmod.h"
#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <vm/seg_kmem.h>
static struct modlmisc modlmisc = {
&mod_miscops, "DRM common interfaces %I%"
@@ -40,14 +48,70 @@ static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlmisc, NULL
};
+static drm_inst_list_t *drm_inst_head;
+static kmutex_t drm_inst_list_lock;
+
+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);
+
+/*
+ * 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 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 *);
+
+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 */
+};
+
+/*
+ * 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 */
+};
+
+
int
_init(void)
{
- int err;
+ int error;
- if ((err = mod_install(&modlinkage)) != 0)
- return (err);
+ if ((error = mod_install(&modlinkage)) != 0) {
+ return (error);
+ }
+ /* initialize the instance list lock */
+ mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
return (0);
}
@@ -59,6 +123,7 @@ _fini(void)
if ((err = mod_remove(&modlinkage)) != 0)
return (err);
+ mutex_destroy(&drm_inst_list_lock);
return (0);
}
@@ -67,3 +132,795 @@ _info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
+
+void *
+drm_supp_register(dev_info_t *dip, drm_device_t *dp)
+{
+ 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);
+ }
+ 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;
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ /* 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_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;
+ }
+
+ return ((void *)mstate);
+
+exit4:
+ if ((dp->driver->use_agp) && agpm)
+ agpmaster_detach(&agpm);
+exit3:
+ pci_config_teardown(&pci_cfg_handle);
+exit2:
+ 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);
+
+ return (NULL);
+}
+
+
+int
+drm_supp_unregister(void *handle)
+{
+ 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);
+ }
+
+ mstate->mis_devp = NULL;
+
+ /* 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);
+
+ return (DDI_SUCCESS);
+}
+
+
+/*ARGSUSED*/
+static int
+drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ drm_inst_state_t *mstate;
+ drm_device_t *dp;
+ struct minordev *mp, *newp;
+ int cloneminor;
+ minor_t minor;
+ 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);
+
+ minor = DEV2MINOR(*devp);
+ ASSERT(minor <= MAX_CLONE_MINOR);
+ if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
+ return (0);
+
+ /*
+ * From here, we start to process drm
+ */
+
+ dp = mstate->mis_devp;
+ if (!dp)
+ return (ENXIO);
+
+ /*
+ * Here, minor consists of minor_number and instance number
+ * the first 3 bits is for instance number.
+ */
+ minor = getminor(*devp);
+
+ newp = kmem_zalloc(sizeof (struct minordev), KM_SLEEP);
+ mutex_enter(&dp->dev_lock);
+ for (cloneminor = minor; cloneminor < MAX_CLONE_MINOR;
+ cloneminor += 1) {
+ for (mp = dp->minordevs; mp != NULL; mp = mp->next) {
+ if (mp->cloneminor == cloneminor) {
+ break;
+ }
+ }
+ if (mp == NULL)
+ goto gotminor;
+ }
+
+ mutex_exit(&dp->dev_lock);
+ return (EMFILE);
+
+gotminor:
+ newp->next = dp->minordevs;
+ newp->cloneminor = cloneminor;
+ dp->minordevs = newp;
+ dp->cloneopens++;
+ mutex_exit(&dp->dev_lock);
+ err = drm_open(dp, devp, flag, otyp, credp);
+ *devp = makedevice(getmajor(*devp), cloneminor);
+ return (err);
+}
+
+/*ARGSUSED*/
+static int
+drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ drm_inst_state_t *mstate;
+ drm_device_t *dp;
+ struct minordev *lastp, *mp;
+ minor_t minor;
+
+ mstate = drm_sup_devt_to_state(dev);
+ if (mstate == NULL)
+ return (EBADF);
+
+ minor = DEV2MINOR(dev);
+ ASSERT(minor <= MAX_CLONE_MINOR);
+ if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
+ return (0);
+
+ dp = mstate->mis_devp;
+ if (dp == NULL) {
+ DRM_ERROR("drm_sun_close: NULL soft state");
+ return (ENXIO);
+ }
+
+ lastp = NULL;
+ mutex_enter(&dp->dev_lock);
+ for (mp = dp->minordevs; mp != NULL; mp = mp->next) {
+ if (mp->cloneminor == minor) {
+ if (lastp == NULL)
+ dp->minordevs = mp->next;
+ else
+ lastp->next = mp->next;
+ dp->cloneopens--;
+ (void) kmem_free(mp, sizeof (struct minordev));
+ break;
+ } else
+ lastp = mp;
+ }
+ mutex_exit(&dp->dev_lock);
+
+ return (drm_close(dp, dev, flag, otyp, credp));
+}
+
+/*ARGSUSED*/
+static int
+drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
+ cred_t *credp, int *rvalp)
+{
+ extern drm_ioctl_desc_t drm_ioctls[];
+
+ 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;
+
+ if (cmd == VIS_GETIDENTIFIER) {
+ if (ddi_copyout(&text_ident, (void *)arg,
+ sizeof (struct vis_identifier), 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);
+
+ retval = func(dp, arg, fpriv, mode);
+
+ return (retval);
+}
+
+/*ARGSUSED*/
+static int
+drm_sun_devmap(dev_t dev, 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;
+ 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,
+ };
+
+ 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:
+ 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);
+ }
+
+ /*
+ * 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;
+ mutex_enter(&dp->dev_lock);
+ 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;
+ }
+ }
+
+ 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);
+ }
+ if (map->flags & _DRM_RESTRICTED) {
+ mutex_exit(&dp->dev_lock);
+ cmn_err(CE_WARN, "restricted map\n");
+ return (-1);
+ }
+
+ 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, &regoff);
+ 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);
+ }
+
+ 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);
+
+ 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;
+
+ 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;
+
+ default:
+ return (DDI_FAILURE);
+ }
+ return (DDI_SUCCESS);
+
+}
+
+/*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)
+{
+ devmap_handle_t *dhp;
+ drm_inst_state_t *statep;
+ struct ddi_umem_cookie *cp;
+
+ statep = drm_sup_devt_to_state(dev);
+ ASSERT(statep != NULL);
+
+ /*
+ * This driver only supports MAP_SHARED,
+ * and doesn't support MAP_PRIVATE
+ */
+ if (flags & MAP_PRIVATE) {
+ cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
+ return (EINVAL);
+ }
+
+ 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;
+
+ 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)
+{
+ devmap_handle_t *dhp;
+ devmap_handle_t *ndhp;
+ drm_inst_state_t *statep;
+ struct ddi_umem_cookie *cp;
+ struct ddi_umem_cookie *ncp;
+
+ dhp = (devmap_handle_t *)dhc;
+ statep = (drm_inst_state_t *)pvtp;
+
+ 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);
+}
+
+
+/*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;
+
+ 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;
+
+ 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
+ */
+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);
+
+ return (entry);
+
+} /* drm_supp_alloc_drv_entry */
+
+/*
+ * drm_supp_free_drv_entry()
+ */
+static void
+drm_supp_free_drv_entry(dev_info_t *dip)
+{
+ 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);
+
+} /* drm_supp_free_drv_entry() */
+
+/*
+ * 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)
+{
+ 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);
+ }
+
+ list = list->disl_next;
+ mutex_exit(&mstate->mis_lock);
+ }
+
+ mutex_exit(&drm_inst_list_lock);
+ return (NULL);
+
+} /* drm_sup_devt_to_state() */
+
+int
+drm_supp_get_irq(void *handle)
+{
+ 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);
+}
+
+int
+drm_supp_device_capability(void *handle, int capid)
+{
+ 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);
+ }
+
+ return (0);
+}