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