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__ */ |
