diff options
-rw-r--r-- | drivers/pci/intr_remapping.c | 89 | ||||
-rw-r--r-- | drivers/pci/intr_remapping.h | 7 | ||||
-rw-r--r-- | include/linux/dmar.h | 10 | ||||
-rw-r--r-- | include/linux/hpet.h | 2 |
4 files changed, 104 insertions, 4 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 4f5b8712931f..2cc3f70ad425 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; |
@@ -351,6 +353,16 @@ int flush_irte(int irq) | |||
351 | return rc; | 353 | return rc; |
352 | } | 354 | } |
353 | 355 | ||
356 | struct intel_iommu *map_hpet_to_ir(u8 hpet_id) | ||
357 | { | ||
358 | int i; | ||
359 | |||
360 | for (i = 0; i < MAX_HPET_TBS; i++) | ||
361 | if (ir_hpet[i].id == hpet_id) | ||
362 | return ir_hpet[i].iommu; | ||
363 | return NULL; | ||
364 | } | ||
365 | |||
354 | struct intel_iommu *map_ioapic_to_ir(int apic) | 366 | struct intel_iommu *map_ioapic_to_ir(int apic) |
355 | { | 367 | { |
356 | int i; | 368 | int i; |
@@ -478,6 +490,36 @@ int set_ioapic_sid(struct irte *irte, int apic) | |||
478 | return 0; | 490 | return 0; |
479 | } | 491 | } |
480 | 492 | ||
493 | int set_hpet_sid(struct irte *irte, u8 id) | ||
494 | { | ||
495 | int i; | ||
496 | u16 sid = 0; | ||
497 | |||
498 | if (!irte) | ||
499 | return -1; | ||
500 | |||
501 | for (i = 0; i < MAX_HPET_TBS; i++) { | ||
502 | if (ir_hpet[i].id == id) { | ||
503 | sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; | ||
504 | break; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | if (sid == 0) { | ||
509 | pr_warning("Failed to set source-id of HPET block (%d)\n", id); | ||
510 | return -1; | ||
511 | } | ||
512 | |||
513 | /* | ||
514 | * Should really use SQ_ALL_16. Some platforms are broken. | ||
515 | * While we figure out the right quirks for these broken platforms, use | ||
516 | * SQ_13_IGNORE_3 for now. | ||
517 | */ | ||
518 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid); | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
481 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 523 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
482 | { | 524 | { |
483 | struct pci_dev *bridge; | 525 | 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) |
diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 4a2b162c256a..69a6fbac0921 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h | |||
@@ -126,7 +126,9 @@ extern int free_irte(int irq); | |||
126 | extern int irq_remapped(int irq); | 126 | extern int irq_remapped(int irq); |
127 | extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); | 127 | extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); |
128 | extern struct intel_iommu *map_ioapic_to_ir(int apic); | 128 | extern struct intel_iommu *map_ioapic_to_ir(int apic); |
129 | extern struct intel_iommu *map_hpet_to_ir(u8 id); | ||
129 | extern int set_ioapic_sid(struct irte *irte, int apic); | 130 | extern int set_ioapic_sid(struct irte *irte, int apic); |
131 | extern int set_hpet_sid(struct irte *irte, u8 id); | ||
130 | extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); | 132 | extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); |
131 | #else | 133 | #else |
132 | static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | 134 | static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) |
@@ -158,10 +160,18 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic) | |||
158 | { | 160 | { |
159 | return NULL; | 161 | return NULL; |
160 | } | 162 | } |
163 | static inline struct intel_iommu *map_hpet_to_ir(unsigned int hpet_id) | ||
164 | { | ||
165 | return NULL; | ||
166 | } | ||
161 | static inline int set_ioapic_sid(struct irte *irte, int apic) | 167 | static inline int set_ioapic_sid(struct irte *irte, int apic) |
162 | { | 168 | { |
163 | return 0; | 169 | return 0; |
164 | } | 170 | } |
171 | static inline int set_hpet_sid(struct irte *irte, u8 id) | ||
172 | { | ||
173 | return -1; | ||
174 | } | ||
165 | static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 175 | static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
166 | { | 176 | { |
167 | return 0; | 177 | return 0; |
diff --git a/include/linux/hpet.h b/include/linux/hpet.h index 79f63a27bcef..219ca4f6bea6 100644 --- a/include/linux/hpet.h +++ b/include/linux/hpet.h | |||
@@ -126,4 +126,6 @@ struct hpet_info { | |||
126 | #define HPET_DPI _IO('h', 0x05) /* disable periodic */ | 126 | #define HPET_DPI _IO('h', 0x05) /* disable periodic */ |
127 | #define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ | 127 | #define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ |
128 | 128 | ||
129 | #define MAX_HPET_TBS 8 /* maximum hpet timer blocks */ | ||
130 | |||
129 | #endif /* !__HPET__ */ | 131 | #endif /* !__HPET__ */ |