diff options
Diffstat (limited to 'drivers/pci/intr_remapping.c')
-rw-r--r-- | drivers/pci/intr_remapping.c | 97 |
1 files changed, 90 insertions, 7 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 0ed78a764ded..6ee98a56946f 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -1,7 +1,9 @@ | |||
1 | #include <linux/interrupt.h> | 1 | #include <linux/interrupt.h> |
2 | #include <linux/dmar.h> | 2 | #include <linux/dmar.h> |
3 | #include <linux/spinlock.h> | 3 | #include <linux/spinlock.h> |
4 | #include <linux/slab.h> | ||
4 | #include <linux/jiffies.h> | 5 | #include <linux/jiffies.h> |
6 | #include <linux/hpet.h> | ||
5 | #include <linux/pci.h> | 7 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 8 | #include <linux/irq.h> |
7 | #include <asm/io_apic.h> | 9 | #include <asm/io_apic.h> |
@@ -14,7 +16,8 @@ | |||
14 | #include "pci.h" | 16 | #include "pci.h" |
15 | 17 | ||
16 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 18 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
17 | static int ir_ioapic_num; | 19 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; |
20 | static int ir_ioapic_num, ir_hpet_num; | ||
18 | int intr_remapping_enabled; | 21 | int intr_remapping_enabled; |
19 | 22 | ||
20 | static int disable_intremap; | 23 | static int disable_intremap; |
@@ -343,6 +346,16 @@ int flush_irte(int irq) | |||
343 | return rc; | 346 | return rc; |
344 | } | 347 | } |
345 | 348 | ||
349 | struct intel_iommu *map_hpet_to_ir(u8 hpet_id) | ||
350 | { | ||
351 | int i; | ||
352 | |||
353 | for (i = 0; i < MAX_HPET_TBS; i++) | ||
354 | if (ir_hpet[i].id == hpet_id) | ||
355 | return ir_hpet[i].iommu; | ||
356 | return NULL; | ||
357 | } | ||
358 | |||
346 | struct intel_iommu *map_ioapic_to_ir(int apic) | 359 | struct intel_iommu *map_ioapic_to_ir(int apic) |
347 | { | 360 | { |
348 | int i; | 361 | int i; |
@@ -470,6 +483,36 @@ int set_ioapic_sid(struct irte *irte, int apic) | |||
470 | return 0; | 483 | return 0; |
471 | } | 484 | } |
472 | 485 | ||
486 | int set_hpet_sid(struct irte *irte, u8 id) | ||
487 | { | ||
488 | int i; | ||
489 | u16 sid = 0; | ||
490 | |||
491 | if (!irte) | ||
492 | return -1; | ||
493 | |||
494 | for (i = 0; i < MAX_HPET_TBS; i++) { | ||
495 | if (ir_hpet[i].id == id) { | ||
496 | sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; | ||
497 | break; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | if (sid == 0) { | ||
502 | pr_warning("Failed to set source-id of HPET block (%d)\n", id); | ||
503 | return -1; | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * Should really use SQ_ALL_16. Some platforms are broken. | ||
508 | * While we figure out the right quirks for these broken platforms, use | ||
509 | * SQ_13_IGNORE_3 for now. | ||
510 | */ | ||
511 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid); | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
473 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 516 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
474 | { | 517 | { |
475 | struct pci_dev *bridge; | 518 | struct pci_dev *bridge; |
@@ -478,7 +521,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev) | |||
478 | return -1; | 521 | return -1; |
479 | 522 | ||
480 | /* PCIe device or Root Complex integrated PCI device */ | 523 | /* PCIe device or Root Complex integrated PCI device */ |
481 | if (dev->is_pcie || !dev->bus->parent) { | 524 | if (pci_is_pcie(dev) || !dev->bus->parent) { |
482 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, | 525 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, |
483 | (dev->bus->number << 8) | dev->devfn); | 526 | (dev->bus->number << 8) | dev->devfn); |
484 | return 0; | 527 | return 0; |
@@ -486,7 +529,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev) | |||
486 | 529 | ||
487 | bridge = pci_find_upstream_pcie_bridge(dev); | 530 | bridge = pci_find_upstream_pcie_bridge(dev); |
488 | if (bridge) { | 531 | if (bridge) { |
489 | if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */ | 532 | if (pci_is_pcie(bridge))/* this is a PCIe-to-PCI/PCIX bridge */ |
490 | set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, | 533 | set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, |
491 | (bridge->bus->number << 8) | dev->bus->number); | 534 | (bridge->bus->number << 8) | dev->bus->number); |
492 | else /* this is a legacy PCI bridge */ | 535 | else /* this is a legacy PCI bridge */ |
@@ -548,7 +591,8 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode) | |||
548 | if (!iommu->ir_table) | 591 | if (!iommu->ir_table) |
549 | return -ENOMEM; | 592 | return -ENOMEM; |
550 | 593 | ||
551 | pages = alloc_pages(GFP_ATOMIC | __GFP_ZERO, INTR_REMAP_PAGE_ORDER); | 594 | pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, |
595 | INTR_REMAP_PAGE_ORDER); | ||
552 | 596 | ||
553 | if (!pages) { | 597 | if (!pages) { |
554 | printk(KERN_ERR "failed to allocate pages of order %d\n", | 598 | printk(KERN_ERR "failed to allocate pages of order %d\n", |
@@ -711,6 +755,34 @@ error: | |||
711 | return -1; | 755 | return -1; |
712 | } | 756 | } |
713 | 757 | ||
758 | static void ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope, | ||
759 | struct intel_iommu *iommu) | ||
760 | { | ||
761 | struct acpi_dmar_pci_path *path; | ||
762 | u8 bus; | ||
763 | int count; | ||
764 | |||
765 | bus = scope->bus; | ||
766 | path = (struct acpi_dmar_pci_path *)(scope + 1); | ||
767 | count = (scope->length - sizeof(struct acpi_dmar_device_scope)) | ||
768 | / sizeof(struct acpi_dmar_pci_path); | ||
769 | |||
770 | while (--count > 0) { | ||
771 | /* | ||
772 | * Access PCI directly due to the PCI | ||
773 | * subsystem isn't initialized yet. | ||
774 | */ | ||
775 | bus = read_pci_config_byte(bus, path->dev, path->fn, | ||
776 | PCI_SECONDARY_BUS); | ||
777 | path++; | ||
778 | } | ||
779 | ir_hpet[ir_hpet_num].bus = bus; | ||
780 | ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->dev, path->fn); | ||
781 | ir_hpet[ir_hpet_num].iommu = iommu; | ||
782 | ir_hpet[ir_hpet_num].id = scope->enumeration_id; | ||
783 | ir_hpet_num++; | ||
784 | } | ||
785 | |||
714 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | 786 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, |
715 | struct intel_iommu *iommu) | 787 | struct intel_iommu *iommu) |
716 | { | 788 | { |
@@ -740,8 +812,8 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | |||
740 | ir_ioapic_num++; | 812 | ir_ioapic_num++; |
741 | } | 813 | } |
742 | 814 | ||
743 | static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | 815 | static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header, |
744 | struct intel_iommu *iommu) | 816 | struct intel_iommu *iommu) |
745 | { | 817 | { |
746 | struct acpi_dmar_hardware_unit *drhd; | 818 | struct acpi_dmar_hardware_unit *drhd; |
747 | struct acpi_dmar_device_scope *scope; | 819 | struct acpi_dmar_device_scope *scope; |
@@ -765,6 +837,17 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | |||
765 | drhd->address); | 837 | drhd->address); |
766 | 838 | ||
767 | ir_parse_one_ioapic_scope(scope, iommu); | 839 | ir_parse_one_ioapic_scope(scope, iommu); |
840 | } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) { | ||
841 | if (ir_hpet_num == MAX_HPET_TBS) { | ||
842 | printk(KERN_WARNING "Exceeded Max HPET blocks\n"); | ||
843 | return -1; | ||
844 | } | ||
845 | |||
846 | printk(KERN_INFO "HPET id %d under DRHD base" | ||
847 | " 0x%Lx\n", scope->enumeration_id, | ||
848 | drhd->address); | ||
849 | |||
850 | ir_parse_one_hpet_scope(scope, iommu); | ||
768 | } | 851 | } |
769 | start += scope->length; | 852 | start += scope->length; |
770 | } | 853 | } |
@@ -785,7 +868,7 @@ int __init parse_ioapics_under_ir(void) | |||
785 | struct intel_iommu *iommu = drhd->iommu; | 868 | struct intel_iommu *iommu = drhd->iommu; |
786 | 869 | ||
787 | if (ecap_ir_support(iommu->ecap)) { | 870 | if (ecap_ir_support(iommu->ecap)) { |
788 | if (ir_parse_ioapic_scope(drhd->hdr, iommu)) | 871 | if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu)) |
789 | return -1; | 872 | return -1; |
790 | 873 | ||
791 | ir_supported = 1; | 874 | ir_supported = 1; |