ia64/xen-unstable

view xen/drivers/passthrough/vtd/intremap.c @ 18650:609d0d34450f

vtd: code cleanup

Remove iommu_page_mapping/unmapping, which are redundant because
intel_iommu_map_page/unmap_page can handle their functions.

Correct IRTA_REG_EIMI_SHIFT to IRTA_REG_EIME_SHIFT.

and also remove useless declarations in iommu.c

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Oct 17 12:04:11 2008 +0100 (2008-10-17)
parents 61218a1763da
children 10a2069a1edb
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 "iommu.h"
28 #include "dmar.h"
29 #include "vtd.h"
30 #include "extern.h"
32 u16 apicid_to_bdf(int apic_id)
33 {
34 struct acpi_drhd_unit *drhd = ioapic_to_drhd(apic_id);
35 struct acpi_ioapic_unit *acpi_ioapic_unit;
37 list_for_each_entry ( acpi_ioapic_unit, &drhd->ioapic_list, list )
38 if ( acpi_ioapic_unit->apic_id == apic_id )
39 return acpi_ioapic_unit->ioapic.info;
41 dprintk(XENLOG_ERR VTDPREFIX, "Didn't find the bdf for the apic_id!\n");
42 return 0;
43 }
45 static int remap_entry_to_ioapic_rte(
46 struct iommu *iommu, struct IO_xAPIC_route_entry *old_rte)
47 {
48 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
49 struct IO_APIC_route_remap_entry *remap_rte;
50 int index = 0;
51 unsigned long flags;
52 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
54 if ( ir_ctrl == NULL )
55 {
56 dprintk(XENLOG_ERR VTDPREFIX,
57 "remap_entry_to_ioapic_rte: ir_ctl is not ready\n");
58 return -EFAULT;
59 }
61 remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
62 index = (remap_rte->index_15 << 15) | remap_rte->index_0_14;
64 if ( index > ir_ctrl->iremap_index )
65 {
66 dprintk(XENLOG_ERR VTDPREFIX,
67 "%s: index (%d) is larger than remap table entry size (%d)!\n",
68 __func__, index, ir_ctrl->iremap_index);
69 return -EFAULT;
70 }
72 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
74 iremap_entries =
75 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
76 iremap_entry = &iremap_entries[index];
78 old_rte->vector = iremap_entry->lo.vector;
79 old_rte->delivery_mode = iremap_entry->lo.dlm;
80 old_rte->dest_mode = iremap_entry->lo.dm;
81 old_rte->trigger = iremap_entry->lo.tm;
82 old_rte->__reserved_2 = 0;
83 old_rte->dest.logical.__reserved_1 = 0;
84 old_rte->dest.logical.logical_dest = iremap_entry->lo.dst >> 8;
86 unmap_vtd_domain_page(iremap_entries);
87 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
88 return 0;
89 }
91 static int ioapic_rte_to_remap_entry(struct iommu *iommu,
92 int apic_id, struct IO_xAPIC_route_entry *old_rte,
93 unsigned int rte_upper, unsigned int value)
94 {
95 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
96 struct iremap_entry new_ire;
97 struct IO_APIC_route_remap_entry *remap_rte;
98 struct IO_xAPIC_route_entry new_rte;
99 int index;
100 unsigned long flags;
101 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
103 remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
104 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
106 if ( remap_rte->format == 0 )
107 {
108 ir_ctrl->iremap_index++;
109 index = ir_ctrl->iremap_index;
110 }
111 else
112 index = (remap_rte->index_15 << 15) | remap_rte->index_0_14;
114 if ( index > IREMAP_ENTRY_NR - 1 )
115 {
116 dprintk(XENLOG_ERR VTDPREFIX,
117 "%s: intremap index (%d) is larger than"
118 " the maximum index (%ld)!\n",
119 __func__, index, IREMAP_ENTRY_NR - 1);
120 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
121 return -EFAULT;
122 }
124 iremap_entries =
125 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
126 iremap_entry = &iremap_entries[index];
128 memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
130 if ( rte_upper )
131 new_ire.lo.dst = (value >> 24) << 8;
132 else
133 {
134 *(((u32 *)&new_rte) + 0) = value;
135 new_ire.lo.fpd = 0;
136 new_ire.lo.dm = new_rte.dest_mode;
137 new_ire.lo.rh = 0;
138 new_ire.lo.tm = new_rte.trigger;
139 new_ire.lo.dlm = new_rte.delivery_mode;
140 new_ire.lo.avail = 0;
141 new_ire.lo.res_1 = 0;
142 new_ire.lo.vector = new_rte.vector;
143 new_ire.lo.res_2 = 0;
144 new_ire.hi.sid = apicid_to_bdf(apic_id);
146 new_ire.hi.sq = 0; /* comparing all 16-bit of SID */
147 new_ire.hi.svt = 1; /* requestor ID verification SID/SQ */
148 new_ire.hi.res_1 = 0;
149 new_ire.lo.p = 1; /* finally, set present bit */
151 /* now construct new ioapic rte entry */
152 remap_rte->vector = new_rte.vector;
153 remap_rte->delivery_mode = 0; /* has to be 0 for remap format */
154 remap_rte->index_15 = (index >> 15) & 0x1;
155 remap_rte->index_0_14 = index & 0x7fff;
157 remap_rte->delivery_status = new_rte.delivery_status;
158 remap_rte->polarity = new_rte.polarity;
159 remap_rte->irr = new_rte.irr;
160 remap_rte->trigger = new_rte.trigger;
161 remap_rte->mask = new_rte.mask;
162 remap_rte->reserved = 0;
163 remap_rte->format = 1; /* indicate remap format */
164 }
166 memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry));
167 iommu_flush_cache_entry(iremap_entry);
168 iommu_flush_iec_index(iommu, 0, index);
169 invalidate_sync(iommu);
171 unmap_vtd_domain_page(iremap_entries);
172 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
173 return 0;
174 }
176 unsigned int io_apic_read_remap_rte(
177 unsigned int apic, unsigned int reg)
178 {
179 struct IO_xAPIC_route_entry old_rte = { 0 };
180 struct IO_APIC_route_remap_entry *remap_rte;
181 int rte_upper = (reg & 1) ? 1 : 0;
182 struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
183 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
185 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ||
186 ir_ctrl->iremap_index == -1 )
187 {
188 *IO_APIC_BASE(apic) = reg;
189 return *(IO_APIC_BASE(apic)+4);
190 }
192 if ( rte_upper )
193 reg--;
195 /* read lower and upper 32-bits of rte entry */
196 *IO_APIC_BASE(apic) = reg;
197 *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4);
198 *IO_APIC_BASE(apic) = reg + 1;
199 *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4);
201 remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
203 if ( remap_rte->format == 0 )
204 {
205 *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
206 return *(IO_APIC_BASE(apic)+4);
207 }
209 if ( remap_entry_to_ioapic_rte(iommu, &old_rte) )
210 {
211 *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
212 return *(IO_APIC_BASE(apic)+4);
213 }
215 if ( rte_upper )
216 return (*(((u32 *)&old_rte) + 1));
217 else
218 return (*(((u32 *)&old_rte) + 0));
219 }
221 void io_apic_write_remap_rte(
222 unsigned int apic, unsigned int reg, unsigned int value)
223 {
224 struct IO_xAPIC_route_entry old_rte = { 0 };
225 struct IO_APIC_route_remap_entry *remap_rte;
226 unsigned int rte_upper = (reg & 1) ? 1 : 0;
227 struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
228 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
229 int saved_mask;
231 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
232 {
233 *IO_APIC_BASE(apic) = reg;
234 *(IO_APIC_BASE(apic)+4) = value;
235 return;
236 }
238 if ( rte_upper )
239 reg--;
241 /* read both lower and upper 32-bits of rte entry */
242 *IO_APIC_BASE(apic) = reg;
243 *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4);
244 *IO_APIC_BASE(apic) = reg + 1;
245 *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4);
247 remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
249 /* mask the interrupt while we change the intremap table */
250 saved_mask = remap_rte->mask;
251 remap_rte->mask = 1;
252 *IO_APIC_BASE(apic) = reg;
253 *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0);
254 remap_rte->mask = saved_mask;
256 if ( ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid,
257 &old_rte, rte_upper, value) )
258 {
259 *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
260 *(IO_APIC_BASE(apic)+4) = value;
261 return;
262 }
264 /* write new entry to ioapic */
265 *IO_APIC_BASE(apic) = reg;
266 *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
267 *IO_APIC_BASE(apic) = reg + 1;
268 *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
269 }
271 #if defined(__i386__) || defined(__x86_64__)
272 static int remap_entry_to_msi_msg(
273 struct iommu *iommu, struct msi_msg *msg)
274 {
275 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
276 struct msi_msg_remap_entry *remap_rte;
277 int index;
278 unsigned long flags;
279 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
281 if ( ir_ctrl == NULL )
282 {
283 dprintk(XENLOG_ERR VTDPREFIX,
284 "remap_entry_to_msi_msg: ir_ctl == NULL");
285 return -EFAULT;
286 }
288 remap_rte = (struct msi_msg_remap_entry *) msg;
289 index = (remap_rte->address_lo.index_15 << 15) |
290 remap_rte->address_lo.index_0_14;
292 if ( index > ir_ctrl->iremap_index )
293 {
294 dprintk(XENLOG_ERR VTDPREFIX,
295 "%s: index (%d) is larger than remap table entry size (%d)\n",
296 __func__, index, ir_ctrl->iremap_index);
297 return -EFAULT;
298 }
300 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
302 iremap_entries =
303 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
304 iremap_entry = &iremap_entries[index];
306 msg->address_hi = MSI_ADDR_BASE_HI;
307 msg->address_lo =
308 MSI_ADDR_BASE_LO |
309 ((iremap_entry->lo.dm == 0) ?
310 MSI_ADDR_DESTMODE_PHYS:
311 MSI_ADDR_DESTMODE_LOGIC) |
312 ((iremap_entry->lo.dlm != dest_LowestPrio) ?
313 MSI_ADDR_REDIRECTION_CPU:
314 MSI_ADDR_REDIRECTION_LOWPRI) |
315 iremap_entry->lo.dst >> 8;
317 msg->data =
318 MSI_DATA_TRIGGER_EDGE |
319 MSI_DATA_LEVEL_ASSERT |
320 ((iremap_entry->lo.dlm != dest_LowestPrio) ?
321 MSI_DATA_DELIVERY_FIXED:
322 MSI_DATA_DELIVERY_LOWPRI) |
323 iremap_entry->lo.vector;
325 unmap_vtd_domain_page(iremap_entries);
326 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
327 return 0;
328 }
330 static int msi_msg_to_remap_entry(
331 struct iommu *iommu, struct pci_dev *pdev,
332 struct msi_desc *msi_desc, struct msi_msg *msg)
333 {
334 struct iremap_entry *iremap_entry = NULL, *iremap_entries;
335 struct iremap_entry new_ire;
336 struct msi_msg_remap_entry *remap_rte;
337 unsigned int index;
338 unsigned long flags;
339 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
341 remap_rte = (struct msi_msg_remap_entry *) msg;
342 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
344 if ( msi_desc->remap_index < 0 )
345 {
346 ir_ctrl->iremap_index++;
347 index = ir_ctrl->iremap_index;
348 msi_desc->remap_index = index;
349 }
350 else
351 index = msi_desc->remap_index;
353 if ( index > IREMAP_ENTRY_NR - 1 )
354 {
355 dprintk(XENLOG_ERR VTDPREFIX,
356 "%s: intremap index (%d) is larger than"
357 " the maximum index (%ld)!\n",
358 __func__, index, IREMAP_ENTRY_NR - 1);
359 msi_desc->remap_index = -1;
360 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
361 return -EFAULT;
362 }
364 iremap_entries =
365 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
366 iremap_entry = &iremap_entries[index];
367 memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
369 /* Set interrupt remapping table entry */
370 new_ire.lo.fpd = 0;
371 new_ire.lo.dm = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
372 new_ire.lo.rh = 0;
373 new_ire.lo.tm = (msg->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
374 new_ire.lo.dlm = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1;
375 new_ire.lo.avail = 0;
376 new_ire.lo.res_1 = 0;
377 new_ire.lo.vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) &
378 MSI_DATA_VECTOR_MASK;
379 new_ire.lo.res_2 = 0;
380 new_ire.lo.dst = ((msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT)
381 & 0xff) << 8;
383 new_ire.hi.sid = (pdev->bus << 8) | pdev->devfn;
384 new_ire.hi.sq = 0;
385 new_ire.hi.svt = 1;
386 new_ire.hi.res_1 = 0;
387 new_ire.lo.p = 1; /* finally, set present bit */
389 /* now construct new MSI/MSI-X rte entry */
390 remap_rte->address_lo.dontcare = 0;
391 remap_rte->address_lo.index_15 = (index >> 15) & 0x1;
392 remap_rte->address_lo.index_0_14 = index & 0x7fff;
393 remap_rte->address_lo.SHV = 1;
394 remap_rte->address_lo.format = 1;
396 remap_rte->address_hi = 0;
397 remap_rte->data = 0;
399 memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry));
400 iommu_flush_cache_entry(iremap_entry);
401 iommu_flush_iec_index(iommu, 0, index);
402 invalidate_sync(iommu);
404 unmap_vtd_domain_page(iremap_entries);
405 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
406 return 0;
407 }
409 void msi_msg_read_remap_rte(
410 struct msi_desc *msi_desc, struct msi_msg *msg)
411 {
412 struct pci_dev *pdev = msi_desc->dev;
413 struct acpi_drhd_unit *drhd = NULL;
414 struct iommu *iommu = NULL;
415 struct ir_ctrl *ir_ctrl;
417 drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
418 iommu = drhd->iommu;
420 ir_ctrl = iommu_ir_ctrl(iommu);
421 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
422 return;
424 remap_entry_to_msi_msg(iommu, msg);
425 }
427 void msi_msg_write_remap_rte(
428 struct msi_desc *msi_desc, struct msi_msg *msg)
429 {
430 struct pci_dev *pdev = msi_desc->dev;
431 struct acpi_drhd_unit *drhd = NULL;
432 struct iommu *iommu = NULL;
433 struct ir_ctrl *ir_ctrl;
435 drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
436 iommu = drhd->iommu;
438 ir_ctrl = iommu_ir_ctrl(iommu);
439 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
440 return;
442 msi_msg_to_remap_entry(iommu, pdev, msi_desc, msg);
443 }
444 #elif defined(__ia64__)
445 void msi_msg_read_remap_rte(
446 struct msi_desc *msi_desc, struct msi_msg *msg)
447 {
448 /* TODO. */
449 }
451 void msi_msg_write_remap_rte(
452 struct msi_desc *msi_desc, struct msi_msg *msg)
453 {
454 /* TODO. */
455 }
456 #endif
458 int intremap_setup(struct iommu *iommu)
459 {
460 struct ir_ctrl *ir_ctrl;
461 s_time_t start_time;
463 if ( !ecap_intr_remap(iommu->ecap) )
464 return -ENODEV;
466 ir_ctrl = iommu_ir_ctrl(iommu);
467 if ( ir_ctrl->iremap_maddr == 0 )
468 {
469 ir_ctrl->iremap_maddr = alloc_pgtable_maddr();
470 if ( ir_ctrl->iremap_maddr == 0 )
471 {
472 dprintk(XENLOG_WARNING VTDPREFIX,
473 "Cannot allocate memory for ir_ctrl->iremap_maddr\n");
474 return -ENODEV;
475 }
476 ir_ctrl->iremap_index = -1;
477 }
479 #if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT)
480 /* set extended interrupt mode bit */
481 ir_ctrl->iremap_maddr |=
482 ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIME_SHIFT) : 0;
483 #endif
484 /* set size of the interrupt remapping table */
485 ir_ctrl->iremap_maddr |= IRTA_REG_TABLE_SIZE;
486 dmar_writeq(iommu->reg, DMAR_IRTA_REG, ir_ctrl->iremap_maddr);
488 /* set SIRTP */
489 iommu->gcmd |= DMA_GCMD_SIRTP;
490 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
492 /* Make sure hardware complete it */
493 start_time = NOW();
494 while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) )
495 {
496 if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
497 {
498 dprintk(XENLOG_ERR VTDPREFIX,
499 "Cannot set SIRTP field for interrupt remapping\n");
500 return -ENODEV;
501 }
502 cpu_relax();
503 }
505 /* enable comaptiblity format interrupt pass through */
506 iommu->gcmd |= DMA_GCMD_CFI;
507 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
509 start_time = NOW();
510 while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) )
511 {
512 if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
513 {
514 dprintk(XENLOG_ERR VTDPREFIX,
515 "Cannot set CFI field for interrupt remapping\n");
516 return -ENODEV;
517 }
518 cpu_relax();
519 }
521 /* enable interrupt remapping hardware */
522 iommu->gcmd |= DMA_GCMD_IRE;
523 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
525 start_time = NOW();
526 while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) )
527 {
528 if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
529 {
530 dprintk(XENLOG_ERR VTDPREFIX,
531 "Cannot set IRE field for interrupt remapping\n");
532 return -ENODEV;
533 }
534 cpu_relax();
535 }
537 /* After set SIRTP, we should do globally invalidate the IEC */
538 iommu_flush_iec_global(iommu);
540 return 0;
541 }