blob: 97ea4209fc8df532a1e89e3ef35c6b0de439576e [file] [log] [blame]
Yinghai Lu5aeecaf2008-08-19 20:49:59 -07001#include <linux/interrupt.h>
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -07002#include <linux/dmar.h>
Suresh Siddha2ae21012008-07-10 11:16:43 -07003#include <linux/spinlock.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09004#include <linux/slab.h>
Suresh Siddha2ae21012008-07-10 11:16:43 -07005#include <linux/jiffies.h>
Suresh Siddha20f30972009-08-04 12:07:08 -07006#include <linux/hpet.h>
Suresh Siddha2ae21012008-07-10 11:16:43 -07007#include <linux/pci.h>
Suresh Siddhab6fcb332008-07-10 11:16:44 -07008#include <linux/irq.h>
Lv Zheng8b484632013-12-03 08:49:16 +08009#include <linux/intel-iommu.h>
10#include <linux/acpi.h>
Jiang Liub106ee62015-04-13 14:11:32 +080011#include <linux/irqdomain.h>
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -070012#include <asm/io_apic.h>
Yinghai Lu17483a12008-12-12 13:14:18 -080013#include <asm/smp.h>
Jaswinder Singh Rajput6d652ea2009-01-07 21:38:59 +053014#include <asm/cpu.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070015#include <asm/irq_remapping.h>
Weidong Hanf007e992009-05-23 00:41:15 +080016#include <asm/pci-direct.h>
Joerg Roedel5e2b9302012-03-30 11:47:05 -070017#include <asm/msidef.h>
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -070018
Suresh Siddha8a8f4222012-03-30 11:47:08 -070019#include "irq_remapping.h"
Joerg Roedel736baef2012-03-30 11:47:00 -070020
Joerg Roedeleef93fd2012-03-30 11:46:59 -070021struct ioapic_scope {
22 struct intel_iommu *iommu;
23 unsigned int id;
24 unsigned int bus; /* PCI bus number */
25 unsigned int devfn; /* PCI devfn number */
26};
27
28struct hpet_scope {
29 struct intel_iommu *iommu;
30 u8 id;
31 unsigned int bus;
32 unsigned int devfn;
33};
34
Jiang Liub106ee62015-04-13 14:11:32 +080035struct intel_ir_data {
36 struct irq_2_iommu irq_2_iommu;
37 struct irte irte_entry;
38 union {
39 struct msi_msg msi_entry;
40 };
41};
42
Joerg Roedeleef93fd2012-03-30 11:46:59 -070043#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
Jiang Liu13d09b62015-01-07 15:31:37 +080044#define IRTE_DEST(dest) ((eim_mode) ? dest : dest << 8)
Joerg Roedeleef93fd2012-03-30 11:46:59 -070045
Jiang Liu13d09b62015-01-07 15:31:37 +080046static int __read_mostly eim_mode;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -070047static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
Suresh Siddha20f30972009-08-04 12:07:08 -070048static struct hpet_scope ir_hpet[MAX_HPET_TBS];
Chris Wrightd1423d52010-07-20 11:06:49 -070049
Jiang Liu3a5670e2014-02-19 14:07:33 +080050/*
51 * Lock ordering:
52 * ->dmar_global_lock
53 * ->irq_2_ir_lock
54 * ->qi->q_lock
55 * ->iommu->register_lock
56 * Note:
57 * intel_irq_remap_ops.{supported,prepare,enable,disable,reenable} are called
58 * in single-threaded environment with interrupt disabled, so no need to tabke
59 * the dmar_global_lock.
60 */
Thomas Gleixner96f8e982011-07-19 16:28:19 +020061static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
Jiang Liub106ee62015-04-13 14:11:32 +080062static struct irq_domain_ops intel_ir_domain_ops;
Thomas Gleixnerd585d062010-10-10 12:34:27 +020063
Jiang Liu694835d2014-01-06 14:18:16 +080064static int __init parse_ioapics_under_ir(void);
65
Yinghai Lue420dfb2008-08-19 20:50:21 -070066static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
67{
Jiang Liu91411da2014-10-27 16:12:09 +080068 struct irq_cfg *cfg = irq_cfg(irq);
Thomas Gleixner349d6762010-10-10 12:29:27 +020069 return cfg ? &cfg->irq_2_iommu : NULL;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -080070}
71
Rashika Kheria6a7885c2013-12-18 12:04:27 +053072static int get_irte(int irq, struct irte *entry)
Suresh Siddhab6fcb332008-07-10 11:16:44 -070073{
Thomas Gleixnerd585d062010-10-10 12:34:27 +020074 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
Suresh Siddha4c5502b2009-03-16 17:04:53 -070075 unsigned long flags;
Thomas Gleixnerd585d062010-10-10 12:34:27 +020076 int index;
Suresh Siddhab6fcb332008-07-10 11:16:44 -070077
Thomas Gleixnerd585d062010-10-10 12:34:27 +020078 if (!entry || !irq_iommu)
Suresh Siddhab6fcb332008-07-10 11:16:44 -070079 return -1;
80
Thomas Gleixner96f8e982011-07-19 16:28:19 +020081 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -070082
Greg Edwardsaf437462014-07-23 10:13:26 -060083 if (unlikely(!irq_iommu->iommu)) {
84 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
85 return -1;
86 }
87
Yinghai Lue420dfb2008-08-19 20:50:21 -070088 index = irq_iommu->irte_index + irq_iommu->sub_handle;
89 *entry = *(irq_iommu->iommu->ir_table->base + index);
Suresh Siddhab6fcb332008-07-10 11:16:44 -070090
Thomas Gleixner96f8e982011-07-19 16:28:19 +020091 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -070092 return 0;
93}
94
Jiang Liu8dedf4c2015-04-13 14:11:31 +080095static int alloc_irte(struct intel_iommu *iommu, int irq,
96 struct irq_2_iommu *irq_iommu, u16 count)
Suresh Siddhab6fcb332008-07-10 11:16:44 -070097{
98 struct ir_table *table = iommu->ir_table;
Jiang Liu91411da2014-10-27 16:12:09 +080099 struct irq_cfg *cfg = irq_cfg(irq);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700100 unsigned int mask = 0;
Suresh Siddha4c5502b2009-03-16 17:04:53 -0700101 unsigned long flags;
Dan Carpenter9f4c7442014-01-09 08:32:36 +0300102 int index;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700103
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200104 if (!count || !irq_iommu)
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700105 return -1;
106
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700107 if (count > 1) {
108 count = __roundup_pow_of_two(count);
109 mask = ilog2(count);
110 }
111
112 if (mask > ecap_max_handle_mask(iommu->ecap)) {
113 printk(KERN_ERR
114 "Requested mask %x exceeds the max invalidation handle"
115 " mask value %Lx\n", mask,
116 ecap_max_handle_mask(iommu->ecap));
117 return -1;
118 }
119
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200120 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
Jiang Liu360eb3c52014-01-06 14:18:08 +0800121 index = bitmap_find_free_region(table->bitmap,
122 INTR_REMAP_TABLE_ENTRIES, mask);
123 if (index < 0) {
124 pr_warn("IR%d: can't allocate an IRTE\n", iommu->seq_id);
125 } else {
126 cfg->remapped = 1;
127 irq_iommu->iommu = iommu;
128 irq_iommu->irte_index = index;
129 irq_iommu->sub_handle = 0;
130 irq_iommu->irte_mask = mask;
131 }
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200132 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700133
134 return index;
135}
136
Yu Zhao704126a2009-01-04 16:28:52 +0800137static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700138{
139 struct qi_desc desc;
140
141 desc.low = QI_IEC_IIDEX(index) | QI_IEC_TYPE | QI_IEC_IM(mask)
142 | QI_IEC_SELECTIVE;
143 desc.high = 0;
144
Yu Zhao704126a2009-01-04 16:28:52 +0800145 return qi_submit_sync(&desc, iommu);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700146}
147
Joerg Roedel263b5e82012-03-30 11:47:06 -0700148static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700149{
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200150 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
Suresh Siddha4c5502b2009-03-16 17:04:53 -0700151 unsigned long flags;
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200152 int index;
153
154 if (!irq_iommu)
155 return -1;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700156
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200157 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
Yinghai Lue420dfb2008-08-19 20:50:21 -0700158 *sub_handle = irq_iommu->sub_handle;
159 index = irq_iommu->irte_index;
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200160 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700161 return index;
162}
163
Joerg Roedel263b5e82012-03-30 11:47:06 -0700164static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700165{
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200166 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
Jiang Liu91411da2014-10-27 16:12:09 +0800167 struct irq_cfg *cfg = irq_cfg(irq);
Suresh Siddha4c5502b2009-03-16 17:04:53 -0700168 unsigned long flags;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700169
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200170 if (!irq_iommu)
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800171 return -1;
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200172
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200173 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800174
Joerg Roedel9b1b0e42012-09-26 12:44:45 +0200175 cfg->remapped = 1;
Yinghai Lue420dfb2008-08-19 20:50:21 -0700176 irq_iommu->iommu = iommu;
177 irq_iommu->irte_index = index;
178 irq_iommu->sub_handle = subhandle;
179 irq_iommu->irte_mask = 0;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700180
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200181 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700182
183 return 0;
184}
185
Jiang Liu8dedf4c2015-04-13 14:11:31 +0800186static int modify_irte(struct irq_2_iommu *irq_iommu,
187 struct irte *irte_modified)
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700188{
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700189 struct intel_iommu *iommu;
Suresh Siddha4c5502b2009-03-16 17:04:53 -0700190 unsigned long flags;
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200191 struct irte *irte;
192 int rc, index;
193
194 if (!irq_iommu)
195 return -1;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700196
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200197 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700198
Yinghai Lue420dfb2008-08-19 20:50:21 -0700199 iommu = irq_iommu->iommu;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700200
Yinghai Lue420dfb2008-08-19 20:50:21 -0700201 index = irq_iommu->irte_index + irq_iommu->sub_handle;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700202 irte = &iommu->ir_table->base[index];
203
Linus Torvaldsc513b672010-08-06 11:02:31 -0700204 set_64bit(&irte->low, irte_modified->low);
205 set_64bit(&irte->high, irte_modified->high);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700206 __iommu_flush_cache(iommu, irte, sizeof(*irte));
207
Yu Zhao704126a2009-01-04 16:28:52 +0800208 rc = qi_flush_iec(iommu, index, 0);
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200209 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
Yu Zhao704126a2009-01-04 16:28:52 +0800210
211 return rc;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700212}
213
Joerg Roedel263b5e82012-03-30 11:47:06 -0700214static struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
Suresh Siddha20f30972009-08-04 12:07:08 -0700215{
216 int i;
217
218 for (i = 0; i < MAX_HPET_TBS; i++)
Jiang Liua7a3dad2014-11-09 22:48:00 +0800219 if (ir_hpet[i].id == hpet_id && ir_hpet[i].iommu)
Suresh Siddha20f30972009-08-04 12:07:08 -0700220 return ir_hpet[i].iommu;
221 return NULL;
222}
223
Joerg Roedel263b5e82012-03-30 11:47:06 -0700224static struct intel_iommu *map_ioapic_to_ir(int apic)
Suresh Siddha89027d32008-07-10 11:16:56 -0700225{
226 int i;
227
228 for (i = 0; i < MAX_IO_APICS; i++)
Jiang Liua7a3dad2014-11-09 22:48:00 +0800229 if (ir_ioapic[i].id == apic && ir_ioapic[i].iommu)
Suresh Siddha89027d32008-07-10 11:16:56 -0700230 return ir_ioapic[i].iommu;
231 return NULL;
232}
233
Joerg Roedel263b5e82012-03-30 11:47:06 -0700234static struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
Suresh Siddha75c46fa2008-07-10 11:16:57 -0700235{
236 struct dmar_drhd_unit *drhd;
237
238 drhd = dmar_find_matched_drhd_unit(dev);
239 if (!drhd)
240 return NULL;
241
242 return drhd->iommu;
243}
244
Weidong Hanc4658b42009-05-23 00:41:14 +0800245static int clear_entries(struct irq_2_iommu *irq_iommu)
246{
247 struct irte *start, *entry, *end;
248 struct intel_iommu *iommu;
249 int index;
250
251 if (irq_iommu->sub_handle)
252 return 0;
253
254 iommu = irq_iommu->iommu;
Jiang Liu8dedf4c2015-04-13 14:11:31 +0800255 index = irq_iommu->irte_index;
Weidong Hanc4658b42009-05-23 00:41:14 +0800256
257 start = iommu->ir_table->base + index;
258 end = start + (1 << irq_iommu->irte_mask);
259
260 for (entry = start; entry < end; entry++) {
Linus Torvaldsc513b672010-08-06 11:02:31 -0700261 set_64bit(&entry->low, 0);
262 set_64bit(&entry->high, 0);
Weidong Hanc4658b42009-05-23 00:41:14 +0800263 }
Jiang Liu360eb3c52014-01-06 14:18:08 +0800264 bitmap_release_region(iommu->ir_table->bitmap, index,
265 irq_iommu->irte_mask);
Weidong Hanc4658b42009-05-23 00:41:14 +0800266
267 return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
268}
269
Joerg Roedel9d619f62012-03-30 11:47:04 -0700270static int free_irte(int irq)
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700271{
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200272 struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
Suresh Siddha4c5502b2009-03-16 17:04:53 -0700273 unsigned long flags;
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200274 int rc;
275
Jiang Liub106ee62015-04-13 14:11:32 +0800276 if (!irq_iommu || irq_iommu->iommu == NULL)
Thomas Gleixnerd585d062010-10-10 12:34:27 +0200277 return -1;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700278
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200279 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700280
Weidong Hanc4658b42009-05-23 00:41:14 +0800281 rc = clear_entries(irq_iommu);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700282
Yinghai Lue420dfb2008-08-19 20:50:21 -0700283 irq_iommu->iommu = NULL;
284 irq_iommu->irte_index = 0;
285 irq_iommu->sub_handle = 0;
286 irq_iommu->irte_mask = 0;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700287
Thomas Gleixner96f8e982011-07-19 16:28:19 +0200288 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700289
Yu Zhao704126a2009-01-04 16:28:52 +0800290 return rc;
Suresh Siddhab6fcb332008-07-10 11:16:44 -0700291}
292
Weidong Hanf007e992009-05-23 00:41:15 +0800293/*
294 * source validation type
295 */
296#define SVT_NO_VERIFY 0x0 /* no verification is required */
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300297#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fields */
Weidong Hanf007e992009-05-23 00:41:15 +0800298#define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */
299
300/*
301 * source-id qualifier
302 */
303#define SQ_ALL_16 0x0 /* verify all 16 bits of request-id */
304#define SQ_13_IGNORE_1 0x1 /* verify most significant 13 bits, ignore
305 * the third least significant bit
306 */
307#define SQ_13_IGNORE_2 0x2 /* verify most significant 13 bits, ignore
308 * the second and third least significant bits
309 */
310#define SQ_13_IGNORE_3 0x3 /* verify most significant 13 bits, ignore
311 * the least three significant bits
312 */
313
314/*
315 * set SVT, SQ and SID fields of irte to verify
316 * source ids of interrupt requests
317 */
318static void set_irte_sid(struct irte *irte, unsigned int svt,
319 unsigned int sq, unsigned int sid)
320{
Chris Wrightd1423d52010-07-20 11:06:49 -0700321 if (disable_sourceid_checking)
322 svt = SVT_NO_VERIFY;
Weidong Hanf007e992009-05-23 00:41:15 +0800323 irte->svt = svt;
324 irte->sq = sq;
325 irte->sid = sid;
326}
327
Joerg Roedel263b5e82012-03-30 11:47:06 -0700328static int set_ioapic_sid(struct irte *irte, int apic)
Weidong Hanf007e992009-05-23 00:41:15 +0800329{
330 int i;
331 u16 sid = 0;
332
333 if (!irte)
334 return -1;
335
Jiang Liu3a5670e2014-02-19 14:07:33 +0800336 down_read(&dmar_global_lock);
Weidong Hanf007e992009-05-23 00:41:15 +0800337 for (i = 0; i < MAX_IO_APICS; i++) {
Jiang Liua7a3dad2014-11-09 22:48:00 +0800338 if (ir_ioapic[i].iommu && ir_ioapic[i].id == apic) {
Weidong Hanf007e992009-05-23 00:41:15 +0800339 sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn;
340 break;
341 }
342 }
Jiang Liu3a5670e2014-02-19 14:07:33 +0800343 up_read(&dmar_global_lock);
Weidong Hanf007e992009-05-23 00:41:15 +0800344
345 if (sid == 0) {
346 pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic);
347 return -1;
348 }
349
Jiang Liu2fe2c602014-01-06 14:18:17 +0800350 set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, sid);
Weidong Hanf007e992009-05-23 00:41:15 +0800351
352 return 0;
353}
354
Joerg Roedel263b5e82012-03-30 11:47:06 -0700355static int set_hpet_sid(struct irte *irte, u8 id)
Suresh Siddha20f30972009-08-04 12:07:08 -0700356{
357 int i;
358 u16 sid = 0;
359
360 if (!irte)
361 return -1;
362
Jiang Liu3a5670e2014-02-19 14:07:33 +0800363 down_read(&dmar_global_lock);
Suresh Siddha20f30972009-08-04 12:07:08 -0700364 for (i = 0; i < MAX_HPET_TBS; i++) {
Jiang Liua7a3dad2014-11-09 22:48:00 +0800365 if (ir_hpet[i].iommu && ir_hpet[i].id == id) {
Suresh Siddha20f30972009-08-04 12:07:08 -0700366 sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn;
367 break;
368 }
369 }
Jiang Liu3a5670e2014-02-19 14:07:33 +0800370 up_read(&dmar_global_lock);
Suresh Siddha20f30972009-08-04 12:07:08 -0700371
372 if (sid == 0) {
373 pr_warning("Failed to set source-id of HPET block (%d)\n", id);
374 return -1;
375 }
376
377 /*
378 * Should really use SQ_ALL_16. Some platforms are broken.
379 * While we figure out the right quirks for these broken platforms, use
380 * SQ_13_IGNORE_3 for now.
381 */
382 set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid);
383
384 return 0;
385}
386
Alex Williamson579305f2014-07-03 09:51:43 -0600387struct set_msi_sid_data {
388 struct pci_dev *pdev;
389 u16 alias;
390};
391
392static int set_msi_sid_cb(struct pci_dev *pdev, u16 alias, void *opaque)
393{
394 struct set_msi_sid_data *data = opaque;
395
396 data->pdev = pdev;
397 data->alias = alias;
398
399 return 0;
400}
401
Joerg Roedel263b5e82012-03-30 11:47:06 -0700402static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
Weidong Hanf007e992009-05-23 00:41:15 +0800403{
Alex Williamson579305f2014-07-03 09:51:43 -0600404 struct set_msi_sid_data data;
Weidong Hanf007e992009-05-23 00:41:15 +0800405
406 if (!irte || !dev)
407 return -1;
408
Alex Williamson579305f2014-07-03 09:51:43 -0600409 pci_for_each_dma_alias(dev, set_msi_sid_cb, &data);
Weidong Hanf007e992009-05-23 00:41:15 +0800410
Alex Williamson579305f2014-07-03 09:51:43 -0600411 /*
412 * DMA alias provides us with a PCI device and alias. The only case
413 * where the it will return an alias on a different bus than the
414 * device is the case of a PCIe-to-PCI bridge, where the alias is for
415 * the subordinate bus. In this case we can only verify the bus.
416 *
417 * If the alias device is on a different bus than our source device
418 * then we have a topology based alias, use it.
419 *
420 * Otherwise, the alias is for a device DMA quirk and we cannot
421 * assume that MSI uses the same requester ID. Therefore use the
422 * original device.
423 */
424 if (PCI_BUS_NUM(data.alias) != data.pdev->bus->number)
425 set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16,
426 PCI_DEVID(PCI_BUS_NUM(data.alias),
427 dev->bus->number));
428 else if (data.pdev->bus->number != dev->bus->number)
429 set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias);
430 else
431 set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
432 PCI_DEVID(dev->bus->number, dev->devfn));
Weidong Hanf007e992009-05-23 00:41:15 +0800433
434 return 0;
435}
436
Suresh Siddha95a02e92012-03-30 11:47:07 -0700437static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode)
Suresh Siddha2ae21012008-07-10 11:16:43 -0700438{
439 u64 addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100440 u32 sts;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700441 unsigned long flags;
442
443 addr = virt_to_phys((void *)iommu->ir_table->base);
444
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200445 raw_spin_lock_irqsave(&iommu->register_lock, flags);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700446
447 dmar_writeq(iommu->reg + DMAR_IRTA_REG,
448 (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE);
449
450 /* Set interrupt-remapping table pointer */
Jan Kiszkaf63ef692014-08-11 13:13:25 +0200451 writel(iommu->gcmd | DMA_GCMD_SIRTP, iommu->reg + DMAR_GCMD_REG);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700452
453 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
454 readl, (sts & DMA_GSTS_IRTPS), sts);
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200455 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700456
457 /*
458 * global invalidation of interrupt entry cache before enabling
459 * interrupt-remapping.
460 */
461 qi_global_iec(iommu);
462
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200463 raw_spin_lock_irqsave(&iommu->register_lock, flags);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700464
465 /* Enable interrupt-remapping */
Suresh Siddha2ae21012008-07-10 11:16:43 -0700466 iommu->gcmd |= DMA_GCMD_IRE;
Andy Lutomirskiaf8d1022013-02-01 14:57:43 -0800467 iommu->gcmd &= ~DMA_GCMD_CFI; /* Block compatibility-format MSIs */
David Woodhousec416daa2009-05-10 20:30:58 +0100468 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700469
470 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
471 readl, (sts & DMA_GSTS_IRES), sts);
472
Andy Lutomirskiaf8d1022013-02-01 14:57:43 -0800473 /*
474 * With CFI clear in the Global Command register, we should be
475 * protected from dangerous (i.e. compatibility) interrupts
476 * regardless of x2apic status. Check just to be sure.
477 */
478 if (sts & DMA_GSTS_CFIS)
479 WARN(1, KERN_WARNING
480 "Compatibility-format IRQs enabled despite intr remapping;\n"
481 "you are vulnerable to IRQ injection.\n");
482
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200483 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700484}
485
Jiang Liua7a3dad2014-11-09 22:48:00 +0800486static int intel_setup_irq_remapping(struct intel_iommu *iommu)
Suresh Siddha2ae21012008-07-10 11:16:43 -0700487{
488 struct ir_table *ir_table;
489 struct page *pages;
Jiang Liu360eb3c52014-01-06 14:18:08 +0800490 unsigned long *bitmap;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700491
Jiang Liua7a3dad2014-11-09 22:48:00 +0800492 if (iommu->ir_table)
493 return 0;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700494
Thomas Gleixnere3a981d2015-01-07 15:31:30 +0800495 ir_table = kzalloc(sizeof(struct ir_table), GFP_KERNEL);
Jiang Liua7a3dad2014-11-09 22:48:00 +0800496 if (!ir_table)
Suresh Siddha2ae21012008-07-10 11:16:43 -0700497 return -ENOMEM;
498
Thomas Gleixnere3a981d2015-01-07 15:31:30 +0800499 pages = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO,
Suresh Siddha824cd752009-10-02 11:01:23 -0700500 INTR_REMAP_PAGE_ORDER);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700501 if (!pages) {
Jiang Liu360eb3c52014-01-06 14:18:08 +0800502 pr_err("IR%d: failed to allocate pages of order %d\n",
503 iommu->seq_id, INTR_REMAP_PAGE_ORDER);
Jiang Liua7a3dad2014-11-09 22:48:00 +0800504 goto out_free_table;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700505 }
506
Jiang Liu360eb3c52014-01-06 14:18:08 +0800507 bitmap = kcalloc(BITS_TO_LONGS(INTR_REMAP_TABLE_ENTRIES),
508 sizeof(long), GFP_ATOMIC);
509 if (bitmap == NULL) {
510 pr_err("IR%d: failed to allocate bitmap\n", iommu->seq_id);
Jiang Liua7a3dad2014-11-09 22:48:00 +0800511 goto out_free_pages;
Jiang Liu360eb3c52014-01-06 14:18:08 +0800512 }
513
Jiang Liub106ee62015-04-13 14:11:32 +0800514 iommu->ir_domain = irq_domain_add_hierarchy(arch_get_ir_parent_domain(),
515 0, INTR_REMAP_TABLE_ENTRIES,
516 NULL, &intel_ir_domain_ops,
517 iommu);
518 if (!iommu->ir_domain) {
519 pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
520 goto out_free_bitmap;
521 }
522 iommu->ir_msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
523
Suresh Siddha2ae21012008-07-10 11:16:43 -0700524 ir_table->base = page_address(pages);
Jiang Liu360eb3c52014-01-06 14:18:08 +0800525 ir_table->bitmap = bitmap;
Jiang Liua7a3dad2014-11-09 22:48:00 +0800526 iommu->ir_table = ir_table;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700527 return 0;
Jiang Liua7a3dad2014-11-09 22:48:00 +0800528
Jiang Liub106ee62015-04-13 14:11:32 +0800529out_free_bitmap:
530 kfree(bitmap);
Jiang Liua7a3dad2014-11-09 22:48:00 +0800531out_free_pages:
532 __free_pages(pages, INTR_REMAP_PAGE_ORDER);
533out_free_table:
534 kfree(ir_table);
535 return -ENOMEM;
536}
537
538static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
539{
540 if (iommu && iommu->ir_table) {
Jiang Liub106ee62015-04-13 14:11:32 +0800541 if (iommu->ir_msi_domain) {
542 irq_domain_remove(iommu->ir_msi_domain);
543 iommu->ir_msi_domain = NULL;
544 }
545 if (iommu->ir_domain) {
546 irq_domain_remove(iommu->ir_domain);
547 iommu->ir_domain = NULL;
548 }
Jiang Liua7a3dad2014-11-09 22:48:00 +0800549 free_pages((unsigned long)iommu->ir_table->base,
550 INTR_REMAP_PAGE_ORDER);
551 kfree(iommu->ir_table->bitmap);
552 kfree(iommu->ir_table);
553 iommu->ir_table = NULL;
554 }
Suresh Siddha2ae21012008-07-10 11:16:43 -0700555}
556
Suresh Siddhaeba67e52009-03-16 17:04:56 -0700557/*
558 * Disable Interrupt Remapping.
559 */
Suresh Siddha95a02e92012-03-30 11:47:07 -0700560static void iommu_disable_irq_remapping(struct intel_iommu *iommu)
Suresh Siddhaeba67e52009-03-16 17:04:56 -0700561{
562 unsigned long flags;
563 u32 sts;
564
565 if (!ecap_ir_support(iommu->ecap))
566 return;
567
Fenghua Yub24696b2009-03-27 14:22:44 -0700568 /*
569 * global invalidation of interrupt entry cache before disabling
570 * interrupt-remapping.
571 */
572 qi_global_iec(iommu);
573
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200574 raw_spin_lock_irqsave(&iommu->register_lock, flags);
Suresh Siddhaeba67e52009-03-16 17:04:56 -0700575
576 sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
577 if (!(sts & DMA_GSTS_IRES))
578 goto end;
579
580 iommu->gcmd &= ~DMA_GCMD_IRE;
581 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
582
583 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
584 readl, !(sts & DMA_GSTS_IRES), sts);
585
586end:
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200587 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Suresh Siddhaeba67e52009-03-16 17:04:56 -0700588}
589
Suresh Siddha41750d32011-08-23 17:05:18 -0700590static int __init dmar_x2apic_optout(void)
591{
592 struct acpi_table_dmar *dmar;
593 dmar = (struct acpi_table_dmar *)dmar_tbl;
594 if (!dmar || no_x2apic_optout)
595 return 0;
596 return dmar->flags & DMAR_X2APIC_OPT_OUT;
597}
598
Thomas Gleixner11190302015-01-07 15:31:29 +0800599static void __init intel_cleanup_irq_remapping(void)
600{
601 struct dmar_drhd_unit *drhd;
602 struct intel_iommu *iommu;
603
604 for_each_iommu(iommu, drhd) {
605 if (ecap_ir_support(iommu->ecap)) {
606 iommu_disable_irq_remapping(iommu);
607 intel_teardown_irq_remapping(iommu);
608 }
609 }
610
611 if (x2apic_supported())
612 pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
613}
614
615static int __init intel_prepare_irq_remapping(void)
616{
617 struct dmar_drhd_unit *drhd;
618 struct intel_iommu *iommu;
619
Jiang Liu2966d952015-01-07 15:31:35 +0800620 if (irq_remap_broken) {
621 printk(KERN_WARNING
622 "This system BIOS has enabled interrupt remapping\n"
623 "on a chipset that contains an erratum making that\n"
624 "feature unstable. To maintain system stability\n"
625 "interrupt remapping is being disabled. Please\n"
626 "contact your BIOS vendor for an update\n");
627 add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
Jiang Liu2966d952015-01-07 15:31:35 +0800628 return -ENODEV;
629 }
630
Thomas Gleixner11190302015-01-07 15:31:29 +0800631 if (dmar_table_init() < 0)
Jiang Liu2966d952015-01-07 15:31:35 +0800632 return -ENODEV;
633
634 if (!dmar_ir_support())
635 return -ENODEV;
Thomas Gleixner11190302015-01-07 15:31:29 +0800636
637 if (parse_ioapics_under_ir() != 1) {
638 printk(KERN_INFO "Not enabling interrupt remapping\n");
639 goto error;
640 }
641
Joerg Roedel69cf1d82015-01-07 15:31:36 +0800642 /* First make sure all IOMMUs support IRQ remapping */
Jiang Liu2966d952015-01-07 15:31:35 +0800643 for_each_iommu(iommu, drhd)
Joerg Roedel69cf1d82015-01-07 15:31:36 +0800644 if (!ecap_ir_support(iommu->ecap))
Thomas Gleixner11190302015-01-07 15:31:29 +0800645 goto error;
Joerg Roedel69cf1d82015-01-07 15:31:36 +0800646
647 /* Do the allocations early */
648 for_each_iommu(iommu, drhd)
649 if (intel_setup_irq_remapping(iommu))
650 goto error;
651
Thomas Gleixner11190302015-01-07 15:31:29 +0800652 return 0;
Jiang Liu2966d952015-01-07 15:31:35 +0800653
Thomas Gleixner11190302015-01-07 15:31:29 +0800654error:
655 intel_cleanup_irq_remapping();
Jiang Liu2966d952015-01-07 15:31:35 +0800656 return -ENODEV;
Thomas Gleixner11190302015-01-07 15:31:29 +0800657}
658
Suresh Siddha95a02e92012-03-30 11:47:07 -0700659static int __init intel_enable_irq_remapping(void)
Suresh Siddha2ae21012008-07-10 11:16:43 -0700660{
661 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +0800662 struct intel_iommu *iommu;
Quentin Lambert2f119c72015-02-06 10:59:53 +0100663 bool setup = false;
Suresh Siddha41750d32011-08-23 17:05:18 -0700664 int eim = 0;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700665
Thomas Gleixner11190302015-01-07 15:31:29 +0800666 if (x2apic_supported()) {
Suresh Siddha41750d32011-08-23 17:05:18 -0700667 eim = !dmar_x2apic_optout();
Andy Lutomirskiaf8d1022013-02-01 14:57:43 -0800668 if (!eim)
669 printk(KERN_WARNING
670 "Your BIOS is broken and requested that x2apic be disabled.\n"
671 "This will slightly decrease performance.\n"
672 "Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
Suresh Siddha41750d32011-08-23 17:05:18 -0700673 }
674
Jiang Liu7c919772014-01-06 14:18:18 +0800675 for_each_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -0700676 /*
Han, Weidong34aaaa92009-04-04 17:21:26 +0800677 * If the queued invalidation is already initialized,
678 * shouldn't disable it.
679 */
680 if (iommu->qi)
681 continue;
682
683 /*
Suresh Siddha1531a6a2009-03-16 17:04:57 -0700684 * Clear previous faults.
685 */
686 dmar_fault(-1, iommu);
687
688 /*
689 * Disable intr remapping and queued invalidation, if already
690 * enabled prior to OS handover.
691 */
Suresh Siddha95a02e92012-03-30 11:47:07 -0700692 iommu_disable_irq_remapping(iommu);
Suresh Siddha1531a6a2009-03-16 17:04:57 -0700693
694 dmar_disable_qi(iommu);
695 }
696
Suresh Siddha2ae21012008-07-10 11:16:43 -0700697 /*
698 * check for the Interrupt-remapping support
699 */
Joerg Roedel69cf1d82015-01-07 15:31:36 +0800700 for_each_iommu(iommu, drhd)
Suresh Siddha2ae21012008-07-10 11:16:43 -0700701 if (eim && !ecap_eim_support(iommu->ecap)) {
702 printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
703 " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
Jiang Liu13d09b62015-01-07 15:31:37 +0800704 eim = 0;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700705 }
Jiang Liu13d09b62015-01-07 15:31:37 +0800706 eim_mode = eim;
707 if (eim)
708 pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
Suresh Siddha2ae21012008-07-10 11:16:43 -0700709
710 /*
711 * Enable queued invalidation for all the DRHD's.
712 */
Jiang Liu7c919772014-01-06 14:18:18 +0800713 for_each_iommu(iommu, drhd) {
714 int ret = dmar_enable_qi(iommu);
Suresh Siddha2ae21012008-07-10 11:16:43 -0700715
716 if (ret) {
717 printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
718 " invalidation, ecap %Lx, ret %d\n",
719 drhd->reg_base_addr, iommu->ecap, ret);
Andy Lutomirskiaf8d1022013-02-01 14:57:43 -0800720 goto error;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700721 }
722 }
723
724 /*
725 * Setup Interrupt-remapping for all the DRHD's now.
726 */
Jiang Liu7c919772014-01-06 14:18:18 +0800727 for_each_iommu(iommu, drhd) {
Jiang Liua7a3dad2014-11-09 22:48:00 +0800728 iommu_set_irq_remapping(iommu, eim);
Quentin Lambert2f119c72015-02-06 10:59:53 +0100729 setup = true;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700730 }
731
732 if (!setup)
733 goto error;
734
Suresh Siddha95a02e92012-03-30 11:47:07 -0700735 irq_remapping_enabled = 1;
Joerg Roedelafcc8a42012-09-26 12:44:36 +0200736
737 /*
738 * VT-d has a different layout for IO-APIC entries when
739 * interrupt remapping is enabled. So it needs a special routine
740 * to print IO-APIC entries for debugging purposes too.
741 */
742 x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries;
743
Suresh Siddha41750d32011-08-23 17:05:18 -0700744 pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
Suresh Siddha2ae21012008-07-10 11:16:43 -0700745
Suresh Siddha41750d32011-08-23 17:05:18 -0700746 return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
Suresh Siddha2ae21012008-07-10 11:16:43 -0700747
748error:
Thomas Gleixner11190302015-01-07 15:31:29 +0800749 intel_cleanup_irq_remapping();
Suresh Siddha2ae21012008-07-10 11:16:43 -0700750 return -1;
751}
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700752
Jiang Liua7a3dad2014-11-09 22:48:00 +0800753static int ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope,
754 struct intel_iommu *iommu,
755 struct acpi_dmar_hardware_unit *drhd)
Suresh Siddha20f30972009-08-04 12:07:08 -0700756{
757 struct acpi_dmar_pci_path *path;
758 u8 bus;
Jiang Liua7a3dad2014-11-09 22:48:00 +0800759 int count, free = -1;
Suresh Siddha20f30972009-08-04 12:07:08 -0700760
761 bus = scope->bus;
762 path = (struct acpi_dmar_pci_path *)(scope + 1);
763 count = (scope->length - sizeof(struct acpi_dmar_device_scope))
764 / sizeof(struct acpi_dmar_pci_path);
765
766 while (--count > 0) {
767 /*
768 * Access PCI directly due to the PCI
769 * subsystem isn't initialized yet.
770 */
Lv Zhengfa5f5082013-10-31 09:30:22 +0800771 bus = read_pci_config_byte(bus, path->device, path->function,
Suresh Siddha20f30972009-08-04 12:07:08 -0700772 PCI_SECONDARY_BUS);
773 path++;
774 }
Jiang Liua7a3dad2014-11-09 22:48:00 +0800775
776 for (count = 0; count < MAX_HPET_TBS; count++) {
777 if (ir_hpet[count].iommu == iommu &&
778 ir_hpet[count].id == scope->enumeration_id)
779 return 0;
780 else if (ir_hpet[count].iommu == NULL && free == -1)
781 free = count;
782 }
783 if (free == -1) {
784 pr_warn("Exceeded Max HPET blocks\n");
785 return -ENOSPC;
786 }
787
788 ir_hpet[free].iommu = iommu;
789 ir_hpet[free].id = scope->enumeration_id;
790 ir_hpet[free].bus = bus;
791 ir_hpet[free].devfn = PCI_DEVFN(path->device, path->function);
792 pr_info("HPET id %d under DRHD base 0x%Lx\n",
793 scope->enumeration_id, drhd->address);
794
795 return 0;
Suresh Siddha20f30972009-08-04 12:07:08 -0700796}
797
Jiang Liua7a3dad2014-11-09 22:48:00 +0800798static int ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
799 struct intel_iommu *iommu,
800 struct acpi_dmar_hardware_unit *drhd)
Weidong Hanf007e992009-05-23 00:41:15 +0800801{
802 struct acpi_dmar_pci_path *path;
803 u8 bus;
Jiang Liua7a3dad2014-11-09 22:48:00 +0800804 int count, free = -1;
Weidong Hanf007e992009-05-23 00:41:15 +0800805
806 bus = scope->bus;
807 path = (struct acpi_dmar_pci_path *)(scope + 1);
808 count = (scope->length - sizeof(struct acpi_dmar_device_scope))
809 / sizeof(struct acpi_dmar_pci_path);
810
811 while (--count > 0) {
812 /*
813 * Access PCI directly due to the PCI
814 * subsystem isn't initialized yet.
815 */
Lv Zhengfa5f5082013-10-31 09:30:22 +0800816 bus = read_pci_config_byte(bus, path->device, path->function,
Weidong Hanf007e992009-05-23 00:41:15 +0800817 PCI_SECONDARY_BUS);
818 path++;
819 }
820
Jiang Liua7a3dad2014-11-09 22:48:00 +0800821 for (count = 0; count < MAX_IO_APICS; count++) {
822 if (ir_ioapic[count].iommu == iommu &&
823 ir_ioapic[count].id == scope->enumeration_id)
824 return 0;
825 else if (ir_ioapic[count].iommu == NULL && free == -1)
826 free = count;
827 }
828 if (free == -1) {
829 pr_warn("Exceeded Max IO APICS\n");
830 return -ENOSPC;
831 }
832
833 ir_ioapic[free].bus = bus;
834 ir_ioapic[free].devfn = PCI_DEVFN(path->device, path->function);
835 ir_ioapic[free].iommu = iommu;
836 ir_ioapic[free].id = scope->enumeration_id;
837 pr_info("IOAPIC id %d under DRHD base 0x%Lx IOMMU %d\n",
838 scope->enumeration_id, drhd->address, iommu->seq_id);
839
840 return 0;
Weidong Hanf007e992009-05-23 00:41:15 +0800841}
842
Suresh Siddha20f30972009-08-04 12:07:08 -0700843static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
844 struct intel_iommu *iommu)
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700845{
Jiang Liua7a3dad2014-11-09 22:48:00 +0800846 int ret = 0;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700847 struct acpi_dmar_hardware_unit *drhd;
848 struct acpi_dmar_device_scope *scope;
849 void *start, *end;
850
851 drhd = (struct acpi_dmar_hardware_unit *)header;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700852 start = (void *)(drhd + 1);
853 end = ((void *)drhd) + header->length;
854
Jiang Liua7a3dad2014-11-09 22:48:00 +0800855 while (start < end && ret == 0) {
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700856 scope = start;
Jiang Liua7a3dad2014-11-09 22:48:00 +0800857 if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_IOAPIC)
858 ret = ir_parse_one_ioapic_scope(scope, iommu, drhd);
859 else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET)
860 ret = ir_parse_one_hpet_scope(scope, iommu, drhd);
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700861 start += scope->length;
862 }
863
Jiang Liua7a3dad2014-11-09 22:48:00 +0800864 return ret;
865}
866
867static void ir_remove_ioapic_hpet_scope(struct intel_iommu *iommu)
868{
869 int i;
870
871 for (i = 0; i < MAX_HPET_TBS; i++)
872 if (ir_hpet[i].iommu == iommu)
873 ir_hpet[i].iommu = NULL;
874
875 for (i = 0; i < MAX_IO_APICS; i++)
876 if (ir_ioapic[i].iommu == iommu)
877 ir_ioapic[i].iommu = NULL;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700878}
879
880/*
881 * Finds the assocaition between IOAPIC's and its Interrupt-remapping
882 * hardware unit.
883 */
Jiang Liu694835d2014-01-06 14:18:16 +0800884static int __init parse_ioapics_under_ir(void)
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700885{
886 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +0800887 struct intel_iommu *iommu;
Quentin Lambert2f119c72015-02-06 10:59:53 +0100888 bool ir_supported = false;
Seth Forshee32ab31e2012-08-08 08:27:03 -0500889 int ioapic_idx;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700890
Jiang Liu7c919772014-01-06 14:18:18 +0800891 for_each_iommu(iommu, drhd)
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700892 if (ecap_ir_support(iommu->ecap)) {
Suresh Siddha20f30972009-08-04 12:07:08 -0700893 if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700894 return -1;
895
Quentin Lambert2f119c72015-02-06 10:59:53 +0100896 ir_supported = true;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700897 }
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700898
Seth Forshee32ab31e2012-08-08 08:27:03 -0500899 if (!ir_supported)
900 return 0;
901
902 for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
903 int ioapic_id = mpc_ioapic_id(ioapic_idx);
904 if (!map_ioapic_to_ir(ioapic_id)) {
905 pr_err(FW_BUG "ioapic %d has no mapping iommu, "
906 "interrupt remapping will be disabled\n",
907 ioapic_id);
908 return -1;
909 }
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700910 }
911
Seth Forshee32ab31e2012-08-08 08:27:03 -0500912 return 1;
Suresh Siddhaad3ad3f2008-07-10 11:16:40 -0700913}
Fenghua Yub24696b2009-03-27 14:22:44 -0700914
Rashika Kheria6a7885c2013-12-18 12:04:27 +0530915static int __init ir_dev_scope_init(void)
Suresh Siddhac2c72862011-08-23 17:05:19 -0700916{
Jiang Liu3a5670e2014-02-19 14:07:33 +0800917 int ret;
918
Suresh Siddha95a02e92012-03-30 11:47:07 -0700919 if (!irq_remapping_enabled)
Suresh Siddhac2c72862011-08-23 17:05:19 -0700920 return 0;
921
Jiang Liu3a5670e2014-02-19 14:07:33 +0800922 down_write(&dmar_global_lock);
923 ret = dmar_dev_scope_init();
924 up_write(&dmar_global_lock);
925
926 return ret;
Suresh Siddhac2c72862011-08-23 17:05:19 -0700927}
928rootfs_initcall(ir_dev_scope_init);
929
Suresh Siddha95a02e92012-03-30 11:47:07 -0700930static void disable_irq_remapping(void)
Fenghua Yub24696b2009-03-27 14:22:44 -0700931{
932 struct dmar_drhd_unit *drhd;
933 struct intel_iommu *iommu = NULL;
934
935 /*
936 * Disable Interrupt-remapping for all the DRHD's now.
937 */
938 for_each_iommu(iommu, drhd) {
939 if (!ecap_ir_support(iommu->ecap))
940 continue;
941
Suresh Siddha95a02e92012-03-30 11:47:07 -0700942 iommu_disable_irq_remapping(iommu);
Fenghua Yub24696b2009-03-27 14:22:44 -0700943 }
944}
945
Suresh Siddha95a02e92012-03-30 11:47:07 -0700946static int reenable_irq_remapping(int eim)
Fenghua Yub24696b2009-03-27 14:22:44 -0700947{
948 struct dmar_drhd_unit *drhd;
Quentin Lambert2f119c72015-02-06 10:59:53 +0100949 bool setup = false;
Fenghua Yub24696b2009-03-27 14:22:44 -0700950 struct intel_iommu *iommu = NULL;
951
952 for_each_iommu(iommu, drhd)
953 if (iommu->qi)
954 dmar_reenable_qi(iommu);
955
956 /*
957 * Setup Interrupt-remapping for all the DRHD's now.
958 */
959 for_each_iommu(iommu, drhd) {
960 if (!ecap_ir_support(iommu->ecap))
961 continue;
962
963 /* Set up interrupt remapping for iommu.*/
Suresh Siddha95a02e92012-03-30 11:47:07 -0700964 iommu_set_irq_remapping(iommu, eim);
Quentin Lambert2f119c72015-02-06 10:59:53 +0100965 setup = true;
Fenghua Yub24696b2009-03-27 14:22:44 -0700966 }
967
968 if (!setup)
969 goto error;
970
971 return 0;
972
973error:
974 /*
975 * handle error condition gracefully here!
976 */
977 return -1;
978}
979
Joerg Roedel0c3f1732012-03-30 11:47:02 -0700980static void prepare_irte(struct irte *irte, int vector,
981 unsigned int dest)
982{
983 memset(irte, 0, sizeof(*irte));
984
985 irte->present = 1;
986 irte->dst_mode = apic->irq_dest_mode;
987 /*
988 * Trigger mode in the IRTE will always be edge, and for IO-APIC, the
989 * actual level or edge trigger will be setup in the IO-APIC
990 * RTE. This will help simplify level triggered irq migration.
991 * For more details, see the comments (in io_apic.c) explainig IO-APIC
992 * irq migration in the presence of interrupt-remapping.
993 */
994 irte->trigger_mode = 0;
995 irte->dlvry_mode = apic->irq_delivery_mode;
996 irte->vector = vector;
997 irte->dest_id = IRTE_DEST(dest);
998 irte->redir_hint = 1;
999}
1000
1001static int intel_setup_ioapic_entry(int irq,
1002 struct IO_APIC_route_entry *route_entry,
1003 unsigned int destination, int vector,
1004 struct io_apic_irq_attr *attr)
1005{
1006 int ioapic_id = mpc_ioapic_id(attr->ioapic);
Jiang Liu3a5670e2014-02-19 14:07:33 +08001007 struct intel_iommu *iommu;
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001008 struct IR_IO_APIC_route_entry *entry;
1009 struct irte irte;
1010 int index;
1011
Jiang Liu3a5670e2014-02-19 14:07:33 +08001012 down_read(&dmar_global_lock);
1013 iommu = map_ioapic_to_ir(ioapic_id);
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001014 if (!iommu) {
1015 pr_warn("No mapping iommu for ioapic %d\n", ioapic_id);
Jiang Liu3a5670e2014-02-19 14:07:33 +08001016 index = -ENODEV;
1017 } else {
Jiang Liu8dedf4c2015-04-13 14:11:31 +08001018 index = alloc_irte(iommu, irq, irq_2_iommu(irq), 1);
Jiang Liu3a5670e2014-02-19 14:07:33 +08001019 if (index < 0) {
1020 pr_warn("Failed to allocate IRTE for ioapic %d\n",
1021 ioapic_id);
1022 index = -ENOMEM;
1023 }
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001024 }
Jiang Liu3a5670e2014-02-19 14:07:33 +08001025 up_read(&dmar_global_lock);
1026 if (index < 0)
1027 return index;
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001028
1029 prepare_irte(&irte, vector, destination);
1030
1031 /* Set source-id of interrupt request */
1032 set_ioapic_sid(&irte, ioapic_id);
1033
Jiang Liu8dedf4c2015-04-13 14:11:31 +08001034 modify_irte(irq_2_iommu(irq), &irte);
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001035
1036 apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
1037 "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
1038 "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X "
1039 "Avail:%X Vector:%02X Dest:%08X "
1040 "SID:%04X SQ:%X SVT:%X)\n",
1041 attr->ioapic, irte.present, irte.fpd, irte.dst_mode,
1042 irte.redir_hint, irte.trigger_mode, irte.dlvry_mode,
1043 irte.avail, irte.vector, irte.dest_id,
1044 irte.sid, irte.sq, irte.svt);
1045
Jiang Liu3a5670e2014-02-19 14:07:33 +08001046 entry = (struct IR_IO_APIC_route_entry *)route_entry;
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001047 memset(entry, 0, sizeof(*entry));
1048
1049 entry->index2 = (index >> 15) & 0x1;
1050 entry->zero = 0;
1051 entry->format = 1;
1052 entry->index = (index & 0x7fff);
1053 /*
1054 * IO-APIC RTE will be configured with virtual vector.
1055 * irq handler will do the explicit EOI to the io-apic.
1056 */
1057 entry->vector = attr->ioapic_pin;
1058 entry->mask = 0; /* enable IRQ */
1059 entry->trigger = attr->trigger;
1060 entry->polarity = attr->polarity;
1061
1062 /* Mask level triggered irqs.
1063 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
1064 */
1065 if (attr->trigger)
1066 entry->mask = 1;
1067
1068 return 0;
1069}
1070
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001071/*
1072 * Migrate the IO-APIC irq in the presence of intr-remapping.
1073 *
1074 * For both level and edge triggered, irq migration is a simple atomic
1075 * update(of vector and cpu destination) of IRTE and flush the hardware cache.
1076 *
1077 * For level triggered, we eliminate the io-apic RTE modification (with the
1078 * updated vector information), by using a virtual vector (io-apic pin number).
1079 * Real vector that is used for interrupting cpu will be coming from
1080 * the interrupt-remapping table entry.
1081 *
1082 * As the migration is a simple atomic update of IRTE, the same mechanism
1083 * is used to migrate MSI irq's in the presence of interrupt-remapping.
1084 */
1085static int
1086intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
1087 bool force)
1088{
Jiang Liu91411da2014-10-27 16:12:09 +08001089 struct irq_cfg *cfg = irqd_cfg(data);
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001090 unsigned int dest, irq = data->irq;
1091 struct irte irte;
Alexander Gordeevff164322012-06-07 15:15:59 +02001092 int err;
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001093
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001094 if (get_irte(irq, &irte))
1095 return -EBUSY;
1096
Alexander Gordeevff164322012-06-07 15:15:59 +02001097 err = assign_irq_vector(irq, cfg, mask);
1098 if (err)
1099 return err;
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001100
Alexander Gordeevff164322012-06-07 15:15:59 +02001101 err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
1102 if (err) {
Dan Carpentered88bed2012-06-12 19:26:33 +03001103 if (assign_irq_vector(irq, cfg, data->affinity))
Alexander Gordeevff164322012-06-07 15:15:59 +02001104 pr_err("Failed to recover vector for irq %d\n", irq);
1105 return err;
1106 }
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001107
1108 irte.vector = cfg->vector;
1109 irte.dest_id = IRTE_DEST(dest);
1110
1111 /*
1112 * Atomically updates the IRTE with the new destination, vector
1113 * and flushes the interrupt entry cache.
1114 */
Jiang Liu8dedf4c2015-04-13 14:11:31 +08001115 modify_irte(irq_2_iommu(irq), &irte);
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001116
1117 /*
1118 * After this point, all the interrupts will start arriving
1119 * at the new destination. So, time to cleanup the previous
1120 * vector allocation.
1121 */
1122 if (cfg->move_in_progress)
1123 send_cleanup_vector(cfg);
1124
1125 cpumask_copy(data->affinity, mask);
Jiang Liub106ee62015-04-13 14:11:32 +08001126
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001127 return 0;
1128}
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001129
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001130static void intel_compose_msi_msg(struct pci_dev *pdev,
1131 unsigned int irq, unsigned int dest,
1132 struct msi_msg *msg, u8 hpet_id)
1133{
1134 struct irq_cfg *cfg;
1135 struct irte irte;
Suresh Siddhac558df42012-05-08 00:08:54 -07001136 u16 sub_handle = 0;
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001137 int ir_index;
1138
Jiang Liu91411da2014-10-27 16:12:09 +08001139 cfg = irq_cfg(irq);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001140
1141 ir_index = map_irq_to_irte_handle(irq, &sub_handle);
1142 BUG_ON(ir_index == -1);
1143
1144 prepare_irte(&irte, cfg->vector, dest);
1145
1146 /* Set source-id of interrupt request */
1147 if (pdev)
1148 set_msi_sid(&irte, pdev);
1149 else
1150 set_hpet_sid(&irte, hpet_id);
1151
Jiang Liu8dedf4c2015-04-13 14:11:31 +08001152 modify_irte(irq_2_iommu(irq), &irte);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001153
1154 msg->address_hi = MSI_ADDR_BASE_HI;
1155 msg->data = sub_handle;
1156 msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
1157 MSI_ADDR_IR_SHV |
1158 MSI_ADDR_IR_INDEX1(ir_index) |
1159 MSI_ADDR_IR_INDEX2(ir_index);
1160}
1161
1162/*
1163 * Map the PCI dev to the corresponding remapping hardware unit
1164 * and allocate 'nvec' consecutive interrupt-remapping table entries
1165 * in it.
1166 */
1167static int intel_msi_alloc_irq(struct pci_dev *dev, int irq, int nvec)
1168{
1169 struct intel_iommu *iommu;
1170 int index;
1171
Jiang Liu3a5670e2014-02-19 14:07:33 +08001172 down_read(&dmar_global_lock);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001173 iommu = map_dev_to_ir(dev);
1174 if (!iommu) {
1175 printk(KERN_ERR
1176 "Unable to map PCI %s to iommu\n", pci_name(dev));
Jiang Liu3a5670e2014-02-19 14:07:33 +08001177 index = -ENOENT;
1178 } else {
Jiang Liu8dedf4c2015-04-13 14:11:31 +08001179 index = alloc_irte(iommu, irq, irq_2_iommu(irq), nvec);
Jiang Liu3a5670e2014-02-19 14:07:33 +08001180 if (index < 0) {
1181 printk(KERN_ERR
1182 "Unable to allocate %d IRTE for PCI %s\n",
1183 nvec, pci_name(dev));
1184 index = -ENOSPC;
1185 }
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001186 }
Jiang Liu3a5670e2014-02-19 14:07:33 +08001187 up_read(&dmar_global_lock);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001188
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001189 return index;
1190}
1191
1192static int intel_msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
1193 int index, int sub_handle)
1194{
1195 struct intel_iommu *iommu;
Jiang Liu3a5670e2014-02-19 14:07:33 +08001196 int ret = -ENOENT;
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001197
Jiang Liu3a5670e2014-02-19 14:07:33 +08001198 down_read(&dmar_global_lock);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001199 iommu = map_dev_to_ir(pdev);
Jiang Liu3a5670e2014-02-19 14:07:33 +08001200 if (iommu) {
1201 /*
1202 * setup the mapping between the irq and the IRTE
1203 * base index, the sub_handle pointing to the
1204 * appropriate interrupt remap table entry.
1205 */
1206 set_irte_irq(irq, iommu, index, sub_handle);
1207 ret = 0;
1208 }
1209 up_read(&dmar_global_lock);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001210
Jiang Liu3a5670e2014-02-19 14:07:33 +08001211 return ret;
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001212}
1213
Yijing Wang5fc24d82014-09-17 17:32:19 +08001214static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001215{
Jiang Liu3a5670e2014-02-19 14:07:33 +08001216 int ret = -1;
1217 struct intel_iommu *iommu;
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001218 int index;
1219
Jiang Liu3a5670e2014-02-19 14:07:33 +08001220 down_read(&dmar_global_lock);
1221 iommu = map_hpet_to_ir(id);
1222 if (iommu) {
Jiang Liu8dedf4c2015-04-13 14:11:31 +08001223 index = alloc_irte(iommu, irq, irq_2_iommu(irq), 1);
Jiang Liu3a5670e2014-02-19 14:07:33 +08001224 if (index >= 0)
1225 ret = 0;
1226 }
1227 up_read(&dmar_global_lock);
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001228
Jiang Liu3a5670e2014-02-19 14:07:33 +08001229 return ret;
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001230}
1231
Jiang Liub106ee62015-04-13 14:11:32 +08001232static struct irq_domain *intel_get_ir_irq_domain(struct irq_alloc_info *info)
1233{
1234 struct intel_iommu *iommu = NULL;
1235
1236 if (!info)
1237 return NULL;
1238
1239 switch (info->type) {
1240 case X86_IRQ_ALLOC_TYPE_IOAPIC:
1241 iommu = map_ioapic_to_ir(info->ioapic_id);
1242 break;
1243 case X86_IRQ_ALLOC_TYPE_HPET:
1244 iommu = map_hpet_to_ir(info->hpet_id);
1245 break;
1246 case X86_IRQ_ALLOC_TYPE_MSI:
1247 case X86_IRQ_ALLOC_TYPE_MSIX:
1248 iommu = map_dev_to_ir(info->msi_dev);
1249 break;
1250 default:
1251 BUG_ON(1);
1252 break;
1253 }
1254
1255 return iommu ? iommu->ir_domain : NULL;
1256}
1257
1258static struct irq_domain *intel_get_irq_domain(struct irq_alloc_info *info)
1259{
1260 struct intel_iommu *iommu;
1261
1262 if (!info)
1263 return NULL;
1264
1265 switch (info->type) {
1266 case X86_IRQ_ALLOC_TYPE_MSI:
1267 case X86_IRQ_ALLOC_TYPE_MSIX:
1268 iommu = map_dev_to_ir(info->msi_dev);
1269 if (iommu)
1270 return iommu->ir_msi_domain;
1271 break;
1272 default:
1273 break;
1274 }
1275
1276 return NULL;
1277}
1278
Joerg Roedel736baef2012-03-30 11:47:00 -07001279struct irq_remap_ops intel_irq_remap_ops = {
Thomas Gleixner11190302015-01-07 15:31:29 +08001280 .prepare = intel_prepare_irq_remapping,
Suresh Siddha95a02e92012-03-30 11:47:07 -07001281 .enable = intel_enable_irq_remapping,
1282 .disable = disable_irq_remapping,
1283 .reenable = reenable_irq_remapping,
Joerg Roedel4f3d8b62012-03-30 11:47:01 -07001284 .enable_faulting = enable_drhd_fault_handling,
Joerg Roedel0c3f1732012-03-30 11:47:02 -07001285 .setup_ioapic_entry = intel_setup_ioapic_entry,
Joerg Roedel4c1bad62012-03-30 11:47:03 -07001286 .set_affinity = intel_ioapic_set_affinity,
Joerg Roedel9d619f62012-03-30 11:47:04 -07001287 .free_irq = free_irte,
Joerg Roedel5e2b9302012-03-30 11:47:05 -07001288 .compose_msi_msg = intel_compose_msi_msg,
1289 .msi_alloc_irq = intel_msi_alloc_irq,
1290 .msi_setup_irq = intel_msi_setup_irq,
Yijing Wang5fc24d82014-09-17 17:32:19 +08001291 .alloc_hpet_msi = intel_alloc_hpet_msi,
Jiang Liub106ee62015-04-13 14:11:32 +08001292 .get_ir_irq_domain = intel_get_ir_irq_domain,
1293 .get_irq_domain = intel_get_irq_domain,
1294};
1295
1296/*
1297 * Migrate the IO-APIC irq in the presence of intr-remapping.
1298 *
1299 * For both level and edge triggered, irq migration is a simple atomic
1300 * update(of vector and cpu destination) of IRTE and flush the hardware cache.
1301 *
1302 * For level triggered, we eliminate the io-apic RTE modification (with the
1303 * updated vector information), by using a virtual vector (io-apic pin number).
1304 * Real vector that is used for interrupting cpu will be coming from
1305 * the interrupt-remapping table entry.
1306 *
1307 * As the migration is a simple atomic update of IRTE, the same mechanism
1308 * is used to migrate MSI irq's in the presence of interrupt-remapping.
1309 */
1310static int
1311intel_ir_set_affinity(struct irq_data *data, const struct cpumask *mask,
1312 bool force)
1313{
1314 struct intel_ir_data *ir_data = data->chip_data;
1315 struct irte *irte = &ir_data->irte_entry;
1316 struct irq_cfg *cfg = irqd_cfg(data);
1317 struct irq_data *parent = data->parent_data;
1318 int ret;
1319
1320 ret = parent->chip->irq_set_affinity(parent, mask, force);
1321 if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
1322 return ret;
1323
1324 /*
1325 * Atomically updates the IRTE with the new destination, vector
1326 * and flushes the interrupt entry cache.
1327 */
1328 irte->vector = cfg->vector;
1329 irte->dest_id = IRTE_DEST(cfg->dest_apicid);
1330 modify_irte(&ir_data->irq_2_iommu, irte);
1331
1332 /*
1333 * After this point, all the interrupts will start arriving
1334 * at the new destination. So, time to cleanup the previous
1335 * vector allocation.
1336 */
1337 if (cfg->move_in_progress)
1338 send_cleanup_vector(cfg);
1339
1340 return IRQ_SET_MASK_OK_DONE;
1341}
1342
1343static void intel_ir_compose_msi_msg(struct irq_data *irq_data,
1344 struct msi_msg *msg)
1345{
1346 struct intel_ir_data *ir_data = irq_data->chip_data;
1347
1348 *msg = ir_data->msi_entry;
1349}
1350
1351static struct irq_chip intel_ir_chip = {
1352 .irq_ack = ir_ack_apic_edge,
1353 .irq_set_affinity = intel_ir_set_affinity,
1354 .irq_compose_msi_msg = intel_ir_compose_msi_msg,
1355};
1356
1357static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
1358 struct irq_cfg *irq_cfg,
1359 struct irq_alloc_info *info,
1360 int index, int sub_handle)
1361{
1362 struct IR_IO_APIC_route_entry *entry;
1363 struct irte *irte = &data->irte_entry;
1364 struct msi_msg *msg = &data->msi_entry;
1365
1366 prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);
1367 switch (info->type) {
1368 case X86_IRQ_ALLOC_TYPE_IOAPIC:
1369 /* Set source-id of interrupt request */
1370 set_ioapic_sid(irte, info->ioapic_id);
1371 apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: Set IRTE entry (P:%d FPD:%d Dst_Mode:%d Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X Avail:%X Vector:%02X Dest:%08X SID:%04X SQ:%X SVT:%X)\n",
1372 info->ioapic_id, irte->present, irte->fpd,
1373 irte->dst_mode, irte->redir_hint,
1374 irte->trigger_mode, irte->dlvry_mode,
1375 irte->avail, irte->vector, irte->dest_id,
1376 irte->sid, irte->sq, irte->svt);
1377
1378 entry = (struct IR_IO_APIC_route_entry *)info->ioapic_entry;
1379 info->ioapic_entry = NULL;
1380 memset(entry, 0, sizeof(*entry));
1381 entry->index2 = (index >> 15) & 0x1;
1382 entry->zero = 0;
1383 entry->format = 1;
1384 entry->index = (index & 0x7fff);
1385 /*
1386 * IO-APIC RTE will be configured with virtual vector.
1387 * irq handler will do the explicit EOI to the io-apic.
1388 */
1389 entry->vector = info->ioapic_pin;
1390 entry->mask = 0; /* enable IRQ */
1391 entry->trigger = info->ioapic_trigger;
1392 entry->polarity = info->ioapic_polarity;
1393 if (info->ioapic_trigger)
1394 entry->mask = 1; /* Mask level triggered irqs. */
1395 break;
1396
1397 case X86_IRQ_ALLOC_TYPE_HPET:
1398 case X86_IRQ_ALLOC_TYPE_MSI:
1399 case X86_IRQ_ALLOC_TYPE_MSIX:
1400 if (info->type == X86_IRQ_ALLOC_TYPE_HPET)
1401 set_hpet_sid(irte, info->hpet_id);
1402 else
1403 set_msi_sid(irte, info->msi_dev);
1404
1405 msg->address_hi = MSI_ADDR_BASE_HI;
1406 msg->data = sub_handle;
1407 msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
1408 MSI_ADDR_IR_SHV |
1409 MSI_ADDR_IR_INDEX1(index) |
1410 MSI_ADDR_IR_INDEX2(index);
1411 break;
1412
1413 default:
1414 BUG_ON(1);
1415 break;
1416 }
1417}
1418
1419static void intel_free_irq_resources(struct irq_domain *domain,
1420 unsigned int virq, unsigned int nr_irqs)
1421{
1422 struct irq_data *irq_data;
1423 struct intel_ir_data *data;
1424 struct irq_2_iommu *irq_iommu;
1425 unsigned long flags;
1426 int i;
1427
1428 for (i = 0; i < nr_irqs; i++) {
1429 irq_data = irq_domain_get_irq_data(domain, virq + i);
1430 if (irq_data && irq_data->chip_data) {
1431 data = irq_data->chip_data;
1432 irq_iommu = &data->irq_2_iommu;
1433 raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
1434 clear_entries(irq_iommu);
1435 raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
1436 irq_domain_reset_irq_data(irq_data);
1437 kfree(data);
1438 }
1439 }
1440}
1441
1442static int intel_irq_remapping_alloc(struct irq_domain *domain,
1443 unsigned int virq, unsigned int nr_irqs,
1444 void *arg)
1445{
1446 struct intel_iommu *iommu = domain->host_data;
1447 struct irq_alloc_info *info = arg;
1448 struct intel_ir_data *data;
1449 struct irq_data *irq_data;
1450 struct irq_cfg *irq_cfg;
1451 int i, ret, index;
1452
1453 if (!info || !iommu)
1454 return -EINVAL;
1455 if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
1456 info->type != X86_IRQ_ALLOC_TYPE_MSIX)
1457 return -EINVAL;
1458
1459 /*
1460 * With IRQ remapping enabled, don't need contiguous CPU vectors
1461 * to support multiple MSI interrupts.
1462 */
1463 if (info->type == X86_IRQ_ALLOC_TYPE_MSI)
1464 info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
1465
1466 ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
1467 if (ret < 0)
1468 return ret;
1469
1470 ret = -ENOMEM;
1471 data = kzalloc(sizeof(*data), GFP_KERNEL);
1472 if (!data)
1473 goto out_free_parent;
1474
1475 down_read(&dmar_global_lock);
1476 index = alloc_irte(iommu, virq, &data->irq_2_iommu, nr_irqs);
1477 up_read(&dmar_global_lock);
1478 if (index < 0) {
1479 pr_warn("Failed to allocate IRTE\n");
1480 kfree(data);
1481 goto out_free_parent;
1482 }
1483
1484 for (i = 0; i < nr_irqs; i++) {
1485 irq_data = irq_domain_get_irq_data(domain, virq + i);
1486 irq_cfg = irqd_cfg(irq_data);
1487 if (!irq_data || !irq_cfg) {
1488 ret = -EINVAL;
1489 goto out_free_data;
1490 }
1491
1492 if (i > 0) {
1493 data = kzalloc(sizeof(*data), GFP_KERNEL);
1494 if (!data)
1495 goto out_free_data;
1496 }
1497 irq_data->hwirq = (index << 16) + i;
1498 irq_data->chip_data = data;
1499 irq_data->chip = &intel_ir_chip;
1500 intel_irq_remapping_prepare_irte(data, irq_cfg, info, index, i);
1501 irq_set_status_flags(virq + i, IRQ_MOVE_PCNTXT);
1502 }
1503 return 0;
1504
1505out_free_data:
1506 intel_free_irq_resources(domain, virq, i);
1507out_free_parent:
1508 irq_domain_free_irqs_common(domain, virq, nr_irqs);
1509 return ret;
1510}
1511
1512static void intel_irq_remapping_free(struct irq_domain *domain,
1513 unsigned int virq, unsigned int nr_irqs)
1514{
1515 intel_free_irq_resources(domain, virq, nr_irqs);
1516 irq_domain_free_irqs_common(domain, virq, nr_irqs);
1517}
1518
1519static void intel_irq_remapping_activate(struct irq_domain *domain,
1520 struct irq_data *irq_data)
1521{
1522 struct intel_ir_data *data = irq_data->chip_data;
1523
1524 modify_irte(&data->irq_2_iommu, &data->irte_entry);
1525}
1526
1527static void intel_irq_remapping_deactivate(struct irq_domain *domain,
1528 struct irq_data *irq_data)
1529{
1530 struct intel_ir_data *data = irq_data->chip_data;
1531 struct irte entry;
1532
1533 memset(&entry, 0, sizeof(entry));
1534 modify_irte(&data->irq_2_iommu, &entry);
1535}
1536
1537static struct irq_domain_ops intel_ir_domain_ops = {
1538 .alloc = intel_irq_remapping_alloc,
1539 .free = intel_irq_remapping_free,
1540 .activate = intel_irq_remapping_activate,
1541 .deactivate = intel_irq_remapping_deactivate,
Joerg Roedel736baef2012-03-30 11:47:00 -07001542};
Jiang Liu6b197242014-11-09 22:47:58 +08001543
Jiang Liua7a3dad2014-11-09 22:48:00 +08001544/*
1545 * Support of Interrupt Remapping Unit Hotplug
1546 */
1547static int dmar_ir_add(struct dmar_drhd_unit *dmaru, struct intel_iommu *iommu)
1548{
1549 int ret;
1550 int eim = x2apic_enabled();
1551
1552 if (eim && !ecap_eim_support(iommu->ecap)) {
1553 pr_info("DRHD %Lx: EIM not supported by DRHD, ecap %Lx\n",
1554 iommu->reg_phys, iommu->ecap);
1555 return -ENODEV;
1556 }
1557
1558 if (ir_parse_ioapic_hpet_scope(dmaru->hdr, iommu)) {
1559 pr_warn("DRHD %Lx: failed to parse managed IOAPIC/HPET\n",
1560 iommu->reg_phys);
1561 return -ENODEV;
1562 }
1563
1564 /* TODO: check all IOAPICs are covered by IOMMU */
1565
1566 /* Setup Interrupt-remapping now. */
1567 ret = intel_setup_irq_remapping(iommu);
1568 if (ret) {
1569 pr_err("DRHD %Lx: failed to allocate resource\n",
1570 iommu->reg_phys);
1571 ir_remove_ioapic_hpet_scope(iommu);
1572 return ret;
1573 }
1574
1575 if (!iommu->qi) {
1576 /* Clear previous faults. */
1577 dmar_fault(-1, iommu);
1578 iommu_disable_irq_remapping(iommu);
1579 dmar_disable_qi(iommu);
1580 }
1581
1582 /* Enable queued invalidation */
1583 ret = dmar_enable_qi(iommu);
1584 if (!ret) {
1585 iommu_set_irq_remapping(iommu, eim);
1586 } else {
1587 pr_err("DRHD %Lx: failed to enable queued invalidation, ecap %Lx, ret %d\n",
1588 iommu->reg_phys, iommu->ecap, ret);
1589 intel_teardown_irq_remapping(iommu);
1590 ir_remove_ioapic_hpet_scope(iommu);
1591 }
1592
1593 return ret;
1594}
1595
Jiang Liu6b197242014-11-09 22:47:58 +08001596int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool insert)
1597{
Jiang Liua7a3dad2014-11-09 22:48:00 +08001598 int ret = 0;
1599 struct intel_iommu *iommu = dmaru->iommu;
1600
1601 if (!irq_remapping_enabled)
1602 return 0;
1603 if (iommu == NULL)
1604 return -EINVAL;
1605 if (!ecap_ir_support(iommu->ecap))
1606 return 0;
1607
1608 if (insert) {
1609 if (!iommu->ir_table)
1610 ret = dmar_ir_add(dmaru, iommu);
1611 } else {
1612 if (iommu->ir_table) {
1613 if (!bitmap_empty(iommu->ir_table->bitmap,
1614 INTR_REMAP_TABLE_ENTRIES)) {
1615 ret = -EBUSY;
1616 } else {
1617 iommu_disable_irq_remapping(iommu);
1618 intel_teardown_irq_remapping(iommu);
1619 ir_remove_ioapic_hpet_scope(iommu);
1620 }
1621 }
1622 }
1623
1624 return ret;
Jiang Liu6b197242014-11-09 22:47:58 +08001625}