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