aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/intr_remapping.c89
-rw-r--r--drivers/pci/intr_remapping.h7
-rw-r--r--include/linux/dmar.h10
-rw-r--r--include/linux/hpet.h2
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
16static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; 17static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
17static int ir_ioapic_num; 18static struct hpet_scope ir_hpet[MAX_HPET_TBS];
19static int ir_ioapic_num, ir_hpet_num;
18int intr_remapping_enabled; 20int intr_remapping_enabled;
19 21
20static int disable_intremap; 22static int disable_intremap;
@@ -351,6 +353,16 @@ int flush_irte(int irq)
351 return rc; 353 return rc;
352} 354}
353 355
356struct 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
354struct intel_iommu *map_ioapic_to_ir(int apic) 366struct 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
493int 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
481int set_msi_sid(struct irte *irte, struct pci_dev *dev) 523int 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
756static 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
714static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, 784static 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
743static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, 813static 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
10struct 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);
126extern int irq_remapped(int irq); 126extern int irq_remapped(int irq);
127extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); 127extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
128extern struct intel_iommu *map_ioapic_to_ir(int apic); 128extern struct intel_iommu *map_ioapic_to_ir(int apic);
129extern struct intel_iommu *map_hpet_to_ir(u8 id);
129extern int set_ioapic_sid(struct irte *irte, int apic); 130extern int set_ioapic_sid(struct irte *irte, int apic);
131extern int set_hpet_sid(struct irte *irte, u8 id);
130extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); 132extern int set_msi_sid(struct irte *irte, struct pci_dev *dev);
131#else 133#else
132static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) 134static 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}
163static inline struct intel_iommu *map_hpet_to_ir(unsigned int hpet_id)
164{
165 return NULL;
166}
161static inline int set_ioapic_sid(struct irte *irte, int apic) 167static inline int set_ioapic_sid(struct irte *irte, int apic)
162{ 168{
163 return 0; 169 return 0;
164} 170}
171static inline int set_hpet_sid(struct irte *irte, u8 id)
172{
173 return -1;
174}
165static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) 175static 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__ */