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