1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2016, Anish Gupta (anish@freebsd.org) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_acpi.h" 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/malloc.h> 38 39 #include <machine/vmparam.h> 40 41 #include <vm/vm.h> 42 #include <vm/pmap.h> 43 44 #include <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <dev/acpica/acpivar.h> 47 48 #include "io/iommu.h" 49 #include "amdvi_priv.h" 50 51 device_t *ivhd_devs; /* IVHD or AMD-Vi device list. */ 52 int ivhd_count; /* Number of IVHD header. */ 53 /* 54 * Cached IVHD header list. 55 * Single entry for each IVHD, filtered the legacy one. 56 */ 57 ACPI_IVRS_HARDWARE1 *ivhd_hdrs[10]; 58 59 extern int amdvi_ptp_level; /* Page table levels. */ 60 61 typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER *ptr, void *arg); 62 /* 63 * Iterate IVRS table for IVHD and IVMD device type. 64 */ 65 static void 66 ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg) 67 { 68 ACPI_TABLE_IVRS *ivrs; 69 ACPI_IVRS_HEADER *ivrs_hdr, *end; 70 ACPI_STATUS status; 71 72 status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); 73 if (ACPI_FAILURE(status)) 74 return; 75 76 if (ivrs->Header.Length == 0) { 77 return; 78 } 79 80 ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1); 81 end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length); 82 83 while (ivrs_hdr < end) { 84 if ((uint8_t *)ivrs_hdr + ivrs_hdr->Length > (uint8_t *)end) { 85 printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n", 86 ivrs_hdr->Length); 87 break; 88 } 89 90 switch (ivrs_hdr->Type) { 91 case IVRS_TYPE_HARDWARE_LEGACY: /* Legacy */ 92 case IVRS_TYPE_HARDWARE_EFR: 93 case IVRS_TYPE_HARDWARE_MIXED: 94 if (!iter(ivrs_hdr, arg)) 95 return; 96 break; 97 98 case ACPI_IVRS_TYPE_MEMORY1: 99 case ACPI_IVRS_TYPE_MEMORY2: 100 case ACPI_IVRS_TYPE_MEMORY3: 101 if (!iter(ivrs_hdr, arg)) 102 return; 103 104 break; 105 106 default: 107 printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type); 108 } 109 110 ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr + 111 ivrs_hdr->Length); 112 } 113 } 114 115 static bool 116 ivrs_is_ivhd(UINT8 type) 117 { 118 119 switch(type) { 120 case IVRS_TYPE_HARDWARE_LEGACY: 121 case IVRS_TYPE_HARDWARE_EFR: 122 case IVRS_TYPE_HARDWARE_MIXED: 123 return (true); 124 125 default: 126 return (false); 127 } 128 } 129 130 /* Count the number of AMD-Vi devices in the system. */ 131 static int 132 ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg) 133 { 134 135 if (ivrs_is_ivhd(ivrs_he->Type)) 136 ivhd_count++; 137 138 return (1); 139 } 140 141 struct find_ivrs_hdr_args { 142 int i; 143 ACPI_IVRS_HEADER *ptr; 144 }; 145 146 static int 147 ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args) 148 { 149 struct find_ivrs_hdr_args *fi; 150 151 fi = (struct find_ivrs_hdr_args *)args; 152 if (ivrs_is_ivhd(ivrs_hdr->Type)) { 153 if (fi->i == 0) { 154 fi->ptr = ivrs_hdr; 155 return (0); 156 } 157 fi->i--; 158 } 159 160 return (1); 161 } 162 163 static ACPI_IVRS_HARDWARE1 * 164 ivhd_find_by_index(int idx) 165 { 166 struct find_ivrs_hdr_args fi; 167 168 fi.i = idx; 169 fi.ptr = NULL; 170 171 ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi); 172 173 return ((ACPI_IVRS_HARDWARE1 *)fi.ptr); 174 } 175 176 static void 177 ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id, 178 uint32_t end_id, uint8_t cfg, bool ats) 179 { 180 struct ivhd_dev_cfg *dev_cfg; 181 182 /* If device doesn't have special data, don't add it. */ 183 if (!cfg) 184 return; 185 186 dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++]; 187 dev_cfg->start_id = start_id; 188 dev_cfg->end_id = end_id; 189 dev_cfg->data = cfg; 190 dev_cfg->enable_ats = ats; 191 } 192 193 /* 194 * Record device attributes as suggested by BIOS. 195 */ 196 static int 197 ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc) 198 { 199 ACPI_IVRS_DE_HEADER *de; 200 uint8_t *p, *end; 201 int range_start_id = 0, range_end_id = 0; 202 uint32_t *extended; 203 uint8_t all_data = 0, range_data = 0; 204 bool range_enable_ats = false, enable_ats; 205 206 softc->start_dev_rid = ~0; 207 softc->end_dev_rid = 0; 208 209 switch (ivhd->Header.Type) { 210 case IVRS_TYPE_HARDWARE_LEGACY: 211 p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1); 212 break; 213 214 case IVRS_TYPE_HARDWARE_EFR: 215 case IVRS_TYPE_HARDWARE_MIXED: 216 p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2); 217 break; 218 219 default: 220 device_printf(softc->dev, 221 "unknown type: 0x%x\n", ivhd->Header.Type); 222 return (-1); 223 } 224 225 end = (uint8_t *)ivhd + ivhd->Header.Length; 226 227 while (p < end) { 228 de = (ACPI_IVRS_DE_HEADER *)p; 229 softc->start_dev_rid = MIN(softc->start_dev_rid, de->Id); 230 softc->end_dev_rid = MAX(softc->end_dev_rid, de->Id); 231 switch (de->Type) { 232 case ACPI_IVRS_TYPE_ALL: 233 all_data = de->DataSetting; 234 break; 235 236 case ACPI_IVRS_TYPE_SELECT: 237 case ACPI_IVRS_TYPE_ALIAS_SELECT: 238 case ACPI_IVRS_TYPE_EXT_SELECT: 239 enable_ats = false; 240 if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) { 241 extended = (uint32_t *)(de + 1); 242 enable_ats = 243 (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? 244 false : true; 245 } 246 ivhd_dev_add_entry(softc, de->Id, de->Id, 247 de->DataSetting | all_data, enable_ats); 248 break; 249 250 case ACPI_IVRS_TYPE_START: 251 case ACPI_IVRS_TYPE_ALIAS_START: 252 case ACPI_IVRS_TYPE_EXT_START: 253 range_start_id = de->Id; 254 range_data = de->DataSetting; 255 if (de->Type == ACPI_IVRS_TYPE_EXT_START) { 256 extended = (uint32_t *)(de + 1); 257 range_enable_ats = 258 (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? 259 false : true; 260 } 261 break; 262 263 case ACPI_IVRS_TYPE_END: 264 range_end_id = de->Id; 265 ivhd_dev_add_entry(softc, range_start_id, range_end_id, 266 range_data | all_data, range_enable_ats); 267 range_start_id = range_end_id = 0; 268 range_data = 0; 269 all_data = 0; 270 break; 271 272 case ACPI_IVRS_TYPE_PAD4: 273 break; 274 275 case ACPI_IVRS_TYPE_SPECIAL: 276 /* HPET or IOAPIC */ 277 break; 278 default: 279 if ((de->Type < 5) || 280 (de->Type >= ACPI_IVRS_TYPE_PAD8)) 281 device_printf(softc->dev, 282 "Unknown dev entry:0x%x\n", de->Type); 283 } 284 285 if (softc->dev_cfg_cnt > 286 (sizeof(softc->dev_cfg) / sizeof(softc->dev_cfg[0]))) { 287 device_printf(softc->dev, 288 "WARN Too many device entries.\n"); 289 return (EINVAL); 290 } 291 if (de->Type < 0x40) 292 p += sizeof(ACPI_IVRS_DEVICE4); 293 else if (de->Type < 0x80) 294 p += sizeof(ACPI_IVRS_DEVICE8A); 295 else { 296 printf("Variable size IVHD type 0x%x not supported\n", 297 de->Type); 298 break; 299 } 300 } 301 302 KASSERT((softc->end_dev_rid >= softc->start_dev_rid), 303 ("Device end[0x%x] < start[0x%x.\n", 304 softc->end_dev_rid, softc->start_dev_rid)); 305 306 return (0); 307 } 308 309 static bool 310 ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new) 311 { 312 /* 313 * Newer IVRS header type take precedence. 314 */ 315 if ((old->DeviceId == new->DeviceId) && 316 (old->Type == IVRS_TYPE_HARDWARE_LEGACY) && 317 ((new->Type == IVRS_TYPE_HARDWARE_EFR) || 318 (new->Type == IVRS_TYPE_HARDWARE_MIXED))) { 319 return (true); 320 } 321 322 return (false); 323 } 324 325 static void 326 ivhd_identify(driver_t *driver, device_t parent) 327 { 328 ACPI_TABLE_IVRS *ivrs; 329 ACPI_IVRS_HARDWARE1 *ivhd; 330 ACPI_STATUS status; 331 int i, count = 0; 332 uint32_t ivrs_ivinfo; 333 334 if (acpi_disabled("ivhd")) 335 return; 336 337 status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); 338 if (ACPI_FAILURE(status)) 339 return; 340 341 if (ivrs->Header.Length == 0) { 342 return; 343 } 344 345 ivrs_ivinfo = ivrs->Info; 346 printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d" 347 " flags:%b\n", 348 REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8), 349 REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22), 350 "\020\001EFRSup"); 351 352 ivrs_hdr_iterate_tbl(ivhd_count_iter, NULL); 353 if (!ivhd_count) 354 return; 355 356 for (i = 0; i < ivhd_count; i++) { 357 ivhd = ivhd_find_by_index(i); 358 KASSERT(ivhd, ("ivhd%d is NULL\n", i)); 359 ivhd_hdrs[i] = ivhd; 360 } 361 362 /* 363 * Scan for presence of legacy and non-legacy device type 364 * for same AMD-Vi device and override the old one. 365 */ 366 for (i = ivhd_count - 1 ; i > 0 ; i--){ 367 if (ivhd_is_newer(&ivhd_hdrs[i-1]->Header, 368 &ivhd_hdrs[i]->Header)) { 369 ivhd_hdrs[i-1] = ivhd_hdrs[i]; 370 ivhd_count--; 371 } 372 } 373 374 ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF, 375 M_WAITOK | M_ZERO); 376 for (i = 0; i < ivhd_count; i++) { 377 ivhd = ivhd_hdrs[i]; 378 KASSERT(ivhd, ("ivhd%d is NULL\n", i)); 379 380 /* 381 * Use a high order to ensure that this driver is probed after 382 * the Host-PCI bridge and the root PCI bus. 383 */ 384 ivhd_devs[i] = BUS_ADD_CHILD(parent, 385 ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i); 386 387 /* 388 * XXX: In case device was not destroyed before, add will fail. 389 * locate the old device instance. 390 */ 391 if (ivhd_devs[i] == NULL) { 392 ivhd_devs[i] = device_find_child(parent, "ivhd", i); 393 if (ivhd_devs[i] == NULL) { 394 printf("AMD-Vi: cant find ivhd%d\n", i); 395 break; 396 } 397 } 398 count++; 399 } 400 401 /* 402 * Update device count in case failed to attach. 403 */ 404 ivhd_count = count; 405 } 406 407 static int 408 ivhd_probe(device_t dev) 409 { 410 ACPI_IVRS_HARDWARE1 *ivhd; 411 int unit; 412 413 if (acpi_get_handle(dev) != NULL) 414 return (ENXIO); 415 416 unit = device_get_unit(dev); 417 KASSERT((unit < ivhd_count), 418 ("ivhd unit %d > count %d", unit, ivhd_count)); 419 ivhd = ivhd_hdrs[unit]; 420 KASSERT(ivhd, ("ivhd is NULL")); 421 422 switch (ivhd->Header.Type) { 423 case IVRS_TYPE_HARDWARE_EFR: 424 device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR"); 425 break; 426 427 case IVRS_TYPE_HARDWARE_MIXED: 428 device_set_desc(dev, "AMD-Vi/IOMMU ivhd in mixed format"); 429 break; 430 431 case IVRS_TYPE_HARDWARE_LEGACY: 432 default: 433 device_set_desc(dev, "AMD-Vi/IOMMU ivhd"); 434 break; 435 } 436 437 return (BUS_PROBE_NOWILDCARD); 438 } 439 440 static void 441 ivhd_print_flag(device_t dev, enum IvrsType ivhd_type, uint8_t flag) 442 { 443 /* 444 * IVHD lgeacy type has two extra high bits in flag which has 445 * been moved to EFR for non-legacy device. 446 */ 447 switch (ivhd_type) { 448 case IVRS_TYPE_HARDWARE_LEGACY: 449 device_printf(dev, "Flag:%b\n", flag, 450 "\020" 451 "\001HtTunEn" 452 "\002PassPW" 453 "\003ResPassPW" 454 "\004Isoc" 455 "\005IotlbSup" 456 "\006Coherent" 457 "\007PreFSup" 458 "\008PPRSup"); 459 break; 460 461 case IVRS_TYPE_HARDWARE_EFR: 462 case IVRS_TYPE_HARDWARE_MIXED: 463 device_printf(dev, "Flag:%b\n", flag, 464 "\020" 465 "\001HtTunEn" 466 "\002PassPW" 467 "\003ResPassPW" 468 "\004Isoc" 469 "\005IotlbSup" 470 "\006Coherent"); 471 break; 472 473 default: 474 device_printf(dev, "Can't decode flag of ivhd type :0x%x\n", 475 ivhd_type); 476 break; 477 } 478 } 479 480 /* 481 * Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40). 482 */ 483 static void 484 ivhd_print_feature(device_t dev, enum IvrsType ivhd_type, uint32_t feature) 485 { 486 switch (ivhd_type) { 487 case IVRS_TYPE_HARDWARE_LEGACY: 488 device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d" 489 " MsiNumPPR = %d PNBanks= %d PNCounters= %d\n", 490 ivhd_type, 491 REG_BITS(feature, 31, 30), 492 REG_BITS(feature, 29, 28), 493 REG_BITS(feature, 27, 23), 494 REG_BITS(feature, 22, 17), 495 REG_BITS(feature, 16, 13)); 496 device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n", 497 REG_BITS(feature, 12, 8), 498 REG_BITS(feature, 4, 3), 499 feature, 500 "\020" 501 "\002NXSup" 502 "\003GTSup" 503 "\004<b4>" 504 "\005IASup" 505 "\006GASup" 506 "\007HESup"); 507 break; 508 509 /* Fewer features or attributes are reported in non-legacy type. */ 510 case IVRS_TYPE_HARDWARE_EFR: 511 case IVRS_TYPE_HARDWARE_MIXED: 512 device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d" 513 " PNBanks= %d PNCounters= %d\n", 514 ivhd_type, 515 REG_BITS(feature, 27, 23), 516 REG_BITS(feature, 22, 17), 517 REG_BITS(feature, 16, 13)); 518 break; 519 520 default: /* Other ivhd type features are not decoded. */ 521 device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type); 522 } 523 } 524 525 /* Print extended features of IOMMU. */ 526 static void 527 ivhd_print_ext_feature(device_t dev, uint64_t ext_feature) 528 { 529 uint32_t ext_low, ext_high; 530 531 if (!ext_feature) 532 return; 533 534 ext_low = ext_feature; 535 device_printf(dev, "Extended features[31:0]:%b " 536 "HATS = 0x%x GATS = 0x%x " 537 "GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x " 538 "GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n", 539 (int)ext_low, 540 "\020" 541 "\001PreFSup" 542 "\002PPRSup" 543 "\003<b2>" 544 "\004NXSup" 545 "\005GTSup" 546 "\006<b5>" 547 "\007IASup" 548 "\008GASup" 549 "\009HESup" 550 "\010PCSup", 551 REG_BITS(ext_low, 11, 10), 552 REG_BITS(ext_low, 13, 12), 553 REG_BITS(ext_low, 15, 14), 554 REG_BITS(ext_low, 17, 16), 555 REG_BITS(ext_low, 20, 18), 556 REG_BITS(ext_low, 23, 21), 557 REG_BITS(ext_low, 25, 24), 558 REG_BITS(ext_low, 29, 28)); 559 560 ext_high = ext_feature >> 32; 561 device_printf(dev, "Extended features[62:32]:%b " 562 "Max PASID: 0x%x DevTblSegSup = 0x%x " 563 "MarcSup = 0x%x\n", 564 (int)(ext_high), 565 "\020" 566 "\006USSup" 567 "\009PprOvrflwEarlySup" 568 "\010PPRAutoRspSup" 569 "\013BlKStopMrkSup" 570 "\014PerfOptSup" 571 "\015MsiCapMmioSup" 572 "\017GIOSup" 573 "\018HASup" 574 "\019EPHSup" 575 "\020AttrFWSup" 576 "\021HDSup" 577 "\023InvIotlbSup", 578 REG_BITS(ext_high, 5, 0), 579 REG_BITS(ext_high, 8, 7), 580 REG_BITS(ext_high, 11, 10)); 581 } 582 583 static int 584 ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE1 * ivhd) 585 { 586 device_t dev; 587 int max_ptp_level; 588 589 dev = softc->dev; 590 591 ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag); 592 ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature); 593 ivhd_print_ext_feature(dev, softc->ext_feature); 594 max_ptp_level = 7; 595 /* Make sure device support minimum page level as requested by user. */ 596 if (max_ptp_level < amdvi_ptp_level) { 597 device_printf(dev, "insufficient PTP level:%d\n", 598 max_ptp_level); 599 return (EINVAL); 600 } else { 601 device_printf(softc->dev, "supported paging level:%d, will use only: %d\n", 602 max_ptp_level, amdvi_ptp_level); 603 } 604 605 device_printf(softc->dev, "device range: 0x%x - 0x%x\n", 606 softc->start_dev_rid, softc->end_dev_rid); 607 608 return (0); 609 } 610 611 static int 612 ivhd_attach(device_t dev) 613 { 614 ACPI_IVRS_HARDWARE1 *ivhd; 615 ACPI_IVRS_HARDWARE2 *ivhd_efr; 616 struct amdvi_softc *softc; 617 int status, unit; 618 619 unit = device_get_unit(dev); 620 KASSERT((unit < ivhd_count), 621 ("ivhd unit %d > count %d", unit, ivhd_count)); 622 /* Make sure its same device for which attach is called. */ 623 KASSERT((ivhd_devs[unit] == dev), 624 ("Not same device old %p new %p", ivhd_devs[unit], dev)); 625 626 softc = device_get_softc(dev); 627 softc->dev = dev; 628 ivhd = ivhd_hdrs[unit]; 629 KASSERT(ivhd, ("ivhd is NULL")); 630 631 softc->ivhd_type = ivhd->Header.Type; 632 softc->pci_seg = ivhd->PciSegmentGroup; 633 softc->pci_rid = ivhd->Header.DeviceId; 634 softc->ivhd_flag = ivhd->Header.Flags; 635 /* 636 * On lgeacy IVHD type(0x10), it is documented as feature 637 * but in newer type it is attribute. 638 */ 639 softc->ivhd_feature = ivhd->FeatureReporting; 640 /* 641 * PCI capability has more capabilities that are not part of IVRS. 642 */ 643 softc->cap_off = ivhd->CapabilityOffset; 644 645 #ifdef notyet 646 /* IVHD Info bit[4:0] is event MSI/X number. */ 647 softc->event_msix = ivhd->Info & 0x1F; 648 #endif 649 switch (ivhd->Header.Type) { 650 case IVRS_TYPE_HARDWARE_EFR: 651 case IVRS_TYPE_HARDWARE_MIXED: 652 ivhd_efr = (ACPI_IVRS_HARDWARE2 *)ivhd; 653 softc->ext_feature = ivhd_efr->EfrRegisterImage; 654 break; 655 } 656 657 softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress); 658 status = ivhd_dev_parse(ivhd, softc); 659 if (status != 0) { 660 device_printf(dev, 661 "endpoint device parsing error=%d\n", status); 662 } 663 664 status = ivhd_print_cap(softc, ivhd); 665 if (status != 0) { 666 return (status); 667 } 668 669 status = amdvi_setup_hw(softc); 670 if (status != 0) { 671 device_printf(dev, "couldn't be initialised, error=%d\n", 672 status); 673 return (status); 674 } 675 676 return (0); 677 } 678 679 static int 680 ivhd_detach(device_t dev) 681 { 682 struct amdvi_softc *softc; 683 684 softc = device_get_softc(dev); 685 686 amdvi_teardown_hw(softc); 687 688 /* 689 * XXX: delete the device. 690 * don't allow detach, return EBUSY. 691 */ 692 return (0); 693 } 694 695 static int 696 ivhd_suspend(device_t dev) 697 { 698 699 return (0); 700 } 701 702 static int 703 ivhd_resume(device_t dev) 704 { 705 706 return (0); 707 } 708 709 static device_method_t ivhd_methods[] = { 710 DEVMETHOD(device_identify, ivhd_identify), 711 DEVMETHOD(device_probe, ivhd_probe), 712 DEVMETHOD(device_attach, ivhd_attach), 713 DEVMETHOD(device_detach, ivhd_detach), 714 DEVMETHOD(device_suspend, ivhd_suspend), 715 DEVMETHOD(device_resume, ivhd_resume), 716 DEVMETHOD_END 717 }; 718 719 static driver_t ivhd_driver = { 720 "ivhd", 721 ivhd_methods, 722 sizeof(struct amdvi_softc), 723 }; 724 725 static devclass_t ivhd_devclass; 726 727 /* 728 * Load this module at the end after PCI re-probing to configure interrupt. 729 */ 730 DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, ivhd_devclass, 0, 0, 731 SI_ORDER_ANY); 732 MODULE_DEPEND(ivhd, acpi, 1, 1, 1); 733 MODULE_DEPEND(ivhd, pci, 1, 1, 1); 734