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 memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 337 switch (memval & I8XX_GC_MODE_MASK) { 338 case I8XX_GC_MODE1: 339 kbytes = 1024; /* 1M preallocated memory */ 340 break; 341 case I8XX_GC_MODE3: 342 kbytes = 8 * 1024; /* 8M preallocated memory */ 343 break; 344 default: 345 kbytes = 0; /* an unexpected case */ 346 } 347 break; 348 default: 349 kbytes = 0; 350 } 351 352 return (kbytes); 353 } 354 355 /*ARGSUSED*/ 356 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 357 void *arg, void **resultp) 358 { 359 agp_target_softstate_t *st; 360 int instance, rval = DDI_FAILURE; 361 dev_t dev; 362 363 switch (cmd) { 364 case DDI_INFO_DEVT2DEVINFO: 365 dev = (dev_t)arg; 366 instance = DEV2INST(dev); 367 st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 368 if (st != NULL) { 369 mutex_enter(&st->tsoft_lock); 370 *resultp = st->tsoft_dip; 371 mutex_exit(&st->tsoft_lock); 372 rval = DDI_SUCCESS; 373 } else 374 *resultp = NULL; 375 376 break; 377 case DDI_INFO_DEVT2INSTANCE: 378 dev = (dev_t)arg; 379 instance = DEV2INST(dev); 380 *resultp = (void *)(uintptr_t)instance; 381 rval = DDI_SUCCESS; 382 default: 383 break; 384 } 385 386 return (rval); 387 } 388 389 static int 390 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 391 { 392 agp_target_softstate_t *softstate; 393 int instance; 394 int status; 395 396 if (cmd != DDI_ATTACH) 397 return (DDI_FAILURE); 398 399 instance = ddi_get_instance(dip); 400 401 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) != 402 DDI_SUCCESS) 403 return (DDI_FAILURE); 404 405 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 406 mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 407 softstate->tsoft_dip = dip; 408 status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 409 if (status != DDI_SUCCESS) { 410 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 411 return (DDI_FAILURE); 412 } 413 414 softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 415 PCI_CONF_VENID); 416 softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 417 if (softstate->tsoft_acaptr == 0) { 418 /* Make a correction for some Intel chipsets */ 419 if ((softstate->tsoft_devid & VENDOR_ID_MASK) == 420 INTEL_VENDOR_ID) 421 softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 422 else 423 return (DDI_FAILURE); 424 } 425 426 status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 427 INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 428 429 if (status != DDI_SUCCESS) { 430 pci_config_teardown(&softstate->tsoft_pcihdl); 431 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 432 return (DDI_FAILURE); 433 } 434 435 return (DDI_SUCCESS); 436 } 437 438 /*ARGSUSED*/ 439 static int 440 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 441 { 442 int instance; 443 agp_target_softstate_t *softstate; 444 445 if (cmd != DDI_DETACH) 446 return (DDI_FAILURE); 447 448 instance = ddi_get_instance(dip); 449 450 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 451 452 ddi_remove_minor_node(dip, AGPTARGET_NAME); 453 pci_config_teardown(&softstate->tsoft_pcihdl); 454 mutex_destroy(&softstate->tsoft_lock); 455 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 456 return (DDI_SUCCESS); 457 } 458 459 /*ARGSUSED*/ 460 static int 461 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 462 cred_t *cred, int *rval) 463 { 464 int instance = DEV2INST(dev); 465 agp_target_softstate_t *st; 466 static char kernel_only[] = 467 "amd64_gart_ioctl: is a kernel only ioctl"; 468 469 if (!(mode & FKIOCTL)) { 470 TARGETDB_PRINT2((CE_CONT, kernel_only)); 471 return (ENXIO); 472 } 473 st = GETSOFTC(instance); 474 475 if (st == NULL) 476 return (ENXIO); 477 478 mutex_enter(&st->tsoft_lock); 479 480 switch (cmd) { 481 case CHIP_DETECT: 482 { 483 int type; 484 switch (st->tsoft_devid & VENDOR_ID_MASK) { 485 case INTEL_VENDOR_ID: 486 type = CHIP_IS_INTEL; 487 break; 488 case AMD_VENDOR_ID: 489 type = CHIP_IS_AMD; 490 break; 491 default: 492 type = 0; 493 } 494 if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 495 mutex_exit(&st->tsoft_lock); 496 return (EFAULT); 497 } 498 499 break; 500 } 501 case I8XX_GET_PREALLOC_SIZE: 502 { 503 size_t prealloc_size; 504 505 if ((st->tsoft_devid & VENDOR_ID_MASK) != 506 INTEL_VENDOR_ID) { 507 mutex_exit(&st->tsoft_lock); 508 return (EINVAL); 509 } 510 511 prealloc_size = i8xx_biosmem_detect(st); 512 if (ddi_copyout(&prealloc_size, (void *)data, 513 sizeof (size_t), mode)) { 514 mutex_exit(&st->tsoft_lock); 515 return (EFAULT); 516 } 517 518 break; 519 } 520 case AGP_TARGET_GETINFO: 521 { 522 i_agp_info_t info; 523 uint32_t value; 524 off_t cap; 525 526 ASSERT(st->tsoft_acaptr); 527 528 cap = st->tsoft_acaptr; 529 value = pci_config_get32(st->tsoft_pcihdl, cap); 530 info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 531 info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 532 info.iagp_devid = st->tsoft_devid; 533 info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 534 cap + AGP_CONF_STATUS); 535 info.iagp_aperbase = agp_target_get_apbase(st); 536 info.iagp_apersize = agp_target_get_apsize(st); 537 538 if (ddi_copyout(&info, (void *)data, 539 sizeof (i_agp_info_t), mode)) { 540 mutex_exit(&st->tsoft_lock); 541 return (EFAULT); 542 } 543 break; 544 545 } 546 /* 547 * This ioctl is only for Intel AGP chipsets. 548 * It is not necessary for the AMD8151 AGP bridge, because 549 * this register in the AMD8151 does not control any hardware. 550 * It is only provided for compatibility with an Intel AGP bridge. 551 * Please refer to the <<AMD8151 data sheet>> page 24, 552 * AGP device GART pointer. 553 */ 554 case AGP_TARGET_SET_GATTADDR: 555 { 556 uint32_t gartaddr; 557 558 if (ddi_copyin((void *)data, &gartaddr, 559 sizeof (uint32_t), mode)) { 560 mutex_exit(&st->tsoft_lock); 561 return (EFAULT); 562 } 563 564 agp_target_set_gartaddr(st, gartaddr); 565 break; 566 } 567 case AGP_TARGET_SETCMD: 568 { 569 uint32_t command; 570 571 if (ddi_copyin((void *)data, &command, 572 sizeof (uint32_t), mode)) { 573 mutex_exit(&st->tsoft_lock); 574 return (EFAULT); 575 } 576 577 ASSERT(st->tsoft_acaptr); 578 579 pci_config_put32(st->tsoft_pcihdl, 580 st->tsoft_acaptr + AGP_CONF_COMMAND, 581 command); 582 break; 583 584 } 585 case AGP_TARGET_FLUSH_GTLB: 586 { 587 uint16_t value; 588 589 ASSERT(st->tsoft_acaptr); 590 591 value = pci_config_get16(st->tsoft_pcihdl, 592 st->tsoft_acaptr + AGP_CONF_CONTROL); 593 value &= ~AGPCTRL_GTLBEN; 594 pci_config_put16(st->tsoft_pcihdl, 595 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 596 value |= AGPCTRL_GTLBEN; 597 pci_config_put16(st->tsoft_pcihdl, 598 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 599 600 break; 601 } 602 case AGP_TARGET_CONFIGURE: 603 { 604 uint8_t value; 605 606 ASSERT(st->tsoft_acaptr); 607 608 value = pci_config_get8(st->tsoft_pcihdl, 609 st->tsoft_acaptr + AGP_CONF_MISC); 610 value |= AGP_MISC_APEN; 611 pci_config_put8(st->tsoft_pcihdl, 612 st->tsoft_acaptr + AGP_CONF_MISC, value); 613 break; 614 615 } 616 case AGP_TARGET_UNCONFIG: 617 { 618 uint32_t value1; 619 uint8_t value2; 620 621 ASSERT(st->tsoft_acaptr); 622 623 pci_config_put16(st->tsoft_pcihdl, 624 st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 625 626 value2 = pci_config_get8(st->tsoft_pcihdl, 627 st->tsoft_acaptr + AGP_CONF_MISC); 628 value2 &= ~AGP_MISC_APEN; 629 pci_config_put8(st->tsoft_pcihdl, 630 st->tsoft_acaptr + AGP_CONF_MISC, value2); 631 632 value1 = pci_config_get32(st->tsoft_pcihdl, 633 st->tsoft_acaptr + AGP_CONF_COMMAND); 634 value1 &= ~AGPCMD_AGPEN; 635 pci_config_put32(st->tsoft_pcihdl, 636 st->tsoft_acaptr + AGP_CONF_COMMAND, 637 value1); 638 639 pci_config_put32(st->tsoft_pcihdl, 640 st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 641 642 break; 643 } 644 645 default: 646 mutex_exit(&st->tsoft_lock); 647 return (ENXIO); 648 } /* end switch */ 649 650 mutex_exit(&st->tsoft_lock); 651 652 return (0); 653 } 654 655 /*ARGSUSED*/ 656 static int 657 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 658 { 659 int instance = DEV2INST(*devp); 660 agp_target_softstate_t *st; 661 662 if (!(flag & FKLYR)) 663 return (ENXIO); 664 665 st = GETSOFTC(instance); 666 667 if (st == NULL) 668 return (ENXIO); 669 670 return (0); 671 } 672 673 /*ARGSUSED*/ 674 static int 675 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 676 { 677 int instance = DEV2INST(dev); 678 agp_target_softstate_t *st; 679 680 st = GETSOFTC(instance); 681 682 if (st == NULL) 683 return (ENXIO); 684 685 return (0); 686 } 687 688 static struct cb_ops agp_target_cb_ops = { 689 agp_target_open, /* cb_open */ 690 agp_target_close, /* cb_close */ 691 nodev, /* cb_strategy */ 692 nodev, /* cb_print */ 693 nodev, /* cb_dump */ 694 nodev, /* cb_read() */ 695 nodev, /* cb_write() */ 696 agp_target_ioctl, /* cb_ioctl */ 697 nodev, /* cb_devmap */ 698 nodev, /* cb_mmap */ 699 nodev, /* cb_segmap */ 700 nochpoll, /* cb_chpoll */ 701 ddi_prop_op, /* cb_prop_op */ 702 0, /* cb_stream */ 703 D_NEW | D_MP, /* cb_flag */ 704 CB_REV, /* cb_ops version? */ 705 nodev, /* cb_aread() */ 706 nodev, /* cb_awrite() */ 707 }; 708 709 /* device operations */ 710 static struct dev_ops agp_target_ops = { 711 DEVO_REV, /* devo_rev */ 712 0, /* devo_refcnt */ 713 agptarget_getinfo, /* devo_getinfo */ 714 nulldev, /* devo_identify */ 715 nulldev, /* devo_probe */ 716 agp_target_attach, /* devo_attach */ 717 agp_target_detach, /* devo_detach */ 718 nodev, /* devo_reset */ 719 &agp_target_cb_ops, /* devo_cb_ops */ 720 0, /* devo_bus_ops */ 721 0, /* devo_power */ 722 }; 723 724 static struct modldrv modldrv = { 725 &mod_driverops, 726 "AGP target driver v%I%", 727 &agp_target_ops, 728 }; 729 730 static struct modlinkage modlinkage = { 731 MODREV_1, /* MODREV_1 is indicated by manual */ 732 {&modldrv, NULL, NULL, NULL} 733 }; 734 735 int 736 _init(void) 737 { 738 int ret; 739 740 ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 741 sizeof (agp_target_softstate_t), 1); 742 743 if (ret) 744 goto err1; 745 746 if ((ret = mod_install(&modlinkage)) != 0) { 747 goto err2; 748 } 749 750 return (DDI_SUCCESS); 751 err2: 752 ddi_soft_state_fini(&agptarget_glob_soft_handle); 753 err1: 754 return (ret); 755 } 756 757 int 758 _info(struct modinfo *modinfop) 759 { 760 return (mod_info(&modlinkage, modinfop)); 761 } 762 763 int 764 _fini(void) 765 { 766 int ret; 767 768 if ((ret = mod_remove(&modlinkage)) == 0) { 769 ddi_soft_state_fini(&agptarget_glob_soft_handle); 770 } 771 return (ret); 772 } 773