ia64/xen-unstable

view xen/drivers/passthrough/vtd/utils.c @ 17923:0972fc23b504

x86: Fix 32-bit build after VT-d cleanups.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat Jun 28 16:29:00 2008 +0100 (2008-06-28)
parents 36bbcc6baadf
children bd7f2a120f94
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 */
20 #include <xen/sched.h>
21 #include <xen/delay.h>
22 #include <xen/iommu.h>
23 #include <xen/time.h>
24 #include <xen/pci.h>
25 #include <xen/pci_regs.h>
26 #include <asm/msi.h>
27 #include "iommu.h"
28 #include "dmar.h"
29 #include "vtd.h"
31 #define INTEL 0x8086
32 #define SEABURG 0x4000
33 #define C_STEP 2
35 int is_usb_device(struct pci_dev *pdev)
36 {
37 u8 bus = pdev->bus;
38 u8 dev = PCI_SLOT(pdev->devfn);
39 u8 func = PCI_FUNC(pdev->devfn);
40 u16 class = pci_conf_read16(bus, dev, func, PCI_CLASS_DEVICE);
41 return (class == 0xc03);
42 }
44 int vtd_hw_check(void)
45 {
46 u16 vendor, device;
47 u8 revision, stepping;
49 vendor = pci_conf_read16(0, 0, 0, PCI_VENDOR_ID);
50 device = pci_conf_read16(0, 0, 0, PCI_DEVICE_ID);
51 revision = pci_conf_read8(0, 0, 0, PCI_REVISION_ID);
52 stepping = revision & 0xf;
54 if ( (vendor == INTEL) && (device == SEABURG) )
55 {
56 if ( stepping < C_STEP )
57 {
58 dprintk(XENLOG_WARNING VTDPREFIX,
59 "*** VT-d disabled - pre C0-step Seaburg found\n");
60 dprintk(XENLOG_WARNING VTDPREFIX,
61 "*** vendor = %x device = %x revision = %x\n",
62 vendor, device, revision);
63 return -ENODEV;
64 }
65 }
67 return 0;
68 }
70 /* Disable vt-d protected memory registers. */
71 void disable_pmr(struct iommu *iommu)
72 {
73 s_time_t start_time;
74 unsigned int val;
76 val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
77 if ( !(val & DMA_PMEN_PRS) )
78 return;
80 dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);
81 start_time = NOW();
83 for ( ; ; )
84 {
85 val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
86 if ( (val & DMA_PMEN_PRS) == 0 )
87 break;
89 if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
90 panic("Disable PMRs timeout\n");
92 cpu_relax();
93 }
95 dprintk(XENLOG_INFO VTDPREFIX,
96 "Disabled protected memory registers\n");
97 }
99 #define PCI_D3hot (3)
100 #define PCI_CONFIG_DWORD_SIZE (64)
101 #define PCI_EXP_DEVCAP_FLR (1 << 28)
102 #define PCI_EXP_DEVCTL_FLR (1 << 15)
104 void pdev_flr(u8 bus, u8 devfn)
105 {
106 u8 pos;
107 u32 dev_cap, dev_status, pm_ctl;
108 int flr = 0;
109 u8 dev = PCI_SLOT(devfn);
110 u8 func = PCI_FUNC(devfn);
112 pos = pci_find_cap_offset(bus, dev, func, PCI_CAP_ID_EXP);
113 if ( pos != 0 )
114 {
115 dev_cap = pci_conf_read32(bus, dev, func, pos + PCI_EXP_DEVCAP);
116 if ( dev_cap & PCI_EXP_DEVCAP_FLR )
117 {
118 pci_conf_write32(bus, dev, func,
119 pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
120 do {
121 dev_status = pci_conf_read32(bus, dev, func,
122 pos + PCI_EXP_DEVSTA);
123 } while ( dev_status & PCI_EXP_DEVSTA_TRPND );
125 flr = 1;
126 }
127 }
129 /* If this device doesn't support function level reset,
130 * program device from D0 t0 D3hot, and then return to D0
131 * to implement function level reset
132 */
133 if ( flr == 0 )
134 {
135 pos = pci_find_cap_offset(bus, dev, func, PCI_CAP_ID_PM);
136 if ( pos != 0 )
137 {
138 int i;
139 u32 config[PCI_CONFIG_DWORD_SIZE];
140 for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
141 config[i] = pci_conf_read32(bus, dev, func, i*4);
143 /* Enter D3hot without soft reset */
144 pm_ctl = pci_conf_read32(bus, dev, func, pos + PCI_PM_CTRL);
145 pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET;
146 pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;
147 pm_ctl |= PCI_D3hot;
148 pci_conf_write32(bus, dev, func, pos + PCI_PM_CTRL, pm_ctl);
149 mdelay(10);
151 /* From D3hot to D0 */
152 pci_conf_write32(bus, dev, func, pos + PCI_PM_CTRL, 0);
153 mdelay(10);
155 /* Write saved configurations to device */
156 for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
157 pci_conf_write32(bus, dev, func, i*4, config[i]);
159 flr = 1;
160 }
161 }
162 }
164 void print_iommu_regs(struct acpi_drhd_unit *drhd)
165 {
166 struct iommu *iommu = drhd->iommu;
168 printk("---- print_iommu_regs ----\n");
169 printk("print_iommu_regs: drhd->address = %"PRIx64"\n", drhd->address);
170 printk("print_iommu_regs: DMAR_VER_REG = %x\n",
171 dmar_readl(iommu->reg,DMAR_VER_REG));
172 printk("print_iommu_regs: DMAR_CAP_REG = %"PRIx64"\n",
173 dmar_readq(iommu->reg,DMAR_CAP_REG));
174 printk("print_iommu_regs: n_fault_reg = %"PRIx64"\n",
175 cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
176 printk("print_iommu_regs: fault_recording_offset_l = %"PRIx64"\n",
177 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
178 printk("print_iommu_regs: fault_recording_offset_h = %"PRIx64"\n",
179 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
180 printk("print_iommu_regs: fault_recording_reg_l = %"PRIx64"\n",
181 dmar_readq(iommu->reg,
182 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
183 printk("print_iommu_regs: fault_recording_reg_h = %"PRIx64"\n",
184 dmar_readq(iommu->reg,
185 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));
186 printk("print_iommu_regs: DMAR_ECAP_REG = %"PRIx64"\n",
187 dmar_readq(iommu->reg,DMAR_ECAP_REG));
188 printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",
189 dmar_readl(iommu->reg,DMAR_GCMD_REG));
190 printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",
191 dmar_readl(iommu->reg,DMAR_GSTS_REG));
192 printk("print_iommu_regs: DMAR_RTADDR_REG = %"PRIx64"\n",
193 dmar_readq(iommu->reg,DMAR_RTADDR_REG));
194 printk("print_iommu_regs: DMAR_CCMD_REG = %"PRIx64"\n",
195 dmar_readq(iommu->reg,DMAR_CCMD_REG));
196 printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",
197 dmar_readl(iommu->reg,DMAR_FSTS_REG));
198 printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",
199 dmar_readl(iommu->reg,DMAR_FECTL_REG));
200 printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",
201 dmar_readl(iommu->reg,DMAR_FEDATA_REG));
202 printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",
203 dmar_readl(iommu->reg,DMAR_FEADDR_REG));
204 printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",
205 dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
206 }
208 u32 get_level_index(unsigned long gmfn, int level)
209 {
210 while ( --level )
211 gmfn = gmfn >> LEVEL_STRIDE;
213 return gmfn & LEVEL_MASK;
214 }
216 void print_vtd_entries(struct iommu *iommu, int bus, int devfn, u64 gmfn)
217 {
218 struct context_entry *ctxt_entry;
219 struct root_entry *root_entry;
220 struct dma_pte pte;
221 u64 *l;
222 u32 l_index, level;
224 printk("print_vtd_entries: iommu = %p bdf = %x:%x:%x gmfn = %"PRIx64"\n",
225 iommu, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);
227 if ( iommu->root_maddr == 0 )
228 {
229 printk(" iommu->root_maddr = 0\n");
230 return;
231 }
233 root_entry = (struct root_entry *)map_vtd_domain_page(iommu->root_maddr);
235 printk(" root_entry = %p\n", root_entry);
236 printk(" root_entry[%x] = %"PRIx64"\n", bus, root_entry[bus].val);
237 if ( !root_present(root_entry[bus]) )
238 {
239 unmap_vtd_domain_page(root_entry);
240 printk(" root_entry[%x] not present\n", bus);
241 return;
242 }
244 ctxt_entry =
245 (struct context_entry *)map_vtd_domain_page(root_entry[bus].val);
246 if ( ctxt_entry == NULL )
247 {
248 unmap_vtd_domain_page(root_entry);
249 printk(" ctxt_entry == NULL\n");
250 return;
251 }
253 printk(" context = %p\n", ctxt_entry);
254 printk(" context[%x] = %"PRIx64"_%"PRIx64"\n",
255 devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);
256 if ( !context_present(ctxt_entry[devfn]) )
257 {
258 unmap_vtd_domain_page(ctxt_entry);
259 unmap_vtd_domain_page(root_entry);
260 printk(" ctxt_entry[%x] not present\n", devfn);
261 return;
262 }
264 level = agaw_to_level(context_address_width(ctxt_entry[devfn]));
265 if ( level != VTD_PAGE_TABLE_LEVEL_3 &&
266 level != VTD_PAGE_TABLE_LEVEL_4)
267 {
268 unmap_vtd_domain_page(ctxt_entry);
269 unmap_vtd_domain_page(root_entry);
270 printk("Unsupported VTD page table level (%d)!\n", level);
271 }
273 l = maddr_to_virt(ctxt_entry[devfn].lo);
274 do
275 {
276 l = (u64*)(((unsigned long)l >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
277 printk(" l%d = %p\n", level, l);
278 if ( l == NULL )
279 {
280 unmap_vtd_domain_page(ctxt_entry);
281 unmap_vtd_domain_page(root_entry);
282 printk(" l%d == NULL\n", level);
283 break;
284 }
285 l_index = get_level_index(gmfn, level);
286 printk(" l%d_index = %x\n", level, l_index);
287 printk(" l%d[%x] = %"PRIx64"\n", level, l_index, l[l_index]);
289 pte.val = l[l_index];
290 if ( !dma_pte_present(pte) )
291 {
292 unmap_vtd_domain_page(ctxt_entry);
293 unmap_vtd_domain_page(root_entry);
294 printk(" l%d[%x] not present\n", level, l_index);
295 break;
296 }
298 l = maddr_to_virt(l[l_index]);
299 } while ( --level );
300 }
302 /*
303 * Local variables:
304 * mode: C
305 * c-set-style: "BSD"
306 * c-basic-offset: 4
307 * indent-tabs-mode: nil
308 * End:
309 */