ia64/xen-unstable

view xen/drivers/passthrough/vtd/intremap.c @ 17910:37ff3322d4f3

vt-d: Minor fixing of interrupt remapping
When ir_ctrl->iremap_index == -1, it means there is no remap
entry. So it needn't to convert from remap format to normal ioapic
format.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 27 14:11:41 2008 +0100 (2008-06-27)
parents 73a1daa9715f
children 0b7f7c564c83
line source
1 /*
2 * Copyright (c) 2006, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Copyright (C) Allen Kay <allen.m.kay@intel.com>
18 * Copyright (C) Xiaohui Xin <xiaohui.xin@intel.com>
19 */
21 #include <xen/irq.h>
22 #include <xen/sched.h>
23 #include <xen/iommu.h>
24 #include <xen/time.h>
25 #include <xen/pci.h>
26 #include <xen/pci_regs.h>
27 #include <asm/msi.h>
28 #include "iommu.h"
29 #include "dmar.h"
30 #include "vtd.h"
31 #include "extern.h"
33 u16 apicid_to_bdf(int apic_id)
34 {
35 struct acpi_drhd_unit *drhd = ioapic_to_drhd(apic_id);
36 struct acpi_ioapic_unit *acpi_ioapic_unit;
38 list_for_each_entry ( acpi_ioapic_unit, &drhd->ioapic_list, list )
39 if ( acpi_ioapic_unit->apic_id == apic_id )
40 return acpi_ioapic_unit->ioapic.info;
42 dprintk(XENLOG_ERR VTDPREFIX, "Didn't find the bdf for the apic_id!\n");
43 return 0;
44 }
46 static void remap_entry_to_ioapic_rte(
47 struct iommu *iommu, struct IO_APIC_route_entry *old_rte)
48 {
49 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
50 struct IO_APIC_route_remap_entry *remap_rte;
51 int index = 0;
52 unsigned long flags;
53 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
55 if ( ir_ctrl == NULL )
56 {
57 dprintk(XENLOG_ERR VTDPREFIX,
58 "remap_entry_to_ioapic_rte: ir_ctl is not ready\n");
59 return;
60 }
62 remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
63 index = (remap_rte->index_15 << 15) | remap_rte->index_0_14;
65 if ( index > ir_ctrl->iremap_index )
66 panic("%s: index (%d) is larger than remap table entry size (%d)!\n",
67 __func__, index, ir_ctrl->iremap_index);
69 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
71 iremap_entries =
72 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
73 iremap_entry = &iremap_entries[index];
75 old_rte->vector = iremap_entry->lo.vector;
76 old_rte->delivery_mode = iremap_entry->lo.dlm;
77 old_rte->dest_mode = iremap_entry->lo.dm;
78 old_rte->trigger = iremap_entry->lo.tm;
79 old_rte->__reserved_2 = 0;
80 old_rte->dest.logical.__reserved_1 = 0;
81 old_rte->dest.logical.logical_dest = iremap_entry->lo.dst >> 8;
83 unmap_vtd_domain_page(iremap_entries);
84 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
85 }
87 static void ioapic_rte_to_remap_entry(struct iommu *iommu,
88 int apic_id, struct IO_APIC_route_entry *old_rte,
89 unsigned int rte_upper, unsigned int value)
90 {
91 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
92 struct iremap_entry new_ire;
93 struct IO_APIC_route_remap_entry *remap_rte;
94 struct IO_APIC_route_entry new_rte;
95 int index;
96 unsigned long flags;
97 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
99 remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
100 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
102 if ( remap_rte->format == 0 )
103 {
104 ir_ctrl->iremap_index++;
105 index = ir_ctrl->iremap_index;
106 }
107 else
108 index = (remap_rte->index_15 << 15) | remap_rte->index_0_14;
110 if ( index > IREMAP_ENTRY_NR - 1 )
111 panic("ioapic_rte_to_remap_entry: intremap index is more than 256!\n");
113 iremap_entries =
114 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
115 iremap_entry = &iremap_entries[index];
117 memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
119 if ( rte_upper )
120 new_ire.lo.dst = (value >> 24) << 8;
121 else
122 {
123 *(((u32 *)&new_rte) + 0) = value;
124 new_ire.lo.fpd = 0;
125 new_ire.lo.dm = new_rte.dest_mode;
126 new_ire.lo.rh = 0;
127 new_ire.lo.tm = new_rte.trigger;
128 new_ire.lo.dlm = new_rte.delivery_mode;
129 new_ire.lo.avail = 0;
130 new_ire.lo.res_1 = 0;
131 new_ire.lo.vector = new_rte.vector;
132 new_ire.lo.res_2 = 0;
133 new_ire.hi.sid = apicid_to_bdf(apic_id);
135 new_ire.hi.sq = 0; /* comparing all 16-bit of SID */
136 new_ire.hi.svt = 1; /* requestor ID verification SID/SQ */
137 new_ire.hi.res_1 = 0;
138 new_ire.lo.p = 1; /* finally, set present bit */
140 /* now construct new ioapic rte entry */
141 remap_rte->vector = new_rte.vector;
142 remap_rte->delivery_mode = 0; /* has to be 0 for remap format */
143 remap_rte->index_15 = (index >> 15) & 0x1;
144 remap_rte->index_0_14 = index & 0x7fff;
146 remap_rte->delivery_status = new_rte.delivery_status;
147 remap_rte->polarity = new_rte.polarity;
148 remap_rte->irr = new_rte.irr;
149 remap_rte->trigger = new_rte.trigger;
150 remap_rte->mask = new_rte.mask;
151 remap_rte->reserved = 0;
152 remap_rte->format = 1; /* indicate remap format */
153 }
155 memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry));
156 iommu_flush_iec_index(iommu, 0, index);
157 invalidate_sync(iommu);
159 unmap_vtd_domain_page(iremap_entries);
160 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
161 return;
162 }
164 unsigned int io_apic_read_remap_rte(
165 unsigned int apic, unsigned int reg)
166 {
167 struct IO_APIC_route_entry old_rte = { 0 };
168 struct IO_APIC_route_remap_entry *remap_rte;
169 int rte_upper = (reg & 1) ? 1 : 0;
170 struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
171 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
173 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ||
174 ir_ctrl->iremap_index == -1 )
175 {
176 *IO_APIC_BASE(apic) = reg;
177 return *(IO_APIC_BASE(apic)+4);
178 }
180 if ( rte_upper )
181 reg--;
183 /* read lower and upper 32-bits of rte entry */
184 *IO_APIC_BASE(apic) = reg;
185 *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4);
186 *IO_APIC_BASE(apic) = reg + 1;
187 *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4);
189 remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
191 if ( remap_rte->mask || (remap_rte->format == 0) )
192 {
193 *IO_APIC_BASE(apic) = reg;
194 return *(IO_APIC_BASE(apic)+4);
195 }
197 remap_entry_to_ioapic_rte(iommu, &old_rte);
198 if ( rte_upper )
199 {
200 *IO_APIC_BASE(apic) = reg + 1;
201 return (*(((u32 *)&old_rte) + 1));
202 }
203 else
204 {
205 *IO_APIC_BASE(apic) = reg;
206 return (*(((u32 *)&old_rte) + 0));
207 }
208 }
210 void io_apic_write_remap_rte(
211 unsigned int apic, unsigned int reg, unsigned int value)
212 {
213 struct IO_APIC_route_entry old_rte = { 0 };
214 struct IO_APIC_route_remap_entry *remap_rte;
215 unsigned int rte_upper = (reg & 1) ? 1 : 0;
216 struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
217 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
218 int saved_mask;
220 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
221 {
222 *IO_APIC_BASE(apic) = reg;
223 *(IO_APIC_BASE(apic)+4) = value;
224 return;
225 }
227 if ( rte_upper )
228 reg--;
230 /* read both lower and upper 32-bits of rte entry */
231 *IO_APIC_BASE(apic) = reg;
232 *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4);
233 *IO_APIC_BASE(apic) = reg + 1;
234 *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4);
236 remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
238 /* mask the interrupt while we change the intremap table */
239 saved_mask = remap_rte->mask;
240 remap_rte->mask = 1;
241 *IO_APIC_BASE(apic) = reg;
242 *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0);
243 remap_rte->mask = saved_mask;
245 ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid,
246 &old_rte, rte_upper, value);
248 /* write new entry to ioapic */
249 *IO_APIC_BASE(apic) = reg;
250 *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
251 *IO_APIC_BASE(apic) = reg + 1;
252 *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
253 }
255 static void remap_entry_to_msi_msg(
256 struct iommu *iommu, struct msi_msg *msg)
257 {
258 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
259 struct msi_msg_remap_entry *remap_rte;
260 int index;
261 unsigned long flags;
262 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
264 if ( ir_ctrl == NULL )
265 {
266 dprintk(XENLOG_ERR VTDPREFIX,
267 "remap_entry_to_msi_msg: ir_ctl == NULL");
268 return;
269 }
271 remap_rte = (struct msi_msg_remap_entry *) msg;
272 index = (remap_rte->address_lo.index_15 << 15) |
273 remap_rte->address_lo.index_0_14;
275 if ( index > ir_ctrl->iremap_index )
276 panic("%s: index (%d) is larger than remap table entry size (%d)\n",
277 __func__, index, ir_ctrl->iremap_index);
279 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
281 iremap_entries =
282 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
283 iremap_entry = &iremap_entries[index];
285 msg->address_hi = MSI_ADDR_BASE_HI;
286 msg->address_lo =
287 MSI_ADDR_BASE_LO |
288 ((iremap_entry->lo.dm == 0) ?
289 MSI_ADDR_DESTMODE_PHYS:
290 MSI_ADDR_DESTMODE_LOGIC) |
291 ((iremap_entry->lo.dlm != dest_LowestPrio) ?
292 MSI_ADDR_REDIRECTION_CPU:
293 MSI_ADDR_REDIRECTION_LOWPRI) |
294 iremap_entry->lo.dst >> 8;
296 msg->data =
297 MSI_DATA_TRIGGER_EDGE |
298 MSI_DATA_LEVEL_ASSERT |
299 ((iremap_entry->lo.dlm != dest_LowestPrio) ?
300 MSI_DATA_DELIVERY_FIXED:
301 MSI_DATA_DELIVERY_LOWPRI) |
302 iremap_entry->lo.vector;
304 unmap_vtd_domain_page(iremap_entries);
305 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
306 }
308 static void msi_msg_to_remap_entry(
309 struct iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg)
310 {
311 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
312 struct iremap_entry new_ire;
313 struct msi_msg_remap_entry *remap_rte;
314 unsigned int index;
315 unsigned long flags;
316 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
317 int i = 0;
319 remap_rte = (struct msi_msg_remap_entry *) msg;
320 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
322 iremap_entries =
323 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
325 /* If the entry for a PCI device has been there, use the old entry,
326 * Or, assign a new entry for it.
327 */
328 for ( i = 0; i <= ir_ctrl->iremap_index; i++ )
329 {
330 iremap_entry = &iremap_entries[i];
331 if ( iremap_entry->hi.sid ==
332 ((pdev->bus << 8) | pdev->devfn) )
333 break;
334 }
336 if ( i > ir_ctrl->iremap_index )
337 {
338 ir_ctrl->iremap_index++;
339 index = ir_ctrl->iremap_index;
340 }
341 else
342 index = i;
344 if ( index > IREMAP_ENTRY_NR - 1 )
345 panic("msi_msg_to_remap_entry: intremap index is more than 256!\n");
347 iremap_entry = &iremap_entries[index];
348 memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
350 /* Set interrupt remapping table entry */
351 new_ire.lo.fpd = 0;
352 new_ire.lo.dm = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
353 new_ire.lo.rh = 0;
354 new_ire.lo.tm = (msg->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
355 new_ire.lo.dlm = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1;
356 new_ire.lo.avail = 0;
357 new_ire.lo.res_1 = 0;
358 new_ire.lo.vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) &
359 MSI_DATA_VECTOR_MASK;
360 new_ire.lo.res_2 = 0;
361 new_ire.lo.dst = ((msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT)
362 & 0xff) << 8;
364 new_ire.hi.sid = (pdev->bus << 8) | pdev->devfn;
365 new_ire.hi.sq = 0;
366 new_ire.hi.svt = 1;
367 new_ire.hi.res_1 = 0;
368 new_ire.lo.p = 1; /* finally, set present bit */
370 /* now construct new MSI/MSI-X rte entry */
371 remap_rte->address_lo.dontcare = 0;
372 remap_rte->address_lo.index_15 = (index >> 15) & 0x1;
373 remap_rte->address_lo.index_0_14 = index & 0x7fff;
374 remap_rte->address_lo.SHV = 1;
375 remap_rte->address_lo.format = 1;
377 remap_rte->address_hi = 0;
378 remap_rte->data = 0;
380 memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry));
381 iommu_flush_iec_index(iommu, 0, index);
382 invalidate_sync(iommu);
384 unmap_vtd_domain_page(iremap_entries);
385 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
386 return;
387 }
389 void msi_msg_read_remap_rte(
390 struct msi_desc *msi_desc, struct msi_msg *msg)
391 {
392 struct pci_dev *pdev = msi_desc->dev;
393 struct acpi_drhd_unit *drhd = NULL;
394 struct iommu *iommu = NULL;
395 struct ir_ctrl *ir_ctrl;
397 drhd = acpi_find_matched_drhd_unit(pdev);
398 iommu = drhd->iommu;
400 ir_ctrl = iommu_ir_ctrl(iommu);
401 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
402 return;
404 remap_entry_to_msi_msg(iommu, msg);
405 }
407 void msi_msg_write_remap_rte(
408 struct msi_desc *msi_desc, struct msi_msg *msg)
409 {
410 struct pci_dev *pdev = msi_desc->dev;
411 struct acpi_drhd_unit *drhd = NULL;
412 struct iommu *iommu = NULL;
413 struct ir_ctrl *ir_ctrl;
415 drhd = acpi_find_matched_drhd_unit(msi_desc->dev);
416 iommu = drhd->iommu;
418 ir_ctrl = iommu_ir_ctrl(iommu);
419 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
420 return;
422 msi_msg_to_remap_entry(iommu, pdev, msg);
423 }
425 int intremap_setup(struct iommu *iommu)
426 {
427 struct ir_ctrl *ir_ctrl;
428 s_time_t start_time;
430 if ( !ecap_intr_remap(iommu->ecap) )
431 return -ENODEV;
433 ir_ctrl = iommu_ir_ctrl(iommu);
434 if ( ir_ctrl->iremap_maddr == 0 )
435 {
436 ir_ctrl->iremap_maddr = alloc_pgtable_maddr();
437 if ( ir_ctrl->iremap_maddr == 0 )
438 {
439 dprintk(XENLOG_WARNING VTDPREFIX,
440 "Cannot allocate memory for ir_ctrl->iremap_maddr\n");
441 return -ENODEV;
442 }
443 ir_ctrl->iremap_index = -1;
444 }
446 #if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT)
447 /* set extended interrupt mode bit */
448 ir_ctrl->iremap_maddr |=
449 ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIMI_SHIFT) : 0;
450 #endif
451 /* size field = 256 entries per 4K page = 8 - 1 */
452 ir_ctrl->iremap_maddr |= 7;
453 dmar_writeq(iommu->reg, DMAR_IRTA_REG, ir_ctrl->iremap_maddr);
455 /* set SIRTP */
456 iommu->gcmd |= DMA_GCMD_SIRTP;
457 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
459 /* Make sure hardware complete it */
460 start_time = NOW();
461 while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) )
462 {
463 if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
464 {
465 dprintk(XENLOG_ERR VTDPREFIX,
466 "Cannot set SIRTP field for interrupt remapping\n");
467 return -ENODEV;
468 }
469 cpu_relax();
470 }
472 /* enable comaptiblity format interrupt pass through */
473 iommu->gcmd |= DMA_GCMD_CFI;
474 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
476 start_time = NOW();
477 while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) )
478 {
479 if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
480 {
481 dprintk(XENLOG_ERR VTDPREFIX,
482 "Cannot set CFI field for interrupt remapping\n");
483 return -ENODEV;
484 }
485 cpu_relax();
486 }
488 /* enable interrupt remapping hardware */
489 iommu->gcmd |= DMA_GCMD_IRE;
490 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
492 start_time = NOW();
493 while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) )
494 {
495 if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
496 {
497 dprintk(XENLOG_ERR VTDPREFIX,
498 "Cannot set IRE field for interrupt remapping\n");
499 return -ENODEV;
500 }
501 cpu_relax();
502 }
504 /* After set SIRTP, we should do globally invalidate the IEC */
505 iommu_flush_iec_global(iommu);
507 return 0;
508 }