1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Common misc module interfaces of DRM under Solaris
  29  */
  30 
  31 /*
  32  * This module calls into gfx and agpmaster misc modules respectively
  33  * for generic graphics operations and AGP master device support.
  34  */
  35 
  36 #include "drm_sunmod.h"
  37 #include <sys/modctl.h>
  38 #include <sys/kmem.h>
  39 #include <vm/seg_kmem.h>
  40 
  41 static struct modlmisc modlmisc = {
  42         &mod_miscops, "DRM common interfaces"
  43 };
  44 
  45 static struct modlinkage modlinkage = {
  46         MODREV_1, (void *)&modlmisc, NULL
  47 };
  48 
  49 static drm_inst_list_t  *drm_inst_head;
  50 static kmutex_t drm_inst_list_lock;
  51 
  52 static int drm_sun_open(dev_t *, int, int, cred_t *);
  53 static int drm_sun_close(dev_t, int, int, cred_t *);
  54 static int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  55 static int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
  56     size_t *, uint_t);
  57 
  58 /*
  59  * devmap callbacks for AGP and PCI GART
  60  */
  61 static int drm_devmap_map(devmap_cookie_t, dev_t,
  62     uint_t, offset_t, size_t, void **);
  63 static int drm_devmap_dup(devmap_cookie_t, void *,
  64     devmap_cookie_t, void **);
  65 static void drm_devmap_unmap(devmap_cookie_t, void *,
  66     offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **);
  67 
  68 static drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *);
  69 static drm_inst_state_t *drm_sup_devt_to_state(dev_t);
  70 static void drm_supp_free_drv_entry(dev_info_t *);
  71 
  72 static struct devmap_callback_ctl drm_devmap_callbacks = {
  73                 DEVMAP_OPS_REV,                 /* devmap_rev */
  74                 drm_devmap_map,                         /* devmap_map */
  75                 NULL,                   /* devmap_access */
  76                 drm_devmap_dup,                 /* devmap_dup */
  77                 drm_devmap_unmap                /* devmap_unmap */
  78 };
  79 
  80 /*
  81  * Common device operations structure for all DRM drivers
  82  */
  83 struct cb_ops drm_cb_ops = {
  84         drm_sun_open,                   /* cb_open */
  85         drm_sun_close,                  /* cb_close */
  86         nodev,                                  /* cb_strategy */
  87         nodev,                                  /* cb_print */
  88         nodev,                                  /* cb_dump */
  89         nodev,                                  /* cb_read */
  90         nodev,                                  /* cb_write */
  91         drm_sun_ioctl,          /* cb_ioctl */
  92         drm_sun_devmap,         /* cb_devmap */
  93         nodev,                                  /* cb_mmap */
  94         NULL,                   /* cb_segmap */
  95         nochpoll,                               /* cb_chpoll */
  96         ddi_prop_op,            /* cb_prop_op */
  97         0,                                      /* cb_stream */
  98         D_NEW | D_MTSAFE |D_DEVMAP      /* cb_flag */
  99 };
 100 
 101 int
 102 _init(void)
 103 {
 104         int     error;
 105 
 106         if ((error = mod_install(&modlinkage)) != 0) {
 107                 return (error);
 108         }
 109 
 110         /* initialize the instance list lock */
 111         mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
 112         return (0);
 113 }
 114 
 115 int
 116 _fini(void)
 117 {
 118         int     err;
 119 
 120         if ((err = mod_remove(&modlinkage)) != 0)
 121                 return (err);
 122 
 123         mutex_destroy(&drm_inst_list_lock);
 124         return (0);
 125 }
 126 
 127 int
 128 _info(struct modinfo *modinfop)
 129 {
 130         return (mod_info(&modlinkage, modinfop));
 131 }
 132 
 133 void *
 134 drm_supp_register(dev_info_t *dip, drm_device_t *dp)
 135 {
 136         int             error;
 137         char    buf[80];
 138         int             instance = ddi_get_instance(dip);
 139         ddi_acc_handle_t        pci_cfg_handle;
 140         agp_master_softc_t      *agpm;
 141         drm_inst_state_t        *mstate;
 142         drm_inst_list_t         *entry;
 143         gfxp_vgatext_softc_ptr_t gfxp;
 144         struct dev_ops  *devop;
 145 
 146         ASSERT(dip != NULL);
 147 
 148         entry = drm_supp_alloc_drv_entry(dip);
 149         if (entry == NULL) {
 150                 cmn_err(CE_WARN, "drm_supp_register: failed to get softstate");
 151                 return (NULL);
 152         }
 153         mstate = &entry->disl_state;
 154 
 155         /*
 156          * DRM drivers are required to use common cb_ops
 157          */
 158         devop = ddi_get_driver(dip);
 159         if (devop->devo_cb_ops != &drm_cb_ops) {
 160                 devop->devo_cb_ops = &drm_cb_ops;
 161         }
 162 
 163         /* Generic graphics initialization */
 164         gfxp = gfxp_vgatext_softc_alloc();
 165         error = gfxp_vgatext_attach(dip, DDI_ATTACH, gfxp);
 166         if (error != DDI_SUCCESS) {
 167                 DRM_ERROR("drm_supp_regiter: failed to init gfx");
 168                 goto exit1;
 169         }
 170 
 171         /* create a minor node for common graphics ops */
 172         (void) sprintf(buf, "%s%d", GFX_NAME, instance);
 173         error = ddi_create_minor_node(dip, buf, S_IFCHR,
 174             INST2NODE0(instance), DDI_NT_DISPLAY, NULL);
 175         if (error != DDI_SUCCESS) {
 176                 DRM_ERROR("drm_supp_regiter: "
 177                     "failed to create minor node for gfx");
 178                 goto exit2;
 179         }
 180 
 181         /* setup mapping for later PCI config space access */
 182         error = pci_config_setup(dip, &pci_cfg_handle);
 183         if (error != DDI_SUCCESS) {
 184                 DRM_ERROR("drm_supp_regiter: "
 185                     "PCI configuration space setup failed");
 186                 goto exit2;
 187         }
 188 
 189         /* AGP master attach */
 190         agpm = NULL;
 191         if (dp->driver->use_agp) {
 192                 DRM_DEBUG("drm_supp_regiter: driver use AGP\n");
 193                 error = agpmaster_attach(dip, &agpm,
 194                     pci_cfg_handle, INST2NODE1(instance));
 195                 if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) {
 196                         DRM_ERROR("drm_supp_regiter: "
 197                             "AGP master support not available");
 198                         goto exit3;
 199                 }
 200         }
 201 
 202         mutex_enter(&mstate->mis_lock);
 203         mstate->mis_major = ddi_driver_major(dip);
 204         mstate->mis_dip = dip;
 205         mstate->mis_gfxp = gfxp;
 206         mstate->mis_agpm = agpm;
 207         mstate->mis_cfg_hdl = pci_cfg_handle;
 208         mstate->mis_devp = dp;
 209         mutex_exit(&mstate->mis_lock);
 210 
 211         /* create minor node for DRM access */
 212         (void) sprintf(buf, "%s%d", DRM_DEVNODE, instance);
 213         if (ddi_create_minor_node(dip, buf, S_IFCHR,
 214             INST2NODE2(instance), DDI_NT_DISPLAY_DRM, 0)) {
 215                 DRM_ERROR("supp_regiter: faled to create minor node for drm");
 216                 goto exit4;
 217         }
 218 
 219         return ((void *)mstate);
 220 
 221 exit4:
 222         if ((dp->driver->use_agp) && agpm)
 223                 agpmaster_detach(&agpm);
 224 exit3:
 225         pci_config_teardown(&pci_cfg_handle);
 226 exit2:
 227         (void) gfxp_vgatext_detach(dip, DDI_DETACH, gfxp);
 228 exit1:
 229         gfxp_vgatext_softc_free(gfxp);
 230         drm_supp_free_drv_entry(dip);
 231         ddi_remove_minor_node(dip, NULL);
 232 
 233         return (NULL);
 234 }
 235 
 236 
 237 int
 238 drm_supp_unregister(void *handle)
 239 {
 240         drm_inst_list_t         *list;
 241         drm_inst_state_t        *mstate;
 242 
 243         list = (drm_inst_list_t *)handle;
 244         mstate = &list->disl_state;
 245         mutex_enter(&mstate->mis_lock);
 246 
 247         /* AGP master detach */
 248         if (mstate->mis_agpm != NULL)
 249                 agpmaster_detach(&mstate->mis_agpm);
 250 
 251         /* free PCI config access handle */
 252         if (mstate->mis_cfg_hdl)
 253                 pci_config_teardown(&mstate->mis_cfg_hdl);
 254 
 255         /* graphics misc module detach */
 256         if (mstate->mis_gfxp) {
 257                 (void) gfxp_vgatext_detach(mstate->mis_dip, DDI_DETACH,
 258                     mstate->mis_gfxp);
 259                 gfxp_vgatext_softc_free(mstate->mis_gfxp);
 260         }
 261 
 262         mstate->mis_devp = NULL;
 263 
 264         /* remove all minor nodes */
 265         ddi_remove_minor_node(mstate->mis_dip, NULL);
 266         mutex_exit(&mstate->mis_lock);
 267         drm_supp_free_drv_entry(mstate->mis_dip);
 268 
 269         return (DDI_SUCCESS);
 270 }
 271 
 272 
 273 /*ARGSUSED*/
 274 static int
 275 drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
 276 {
 277         drm_inst_state_t        *mstate;
 278         drm_cminor_t    *mp, *newp;
 279         drm_device_t    *dp;
 280         minor_t         minor;
 281         int             newminor;
 282         int             instance;
 283         int             err;
 284 
 285         mstate = drm_sup_devt_to_state(*devp);
 286         /*
 287          * return ENXIO for deferred attach so that system can
 288          * attach us again.
 289          */
 290         if (mstate == NULL)
 291                 return (ENXIO);
 292 
 293         /*
 294          * The lest significant 15 bits are used for minor_number, and
 295          * the mid 3 bits are used for instance number. All minor numbers
 296          * are used as follows:
 297          * 0 -- gfx
 298          * 1 -- agpmaster
 299          * 2 -- drm
 300          * (3, MAX_CLONE_MINOR) -- drm minor node for clone open.
 301          */
 302         minor = DEV2MINOR(*devp);
 303         instance = DEV2INST(*devp);
 304         ASSERT(minor <= MAX_CLONE_MINOR);
 305 
 306         /*
 307          * No operations for VGA & AGP mater devices, always return OK.
 308          */
 309         if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
 310                 return (0);
 311 
 312         /*
 313          * From here, we start to process drm
 314          */
 315 
 316         dp = mstate->mis_devp;
 317         if (!dp)
 318                 return (ENXIO);
 319 
 320         /*
 321          * Drm driver implements a software lock to serialize access
 322          * to graphics hardware based on per-process granulation. Before
 323          * operating graphics hardware, all clients, including kernel
 324          * and applications, must acquire this lock via DRM_IOCTL_LOCK
 325          * ioctl, and release it via DRM_IOCTL_UNLOCK after finishing
 326          * operations. Drm driver will grant r/w permission to the
 327          * process which acquires this lock (Kernel is assumed to have
 328          * process ID 0).
 329          *
 330          * A process might be terminated without releasing drm lock, in
 331          * this case, drm driver is responsible for clearing the holding.
 332          * To be informed of process exiting, drm driver uses clone open
 333          * to guarantee that each call to open(9e) have one corresponding
 334          * call to close(9e). In most cases, a process will close drm
 335          * during process termination, so that drm driver could have a
 336          * chance to release drm lock.
 337          *
 338          * In fact, a driver cannot know exactly when a process exits.
 339          * Clone open doesn't address this issue completely: Because of
 340          * inheritance, child processes inherit file descriptors from
 341          * their parent. As a result, if the parent exits before its
 342          * children, drm close(9e) entrypoint won't be called until all
 343          * of its children terminate.
 344          *
 345          * Another issue brought up by inhertance is the process PID
 346          * that calls the drm close() entry point may not be the same
 347          * as the one who called open(). Per-process struct is allocated
 348          * when a process first open() drm, and released when the process
 349          * last close() drm. Since open()/close() may be not the same
 350          * process, PID cannot be used for key to lookup per-process
 351          * struct. So, we associate minor number with per-process struct
 352          * during open()'ing, and find corresponding process struct
 353          * via minor number when close() is called.
 354          */
 355         newp = kmem_zalloc(sizeof (drm_cminor_t), KM_SLEEP);
 356         mutex_enter(&dp->dev_lock);
 357         for (newminor = DRM_MIN_CLONEMINOR; newminor < MAX_CLONE_MINOR;
 358             newminor ++) {
 359                 TAILQ_FOREACH(mp, &dp->minordevs, link) {
 360                         if (mp->minor == newminor)
 361                                 break;
 362                 }
 363                 if (mp == NULL)
 364                         goto gotminor;
 365         }
 366 
 367         mutex_exit(&dp->dev_lock);
 368         (void) kmem_free(newp, sizeof (drm_cminor_t));
 369         return (EMFILE);
 370 
 371 gotminor:
 372         TAILQ_INSERT_TAIL(&dp->minordevs, newp, link);
 373         newp->minor = newminor;
 374         mutex_exit(&dp->dev_lock);
 375         err = drm_open(dp, newp, flag, otyp, credp);
 376         if (err) {
 377                 mutex_enter(&dp->dev_lock);
 378                 TAILQ_REMOVE(&dp->minordevs, newp, link);
 379                 (void) kmem_free(newp, sizeof (drm_cminor_t));
 380                 mutex_exit(&dp->dev_lock);
 381 
 382                 return (err);
 383         }
 384 
 385         /* return a clone minor */
 386         newminor = newminor | (instance << NBITSMNODE);
 387         *devp = makedevice(getmajor(*devp), newminor);
 388         return (err);
 389 }
 390 
 391 /*ARGSUSED*/
 392 static int
 393 drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
 394 {
 395         drm_inst_state_t        *mstate;
 396         drm_device_t            *dp;
 397         minor_t         minor;
 398         int             ret;
 399 
 400         mstate = drm_sup_devt_to_state(dev);
 401         if (mstate == NULL)
 402                 return (EBADF);
 403 
 404         minor = DEV2MINOR(dev);
 405         ASSERT(minor <= MAX_CLONE_MINOR);
 406         if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
 407                 return (0);
 408 
 409         dp = mstate->mis_devp;
 410         if (dp == NULL) {
 411                 DRM_ERROR("drm_sun_close: NULL soft state");
 412                 return (ENXIO);
 413         }
 414 
 415         ret = drm_close(dp, minor, flag, otyp, credp);
 416 
 417         return (ret);
 418 }
 419 
 420 /*ARGSUSED*/
 421 static int
 422 drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 423     cred_t *credp, int *rvalp)
 424 {
 425         extern drm_ioctl_desc_t drm_ioctls[];
 426 
 427         drm_inst_state_t        *mstate;
 428         drm_device_t            *dp;
 429         drm_ioctl_desc_t        *ioctl;
 430         drm_ioctl_t             *func;
 431         drm_file_t              *fpriv;
 432         minor_t         minor;
 433         int             retval;
 434         int             nr;
 435 
 436         if (cmd == VIS_GETIDENTIFIER) {
 437                 if (ddi_copyout(&text_ident, (void *)arg,
 438                     sizeof (struct vis_identifier), mode))
 439                         return (EFAULT);
 440         }
 441 
 442         mstate = drm_sup_devt_to_state(dev);
 443         if (mstate == NULL) {
 444                 return (EIO);
 445         }
 446 
 447         minor = DEV2MINOR(dev);
 448         ASSERT(minor <= MAX_CLONE_MINOR);
 449         switch (minor) {
 450         case GFX_MINOR:
 451                 retval = gfxp_vgatext_ioctl(dev, cmd, arg,
 452                     mode, credp, rvalp, mstate->mis_gfxp);
 453                 return (retval);
 454 
 455         case AGPMASTER_MINOR:
 456                 retval = agpmaster_ioctl(dev, cmd, arg, mode,
 457                     credp, rvalp, mstate->mis_agpm);
 458                 return (retval);
 459 
 460         case DRM_MINOR:
 461         default:        /* DRM cloning minor nodes */
 462                 break;
 463         }
 464 
 465         dp = mstate->mis_devp;
 466         ASSERT(dp != NULL);
 467 
 468         nr = DRM_IOCTL_NR(cmd);
 469         ioctl = &drm_ioctls[nr];
 470         atomic_inc_32(&dp->counts[_DRM_STAT_IOCTLS]);
 471 
 472         /* It's not a core DRM ioctl, try driver-specific. */
 473         if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
 474                 /* The array entries begin at DRM_COMMAND_BASE ioctl nr */
 475                 nr -= DRM_COMMAND_BASE;
 476                 if (nr > dp->driver->max_driver_ioctl) {
 477                         DRM_ERROR("Bad driver ioctl number, 0x%x (of 0x%x)",
 478                             nr, dp->driver->max_driver_ioctl);
 479                         return (EINVAL);
 480                 }
 481                 ioctl = &dp->driver->driver_ioctls[nr];
 482         }
 483 
 484         func = ioctl->func;
 485         if (func == NULL) {
 486                 return (ENOTSUP);
 487         }
 488 
 489         mutex_enter(&dp->dev_lock);
 490         fpriv = drm_find_file_by_proc(dp, credp);
 491         mutex_exit(&dp->dev_lock);
 492         if (fpriv == NULL) {
 493                 DRM_ERROR("drm_sun_ioctl : can't find authenticator");
 494                 return (EACCES);
 495         }
 496 
 497         if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) ||
 498             ((ioctl->flags & DRM_AUTH) && !fpriv->authenticated) ||
 499             ((ioctl->flags & DRM_MASTER) && !fpriv->master))
 500                 return (EACCES);
 501 
 502         fpriv->dev = dev;
 503         fpriv->credp = credp;
 504 
 505         retval = func(dp, arg, fpriv, mode);
 506 
 507         return (retval);
 508 }
 509 
 510 /*ARGSUSED*/
 511 static int
 512 drm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset,
 513     size_t len, size_t *maplen, uint_t model)
 514 {
 515         extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
 516 
 517         drm_inst_state_t        *mstate;
 518         drm_device_t            *dp;
 519         ddi_umem_cookie_t       cookie;
 520         drm_local_map_t         *map = NULL;
 521         unsigned long   aperbase;
 522         u_offset_t              handle;
 523         offset_t                koff;
 524         caddr_t                 kva;
 525         minor_t                 minor;
 526         size_t                  length;
 527         int                     ret;
 528 
 529         static ddi_device_acc_attr_t dev_attr = {
 530                 DDI_DEVICE_ATTR_V0,
 531                 DDI_NEVERSWAP_ACC,
 532                 DDI_STRICTORDER_ACC,
 533         };
 534         static ddi_device_acc_attr_t gem_dev_attr = {
 535                 DDI_DEVICE_ATTR_V0,
 536                 DDI_NEVERSWAP_ACC,
 537                 DDI_MERGING_OK_ACC
 538         };
 539 
 540         mstate = drm_sup_devt_to_state(dev);
 541         if (mstate == NULL)
 542                 return (ENXIO);
 543 
 544         minor = DEV2MINOR(dev);
 545         switch (minor) {
 546         case GFX_MINOR:
 547                 ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model,
 548                     mstate->mis_gfxp);
 549                 return (ret);
 550 
 551         case AGPMASTER_MINOR:
 552                 return (ENOTSUP);
 553 
 554         case DRM_MINOR:
 555                 break;
 556 
 557         default:
 558                 /* DRM cloning nodes */
 559                 if (minor > MAX_CLONE_MINOR)
 560                         return (EBADF);
 561                 break;
 562         }
 563 
 564 
 565         dp = mstate->mis_devp;
 566         if (dp == NULL) {
 567                 DRM_ERROR("drm_sun_devmap: NULL soft state");
 568                 return (EINVAL);
 569         }
 570 
 571         mutex_enter(&dp->dev_lock);
 572 
 573         if (dp->driver->use_gem == 1) {
 574                 struct idr_list *entry;
 575                 drm_cminor_t *mp;
 576 
 577                 mp = drm_find_file_by_minor(dp, minor);
 578                 if (!mp) {
 579                         mutex_exit(&dp->dev_lock);
 580                         DRM_ERROR("drm_sun_devmap: can't find authenticator");
 581                         return (EACCES);
 582                 }
 583 
 584                 spin_lock(&dp->struct_mutex);
 585                 idr_list_for_each(entry, &(mp->fpriv->object_idr)) {
 586                         if ((uintptr_t)entry->obj == (u_offset_t)offset) {
 587                                 map = entry->obj->map;
 588                                 goto goon;
 589                         }
 590                 }
 591 goon:
 592                 spin_unlock(&dp->struct_mutex);
 593         }
 594 
 595         if (map == NULL) {
 596                 /*
 597                  * We will solve 32-bit application on 64-bit kernel
 598                  * issue later, now, we just use low 32-bit
 599                  */
 600                 handle = (u_offset_t)offset;
 601                 handle &= 0xffffffff;
 602 
 603                 TAILQ_FOREACH(map, &dp->maplist, link) {
 604                         if (handle ==
 605                             ((u_offset_t)((uintptr_t)map->handle) & 0xffffffff))
 606                                 break;
 607                 }
 608 
 609                 /*
 610                  * Temporarily, because offset is phys_addr for register
 611                  * and framebuffer, is kernel virtual_addr for others
 612                  * Maybe we will use hash table to solve this issue later.
 613                  */
 614                 if (map == NULL) {
 615                         TAILQ_FOREACH(map, &dp->maplist, link) {
 616                                 if (handle == (map->offset & 0xffffffff))
 617                                         break;
 618                         }
 619                 }
 620         }
 621 
 622         if (map == NULL) {
 623                 u_offset_t      tmp;
 624 
 625                 mutex_exit(&dp->dev_lock);
 626                 cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n",
 627                     offset, (int)len);
 628                 cmn_err(CE_WARN, "Current mapping:\n");
 629                 TAILQ_FOREACH(map, &dp->maplist, link) {
 630                 tmp = (u_offset_t)((uintptr_t)map->handle) & 0xffffffff;
 631                 cmn_err(CE_WARN, "map(handle=0x%p, size=0x%lx,type=%d,"
 632                     "offset=0x%lx), handle=%llx, tmp=%lld", map->handle,
 633                     map->size, map->type, map->offset, handle, tmp);
 634                 }
 635                 return (-1);
 636         }
 637         if (map->flags & _DRM_RESTRICTED) {
 638                 mutex_exit(&dp->dev_lock);
 639                 cmn_err(CE_WARN, "restricted map\n");
 640                 return (-1);
 641         }
 642 
 643         mutex_exit(&dp->dev_lock);
 644         switch (map->type) {
 645         case _DRM_FRAME_BUFFER:
 646         case _DRM_REGISTERS:
 647                 {
 648                         int     regno;
 649                         off_t   regoff;
 650 
 651                         regno = drm_get_pci_index_reg(dp->dip,
 652                             map->offset, (uint_t)len, &regoff);
 653                         if (regno < 0) {
 654                                 DRM_ERROR("devmap: failed to get register"
 655                                     " offset=0x%llx, len=0x%x", handle, len);
 656                                 return (EINVAL);
 657                         }
 658 
 659                         ret = devmap_devmem_setup(dhp, dp->dip, NULL,
 660                             regno, (offset_t)regoff, len, PROT_ALL,
 661                             0, &dev_attr);
 662                         if (ret != 0) {
 663                                 *maplen = 0;
 664                                 DRM_ERROR("devmap: failed, regno=%d,type=%d,"
 665                                     " handle=0x%x, offset=0x%llx, len=0x%x",
 666                                     regno, map->type, handle, offset, len);
 667                                 return (ret);
 668                         }
 669                         *maplen = len;
 670                         return (ret);
 671                 }
 672 
 673         case _DRM_SHM:
 674                 if (map->drm_umem_cookie == NULL)
 675                         return (EINVAL);
 676                 length = ptob(btopr(map->size));
 677                 ret = devmap_umem_setup(dhp, dp->dip, NULL,
 678                     map->drm_umem_cookie, 0, length,
 679                     PROT_ALL, IOMEM_DATA_CACHED, NULL);
 680                 if (ret != 0) {
 681                         *maplen = 0;
 682                         return (ret);
 683                 }
 684                 *maplen = length;
 685 
 686                 return (DDI_SUCCESS);
 687 
 688         case _DRM_AGP:
 689                 if (dp->agp == NULL) {
 690                         cmn_err(CE_WARN, "drm_sun_devmap: attempted to mmap AGP"
 691                             "memory before AGP support is enabled");
 692                         return (DDI_FAILURE);
 693                 }
 694 
 695                 aperbase = dp->agp->base;
 696                 koff = map->offset - aperbase;
 697                 length = ptob(btopr(len));
 698                 kva = map->dev_addr;
 699                 cookie = gfxp_umem_cookie_init(kva, length);
 700                 if (cookie == NULL) {
 701                         cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
 702                         return (DDI_FAILURE);
 703                 }
 704 
 705                 if ((ret = devmap_umem_setup(dhp, dp->dip,
 706                     &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
 707                     IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) {
 708                         gfxp_umem_cookie_destroy(cookie);
 709                         cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
 710                         return (DDI_FAILURE);
 711                 }
 712                 *maplen = length;
 713                 break;
 714 
 715         case _DRM_SCATTER_GATHER:
 716                 koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual;
 717                 kva = map->dev_addr + koff;
 718                 length = ptob(btopr(len));
 719                 if (length > map->size) {
 720                         cmn_err(CE_WARN, "offset=0x%lx, virtual=0x%p,"
 721                             "mapsize=0x%lx,len=0x%lx", map->offset,
 722                             dp->sg->virtual, map->size, len);
 723                         return (DDI_FAILURE);
 724                 }
 725                 cookie = gfxp_umem_cookie_init(kva, length);
 726                 if (cookie == NULL) {
 727                         cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
 728                         return (DDI_FAILURE);
 729                 }
 730                 ret = devmap_umem_setup(dhp, dp->dip,
 731                     &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
 732                     IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
 733                 if (ret != 0) {
 734                         cmn_err(CE_WARN, "sun_devmap: umem_setup fail");
 735                         gfxp_umem_cookie_destroy(cookie);
 736                         return (DDI_FAILURE);
 737                 }
 738                 *maplen = length;
 739                 break;
 740 
 741         case _DRM_TTM:
 742                 if (map->drm_umem_cookie == NULL)
 743                         return (EINVAL);
 744 
 745                 if (gfxp_devmap_umem_setup(dhp, dp->dip,
 746                     NULL, map->drm_umem_cookie, 0, map->size, PROT_ALL,
 747                     IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP,
 748                     &gem_dev_attr)) {
 749                         cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
 750                         return (DDI_FAILURE);
 751                 }
 752                 *maplen = map->size;
 753                 return (DDI_SUCCESS);
 754 
 755         default:
 756                 return (DDI_FAILURE);
 757         }
 758         return (DDI_SUCCESS);
 759 
 760 }
 761 
 762 /*ARGSUSED*/
 763 static int
 764 drm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags,
 765     offset_t offset, size_t len, void **new_priv)
 766 {
 767         devmap_handle_t                 *dhp;
 768         drm_inst_state_t                *statep;
 769         struct ddi_umem_cookie  *cp;
 770 
 771         statep = drm_sup_devt_to_state(dev);
 772         ASSERT(statep != NULL);
 773 
 774         /*
 775          * This driver only supports MAP_SHARED,
 776          * and doesn't support MAP_PRIVATE
 777          */
 778         if (flags & MAP_PRIVATE) {
 779                 cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
 780                 return (EINVAL);
 781         }
 782 
 783         mutex_enter(&statep->dis_ctxlock);
 784         dhp = (devmap_handle_t *)dhc;
 785         cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
 786         cp->cook_refcnt = 1;
 787         mutex_exit(&statep->dis_ctxlock);
 788         *new_priv = statep;
 789 
 790         return (0);
 791 }
 792 
 793 /*ARGSUSED*/
 794 static void
 795 drm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
 796     devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
 797     void **new_pvtp2)
 798 {
 799         devmap_handle_t         *dhp;
 800         devmap_handle_t         *ndhp;
 801         drm_inst_state_t                *statep;
 802         struct ddi_umem_cookie  *cp;
 803         struct ddi_umem_cookie  *ncp;
 804 
 805         dhp = (devmap_handle_t *)dhc;
 806         statep = (drm_inst_state_t *)pvtp;
 807 
 808         mutex_enter(&statep->dis_ctxlock);
 809         cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
 810         if (new_dhp1 != NULL) {
 811                 ndhp = (devmap_handle_t *)new_dhp1;
 812                 ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
 813                 ncp->cook_refcnt ++;
 814                 *new_pvtp1 = statep;
 815                 ASSERT(ncp == cp);
 816         }
 817 
 818         if (new_dhp2 != NULL) {
 819                 ndhp = (devmap_handle_t *)new_dhp2;
 820                 ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
 821                 ncp->cook_refcnt ++;
 822                 *new_pvtp2 = statep;
 823                 ASSERT(ncp == cp);
 824         }
 825 
 826         cp->cook_refcnt --;
 827         if (cp->cook_refcnt == 0) {
 828                 gfxp_umem_cookie_destroy(dhp->dh_cookie);
 829                 dhp->dh_cookie = NULL;
 830         }
 831         mutex_exit(&statep->dis_ctxlock);
 832 }
 833 
 834 
 835 /*ARGSUSED*/
 836 static int
 837 drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
 838     void **new_pvtp)
 839 {
 840         devmap_handle_t                 *dhp;
 841         drm_inst_state_t    *statep;
 842         struct ddi_umem_cookie *cp;
 843 
 844         statep = (drm_inst_state_t *)pvtp;
 845         mutex_enter(&statep->dis_ctxlock);
 846         dhp = (devmap_handle_t *)dhc;
 847         cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
 848         cp->cook_refcnt ++;
 849         mutex_exit(&statep->dis_ctxlock);
 850         *new_pvtp = statep;
 851 
 852         return (0);
 853 }
 854 
 855 int
 856 drm_dev_to_instance(dev_t dev)
 857 {
 858         return (DEV2INST(dev));
 859 }
 860 
 861 /*
 862  * drm_supp_alloc_drv_entry()
 863  *
 864  * Description:
 865  *      Create a DRM entry and add it into the instance list (drm_inst_head).
 866  *      Note that we don't allow a duplicated entry
 867  */
 868 static drm_inst_list_t *
 869 drm_supp_alloc_drv_entry(dev_info_t *dip)
 870 {
 871         drm_inst_list_t **plist;
 872         drm_inst_list_t *list;
 873         drm_inst_list_t *entry;
 874 
 875         /* protect the driver list */
 876         mutex_enter(&drm_inst_list_lock);
 877         plist = &drm_inst_head;
 878         list = *plist;
 879         while (list) {
 880                 if (list->disl_state.mis_dip == dip) {
 881                         mutex_exit(&drm_inst_list_lock);
 882                         cmn_err(CE_WARN, "%s%d already registered",
 883                             ddi_driver_name(dip), ddi_get_instance(dip));
 884                         return (NULL);
 885                 }
 886                 plist = &list->disl_next;
 887                 list = list->disl_next;
 888         }
 889 
 890         /* "dip" is not registered, create new one and add to list */
 891         entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
 892         *plist = entry;
 893         entry->disl_state.mis_dip = dip;
 894         mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL);
 895         mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL);
 896         mutex_exit(&drm_inst_list_lock);
 897 
 898         return (entry);
 899 
 900 }       /* drm_supp_alloc_drv_entry */
 901 
 902 /*
 903  * drm_supp_free_drv_entry()
 904  */
 905 static void
 906 drm_supp_free_drv_entry(dev_info_t *dip)
 907 {
 908         drm_inst_list_t         *list;
 909         drm_inst_list_t         **plist;
 910         drm_inst_state_t        *mstate;
 911 
 912         /* protect the driver list */
 913         mutex_enter(&drm_inst_list_lock);
 914         plist = &drm_inst_head;
 915         list = *plist;
 916         while (list) {
 917                 if (list->disl_state.mis_dip == dip) {
 918                         *plist = list->disl_next;
 919                         mstate = &list->disl_state;
 920                         mutex_destroy(&mstate->mis_lock);
 921                         mutex_destroy(&mstate->dis_ctxlock);
 922                         kmem_free(list, sizeof (*list));
 923                         mutex_exit(&drm_inst_list_lock);
 924                         return;
 925                 }
 926                 plist = &list->disl_next;
 927                 list = list->disl_next;
 928         }
 929         mutex_exit(&drm_inst_list_lock);
 930 
 931 }       /* drm_supp_free_drv_entry() */
 932 
 933 /*
 934  * drm_sup_devt_to_state()
 935  *
 936  * description:
 937  *      Get the soft state of DRM instance by device number
 938  */
 939 static drm_inst_state_t *
 940 drm_sup_devt_to_state(dev_t dev)
 941 {
 942         drm_inst_list_t *list;
 943         drm_inst_state_t        *mstate;
 944         major_t major = getmajor(dev);
 945         int             instance = DEV2INST(dev);
 946 
 947         mutex_enter(&drm_inst_list_lock);
 948         list = drm_inst_head;
 949         while (list) {
 950                 mstate = &list->disl_state;
 951                 mutex_enter(&mstate->mis_lock);
 952 
 953                 if ((mstate->mis_major == major) &&
 954                     (ddi_get_instance(mstate->mis_dip) == instance)) {
 955                         mutex_exit(&mstate->mis_lock);
 956                         mutex_exit(&drm_inst_list_lock);
 957                         return (mstate);
 958                 }
 959 
 960                 list = list->disl_next;
 961                 mutex_exit(&mstate->mis_lock);
 962         }
 963 
 964         mutex_exit(&drm_inst_list_lock);
 965         return (NULL);
 966 
 967 }       /* drm_sup_devt_to_state() */
 968 
 969 int
 970 drm_supp_get_irq(void *handle)
 971 {
 972         drm_inst_list_t *list;
 973         drm_inst_state_t    *mstate;
 974         int             irq;
 975 
 976         list = (drm_inst_list_t *)handle;
 977         mstate = &list->disl_state;
 978         ASSERT(mstate != NULL);
 979         irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE);
 980         return (irq);
 981 }
 982 
 983 int
 984 drm_supp_device_capability(void *handle, int capid)
 985 {
 986         drm_inst_list_t *list;
 987         drm_inst_state_t    *mstate;
 988         uint8_t         cap = 0;
 989         uint16_t        caps_ptr;
 990 
 991         list = (drm_inst_list_t *)handle;
 992         mstate = &list->disl_state;
 993         ASSERT(mstate != NULL);
 994 
 995         /* has capabilities list ? */
 996         if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) &
 997             PCI_CONF_CAP_MASK) == 0)
 998                 return (NULL);
 999 
1000         caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR);
1001         while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
1002                 cap = pci_config_get32(mstate->mis_cfg_hdl, caps_ptr);
1003                 if ((cap & PCI_CONF_CAPID_MASK) == capid)
1004                         return (cap);
1005                 caps_ptr = pci_config_get8(mstate->mis_cfg_hdl,
1006                     caps_ptr + PCI_CAP_NEXT_PTR);
1007         }
1008 
1009         return (0);
1010 }