1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 #include <sys/systm.h> 9 #include <sys/conf.h> 10 #include <sys/modctl.h> 11 #include <sys/file.h> 12 #include <sys/stat.h> 13 #include <sys/ddi.h> 14 #include <sys/sunddi.h> 15 #include <sys/modctl.h> 16 #include <sys/sunldi.h> 17 #include <sys/pci.h> 18 #include <sys/agpgart.h> 19 #include <sys/agp/agpdefs.h> 20 #include <sys/agp/agptarget_io.h> 21 22 int agptarget_debug_var = 0; 23 #define TARGETDB_PRINT2(fmt) if (agptarget_debug_var >= 1) cmn_err fmt 24 #define INST2NODENUM(inst) (inst) 25 #define DEV2INST(dev) (getminor(dev)) 26 27 typedef struct agp_target_softstate { 28 dev_info_t *tsoft_dip; 29 ddi_acc_handle_t tsoft_pcihdl; 30 uint32_t tsoft_devid; 31 /* The offset of the ACAPID register */ 32 off_t tsoft_acaptr; 33 kmutex_t tsoft_lock; 34 }agp_target_softstate_t; 35 36 static void *agptarget_glob_soft_handle; 37 38 #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 39 ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 40 41 /* 42 * The AMD8151 bridge is the only supported 64 bit hardware 43 */ 44 static int 45 is_64bit_aper(agp_target_softstate_t *softstate) 46 { 47 return (softstate->tsoft_devid == AMD_BR_8151); 48 } 49 50 /* 51 * agp_target_cap_find() 52 * 53 * Description: 54 * This function searches the linked capability list to find the offset 55 * of the AGP capability register. When it was not found, return 0. 56 * This works for standard AGP chipsets, but not for some Intel chipsets, 57 * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 58 * these chipsets even if AGP is supported. So the offset of acapid 59 * should be set manually in thoses cases. 60 * 61 * Arguments: 62 * pci_handle ddi acc handle of pci config 63 * 64 * Returns: 65 * 0 No capability pointer register found 66 * nexcap The AGP capability pointer register offset 67 */ 68 static off_t 69 agp_target_cap_find(ddi_acc_handle_t pci_handle) 70 { 71 off_t nextcap = 0; 72 uint32_t ncapid = 0; 73 uint8_t value = 0; 74 75 /* Check if this device supports the capability pointer */ 76 value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 77 & PCI_CONF_CAP_MASK); 78 79 if (!value) 80 return (0); 81 /* Get the offset of the first capability pointer from CAPPTR */ 82 nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 83 84 /* Check the AGP capability from the first capability pointer */ 85 while (nextcap) { 86 ncapid = pci_config_get32(pci_handle, nextcap); 87 /* 88 * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 89 * 845 data sheet page 69 90 */ 91 if ((ncapid & PCI_CONF_CAPID_MASK) == 92 AGP_CAP_ID) /* The AGP cap was found */ 93 break; 94 95 nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 96 } 97 98 return (nextcap); 99 100 } 101 102 /* 103 * agp_target_get_aperbase() 104 * 105 * Description: 106 * This function gets the AGP aperture base address from the AGP target 107 * register, the AGP aperture base register was programmed by the BIOS. 108 * 109 * Arguments: 110 * softstate driver soft state pointer 111 * 112 * Returns: 113 * aper_base AGP aperture base address 114 * 115 * Notes: 116 * If a 64bit bridge device is available, the AGP aperture base address 117 * can be 64 bit. 118 */ 119 static uint64_t 120 agp_target_get_apbase(agp_target_softstate_t *softstate) 121 { 122 uint64_t aper_base; 123 124 if (!is_64bit_aper(softstate)) { 125 aper_base = pci_config_get32(softstate->tsoft_pcihdl, 126 AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 127 } else { 128 aper_base = pci_config_get64(softstate->tsoft_pcihdl, 129 AGP_CONF_APERBASE); 130 /* 32-bit or 64-bit aperbase base pointer */ 131 if ((aper_base & AGP_APER_TYPE_MASK) == 0) 132 aper_base &= AGP_32_APERBASE_MASK; 133 else 134 aper_base &= AGP_64_APERBASE_MASK; 135 } 136 return (aper_base); 137 } 138 139 /* 140 * agp_target_get_apsize() 141 * 142 * Description: 143 * This function gets the AGP aperture size by reading the AGP aperture 144 * size register. 145 * Arguments: 146 * softstate driver soft state pointer 147 * 148 * Return: 149 * size The AGP aperture size in megabytes 150 * 0 an unexpected error 151 */ 152 static size_t 153 agp_target_get_apsize(agp_target_softstate_t *softstate) 154 { 155 off_t cap; 156 uint16_t value; 157 size_t size, regsize; 158 159 ASSERT(softstate->tsoft_acaptr); 160 cap = softstate->tsoft_acaptr; 161 162 if ((softstate->tsoft_devid & VENDOR_ID_MASK) == INTEL_VENDOR_ID) { 163 /* extend this value to 16 bit for later tests */ 164 value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 165 cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 166 } else { 167 value = pci_config_get16(softstate->tsoft_pcihdl, 168 cap + AGP_CONF_APERSIZE); 169 } 170 171 if (value & AGP_APER_128M_MASK) { 172 switch (value & AGP_APER_128M_MASK) { 173 case AGP_APER_4M: 174 size = 4; /* 4M */ 175 break; 176 case AGP_APER_8M: 177 size = 8; /* 8M */ 178 break; 179 case AGP_APER_16M: 180 size = 16; /* 16M */ 181 break; 182 case AGP_APER_32M: 183 size = 32; /* 32M */ 184 break; 185 case AGP_APER_64M: 186 size = 64; /* 64M */ 187 break; 188 case AGP_APER_128M: 189 size = 128; /* 128M */ 190 break; 191 default: 192 size = 0; /* not true */ 193 } 194 } else { 195 switch (value & AGP_APER_4G_MASK) { 196 case AGP_APER_256M: 197 size = 256; /* 256 M */ 198 break; 199 case AGP_APER_512M: 200 size = 512; /* 512 M */ 201 break; 202 case AGP_APER_1024M: 203 size = 1024; /* 1024 M */ 204 break; 205 case AGP_APER_2048M: 206 size = 2048; /* 2048 M */ 207 break; 208 case AGP_APER_4G: 209 size = 4096; /* 4096 M */ 210 break; 211 default: 212 size = 0; /* not true */ 213 } 214 } 215 /* 216 * In some cases, there is no APSIZE register, so the size value 217 * of 256M could be wrong. Check the value by reading the size of 218 * the first register which was set in the PCI configuration space. 219 */ 220 if (size == 256) { 221 if (ddi_dev_regsize(softstate->tsoft_dip, 222 AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 223 return (0); 224 225 if (MB2BYTES(size) != regsize) { 226 TARGETDB_PRINT2((CE_WARN, 227 "APSIZE 256M doesn't match regsize %lx", 228 regsize)); 229 TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 230 size = BYTES2MB(regsize); 231 } 232 } 233 234 return (size); 235 } 236 237 static void 238 agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 239 { 240 ASSERT(softstate->tsoft_acaptr); 241 242 /* Disable the GTLB for Intel chipsets */ 243 pci_config_put16(softstate->tsoft_pcihdl, 244 softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 245 246 pci_config_put32(softstate->tsoft_pcihdl, 247 softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 248 gartaddr & AGP_ATTBASE_MASK); 249 } 250 251 static size_t 252 i8xx_biosmem_detect(agp_target_softstate_t *softstate) 253 { 254 uint8_t memval; 255 size_t kbytes; 256 257 switch (softstate->tsoft_devid) { 258 case INTEL_BR_810: 259 case INTEL_BR_810DC: 260 case INTEL_BR_810E: 261 memval = pci_config_get8(softstate->tsoft_pcihdl, 262 I810_CONF_SMRAM); 263 switch (memval & I810_GMS_MASK) { 264 case 0x80: 265 kbytes = 512; /* 512K preallocated memory */ 266 break; 267 case 0xc0: 268 kbytes = 1024; /* 1024K preallocated memory */ 269 break; 270 default: 271 kbytes = 0; /* an unexpected case */ 272 } 273 break; 274 case INTEL_BR_830M: 275 case INTEL_BR_845: 276 memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 277 switch (memval & I8XX_GC_MODE_MASK) { 278 case I8XX_GC_MODE2: 279 kbytes = 512; /* 512K preallocated memory */ 280 break; 281 case I8XX_GC_MODE3: 282 kbytes = 1024; /* 1M preallocated memory */ 283 break; 284 case I8XX_GC_MODE4: 285 kbytes = 8 * 1024; /* 8M preallocated memory */ 286 break; 287 default: 288 kbytes = 0; /* an unexpected case */ 289 } 290 break; 291 case INTEL_BR_855GM: 292 memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 293 switch (memval & I8XX_GC_MODE_MASK) { 294 case I8XX_GC_MODE1: 295 kbytes = 1024; /* 1M preallocated memory */ 296 break; 297 case I8XX_GC_MODE2: 298 kbytes = 4 * 1024; /* 4M preallocated memory */ 299 break; 300 case I8XX_GC_MODE3: 301 kbytes = 8 * 1024; /* 8M preallocated memory */ 302 break; 303 case I8XX_GC_MODE4: 304 kbytes = 16 * 1024; /* 16M preallocated memory */ 305 break; 306 case I8XX_GC_MODE5: 307 kbytes = 32 * 1024; /* 32M preallocated memory */ 308 break; 309 default: 310 kbytes = 0; /* an unexpected case */ 311 } 312 break; 313 case INTEL_BR_865: 314 case INTEL_BR_910M: 315 memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 316 switch (memval & I8XX_GC_MODE_MASK) { 317 case I8XX_GC_MODE1: 318 kbytes = 1024; /* 1M preallocated memory */ 319 break; 320 case I8XX_GC_MODE3: 321 kbytes = 8 * 1024; /* 8M preallocated memory */ 322 break; 323 /* 324 * There is no option for 16M in 910GM datasheet, 325 * but some BIOS add this option for 16M support. 326 */ 327 case I8XX_GC_MODE4: 328 kbytes = 16 * 1024; /* 16M preallocated memory */ 329 break; 330 default: 331 kbytes = 0; /* an unexpected case */ 332 } 333 break; 334 case INTEL_BR_910: 335 case INTEL_BR_945: 336 case INTEL_BR_945GM: 337 memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 338 switch (memval & I8XX_GC_MODE_MASK) { 339 case I8XX_GC_MODE1: 340 kbytes = 1024; /* 1M preallocated memory */ 341 break; 342 case I8XX_GC_MODE3: 343 kbytes = 8 * 1024; /* 8M preallocated memory */ 344 break; 345 default: 346 kbytes = 0; /* an unexpected case */ 347 } 348 break; 349 default: 350 kbytes = 0; 351 } 352 353 return (kbytes); 354 } 355 356 /*ARGSUSED*/ 357 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 358 void *arg, void **resultp) 359 { 360 agp_target_softstate_t *st; 361 int instance, rval = DDI_FAILURE; 362 dev_t dev; 363 364 switch (cmd) { 365 case DDI_INFO_DEVT2DEVINFO: 366 dev = (dev_t)arg; 367 instance = DEV2INST(dev); 368 st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 369 if (st != NULL) { 370 mutex_enter(&st->tsoft_lock); 371 *resultp = st->tsoft_dip; 372 mutex_exit(&st->tsoft_lock); 373 rval = DDI_SUCCESS; 374 } else 375 *resultp = NULL; 376 377 break; 378 case DDI_INFO_DEVT2INSTANCE: 379 dev = (dev_t)arg; 380 instance = DEV2INST(dev); 381 *resultp = (void *)(uintptr_t)instance; 382 rval = DDI_SUCCESS; 383 default: 384 break; 385 } 386 387 return (rval); 388 } 389 390 static int 391 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 392 { 393 agp_target_softstate_t *softstate; 394 int instance; 395 int status; 396 397 if (cmd != DDI_ATTACH) 398 return (DDI_FAILURE); 399 400 instance = ddi_get_instance(dip); 401 402 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) != 403 DDI_SUCCESS) 404 return (DDI_FAILURE); 405 406 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 407 mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 408 softstate->tsoft_dip = dip; 409 status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 410 if (status != DDI_SUCCESS) { 411 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 412 return (DDI_FAILURE); 413 } 414 415 softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 416 PCI_CONF_VENID); 417 softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 418 if (softstate->tsoft_acaptr == 0) { 419 /* Make a correction for some Intel chipsets */ 420 if ((softstate->tsoft_devid & VENDOR_ID_MASK) == 421 INTEL_VENDOR_ID) 422 softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 423 else 424 return (DDI_FAILURE); 425 } 426 427 status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 428 INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 429 430 if (status != DDI_SUCCESS) { 431 pci_config_teardown(&softstate->tsoft_pcihdl); 432 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 433 return (DDI_FAILURE); 434 } 435 436 return (DDI_SUCCESS); 437 } 438 439 /*ARGSUSED*/ 440 static int 441 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 442 { 443 int instance; 444 agp_target_softstate_t *softstate; 445 446 if (cmd != DDI_DETACH) 447 return (DDI_FAILURE); 448 449 instance = ddi_get_instance(dip); 450 451 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 452 453 ddi_remove_minor_node(dip, AGPTARGET_NAME); 454 pci_config_teardown(&softstate->tsoft_pcihdl); 455 mutex_destroy(&softstate->tsoft_lock); 456 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 457 return (DDI_SUCCESS); 458 } 459 460 /*ARGSUSED*/ 461 static int 462 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 463 cred_t *cred, int *rval) 464 { 465 int instance = DEV2INST(dev); 466 agp_target_softstate_t *st; 467 static char kernel_only[] = 468 "amd64_gart_ioctl: is a kernel only ioctl"; 469 470 if (!(mode & FKIOCTL)) { 471 TARGETDB_PRINT2((CE_CONT, kernel_only)); 472 return (ENXIO); 473 } 474 st = GETSOFTC(instance); 475 476 if (st == NULL) 477 return (ENXIO); 478 479 mutex_enter(&st->tsoft_lock); 480 481 switch (cmd) { 482 case CHIP_DETECT: 483 { 484 int type; 485 switch (st->tsoft_devid & VENDOR_ID_MASK) { 486 case INTEL_VENDOR_ID: 487 type = CHIP_IS_INTEL; 488 break; 489 case AMD_VENDOR_ID: 490 type = CHIP_IS_AMD; 491 break; 492 default: 493 type = 0; 494 } 495 if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 496 mutex_exit(&st->tsoft_lock); 497 return (EFAULT); 498 } 499 500 break; 501 } 502 case I8XX_GET_PREALLOC_SIZE: 503 { 504 size_t prealloc_size; 505 506 if ((st->tsoft_devid & VENDOR_ID_MASK) != 507 INTEL_VENDOR_ID) { 508 mutex_exit(&st->tsoft_lock); 509 return (EINVAL); 510 } 511 512 prealloc_size = i8xx_biosmem_detect(st); 513 if (ddi_copyout(&prealloc_size, (void *)data, 514 sizeof (size_t), mode)) { 515 mutex_exit(&st->tsoft_lock); 516 return (EFAULT); 517 } 518 519 break; 520 } 521 case AGP_TARGET_GETINFO: 522 { 523 i_agp_info_t info; 524 uint32_t value; 525 off_t cap; 526 527 ASSERT(st->tsoft_acaptr); 528 529 cap = st->tsoft_acaptr; 530 value = pci_config_get32(st->tsoft_pcihdl, cap); 531 info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 532 info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 533 info.iagp_devid = st->tsoft_devid; 534 info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 535 cap + AGP_CONF_STATUS); 536 info.iagp_aperbase = agp_target_get_apbase(st); 537 info.iagp_apersize = agp_target_get_apsize(st); 538 539 if (ddi_copyout(&info, (void *)data, 540 sizeof (i_agp_info_t), mode)) { 541 mutex_exit(&st->tsoft_lock); 542 return (EFAULT); 543 } 544 break; 545 546 } 547 /* 548 * This ioctl is only for Intel AGP chipsets. 549 * It is not necessary for the AMD8151 AGP bridge, because 550 * this register in the AMD8151 does not control any hardware. 551 * It is only provided for compatibility with an Intel AGP bridge. 552 * Please refer to the <<AMD8151 data sheet>> page 24, 553 * AGP device GART pointer. 554 */ 555 case AGP_TARGET_SET_GATTADDR: 556 { 557 uint32_t gartaddr; 558 559 if (ddi_copyin((void *)data, &gartaddr, 560 sizeof (uint32_t), mode)) { 561 mutex_exit(&st->tsoft_lock); 562 return (EFAULT); 563 } 564 565 agp_target_set_gartaddr(st, gartaddr); 566 break; 567 } 568 case AGP_TARGET_SETCMD: 569 { 570 uint32_t command; 571 572 if (ddi_copyin((void *)data, &command, 573 sizeof (uint32_t), mode)) { 574 mutex_exit(&st->tsoft_lock); 575 return (EFAULT); 576 } 577 578 ASSERT(st->tsoft_acaptr); 579 580 pci_config_put32(st->tsoft_pcihdl, 581 st->tsoft_acaptr + AGP_CONF_COMMAND, 582 command); 583 break; 584 585 } 586 case AGP_TARGET_FLUSH_GTLB: 587 { 588 uint16_t value; 589 590 ASSERT(st->tsoft_acaptr); 591 592 value = pci_config_get16(st->tsoft_pcihdl, 593 st->tsoft_acaptr + AGP_CONF_CONTROL); 594 value &= ~AGPCTRL_GTLBEN; 595 pci_config_put16(st->tsoft_pcihdl, 596 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 597 value |= AGPCTRL_GTLBEN; 598 pci_config_put16(st->tsoft_pcihdl, 599 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 600 601 break; 602 } 603 case AGP_TARGET_CONFIGURE: 604 { 605 uint8_t value; 606 607 ASSERT(st->tsoft_acaptr); 608 609 value = pci_config_get8(st->tsoft_pcihdl, 610 st->tsoft_acaptr + AGP_CONF_MISC); 611 value |= AGP_MISC_APEN; 612 pci_config_put8(st->tsoft_pcihdl, 613 st->tsoft_acaptr + AGP_CONF_MISC, value); 614 break; 615 616 } 617 case AGP_TARGET_UNCONFIG: 618 { 619 uint32_t value1; 620 uint8_t value2; 621 622 ASSERT(st->tsoft_acaptr); 623 624 pci_config_put16(st->tsoft_pcihdl, 625 st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 626 627 value2 = pci_config_get8(st->tsoft_pcihdl, 628 st->tsoft_acaptr + AGP_CONF_MISC); 629 value2 &= ~AGP_MISC_APEN; 630 pci_config_put8(st->tsoft_pcihdl, 631 st->tsoft_acaptr + AGP_CONF_MISC, value2); 632 633 value1 = pci_config_get32(st->tsoft_pcihdl, 634 st->tsoft_acaptr + AGP_CONF_COMMAND); 635 value1 &= ~AGPCMD_AGPEN; 636 pci_config_put32(st->tsoft_pcihdl, 637 st->tsoft_acaptr + AGP_CONF_COMMAND, 638 value1); 639 640 pci_config_put32(st->tsoft_pcihdl, 641 st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 642 643 break; 644 } 645 646 default: 647 mutex_exit(&st->tsoft_lock); 648 return (ENXIO); 649 } /* end switch */ 650 651 mutex_exit(&st->tsoft_lock); 652 653 return (0); 654 } 655 656 /*ARGSUSED*/ 657 static int 658 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 659 { 660 int instance = DEV2INST(*devp); 661 agp_target_softstate_t *st; 662 663 if (!(flag & FKLYR)) 664 return (ENXIO); 665 666 st = GETSOFTC(instance); 667 668 if (st == NULL) 669 return (ENXIO); 670 671 return (0); 672 } 673 674 /*ARGSUSED*/ 675 static int 676 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 677 { 678 int instance = DEV2INST(dev); 679 agp_target_softstate_t *st; 680 681 st = GETSOFTC(instance); 682 683 if (st == NULL) 684 return (ENXIO); 685 686 return (0); 687 } 688 689 static struct cb_ops agp_target_cb_ops = { 690 agp_target_open, /* cb_open */ 691 agp_target_close, /* cb_close */ 692 nodev, /* cb_strategy */ 693 nodev, /* cb_print */ 694 nodev, /* cb_dump */ 695 nodev, /* cb_read() */ 696 nodev, /* cb_write() */ 697 agp_target_ioctl, /* cb_ioctl */ 698 nodev, /* cb_devmap */ 699 nodev, /* cb_mmap */ 700 nodev, /* cb_segmap */ 701 nochpoll, /* cb_chpoll */ 702 ddi_prop_op, /* cb_prop_op */ 703 0, /* cb_stream */ 704 D_NEW | D_MP, /* cb_flag */ 705 CB_REV, /* cb_ops version? */ 706 nodev, /* cb_aread() */ 707 nodev, /* cb_awrite() */ 708 }; 709 710 /* device operations */ 711 static struct dev_ops agp_target_ops = { 712 DEVO_REV, /* devo_rev */ 713 0, /* devo_refcnt */ 714 agptarget_getinfo, /* devo_getinfo */ 715 nulldev, /* devo_identify */ 716 nulldev, /* devo_probe */ 717 agp_target_attach, /* devo_attach */ 718 agp_target_detach, /* devo_detach */ 719 nodev, /* devo_reset */ 720 &agp_target_cb_ops, /* devo_cb_ops */ 721 0, /* devo_bus_ops */ 722 0, /* devo_power */ 723 }; 724 725 static struct modldrv modldrv = { 726 &mod_driverops, 727 "AGP target driver v%I%", 728 &agp_target_ops, 729 }; 730 731 static struct modlinkage modlinkage = { 732 MODREV_1, /* MODREV_1 is indicated by manual */ 733 {&modldrv, NULL, NULL, NULL} 734 }; 735 736 int 737 _init(void) 738 { 739 int ret; 740 741 ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 742 sizeof (agp_target_softstate_t), 1); 743 744 if (ret) 745 goto err1; 746 747 if ((ret = mod_install(&modlinkage)) != 0) { 748 goto err2; 749 } 750 751 return (DDI_SUCCESS); 752 err2: 753 ddi_soft_state_fini(&agptarget_glob_soft_handle); 754 err1: 755 return (ret); 756 } 757 758 int 759 _info(struct modinfo *modinfop) 760 { 761 return (mod_info(&modlinkage, modinfop)); 762 } 763 764 int 765 _fini(void) 766 { 767 int ret; 768 769 if ((ret = mod_remove(&modlinkage)) == 0) { 770 ddi_soft_state_fini(&agptarget_glob_soft_handle); 771 } 772 return (ret); 773 } 774