diff options
Diffstat (limited to 'drivers/pci/intr_remapping.c')
-rw-r--r-- | drivers/pci/intr_remapping.c | 89 |
1 files changed, 85 insertions, 4 deletions
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; |