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