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