aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2009-08-04 15:07:08 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-08-27 17:33:20 -0400
commit20f3097bfe5fb5ced0b14f9ea2620c4039bf1dde (patch)
tree437d792e28f9c64198d64730196abf0a3bb1e7c6
parent5946fa3d5cdeb846a647a1900026af9f8b08c8b5 (diff)
intr-remap: generic support for remapping HPET MSIs
Generic support for remapping HPET MSI's by parsing the HPET timer block device scope in the ACPI DRHD tables. This is needed for platforms supporting interrupt-remapping and MSI capable HPET timer block. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Cc: Jay Fenlason <fenlason@redhat.com> LKML-Reference: <20090804190729.477649000@intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-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__ */