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; 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 int *count; 138 139 count = (int *)arg; 140 if (ivrs_is_ivhd(ivrs_he->Type)) 141 (*count)++; 142 143 return (1); 144 } 145 146 struct find_ivrs_hdr_args { 147 int i; 148 ACPI_IVRS_HEADER *ptr; 149 }; 150 151 static int 152 ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args) 153 { 154 struct find_ivrs_hdr_args *fi; 155 156 fi = (struct find_ivrs_hdr_args *)args; 157 if (ivrs_is_ivhd(ivrs_hdr->Type)) { 158 if (fi->i == 0) { 159 fi->ptr = ivrs_hdr; 160 return (0); 161 } 162 fi->i--; 163 } 164 165 return (1); 166 } 167 168 static ACPI_IVRS_HARDWARE1 * 169 ivhd_find_by_index(int idx) 170 { 171 struct find_ivrs_hdr_args fi; 172 173 fi.i = idx; 174 fi.ptr = NULL; 175 176 ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi); 177 178 return ((ACPI_IVRS_HARDWARE1 *)fi.ptr); 179 } 180 181 static void 182 ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id, 183 uint32_t end_id, uint8_t cfg, bool ats) 184 { 185 struct ivhd_dev_cfg *dev_cfg; 186 187 /* If device doesn't have special data, don't add it. */ 188 if (!cfg) 189 return; 190 191 dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++]; 192 dev_cfg->start_id = start_id; 193 dev_cfg->end_id = end_id; 194 dev_cfg->data = cfg; 195 dev_cfg->enable_ats = ats; 196 } 197 198 /* 199 * Record device attributes as suggested by BIOS. 200 */ 201 static int 202 ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc) 203 { 204 ACPI_IVRS_DE_HEADER *de; 205 uint8_t *p, *end; 206 int range_start_id = 0, range_end_id = 0; 207 uint32_t *extended; 208 uint8_t all_data = 0, range_data = 0; 209 bool range_enable_ats = false, enable_ats; 210 211 softc->start_dev_rid = ~0; 212 softc->end_dev_rid = 0; 213 214 switch (ivhd->Header.Type) { 215 case IVRS_TYPE_HARDWARE_LEGACY: 216 p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1); 217 break; 218 219 case IVRS_TYPE_HARDWARE_EFR: 220 case IVRS_TYPE_HARDWARE_MIXED: 221 p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2); 222 break; 223 224 default: 225 device_printf(softc->dev, 226 "unknown type: 0x%x\n", ivhd->Header.Type); 227 return (-1); 228 } 229 230 end = (uint8_t *)ivhd + ivhd->Header.Length; 231 232 while (p < end) { 233 de = (ACPI_IVRS_DE_HEADER *)p; 234 softc->start_dev_rid = MIN(softc->start_dev_rid, de->Id); 235 softc->end_dev_rid = MAX(softc->end_dev_rid, de->Id); 236 switch (de->Type) { 237 case ACPI_IVRS_TYPE_ALL: 238 all_data = de->DataSetting; 239 break; 240 241 case ACPI_IVRS_TYPE_SELECT: 242 case ACPI_IVRS_TYPE_ALIAS_SELECT: 243 case ACPI_IVRS_TYPE_EXT_SELECT: 244 enable_ats = false; 245 if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) { 246 extended = (uint32_t *)(de + 1); 247 enable_ats = 248 (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? 249 false : true; 250 } 251 ivhd_dev_add_entry(softc, de->Id, de->Id, 252 de->DataSetting | all_data, enable_ats); 253 break; 254 255 case ACPI_IVRS_TYPE_START: 256 case ACPI_IVRS_TYPE_ALIAS_START: 257 case ACPI_IVRS_TYPE_EXT_START: 258 range_start_id = de->Id; 259 range_data = de->DataSetting; 260 if (de->Type == ACPI_IVRS_TYPE_EXT_START) { 261 extended = (uint32_t *)(de + 1); 262 range_enable_ats = 263 (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? 264 false : true; 265 } 266 break; 267 268 case ACPI_IVRS_TYPE_END: 269 range_end_id = de->Id; 270 ivhd_dev_add_entry(softc, range_start_id, range_end_id, 271 range_data | all_data, range_enable_ats); 272 range_start_id = range_end_id = 0; 273 range_data = 0; 274 all_data = 0; 275 break; 276 277 case ACPI_IVRS_TYPE_PAD4: 278 break; 279 280 case ACPI_IVRS_TYPE_SPECIAL: 281 /* HPET or IOAPIC */ 282 break; 283 default: 284 if ((de->Type < 5) || 285 (de->Type >= ACPI_IVRS_TYPE_PAD8)) 286 device_printf(softc->dev, 287 "Unknown dev entry:0x%x\n", de->Type); 288 } 289 290 if (softc->dev_cfg_cnt > 291 (sizeof(softc->dev_cfg) / sizeof(softc->dev_cfg[0]))) { 292 device_printf(softc->dev, 293 "WARN Too many device entries.\n"); 294 return (EINVAL); 295 } 296 if (de->Type < 0x40) 297 p += sizeof(ACPI_IVRS_DEVICE4); 298 else if (de->Type < 0x80) 299 p += sizeof(ACPI_IVRS_DEVICE8A); 300 else { 301 printf("Variable size IVHD type 0x%x not supported\n", 302 de->Type); 303 break; 304 } 305 } 306 307 KASSERT((softc->end_dev_rid >= softc->start_dev_rid), 308 ("Device end[0x%x] < start[0x%x.\n", 309 softc->end_dev_rid, softc->start_dev_rid)); 310 311 return (0); 312 } 313 314 static bool 315 ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new) 316 { 317 if (old->DeviceId == new->DeviceId) { 318 /* 319 * Newer IVRS header type take precedence. 320 */ 321 if (old->Type == IVRS_TYPE_HARDWARE_LEGACY && 322 ((new->Type == IVRS_TYPE_HARDWARE_EFR) || 323 (new->Type == IVRS_TYPE_HARDWARE_MIXED))) 324 return (true); 325 326 /* 327 * Mixed format IVHD header type take precedence 328 * over fixed format IVHD header types. 329 */ 330 if (old->Type == IVRS_TYPE_HARDWARE_EFR && 331 new->Type == IVRS_TYPE_HARDWARE_MIXED) 332 return (true); 333 } 334 335 return (false); 336 } 337 338 static void 339 ivhd_identify(driver_t *driver, device_t parent) 340 { 341 ACPI_TABLE_IVRS *ivrs; 342 ACPI_IVRS_HARDWARE1 *ivhd; 343 ACPI_STATUS status; 344 int i, j, count = 0; 345 uint32_t ivrs_ivinfo; 346 347 if (acpi_disabled("ivhd")) 348 return; 349 350 status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); 351 if (ACPI_FAILURE(status)) 352 return; 353 354 if (ivrs->Header.Length == 0) { 355 return; 356 } 357 358 ivrs_ivinfo = ivrs->Info; 359 printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d" 360 " flags:%b\n", 361 REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8), 362 REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22), 363 "\020\001EFRSup"); 364 365 ivrs_hdr_iterate_tbl(ivhd_count_iter, &count); 366 if (!count) 367 return; 368 369 ivhd_hdrs = malloc(sizeof(void *) * count, M_DEVBUF, 370 M_WAITOK | M_ZERO); 371 for (i = 0; i < count; i++) { 372 ivhd = ivhd_find_by_index(i); 373 KASSERT(ivhd, ("ivhd%d is NULL\n", i)); 374 375 /* 376 * Scan for presence of legacy and non-legacy device type 377 * for same IOMMU device and override the old one. 378 * 379 * If there is no existing IVHD to the same IOMMU device, 380 * the IVHD header pointer is appended. 381 */ 382 for (j = 0; j < ivhd_count; j++) { 383 if (ivhd_is_newer(&ivhd_hdrs[j]->Header, &ivhd->Header)) 384 break; 385 } 386 ivhd_hdrs[j] = ivhd; 387 if (j == ivhd_count) 388 ivhd_count++; 389 } 390 391 ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF, 392 M_WAITOK | M_ZERO); 393 for (i = 0, j = 0; i < ivhd_count; i++) { 394 ivhd = ivhd_hdrs[i]; 395 KASSERT(ivhd, ("ivhd%d is NULL\n", i)); 396 397 /* 398 * Use a high order to ensure that this driver is probed after 399 * the Host-PCI bridge and the root PCI bus. 400 */ 401 ivhd_devs[i] = BUS_ADD_CHILD(parent, 402 ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i); 403 404 /* 405 * XXX: In case device was not destroyed before, add will fail. 406 * locate the old device instance. 407 */ 408 if (ivhd_devs[i] == NULL) { 409 ivhd_devs[i] = device_find_child(parent, "ivhd", i); 410 if (ivhd_devs[i] == NULL) { 411 printf("AMD-Vi: cant find ivhd%d\n", i); 412 break; 413 } 414 } 415 j++; 416 } 417 418 /* 419 * Update device count in case failed to attach. 420 */ 421 ivhd_count = j; 422 } 423 424 static int 425 ivhd_probe(device_t dev) 426 { 427 ACPI_IVRS_HARDWARE1 *ivhd; 428 int unit; 429 430 if (acpi_get_handle(dev) != NULL) 431 return (ENXIO); 432 433 unit = device_get_unit(dev); 434 KASSERT((unit < ivhd_count), 435 ("ivhd unit %d > count %d", unit, ivhd_count)); 436 ivhd = ivhd_hdrs[unit]; 437 KASSERT(ivhd, ("ivhd is NULL")); 438 439 switch (ivhd->Header.Type) { 440 case IVRS_TYPE_HARDWARE_EFR: 441 device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR"); 442 break; 443 444 case IVRS_TYPE_HARDWARE_MIXED: 445 device_set_desc(dev, "AMD-Vi/IOMMU ivhd in mixed format"); 446 break; 447 448 case IVRS_TYPE_HARDWARE_LEGACY: 449 default: 450 device_set_desc(dev, "AMD-Vi/IOMMU ivhd"); 451 break; 452 } 453 454 return (BUS_PROBE_NOWILDCARD); 455 } 456 457 static void 458 ivhd_print_flag(device_t dev, enum IvrsType ivhd_type, uint8_t flag) 459 { 460 /* 461 * IVHD lgeacy type has two extra high bits in flag which has 462 * been moved to EFR for non-legacy device. 463 */ 464 switch (ivhd_type) { 465 case IVRS_TYPE_HARDWARE_LEGACY: 466 device_printf(dev, "Flag:%b\n", flag, 467 "\020" 468 "\001HtTunEn" 469 "\002PassPW" 470 "\003ResPassPW" 471 "\004Isoc" 472 "\005IotlbSup" 473 "\006Coherent" 474 "\007PreFSup" 475 "\008PPRSup"); 476 break; 477 478 case IVRS_TYPE_HARDWARE_EFR: 479 case IVRS_TYPE_HARDWARE_MIXED: 480 device_printf(dev, "Flag:%b\n", flag, 481 "\020" 482 "\001HtTunEn" 483 "\002PassPW" 484 "\003ResPassPW" 485 "\004Isoc" 486 "\005IotlbSup" 487 "\006Coherent"); 488 break; 489 490 default: 491 device_printf(dev, "Can't decode flag of ivhd type :0x%x\n", 492 ivhd_type); 493 break; 494 } 495 } 496 497 /* 498 * Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40). 499 */ 500 static void 501 ivhd_print_feature(device_t dev, enum IvrsType ivhd_type, uint32_t feature) 502 { 503 switch (ivhd_type) { 504 case IVRS_TYPE_HARDWARE_LEGACY: 505 device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d" 506 " MsiNumPPR = %d PNBanks= %d PNCounters= %d\n", 507 ivhd_type, 508 REG_BITS(feature, 31, 30), 509 REG_BITS(feature, 29, 28), 510 REG_BITS(feature, 27, 23), 511 REG_BITS(feature, 22, 17), 512 REG_BITS(feature, 16, 13)); 513 device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n", 514 REG_BITS(feature, 12, 8), 515 REG_BITS(feature, 4, 3), 516 feature, 517 "\020" 518 "\002NXSup" 519 "\003GTSup" 520 "\004<b4>" 521 "\005IASup" 522 "\006GASup" 523 "\007HESup"); 524 break; 525 526 /* Fewer features or attributes are reported in non-legacy type. */ 527 case IVRS_TYPE_HARDWARE_EFR: 528 case IVRS_TYPE_HARDWARE_MIXED: 529 device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d" 530 " PNBanks= %d PNCounters= %d\n", 531 ivhd_type, 532 REG_BITS(feature, 27, 23), 533 REG_BITS(feature, 22, 17), 534 REG_BITS(feature, 16, 13)); 535 break; 536 537 default: /* Other ivhd type features are not decoded. */ 538 device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type); 539 } 540 } 541 542 /* Print extended features of IOMMU. */ 543 static void 544 ivhd_print_ext_feature(device_t dev, uint64_t ext_feature) 545 { 546 uint32_t ext_low, ext_high; 547 548 if (!ext_feature) 549 return; 550 551 ext_low = ext_feature; 552 device_printf(dev, "Extended features[31:0]:%b " 553 "HATS = 0x%x GATS = 0x%x " 554 "GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x " 555 "GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n", 556 (int)ext_low, 557 "\020" 558 "\001PreFSup" 559 "\002PPRSup" 560 "\003<b2>" 561 "\004NXSup" 562 "\005GTSup" 563 "\006<b5>" 564 "\007IASup" 565 "\008GASup" 566 "\009HESup" 567 "\010PCSup", 568 REG_BITS(ext_low, 11, 10), 569 REG_BITS(ext_low, 13, 12), 570 REG_BITS(ext_low, 15, 14), 571 REG_BITS(ext_low, 17, 16), 572 REG_BITS(ext_low, 20, 18), 573 REG_BITS(ext_low, 23, 21), 574 REG_BITS(ext_low, 25, 24), 575 REG_BITS(ext_low, 29, 28)); 576 577 ext_high = ext_feature >> 32; 578 device_printf(dev, "Extended features[62:32]:%b " 579 "Max PASID: 0x%x DevTblSegSup = 0x%x " 580 "MarcSup = 0x%x\n", 581 (int)(ext_high), 582 "\020" 583 "\006USSup" 584 "\009PprOvrflwEarlySup" 585 "\010PPRAutoRspSup" 586 "\013BlKStopMrkSup" 587 "\014PerfOptSup" 588 "\015MsiCapMmioSup" 589 "\017GIOSup" 590 "\018HASup" 591 "\019EPHSup" 592 "\020AttrFWSup" 593 "\021HDSup" 594 "\023InvIotlbSup", 595 REG_BITS(ext_high, 5, 0), 596 REG_BITS(ext_high, 8, 7), 597 REG_BITS(ext_high, 11, 10)); 598 } 599 600 static int 601 ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE1 * ivhd) 602 { 603 device_t dev; 604 int max_ptp_level; 605 606 dev = softc->dev; 607 608 ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag); 609 ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature); 610 ivhd_print_ext_feature(dev, softc->ext_feature); 611 max_ptp_level = 7; 612 /* Make sure device support minimum page level as requested by user. */ 613 if (max_ptp_level < amdvi_ptp_level) { 614 device_printf(dev, "insufficient PTP level:%d\n", 615 max_ptp_level); 616 return (EINVAL); 617 } else { 618 device_printf(softc->dev, "supported paging level:%d, will use only: %d\n", 619 max_ptp_level, amdvi_ptp_level); 620 } 621 622 device_printf(softc->dev, "device range: 0x%x - 0x%x\n", 623 softc->start_dev_rid, softc->end_dev_rid); 624 625 return (0); 626 } 627 628 static int 629 ivhd_attach(device_t dev) 630 { 631 ACPI_IVRS_HARDWARE1 *ivhd; 632 ACPI_IVRS_HARDWARE2 *ivhd_efr; 633 struct amdvi_softc *softc; 634 int status, unit; 635 636 unit = device_get_unit(dev); 637 KASSERT((unit < ivhd_count), 638 ("ivhd unit %d > count %d", unit, ivhd_count)); 639 /* Make sure its same device for which attach is called. */ 640 KASSERT((ivhd_devs[unit] == dev), 641 ("Not same device old %p new %p", ivhd_devs[unit], dev)); 642 643 softc = device_get_softc(dev); 644 softc->dev = dev; 645 ivhd = ivhd_hdrs[unit]; 646 KASSERT(ivhd, ("ivhd is NULL")); 647 softc->pci_dev = pci_find_bsf(PCI_RID2BUS(ivhd->Header.DeviceId), 648 PCI_RID2SLOT(ivhd->Header.DeviceId), 649 PCI_RID2FUNC(ivhd->Header.DeviceId)); 650 651 softc->ivhd_type = ivhd->Header.Type; 652 softc->pci_seg = ivhd->PciSegmentGroup; 653 softc->pci_rid = ivhd->Header.DeviceId; 654 softc->ivhd_flag = ivhd->Header.Flags; 655 /* 656 * On lgeacy IVHD type(0x10), it is documented as feature 657 * but in newer type it is attribute. 658 */ 659 softc->ivhd_feature = ivhd->FeatureReporting; 660 /* 661 * PCI capability has more capabilities that are not part of IVRS. 662 */ 663 softc->cap_off = ivhd->CapabilityOffset; 664 665 #ifdef notyet 666 /* IVHD Info bit[4:0] is event MSI/X number. */ 667 softc->event_msix = ivhd->Info & 0x1F; 668 #endif 669 switch (ivhd->Header.Type) { 670 case IVRS_TYPE_HARDWARE_EFR: 671 case IVRS_TYPE_HARDWARE_MIXED: 672 ivhd_efr = (ACPI_IVRS_HARDWARE2 *)ivhd; 673 softc->ext_feature = ivhd_efr->EfrRegisterImage; 674 break; 675 } 676 677 softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress); 678 status = ivhd_dev_parse(ivhd, softc); 679 if (status != 0) { 680 device_printf(dev, 681 "endpoint device parsing error=%d\n", status); 682 } 683 684 status = ivhd_print_cap(softc, ivhd); 685 if (status != 0) { 686 return (status); 687 } 688 689 status = amdvi_setup_hw(softc); 690 if (status != 0) { 691 device_printf(dev, "couldn't be initialised, error=%d\n", 692 status); 693 return (status); 694 } 695 696 return (0); 697 } 698 699 static int 700 ivhd_detach(device_t dev) 701 { 702 struct amdvi_softc *softc; 703 704 softc = device_get_softc(dev); 705 706 amdvi_teardown_hw(softc); 707 708 /* 709 * XXX: delete the device. 710 * don't allow detach, return EBUSY. 711 */ 712 return (0); 713 } 714 715 static int 716 ivhd_suspend(device_t dev) 717 { 718 719 return (0); 720 } 721 722 static int 723 ivhd_resume(device_t dev) 724 { 725 726 return (0); 727 } 728 729 static device_method_t ivhd_methods[] = { 730 DEVMETHOD(device_identify, ivhd_identify), 731 DEVMETHOD(device_probe, ivhd_probe), 732 DEVMETHOD(device_attach, ivhd_attach), 733 DEVMETHOD(device_detach, ivhd_detach), 734 DEVMETHOD(device_suspend, ivhd_suspend), 735 DEVMETHOD(device_resume, ivhd_resume), 736 DEVMETHOD_END 737 }; 738 739 static driver_t ivhd_driver = { 740 "ivhd", 741 ivhd_methods, 742 sizeof(struct amdvi_softc), 743 }; 744 745 static devclass_t ivhd_devclass; 746 747 /* 748 * Load this module at the end after PCI re-probing to configure interrupt. 749 */ 750 DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, ivhd_devclass, 0, 0, 751 SI_ORDER_ANY); 752 MODULE_DEPEND(ivhd, acpi, 1, 1, 1); 753 MODULE_DEPEND(ivhd, pci, 1, 1, 1); 754