diff options
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r-- | drivers/pci/dmar.c | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 14bbaa17e2ca..e5f8fc164fd3 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -175,15 +175,6 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) | |||
175 | int ret = 0; | 175 | int ret = 0; |
176 | 176 | ||
177 | drhd = (struct acpi_dmar_hardware_unit *)header; | 177 | drhd = (struct acpi_dmar_hardware_unit *)header; |
178 | if (!drhd->address) { | ||
179 | /* Promote an attitude of violence to a BIOS engineer today */ | ||
180 | WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" | ||
181 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
182 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
183 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
184 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
185 | return -ENODEV; | ||
186 | } | ||
187 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); | 178 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); |
188 | if (!dmaru) | 179 | if (!dmaru) |
189 | return -ENOMEM; | 180 | return -ENOMEM; |
@@ -354,6 +345,7 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | |||
354 | struct acpi_dmar_hardware_unit *drhd; | 345 | struct acpi_dmar_hardware_unit *drhd; |
355 | struct acpi_dmar_reserved_memory *rmrr; | 346 | struct acpi_dmar_reserved_memory *rmrr; |
356 | struct acpi_dmar_atsr *atsr; | 347 | struct acpi_dmar_atsr *atsr; |
348 | struct acpi_dmar_rhsa *rhsa; | ||
357 | 349 | ||
358 | switch (header->type) { | 350 | switch (header->type) { |
359 | case ACPI_DMAR_TYPE_HARDWARE_UNIT: | 351 | case ACPI_DMAR_TYPE_HARDWARE_UNIT: |
@@ -375,6 +367,12 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | |||
375 | atsr = container_of(header, struct acpi_dmar_atsr, header); | 367 | atsr = container_of(header, struct acpi_dmar_atsr, header); |
376 | printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); | 368 | printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); |
377 | break; | 369 | break; |
370 | case ACPI_DMAR_HARDWARE_AFFINITY: | ||
371 | rhsa = container_of(header, struct acpi_dmar_rhsa, header); | ||
372 | printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n", | ||
373 | (unsigned long long)rhsa->base_address, | ||
374 | rhsa->proximity_domain); | ||
375 | break; | ||
378 | } | 376 | } |
379 | } | 377 | } |
380 | 378 | ||
@@ -459,9 +457,13 @@ parse_dmar_table(void) | |||
459 | ret = dmar_parse_one_atsr(entry_header); | 457 | ret = dmar_parse_one_atsr(entry_header); |
460 | #endif | 458 | #endif |
461 | break; | 459 | break; |
460 | case ACPI_DMAR_HARDWARE_AFFINITY: | ||
461 | /* We don't do anything with RHSA (yet?) */ | ||
462 | break; | ||
462 | default: | 463 | default: |
463 | printk(KERN_WARNING PREFIX | 464 | printk(KERN_WARNING PREFIX |
464 | "Unknown DMAR structure type\n"); | 465 | "Unknown DMAR structure type %d\n", |
466 | entry_header->type); | ||
465 | ret = 0; /* for forward compatibility */ | 467 | ret = 0; /* for forward compatibility */ |
466 | break; | 468 | break; |
467 | } | 469 | } |
@@ -580,12 +582,50 @@ int __init dmar_table_init(void) | |||
580 | return 0; | 582 | return 0; |
581 | } | 583 | } |
582 | 584 | ||
585 | int __init check_zero_address(void) | ||
586 | { | ||
587 | struct acpi_table_dmar *dmar; | ||
588 | struct acpi_dmar_header *entry_header; | ||
589 | struct acpi_dmar_hardware_unit *drhd; | ||
590 | |||
591 | dmar = (struct acpi_table_dmar *)dmar_tbl; | ||
592 | entry_header = (struct acpi_dmar_header *)(dmar + 1); | ||
593 | |||
594 | while (((unsigned long)entry_header) < | ||
595 | (((unsigned long)dmar) + dmar_tbl->length)) { | ||
596 | /* Avoid looping forever on bad ACPI tables */ | ||
597 | if (entry_header->length == 0) { | ||
598 | printk(KERN_WARNING PREFIX | ||
599 | "Invalid 0-length structure\n"); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { | ||
604 | drhd = (void *)entry_header; | ||
605 | if (!drhd->address) { | ||
606 | /* Promote an attitude of violence to a BIOS engineer today */ | ||
607 | WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" | ||
608 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
609 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
610 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
611 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
612 | return 0; | ||
613 | } | ||
614 | break; | ||
615 | } | ||
616 | |||
617 | entry_header = ((void *)entry_header + entry_header->length); | ||
618 | } | ||
619 | return 1; | ||
620 | } | ||
621 | |||
583 | void __init detect_intel_iommu(void) | 622 | void __init detect_intel_iommu(void) |
584 | { | 623 | { |
585 | int ret; | 624 | int ret; |
586 | 625 | ||
587 | ret = dmar_table_detect(); | 626 | ret = dmar_table_detect(); |
588 | 627 | if (ret) | |
628 | ret = check_zero_address(); | ||
589 | { | 629 | { |
590 | #ifdef CONFIG_INTR_REMAP | 630 | #ifdef CONFIG_INTR_REMAP |
591 | struct acpi_table_dmar *dmar; | 631 | struct acpi_table_dmar *dmar; |