aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/intr_remapping.c834
-rw-r--r--drivers/iommu/intr_remapping.h17
2 files changed, 851 insertions, 0 deletions
diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intr_remapping.c
new file mode 100644
index 00000000000..6777ca04947
--- /dev/null
+++ b/drivers/iommu/intr_remapping.c
@@ -0,0 +1,834 @@
1#include <linux/interrupt.h>
2#include <linux/dmar.h>
3#include <linux/spinlock.h>
4#include <linux/slab.h>
5#include <linux/jiffies.h>
6#include <linux/hpet.h>
7#include <linux/pci.h>
8#include <linux/irq.h>
9#include <asm/io_apic.h>
10#include <asm/smp.h>
11#include <asm/cpu.h>
12#include <linux/intel-iommu.h>
13#include "intr_remapping.h"
14#include <acpi/acpi.h>
15#include <asm/pci-direct.h>
16
17static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
18static struct hpet_scope ir_hpet[MAX_HPET_TBS];
19static int ir_ioapic_num, ir_hpet_num;
20int intr_remapping_enabled;
21
22static int disable_intremap;
23static int disable_sourceid_checking;
24static int no_x2apic_optout;
25
26static __init int setup_nointremap(char *str)
27{
28 disable_intremap = 1;
29 return 0;
30}
31early_param("nointremap", setup_nointremap);
32
33static __init int setup_intremap(char *str)
34{
35 if (!str)
36 return -EINVAL;
37
38 while (*str) {
39 if (!strncmp(str, "on", 2))
40 disable_intremap = 0;
41 else if (!strncmp(str, "off", 3))
42 disable_intremap = 1;
43 else if (!strncmp(str, "nosid", 5))
44 disable_sourceid_checking = 1;
45 else if (!strncmp(str, "no_x2apic_optout", 16))
46 no_x2apic_optout = 1;
47
48 str += strcspn(str, ",");
49 while (*str == ',')
50 str++;
51 }
52
53 return 0;
54}
55early_param("intremap", setup_intremap);
56
57static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
58
59static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
60{
61 struct irq_cfg *cfg = irq_get_chip_data(irq);
62 return cfg ? &cfg->irq_2_iommu : NULL;
63}
64
65int get_irte(int irq, struct irte *entry)
66{
67 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
68 unsigned long flags;
69 int index;
70
71 if (!entry || !irq_iommu)
72 return -1;
73
74 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
75
76 index = irq_iommu->irte_index + irq_iommu->sub_handle;
77 *entry = *(irq_iommu->iommu->ir_table->base + index);
78
79 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
80 return 0;
81}
82
83int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
84{
85 struct ir_table *table = iommu->ir_table;
86 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
87 u16 index, start_index;
88 unsigned int mask = 0;
89 unsigned long flags;
90 int i;
91
92 if (!count || !irq_iommu)
93 return -1;
94
95 /*
96 * start the IRTE search from index 0.
97 */
98 index = start_index = 0;
99
100 if (count > 1) {
101 count = __roundup_pow_of_two(count);
102 mask = ilog2(count);
103 }
104
105 if (mask > ecap_max_handle_mask(iommu->ecap)) {
106 printk(KERN_ERR
107 "Requested mask %x exceeds the max invalidation handle"
108 " mask value %Lx\n", mask,
109 ecap_max_handle_mask(iommu->ecap));
110 return -1;
111 }
112
113 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
114 do {
115 for (i = index; i < index + count; i++)
116 if (table->base[i].present)
117 break;
118 /* empty index found */
119 if (i == index + count)
120 break;
121
122 index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
123
124 if (index == start_index) {
125 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
126 printk(KERN_ERR "can't allocate an IRTE\n");
127 return -1;
128 }
129 } while (1);
130
131 for (i = index; i < index + count; i++)
132 table->base[i].present = 1;
133
134 irq_iommu->iommu = iommu;
135 irq_iommu->irte_index = index;
136 irq_iommu->sub_handle = 0;
137 irq_iommu->irte_mask = mask;
138
139 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
140
141 return index;
142}
143
144static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
145{
146 struct qi_desc desc;
147
148 desc.low = QI_IEC_IIDEX(index) | QI_IEC_TYPE | QI_IEC_IM(mask)
149 | QI_IEC_SELECTIVE;
150 desc.high = 0;
151
152 return qi_submit_sync(&desc, iommu);
153}
154
155int map_irq_to_irte_handle(int irq, u16 *sub_handle)
156{
157 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
158 unsigned long flags;
159 int index;
160
161 if (!irq_iommu)
162 return -1;
163
164 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
165 *sub_handle = irq_iommu->sub_handle;
166 index = irq_iommu->irte_index;
167 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
168 return index;
169}
170
171int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
172{
173 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
174 unsigned long flags;
175
176 if (!irq_iommu)
177 return -1;
178
179 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
180
181 irq_iommu->iommu = iommu;
182 irq_iommu->irte_index = index;
183 irq_iommu->sub_handle = subhandle;
184 irq_iommu->irte_mask = 0;
185
186 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
187
188 return 0;
189}
190
191int modify_irte(int irq, struct irte *irte_modified)
192{
193 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
194 struct intel_iommu *iommu;
195 unsigned long flags;
196 struct irte *irte;
197 int rc, index;
198
199 if (!irq_iommu)
200 return -1;
201
202 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
203
204 iommu = irq_iommu->iommu;
205
206 index = irq_iommu->irte_index + irq_iommu->sub_handle;
207 irte = &iommu->ir_table->base[index];
208
209 set_64bit(&irte->low, irte_modified->low);
210 set_64bit(&irte->high, irte_modified->high);
211 __iommu_flush_cache(iommu, irte, sizeof(*irte));
212
213 rc = qi_flush_iec(iommu, index, 0);
214 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
215
216 return rc;
217}
218
219struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
220{
221 int i;