60405de4d8688d96dd05157c28db3ade5c9bc234kz * CDDL HEADER START
60405de4d8688d96dd05157c28db3ade5c9bc234kz * The contents of this file are subject to the terms of the
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Common Development and Distribution License (the "License").
60405de4d8688d96dd05157c28db3ade5c9bc234kz * You may not use this file except in compliance with the License.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
60405de4d8688d96dd05157c28db3ade5c9bc234kz * See the License for the specific language governing permissions
60405de4d8688d96dd05157c28db3ade5c9bc234kz * and limitations under the License.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * When distributing Covered Code, include this CDDL HEADER in each
60405de4d8688d96dd05157c28db3ade5c9bc234kz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * If applicable, add the following below this CDDL HEADER, with the
60405de4d8688d96dd05157c28db3ade5c9bc234kz * fields enclosed by brackets "[]" replaced with your own identifying
60405de4d8688d96dd05157c28db3ade5c9bc234kz * information: Portions Copyright [yyyy] [name of copyright owner]
60405de4d8688d96dd05157c28db3ade5c9bc234kz * CDDL HEADER END
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Use is subject to license terms.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Common misc module interfaces of DRM under Solaris
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * This module calls into gfx and agpmaster misc modules respectively
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * for generic graphics operations and AGP master device support.
d0538f66491267879b7418b21ad78e3dcc2dcc83cgstatic int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
d0538f66491267879b7418b21ad78e3dcc2dcc83cgstatic int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * devmap callbacks for AGP and PCI GART
d0538f66491267879b7418b21ad78e3dcc2dcc83cg offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **);
d0538f66491267879b7418b21ad78e3dcc2dcc83cgstatic drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *);
d0538f66491267879b7418b21ad78e3dcc2dcc83cgstatic struct devmap_callback_ctl drm_devmap_callbacks = {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * Common device operations structure for all DRM drivers
d0538f66491267879b7418b21ad78e3dcc2dcc83cg 0, /* cb_stream */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* initialize the instance list lock */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (0);
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (0);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg cmn_err(CE_WARN, "drm_supp_register: failed to get softstate");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * DRM drivers are required to use common cb_ops
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* Generic graphics initialization */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* create a minor node for common graphics ops */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg "failed to create minor node for gfx");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* setup mapping for later PCI config space access */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg "PCI configuration space setup failed");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* AGP master attach */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg "AGP master support not available");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* create minor node for DRM access */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg DRM_ERROR("supp_regiter: faled to create minor node for drm");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return ((void *)mstate);
c1374a13e412c4ec42cba867e57347a0e049a822Surya Prakki (void) gfxp_vgatext_detach(dip, DDI_DETACH, gfxp);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* AGP master detach */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* free PCI config access handle */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* graphics misc module detach */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* remove all minor nodes */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cgdrm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * return ENXIO for deferred attach so that system can
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * attach us again.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * The lest significant 15 bits are used for minor_number, and
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * the mid 3 bits are used for instance number. All minor numbers
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * are used as follows:
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * 0 -- gfx
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * 1 -- agpmaster
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * 2 -- drm
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * (3, MAX_CLONE_MINOR) -- drm minor node for clone open.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * No operations for VGA & AGP mater devices, always return OK.
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (0);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * From here, we start to process drm
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * Drm driver implements a software lock to serialize access
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * to graphics hardware based on per-process granulation. Before
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * operating graphics hardware, all clients, including kernel
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * and applications, must acquire this lock via DRM_IOCTL_LOCK
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * ioctl, and release it via DRM_IOCTL_UNLOCK after finishing
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * operations. Drm driver will grant r/w permission to the
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * process which acquires this lock (Kernel is assumed to have
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * process ID 0).
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * A process might be terminated without releasing drm lock, in
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * this case, drm driver is responsible for clearing the holding.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * To be informed of process exiting, drm driver uses clone open
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * to guarantee that each call to open(9e) have one corresponding
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * call to close(9e). In most cases, a process will close drm
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * during process termination, so that drm driver could have a
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * chance to release drm lock.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * In fact, a driver cannot know exactly when a process exits.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * Clone open doesn't address this issue completely: Because of
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * inheritance, child processes inherit file descriptors from
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * their parent. As a result, if the parent exits before its
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * children, drm close(9e) entrypoint won't be called until all
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * of its children terminate.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * Another issue brought up by inhertance is the process PID
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * that calls the drm close() entry point may not be the same
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * as the one who called open(). Per-process struct is allocated
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * when a process first open() drm, and released when the process
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * last close() drm. Since open()/close() may be not the same
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * process, PID cannot be used for key to lookup per-process
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * struct. So, we associate minor number with per-process struct
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * during open()'ing, and find corresponding process struct
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg * via minor number when close() is called.
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg for (newminor = DRM_MIN_CLONEMINOR; newminor < MAX_CLONE_MINOR;
194eb4bb9c059fd0abdb05ffbd39c96998f77443tao chen - Sun Microsystems - Beijing China (void) kmem_free(newp, sizeof (drm_cminor_t));
194eb4bb9c059fd0abdb05ffbd39c96998f77443tao chen - Sun Microsystems - Beijing China (void) kmem_free(newp, sizeof (drm_cminor_t));
fca314aae8ba1403ba891f2b0e7a172bcdc055c8cg /* return a clone minor */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cgdrm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (0);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cg switch (minor) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg default: /* DRM cloning minor nodes */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* It's not a core DRM ioctl, try driver-specific. */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* The array entries begin at DRM_COMMAND_BASE ioctl nr */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) ||
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China fpriv->dev = dev;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China fpriv->credp = credp;
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cgdrm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China drm_local_map_t *map = NULL;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China static ddi_device_acc_attr_t gem_dev_attr = {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China DDI_DEVICE_ATTR_V0,
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China DDI_NEVERSWAP_ACC,
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China DDI_MERGING_OK_ACC
d0538f66491267879b7418b21ad78e3dcc2dcc83cg switch (minor) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* DRM cloning nodes */
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China if (dp->driver->use_gem == 1) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China struct idr_list *entry;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China drm_cminor_t *mp;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China mp = drm_find_file_by_minor(dp, minor);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China mutex_exit(&dp->dev_lock);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China DRM_ERROR("drm_sun_devmap: can't find authenticator");
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China return (EACCES);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China spin_lock(&dp->struct_mutex);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China idr_list_for_each(entry, &(mp->fpriv->object_idr)) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China if ((uintptr_t)entry->obj == (u_offset_t)offset) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China map = entry->obj->map;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China spin_unlock(&dp->struct_mutex);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China * We will solve 32-bit application on 64-bit kernel
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China * issue later, now, we just use low 32-bit
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China handle = (u_offset_t)offset;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China handle &= 0xffffffff;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China ((u_offset_t)((uintptr_t)map->handle) & 0xffffffff))
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China * Temporarily, because offset is phys_addr for register
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China * and framebuffer, is kernel virtual_addr for others
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China * Maybe we will use hash table to solve this issue later.
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China if (map == NULL) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China TAILQ_FOREACH(map, &dp->maplist, link) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China if (handle == (map->offset & 0xffffffff))
d0538f66491267879b7418b21ad78e3dcc2dcc83cg cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n",
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (-1);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (-1);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if (regno < 0) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if (ret != 0) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg " handle=0x%x, offset=0x%llx, len=0x%x",
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if (ret != 0) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg "memory before AGP support is enabled");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) {
d0538f66491267879b7418b21ad78e3dcc2dcc83cg koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual;
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if (ret != 0) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China if (map->drm_umem_cookie == NULL)
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China return (EINVAL);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China if (gfxp_devmap_umem_setup(dhp, dp->dip,
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China NULL, map->drm_umem_cookie, 0, map->size, PROT_ALL,
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP,
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China &gem_dev_attr)) {
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China return (DDI_FAILURE);
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China *maplen = map->size;
0035d21c77a24d02faf34c10aabc120ca692efb5miao chen - Sun Microsystems - Beijing China return (DDI_SUCCESS);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cgdrm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * This driver only supports MAP_SHARED,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * and doesn't support MAP_PRIVATE
d0538f66491267879b7418b21ad78e3dcc2dcc83cg cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (0);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cgstatic void
d0538f66491267879b7418b21ad78e3dcc2dcc83cgdrm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg/*ARGSUSED*/
d0538f66491267879b7418b21ad78e3dcc2dcc83cgdrm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (0);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * drm_supp_alloc_drv_entry()
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * Description:
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * Create a DRM entry and add it into the instance list (drm_inst_head).
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * Note that we don't allow a duplicated entry
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* protect the driver list */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* "dip" is not registered, create new one and add to list */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg} /* drm_supp_alloc_drv_entry */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * drm_supp_free_drv_entry()
d0538f66491267879b7418b21ad78e3dcc2dcc83cgstatic void
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* protect the driver list */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg} /* drm_supp_free_drv_entry() */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * drm_sup_devt_to_state()
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * description:
d0538f66491267879b7418b21ad78e3dcc2dcc83cg * Get the soft state of DRM instance by device number
d0538f66491267879b7418b21ad78e3dcc2dcc83cg} /* drm_sup_devt_to_state() */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg /* has capabilities list ? */
d0538f66491267879b7418b21ad78e3dcc2dcc83cg if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) &
d0538f66491267879b7418b21ad78e3dcc2dcc83cg caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR);
d0538f66491267879b7418b21ad78e3dcc2dcc83cg return (0);