aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/msidef.h1
-rw-r--r--arch/x86/kernel/apic/io_apic.c9
-rw-r--r--arch/x86/kernel/apic/probe_64.c9
-rw-r--r--drivers/pci/dmar.c102
-rw-r--r--drivers/pci/intel-iommu.c3
-rw-r--r--drivers/pci/intr_remapping.c2
-rw-r--r--include/linux/dmar.h5
-rw-r--r--include/linux/intel-iommu.h4
8 files changed, 107 insertions, 28 deletions
diff --git a/arch/x86/include/asm/msidef.h b/arch/x86/include/asm/msidef.h
index 6706b3006f1..4cc48af23fe 100644
--- a/arch/x86/include/asm/msidef.h
+++ b/arch/x86/include/asm/msidef.h
@@ -47,6 +47,7 @@
47#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 47#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
48#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \ 48#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \
49 MSI_ADDR_DEST_ID_MASK) 49 MSI_ADDR_DEST_ID_MASK)
50#define MSI_ADDR_EXT_DEST_ID(dest) ((dest) & 0xffffff00)
50 51
51#define MSI_ADDR_IR_EXT_INT (1 << 4) 52#define MSI_ADDR_IR_EXT_INT (1 << 4)
52#define MSI_ADDR_IR_SHV (1 << 3) 53#define MSI_ADDR_IR_SHV (1 << 3)
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 00e6071cefc..b18a7734d68 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3294,7 +3294,12 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
3294 } else 3294 } else
3295#endif 3295#endif
3296 { 3296 {
3297 msg->address_hi = MSI_ADDR_BASE_HI; 3297 if (x2apic_enabled())
3298 msg->address_hi = MSI_ADDR_BASE_HI |
3299 MSI_ADDR_EXT_DEST_ID(dest);
3300 else
3301 msg->address_hi = MSI_ADDR_BASE_HI;
3302
3298 msg->address_lo = 3303 msg->address_lo =
3299 MSI_ADDR_BASE_LO | 3304 MSI_ADDR_BASE_LO |
3300 ((apic->irq_dest_mode == 0) ? 3305 ((apic->irq_dest_mode == 0) ?
@@ -3528,7 +3533,7 @@ void arch_teardown_msi_irq(unsigned int irq)
3528 destroy_irq(irq); 3533 destroy_irq(irq);
3529} 3534}
3530 3535
3531#ifdef CONFIG_DMAR 3536#if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
3532#ifdef CONFIG_SMP 3537#ifdef CONFIG_SMP
3533static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask) 3538static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
3534{ 3539{
diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c
index 8d7748efe6a..8297c2b8ed2 100644
--- a/arch/x86/kernel/apic/probe_64.c
+++ b/arch/x86/kernel/apic/probe_64.c
@@ -68,6 +68,15 @@ void __init default_setup_apic_routing(void)
68 apic = &apic_physflat; 68 apic = &apic_physflat;
69 printk(KERN_INFO "Setting APIC routing to %s\n", apic->name); 69 printk(KERN_INFO "Setting APIC routing to %s\n", apic->name);
70 } 70 }
71
72#ifdef CONFIG_X86_X2APIC
73 /*
74 * Now that apic routing model is selected, configure the
75 * fault handling for intr remapping.
76 */
77 if (intr_remapping_enabled)
78 enable_drhd_fault_handling();
79#endif
71} 80}
72 81
73/* Same for both flat and physical. */ 82/* Same for both flat and physical. */
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 75d34bf2db5..bb4ed985f9c 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -511,6 +511,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
511 return -ENOMEM; 511 return -ENOMEM;
512 512
513 iommu->seq_id = iommu_allocated++; 513 iommu->seq_id = iommu_allocated++;
514 sprintf (iommu->name, "dmar%d", iommu->seq_id);
514 515
515 iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE); 516 iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
516 if (!iommu->reg) { 517 if (!iommu->reg) {
@@ -817,7 +818,13 @@ int dmar_enable_qi(struct intel_iommu *iommu)
817 818
818/* iommu interrupt handling. Most stuff are MSI-like. */ 819/* iommu interrupt handling. Most stuff are MSI-like. */
819 820
820static const char *fault_reason_strings[] = 821enum faulttype {
822 DMA_REMAP,
823 INTR_REMAP,
824 UNKNOWN,
825};
826
827static const char *dma_remap_fault_reasons[] =
821{ 828{
822 "Software", 829 "Software",
823 "Present bit in root entry is clear", 830 "Present bit in root entry is clear",
@@ -833,14 +840,33 @@ static const char *fault_reason_strings[] =
833 "non-zero reserved fields in CTP", 840 "non-zero reserved fields in CTP",
834 "non-zero reserved fields in PTE", 841 "non-zero reserved fields in PTE",
835}; 842};
843
844static const char *intr_remap_fault_reasons[] =
845{
846 "Detected reserved fields in the decoded interrupt-remapped request",
847 "Interrupt index exceeded the interrupt-remapping table size",
848 "Present field in the IRTE entry is clear",
849 "Error accessing interrupt-remapping table pointed by IRTA_REG",
850 "Detected reserved fields in the IRTE entry",
851 "Blocked a compatibility format interrupt request",
852 "Blocked an interrupt request due to source-id verification failure",
853};
854
836#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1) 855#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1)
837 856
838const char *dmar_get_fault_reason(u8 fault_reason) 857const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
839{ 858{
840 if (fault_reason > MAX_FAULT_REASON_IDX) 859 if (fault_reason >= 0x20 && (fault_reason <= 0x20 +
860 ARRAY_SIZE(intr_remap_fault_reasons))) {
861 *fault_type = INTR_REMAP;
862 return intr_remap_fault_reasons[fault_reason - 0x20];
863 } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
864 *fault_type = DMA_REMAP;
865 return dma_remap_fault_reasons[fault_reason];
866 } else {
867 *fault_type = UNKNOWN;
841 return "Unknown"; 868 return "Unknown";
842 else 869 }
843 return fault_reason_strings[fault_reason];
844} 870}
845 871
846void dmar_msi_unmask(unsigned int irq) 872void dmar_msi_unmask(unsigned int irq)
@@ -897,16 +923,25 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
897 u8 fault_reason, u16 source_id, unsigned long long addr) 923 u8 fault_reason, u16 source_id, unsigned long long addr)
898{ 924{
899 const char *reason; 925 const char *reason;
926 int fault_type;
900 927
901 reason = dmar_get_fault_reason(fault_reason); 928 reason = dmar_get_fault_reason(fault_reason, &fault_type);
902 929
903 printk(KERN_ERR 930 if (fault_type == INTR_REMAP)
904 "DMAR:[%s] Request device [%02x:%02x.%d] " 931 printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] "
905 "fault addr %llx \n" 932 "fault index %llx\n"
906 "DMAR:[fault reason %02d] %s\n", 933 "INTR-REMAP:[fault reason %02d] %s\n",
907 (type ? "DMA Read" : "DMA Write"), 934 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
908 (source_id >> 8), PCI_SLOT(source_id & 0xFF), 935 PCI_FUNC(source_id & 0xFF), addr >> 48,
909 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason); 936 fault_reason, reason);
937 else
938 printk(KERN_ERR
939 "DMAR:[%s] Request device [%02x:%02x.%d] "
940 "fault addr %llx \n"
941 "DMAR:[fault reason %02d] %s\n",
942 (type ? "DMA Read" : "DMA Write"),
943 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
944 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
910 return 0; 945 return 0;
911} 946}
912 947
@@ -920,10 +955,13 @@ static irqreturn_t dmar_fault(int irq, void *dev_id)
920 955
921 spin_lock_irqsave(&iommu->register_lock, flag); 956 spin_lock_irqsave(&iommu->register_lock, flag);
922 fault_status = readl(iommu->reg + DMAR_FSTS_REG); 957 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
958 if (fault_status)
959 printk(KERN_ERR "DRHD: handling fault status reg %x\n",
960 fault_status);
923 961
924 /* TBD: ignore advanced fault log currently */ 962 /* TBD: ignore advanced fault log currently */
925 if (!(fault_status & DMA_FSTS_PPF)) 963 if (!(fault_status & DMA_FSTS_PPF))
926 goto clear_overflow; 964 goto clear_rest;
927 965
928 fault_index = dma_fsts_fault_record_index(fault_status); 966 fault_index = dma_fsts_fault_record_index(fault_status);
929 reg = cap_fault_reg_offset(iommu->cap); 967 reg = cap_fault_reg_offset(iommu->cap);
@@ -964,11 +1002,10 @@ static irqreturn_t dmar_fault(int irq, void *dev_id)
964 fault_index = 0; 1002 fault_index = 0;
965 spin_lock_irqsave(&iommu->register_lock, flag); 1003 spin_lock_irqsave(&iommu->register_lock, flag);
966 } 1004 }
967clear_overflow: 1005clear_rest:
968 /* clear primary fault overflow */ 1006 /* clear all the other faults */
969 fault_status = readl(iommu->reg + DMAR_FSTS_REG); 1007 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
970 if (fault_status & DMA_FSTS_PFO) 1008 writel(fault_status, iommu->reg + DMAR_FSTS_REG);
971 writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
972 1009
973 spin_unlock_irqrestore(&iommu->register_lock, flag); 1010 spin_unlock_irqrestore(&iommu->register_lock, flag);
974 return IRQ_HANDLED; 1011 return IRQ_HANDLED;
@@ -978,6 +1015,12 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
978{ 1015{
979 int irq, ret; 1016 int irq, ret;
980 1017
1018 /*
1019 * Check if the fault interrupt is already initialized.
1020 */
1021 if (iommu->irq)
1022 return 0;
1023
981 irq = create_irq(); 1024 irq = create_irq();
982 if (!irq) { 1025 if (!irq) {
983 printk(KERN_ERR "IOMMU: no free vectors\n"); 1026 printk(KERN_ERR "IOMMU: no free vectors\n");
@@ -1003,3 +1046,26 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
1003 printk(KERN_ERR "IOMMU: can't request irq\n"); 1046 printk(KERN_ERR "IOMMU: can't request irq\n");
1004 return ret; 1047 return ret;
1005} 1048}
1049
1050int __init enable_drhd_fault_handling(void)
1051{
1052 struct dmar_drhd_unit *drhd;
1053
1054 /*
1055 * Enable fault control interrupt.
1056 */
1057 for_each_drhd_unit(drhd) {
1058 int ret;
1059 struct intel_iommu *iommu = drhd->iommu;
1060 ret = dmar_set_interrupt(iommu);
1061
1062 if (ret) {
1063 printk(KERN_ERR "DRHD %Lx: failed to enable fault, "
1064 " interrupt, ret %d\n",
1065 (unsigned long long)drhd->reg_base_addr, ret);
1066 return -1;
1067 }
1068 }
1069
1070 return 0;
1071}
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 4a4ab651b70..25fc1df486b 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1799,7 +1799,7 @@ static int __init init_dmars(void)
1799 struct dmar_rmrr_unit *rmrr; 1799 struct dmar_rmrr_unit *rmrr;
1800 struct pci_dev *pdev; 1800 struct pci_dev *pdev;
1801 struct intel_iommu *iommu; 1801 struct intel_iommu *iommu;
1802 int i, ret, unit = 0; 1802 int i, ret;
1803 1803
1804 /* 1804 /*
1805 * for each drhd 1805 * for each drhd
@@ -1921,7 +1921,6 @@ static int __init init_dmars(void)
1921 if (drhd->ignored) 1921 if (drhd->ignored)
1922 continue; 1922 continue;
1923 iommu = drhd->iommu; 1923 iommu = drhd->iommu;
1924 sprintf (iommu->name, "dmar%d", unit++);
1925 1924
1926 iommu_flush_write_buffer(iommu); 1925 iommu_flush_write_buffer(iommu);
1927 1926
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 5ffa65fffb6..c38e3f437a8 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -308,7 +308,7 @@ int modify_irte(int irq, struct irte *irte_modified)
308 index = irq_iommu->irte_index + irq_iommu->sub_handle; 308 index = irq_iommu->irte_index + irq_iommu->sub_handle;
309 irte = &iommu->ir_table->base[index]; 309 irte = &iommu->ir_table->base[index];
310 310
311 set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1)); 311 set_64bit((unsigned long *)irte, irte_modified->low);
312 __iommu_flush_cache(iommu, irte, sizeof(*irte)); 312 __iommu_flush_cache(iommu, irte, sizeof(*irte));
313 313
314 rc = qi_flush_iec(iommu, index, 0); 314 rc = qi_flush_iec(iommu, index, 0);
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index f28440784cf..c7768330c11 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -49,6 +49,7 @@ extern int dmar_dev_scope_init(void);
49 49
50/* Intel IOMMU detection */ 50/* Intel IOMMU detection */
51extern void detect_intel_iommu(void); 51extern void detect_intel_iommu(void);
52extern int enable_drhd_fault_handling(void);
52 53
53 54
54extern int parse_ioapics_under_ir(void); 55extern int parse_ioapics_under_ir(void);
@@ -116,9 +117,6 @@ extern struct intel_iommu *map_ioapic_to_ir(int apic);
116#define intr_remapping_enabled (0) 117#define intr_remapping_enabled (0)
117#endif 118#endif
118 119
119#ifdef CONFIG_DMAR
120extern const char *dmar_get_fault_reason(u8 fault_reason);
121
122/* Can't use the common MSI interrupt functions 120/* Can't use the common MSI interrupt functions
123 * since DMAR is not a pci device 121 * since DMAR is not a pci device
124 */ 122 */
@@ -129,6 +127,7 @@ extern void dmar_msi_write(int irq, struct msi_msg *msg);
129extern int dmar_set_interrupt(struct intel_iommu *iommu); 127extern int dmar_set_interrupt(struct intel_iommu *iommu);
130extern int arch_setup_dmar_msi(unsigned int irq); 128extern int arch_setup_dmar_msi(unsigned int irq);
131 129
130#ifdef CONFIG_DMAR
132extern int iommu_detected, no_iommu; 131extern int iommu_detected, no_iommu;
133extern struct list_head dmar_rmrr_units; 132extern struct list_head dmar_rmrr_units;
134struct dmar_rmrr_unit { 133struct dmar_rmrr_unit {
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index d2e3cbfba14..a9563840644 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -292,6 +292,8 @@ struct intel_iommu {
292 spinlock_t register_lock; /* protect register handling */ 292 spinlock_t register_lock; /* protect register handling */
293 int seq_id; /* sequence id of the iommu */ 293 int seq_id; /* sequence id of the iommu */
294 int agaw; /* agaw of this iommu */ 294 int agaw; /* agaw of this iommu */
295 unsigned int irq;
296 unsigned char name[13]; /* Device Name */
295 297
296#ifdef CONFIG_DMAR 298#ifdef CONFIG_DMAR
297 unsigned long *domain_ids; /* bitmap of domains */ 299 unsigned long *domain_ids; /* bitmap of domains */
@@ -299,8 +301,6 @@ struct intel_iommu {
299 spinlock_t lock; /* protect context, domain ids */ 301 spinlock_t lock; /* protect context, domain ids */
300 struct root_entry *root_entry; /* virtual address */ 302 struct root_entry *root_entry; /* virtual address */
301 303
302 unsigned int irq;
303 unsigned char name[7]; /* Device Name */
304 struct iommu_flush flush; 304 struct iommu_flush flush;
305#endif 305#endif
306 struct q_inval *qi; /* Queued invalidation info */ 306 struct q_inval *qi; /* Queued invalidation info */