diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/dmar.c | 59 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 18 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_ibm.c | 2 | ||||
-rw-r--r-- | drivers/pci/intel-iommu.c | 45 | ||||
-rw-r--r-- | drivers/pci/intr_remapping.c | 89 | ||||
-rw-r--r-- | drivers/pci/intr_remapping.h | 7 |
7 files changed, 192 insertions, 30 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 0e98f6b6f515..6cdc931f7c17 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; |
@@ -591,12 +582,53 @@ int __init dmar_table_init(void) | |||
591 | return 0; | 582 | return 0; |
592 | } | 583 | } |
593 | 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 | #ifdef CONFIG_DMAR | ||
613 | dmar_disabled = 1; | ||
614 | #endif | ||
615 | return 0; | ||
616 | } | ||
617 | break; | ||
618 | } | ||
619 | |||
620 | entry_header = ((void *)entry_header + entry_header->length); | ||
621 | } | ||
622 | return 1; | ||
623 | } | ||
624 | |||
594 | void __init detect_intel_iommu(void) | 625 | void __init detect_intel_iommu(void) |
595 | { | 626 | { |
596 | int ret; | 627 | int ret; |
597 | 628 | ||
598 | ret = dmar_table_detect(); | 629 | ret = dmar_table_detect(); |
599 | 630 | if (ret) | |
631 | ret = check_zero_address(); | ||
600 | { | 632 | { |
601 | #ifdef CONFIG_INTR_REMAP | 633 | #ifdef CONFIG_INTR_REMAP |
602 | struct acpi_table_dmar *dmar; | 634 | struct acpi_table_dmar *dmar; |
@@ -613,13 +645,16 @@ void __init detect_intel_iommu(void) | |||
613 | "x2apic and Intr-remapping.\n"); | 645 | "x2apic and Intr-remapping.\n"); |
614 | #endif | 646 | #endif |
615 | #ifdef CONFIG_DMAR | 647 | #ifdef CONFIG_DMAR |
616 | if (ret && !no_iommu && !iommu_detected && !swiotlb && | 648 | if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { |
617 | !dmar_disabled) { | ||
618 | iommu_detected = 1; | 649 | iommu_detected = 1; |
619 | /* Make sure ACS will be enabled */ | 650 | /* Make sure ACS will be enabled */ |
620 | pci_request_acs(); | 651 | pci_request_acs(); |
621 | } | 652 | } |
622 | #endif | 653 | #endif |
654 | #ifdef CONFIG_X86 | ||
655 | if (ret) | ||
656 | x86_init.iommu.iommu_init = intel_iommu_init; | ||
657 | #endif | ||
623 | } | 658 | } |
624 | early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); | 659 | early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); |
625 | dmar_tbl = NULL; | 660 | dmar_tbl = NULL; |
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 6833d7bdbbff..3c76fc67cf0e 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -472,7 +472,7 @@ int acpi_pci_detect_ejectable(acpi_handle handle) | |||
472 | return found; | 472 | return found; |
473 | 473 | ||
474 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, | 474 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, |
475 | check_hotplug, (void *)&found, NULL); | 475 | check_hotplug, NULL, (void *)&found, NULL); |
476 | return found; | 476 | return found; |
477 | } | 477 | } |
478 | EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable); | 478 | EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable); |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8f4a2073d83a..8e952fdab764 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -264,7 +264,7 @@ static int detect_ejectable_slots(acpi_handle handle) | |||
264 | int found = acpi_pci_detect_ejectable(handle); | 264 | int found = acpi_pci_detect_ejectable(handle); |
265 | if (!found) { | 265 | if (!found) { |
266 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 266 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
267 | is_pci_dock_device, (void *)&found, NULL); | 267 | is_pci_dock_device, NULL, (void *)&found, NULL); |
268 | } | 268 | } |
269 | return found; | 269 | return found; |
270 | } | 270 | } |
@@ -279,7 +279,7 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
279 | 279 | ||
280 | /* register all slot objects under this bridge */ | 280 | /* register all slot objects under this bridge */ |
281 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, | 281 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, |
282 | register_slot, bridge, NULL); | 282 | register_slot, NULL, bridge, NULL); |
283 | if (ACPI_FAILURE(status)) { | 283 | if (ACPI_FAILURE(status)) { |
284 | list_del(&bridge->list); | 284 | list_del(&bridge->list); |
285 | return; | 285 | return; |
@@ -441,7 +441,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
441 | 441 | ||
442 | /* search P2P bridges under this p2p bridge */ | 442 | /* search P2P bridges under this p2p bridge */ |
443 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 443 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
444 | find_p2p_bridge, NULL, NULL); | 444 | find_p2p_bridge, NULL, NULL, NULL); |
445 | if (ACPI_FAILURE(status)) | 445 | if (ACPI_FAILURE(status)) |
446 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); | 446 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |
447 | 447 | ||
@@ -479,7 +479,7 @@ static int add_bridge(acpi_handle handle) | |||
479 | 479 | ||
480 | /* search P2P bridges under this host bridge */ | 480 | /* search P2P bridges under this host bridge */ |
481 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 481 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
482 | find_p2p_bridge, NULL, NULL); | 482 | find_p2p_bridge, NULL, NULL, NULL); |
483 | 483 | ||
484 | if (ACPI_FAILURE(status)) | 484 | if (ACPI_FAILURE(status)) |
485 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); | 485 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |
@@ -563,7 +563,7 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
563 | /* cleanup p2p bridges under this P2P bridge | 563 | /* cleanup p2p bridges under this P2P bridge |
564 | in a depth-first manner */ | 564 | in a depth-first manner */ |
565 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 565 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
566 | cleanup_p2p_bridge, NULL, NULL); | 566 | cleanup_p2p_bridge, NULL, NULL, NULL); |
567 | 567 | ||
568 | bridge = acpiphp_handle_to_bridge(handle); | 568 | bridge = acpiphp_handle_to_bridge(handle); |
569 | if (bridge) | 569 | if (bridge) |
@@ -579,7 +579,7 @@ static void remove_bridge(acpi_handle handle) | |||
579 | /* cleanup p2p bridges under this host bridge | 579 | /* cleanup p2p bridges under this host bridge |
580 | in a depth-first manner */ | 580 | in a depth-first manner */ |
581 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | 581 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, |
582 | (u32)1, cleanup_p2p_bridge, NULL, NULL); | 582 | (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL); |
583 | 583 | ||
584 | /* | 584 | /* |
585 | * On root bridges with hotplug slots directly underneath (ie, | 585 | * On root bridges with hotplug slots directly underneath (ie, |
@@ -1153,7 +1153,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1153 | bridge = acpiphp_handle_to_bridge(handle); | 1153 | bridge = acpiphp_handle_to_bridge(handle); |
1154 | if (type == ACPI_NOTIFY_BUS_CHECK) { | 1154 | if (type == ACPI_NOTIFY_BUS_CHECK) { |
1155 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, | 1155 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, |
1156 | count_sub_bridges, &num_sub_bridges, NULL); | 1156 | count_sub_bridges, NULL, &num_sub_bridges, NULL); |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | if (!bridge && !num_sub_bridges) { | 1159 | if (!bridge && !num_sub_bridges) { |
@@ -1174,7 +1174,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1174 | } | 1174 | } |
1175 | if (num_sub_bridges) | 1175 | if (num_sub_bridges) |
1176 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | 1176 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, |
1177 | ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL); | 1177 | ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); |
1178 | break; | 1178 | break; |
1179 | 1179 | ||
1180 | case ACPI_NOTIFY_DEVICE_CHECK: | 1180 | case ACPI_NOTIFY_DEVICE_CHECK: |
@@ -1298,7 +1298,7 @@ int __init acpiphp_glue_init(void) | |||
1298 | int num = 0; | 1298 | int num = 0; |
1299 | 1299 | ||
1300 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 1300 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
1301 | ACPI_UINT32_MAX, find_root_bridges, &num, NULL); | 1301 | ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); |
1302 | 1302 | ||
1303 | if (num <= 0) | 1303 | if (num <= 0) |
1304 | return -1; | 1304 | return -1; |
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index e7be66dbac21..aa5df485f8cf 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c | |||
@@ -434,7 +434,7 @@ static int __init ibm_acpiphp_init(void) | |||
434 | dbg("%s\n", __func__); | 434 | dbg("%s\n", __func__); |
435 | 435 | ||
436 | if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 436 | if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
437 | ACPI_UINT32_MAX, ibm_find_acpi_device, | 437 | ACPI_UINT32_MAX, ibm_find_acpi_device, NULL, |
438 | &ibm_acpi_handle, NULL) != FOUND_APCI) { | 438 | &ibm_acpi_handle, NULL) != FOUND_APCI) { |
439 | err("%s: acpi_walk_namespace failed\n", __func__); | 439 | err("%s: acpi_walk_namespace failed\n", __func__); |
440 | retval = -ENODEV; | 440 | retval = -ENODEV; |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index b8802ae4bcdb..8d6159426311 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -2767,7 +2767,15 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size, | |||
2767 | 2767 | ||
2768 | size = PAGE_ALIGN(size); | 2768 | size = PAGE_ALIGN(size); |
2769 | order = get_order(size); | 2769 | order = get_order(size); |
2770 | flags &= ~(GFP_DMA | GFP_DMA32); | 2770 | |
2771 | if (!iommu_no_mapping(hwdev)) | ||
2772 | flags &= ~(GFP_DMA | GFP_DMA32); | ||
2773 | else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) { | ||
2774 | if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32)) | ||
2775 | flags |= GFP_DMA; | ||
2776 | else | ||
2777 | flags |= GFP_DMA32; | ||
2778 | } | ||
2771 | 2779 | ||
2772 | vaddr = (void *)__get_free_pages(flags, order); | 2780 | vaddr = (void *)__get_free_pages(flags, order); |
2773 | if (!vaddr) | 2781 | if (!vaddr) |
@@ -3207,6 +3215,33 @@ static int __init init_iommu_sysfs(void) | |||
3207 | } | 3215 | } |
3208 | #endif /* CONFIG_PM */ | 3216 | #endif /* CONFIG_PM */ |
3209 | 3217 | ||
3218 | /* | ||
3219 | * Here we only respond to action of unbound device from driver. | ||
3220 | * | ||
3221 | * Added device is not attached to its DMAR domain here yet. That will happen | ||
3222 | * when mapping the device to iova. | ||
3223 | */ | ||
3224 | static int device_notifier(struct notifier_block *nb, | ||
3225 | unsigned long action, void *data) | ||
3226 | { | ||
3227 | struct device *dev = data; | ||
3228 | struct pci_dev *pdev = to_pci_dev(dev); | ||
3229 | struct dmar_domain *domain; | ||
3230 | |||
3231 | domain = find_domain(pdev); | ||
3232 | if (!domain) | ||
3233 | return 0; | ||
3234 | |||
3235 | if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) | ||
3236 | domain_remove_one_dev_info(domain, pdev); | ||
3237 | |||
3238 | return 0; | ||
3239 | } | ||
3240 | |||
3241 | static struct notifier_block device_nb = { | ||
3242 | .notifier_call = device_notifier, | ||
3243 | }; | ||
3244 | |||
3210 | int __init intel_iommu_init(void) | 3245 | int __init intel_iommu_init(void) |
3211 | { | 3246 | { |
3212 | int ret = 0; | 3247 | int ret = 0; |
@@ -3231,7 +3266,7 @@ int __init intel_iommu_init(void) | |||
3231 | * Check the need for DMA-remapping initialization now. | 3266 | * Check the need for DMA-remapping initialization now. |
3232 | * Above initialization will also be used by Interrupt-remapping. | 3267 | * Above initialization will also be used by Interrupt-remapping. |
3233 | */ | 3268 | */ |
3234 | if (no_iommu || swiotlb || dmar_disabled) | 3269 | if (no_iommu || dmar_disabled) |
3235 | return -ENODEV; | 3270 | return -ENODEV; |
3236 | 3271 | ||
3237 | iommu_init_mempool(); | 3272 | iommu_init_mempool(); |
@@ -3252,13 +3287,17 @@ int __init intel_iommu_init(void) | |||
3252 | "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n"); | 3287 | "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n"); |
3253 | 3288 | ||
3254 | init_timer(&unmap_timer); | 3289 | init_timer(&unmap_timer); |
3255 | force_iommu = 1; | 3290 | #ifdef CONFIG_SWIOTLB |
3291 | swiotlb = 0; | ||
3292 | #endif | ||
3256 | dma_ops = &intel_dma_ops; | 3293 | dma_ops = &intel_dma_ops; |
3257 | 3294 | ||
3258 | init_iommu_sysfs(); | 3295 | init_iommu_sysfs(); |
3259 | 3296 | ||
3260 | register_iommu(&intel_iommu_ops); | 3297 | register_iommu(&intel_iommu_ops); |
3261 | 3298 | ||
3299 | bus_register_notifier(&pci_bus_type, &device_nb); | ||
3300 | |||
3262 | return 0; | 3301 | return 0; |
3263 | } | 3302 | } |
3264 | 3303 | ||
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 3e6d8d79a09d..1487bf2be863 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/dmar.h> | 2 | #include <linux/dmar.h> |
3 | #include <linux/spinlock.h> | 3 | #include <linux/spinlock.h> |
4 | #include <linux/jiffies.h> | 4 | #include <linux/jiffies.h> |
5 | #include <linux/hpet.h> | ||
5 | #include <linux/pci.h> | 6 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 7 | #include <linux/irq.h> |
7 | #include <asm/io_apic.h> | 8 | #include <asm/io_apic.h> |
@@ -14,7 +15,8 @@ | |||
14 | #include "pci.h" | 15 | #include "pci.h" |
15 | 16 | ||
16 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 17 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
17 | static int ir_ioapic_num; | 18 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; |
19 | static int ir_ioapic_num, ir_hpet_num; | ||
18 | int intr_remapping_enabled; | 20 | int intr_remapping_enabled; |
19 | 21 | ||
20 | static int disable_intremap; | 22 | static int disable_intremap; |
@@ -343,6 +345,16 @@ int flush_irte(int irq) | |||
343 | return rc; | 345 | return rc; |
344 | } | 346 | } |
345 | 347 | ||
348 | struct intel_iommu *map_hpet_to_ir(u8 hpet_id) | ||
349 | { | ||
350 | int i; | ||
351 | |||
352 | for (i = 0; i < MAX_HPET_TBS; i++) | ||
353 | if (ir_hpet[i].id == hpet_id) | ||
354 | return ir_hpet[i].iommu; | ||
355 | return NULL; | ||
356 | } | ||
357 | |||
346 | struct intel_iommu *map_ioapic_to_ir(int apic) | 358 | struct intel_iommu *map_ioapic_to_ir(int apic) |
347 | { | 359 | { |
348 | int i; | 360 | int i; |
@@ -470,6 +482,36 @@ int set_ioapic_sid(struct irte *irte, int apic) | |||
470 | return 0; | 482 | return 0; |
471 | } | 483 | } |
472 | 484 | ||
485 | int set_hpet_sid(struct irte *irte, u8 id) | ||
486 | { | ||
487 | int i; | ||
488 | u16 sid = 0; | ||
489 | |||
490 | if (!irte) | ||
491 | return -1; | ||
492 | |||
493 | for (i = 0; i < MAX_HPET_TBS; i++) { | ||
494 | if (ir_hpet[i].id == id) { | ||
495 | sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; | ||
496 | break; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | if (sid == 0) { | ||
501 | pr_warning("Failed to set source-id of HPET block (%d)\n", id); | ||
502 | return -1; | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * Should really use SQ_ALL_16. Some platforms are broken. | ||
507 | * While we figure out the right quirks for these broken platforms, use | ||
508 | * SQ_13_IGNORE_3 for now. | ||
509 | */ | ||
510 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
473 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 515 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
474 | { | 516 | { |
475 | struct pci_dev *bridge; | 517 | struct pci_dev *bridge; |
@@ -711,6 +753,34 @@ error: | |||
711 | return -1; | 753 | return -1; |
712 | } | 754 | } |
713 | 755 | ||
756 | static void ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope, | ||
757 | struct intel_iommu *iommu) | ||
758 | { | ||
759 | struct acpi_dmar_pci_path *path; | ||
760 | u8 bus; | ||
761 | int count; | ||
762 | |||
763 | bus = scope->bus; | ||
764 | path = (struct acpi_dmar_pci_path *)(scope + 1); | ||
765 | count = (scope->length - sizeof(struct acpi_dmar_device_scope)) | ||
766 | / sizeof(struct acpi_dmar_pci_path); | ||
767 | |||
768 | while (--count > 0) { | ||
769 | /* | ||
770 | * Access PCI directly due to the PCI | ||
771 | * subsystem isn't initialized yet. | ||
772 | */ | ||
773 | bus = read_pci_config_byte(bus, path->dev, path->fn, | ||
774 | PCI_SECONDARY_BUS); | ||
775 | path++; | ||
776 | } | ||
777 | ir_hpet[ir_hpet_num].bus = bus; | ||
778 | ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->dev, path->fn); | ||
779 | ir_hpet[ir_hpet_num].iommu = iommu; | ||
780 | ir_hpet[ir_hpet_num].id = scope->enumeration_id; | ||
781 | ir_hpet_num++; | ||
782 | } | ||
783 | |||
714 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | 784 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, |
715 | struct intel_iommu *iommu) | 785 | struct intel_iommu *iommu) |
716 | { | 786 | { |
@@ -740,8 +810,8 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | |||
740 | ir_ioapic_num++; | 810 | ir_ioapic_num++; |
741 | } | 811 | } |
742 | 812 | ||
743 | static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | 813 | static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header, |
744 | struct intel_iommu *iommu) | 814 | struct intel_iommu *iommu) |
745 | { | 815 | { |
746 | struct acpi_dmar_hardware_unit *drhd; | 816 | struct acpi_dmar_hardware_unit *drhd; |
747 | struct acpi_dmar_device_scope *scope; | 817 | struct acpi_dmar_device_scope *scope; |
@@ -765,6 +835,17 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | |||
765 | drhd->address); | 835 | drhd->address); |
766 | 836 | ||
767 | ir_parse_one_ioapic_scope(scope, iommu); | 837 | ir_parse_one_ioapic_scope(scope, iommu); |
838 | } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) { | ||
839 | if (ir_hpet_num == MAX_HPET_TBS) { | ||
840 | printk(KERN_WARNING "Exceeded Max HPET blocks\n"); | ||
841 | return -1; | ||
842 | } | ||
843 | |||
844 | printk(KERN_INFO "HPET id %d under DRHD base" | ||
845 | " 0x%Lx\n", scope->enumeration_id, | ||
846 | drhd->address); | ||
847 | |||
848 | ir_parse_one_hpet_scope(scope, iommu); | ||
768 | } | 849 | } |
769 | start += scope->length; | 850 | start += scope->length; |
770 | } | 851 | } |
@@ -785,7 +866,7 @@ int __init parse_ioapics_under_ir(void) | |||
785 | struct intel_iommu *iommu = drhd->iommu; | 866 | struct intel_iommu *iommu = drhd->iommu; |
786 | 867 | ||
787 | if (ecap_ir_support(iommu->ecap)) { | 868 | if (ecap_ir_support(iommu->ecap)) { |
788 | if (ir_parse_ioapic_scope(drhd->hdr, iommu)) | 869 | if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu)) |
789 | return -1; | 870 | return -1; |
790 | 871 | ||
791 | ir_supported = 1; | 872 | ir_supported = 1; |
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h index 63a263c18415..5662fecfee60 100644 --- a/drivers/pci/intr_remapping.h +++ b/drivers/pci/intr_remapping.h | |||
@@ -7,4 +7,11 @@ struct ioapic_scope { | |||
7 | unsigned int devfn; /* PCI devfn number */ | 7 | unsigned int devfn; /* PCI devfn number */ |
8 | }; | 8 | }; |
9 | 9 | ||
10 | struct hpet_scope { | ||
11 | struct intel_iommu *iommu; | ||
12 | u8 id; | ||
13 | unsigned int bus; | ||
14 | unsigned int devfn; | ||
15 | }; | ||
16 | |||
10 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) | 17 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) |