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