debuggers.hg

view xen/drivers/passthrough/vtd/quirks.c @ 22795:93e7bf0e1845

vt-d: quirks for Sandybridge errata workaround, WLAN, VT-d fault escalation

Adding errata workaround for newly released Sandybridge processor
graphics, additional WLAN device ID's for WLAN quirk, a quirk for
masking VT-d fault escalation to IOH HW that can cause system hangs on
some OEM hardware where the BIOS erroneously escalates VT-d faults to
the platform.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author Allen Kay <allen.m.kay@intel.com>
date Fri Jan 14 08:11:46 2011 +0000 (2011-01-14)
parents e635e6641c07
children 1637fdbfc21e
line source
1 /*
2 * Copyright (c) 2010, 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 * Author: Allen Kay <allen.m.kay@intel.com>
18 */
20 #include <xen/irq.h>
21 #include <xen/sched.h>
22 #include <xen/xmalloc.h>
23 #include <xen/domain_page.h>
24 #include <xen/iommu.h>
25 #include <asm/hvm/iommu.h>
26 #include <xen/numa.h>
27 #include <xen/softirq.h>
28 #include <xen/time.h>
29 #include <xen/pci.h>
30 #include <xen/pci_regs.h>
31 #include <xen/keyhandler.h>
32 #include <asm/msi.h>
33 #include <asm/irq.h>
34 #include <mach_apic.h>
35 #include "iommu.h"
36 #include "dmar.h"
37 #include "extern.h"
38 #include "vtd.h"
40 #define IOH_DEV 0
41 #define IGD_DEV 2
43 #define IGD_BAR_MASK 0xFFFFFFFFFFFF0000
44 #define GGC 0x52
45 #define GGC_MEMORY_VT_ENABLED (0x8 << 8)
47 #define IS_CTG(id) (id == 0x2a408086)
48 #define IS_ILK(id) (id == 0x00408086 || id == 0x00448086 || id== 0x00628086 || id == 0x006A8086)
49 #define IS_CPT(id) (id == 0x01008086 || id == 0x01048086)
50 #define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 || id == 0x01268086 || id == 0x01028086 || id == 0x01128086 || id == 0x01228086 || id == 0x010A8086)
52 u32 ioh_id;
53 u32 igd_id;
54 bool_t rwbf_quirk;
55 static int is_cantiga_b3;
56 static int is_snb_gfx;
57 static u8 *igd_reg_va;
59 /*
60 * QUIRK to workaround Xen boot issue on Calpella/Ironlake OEM BIOS
61 * not enabling VT-d properly in IGD. The workaround is to not enabling
62 * IGD VT-d translation if VT is not enabled in IGD.
63 */
64 int is_igd_vt_enabled_quirk(void)
65 {
66 u16 ggc;
68 if ( !IS_ILK(ioh_id) )
69 return 1;
71 /* integrated graphics on Intel platforms is located at 0:2.0 */
72 ggc = pci_conf_read16(0, IGD_DEV, 0, GGC);
73 return ( ggc & GGC_MEMORY_VT_ENABLED ? 1 : 0 );
74 }
76 /*
77 * QUIRK to workaround cantiga VT-d buffer flush issue.
78 * The workaround is to force write buffer flush even if
79 * VT-d capability indicates it is not required.
80 */
81 static void cantiga_b3_errata_init(void)
82 {
83 u16 vid;
84 u8 did_hi, rid;
86 vid = pci_conf_read16(0, IGD_DEV, 0, 0);
87 if ( vid != 0x8086 )
88 return;
90 did_hi = pci_conf_read8(0, IGD_DEV, 0, 3);
91 rid = pci_conf_read8(0, IGD_DEV, 0, 8);
93 if ( (did_hi == 0x2A) && (rid == 0x7) )
94 is_cantiga_b3 = 1;
95 }
97 /* check for Sandybridge IGD device ID's */
98 static void snb_errata_init(void)
99 {
100 is_snb_gfx = IS_SNB_GFX(igd_id);
101 }
103 /*
104 * QUIRK to workaround Cantiga IGD VT-d low power errata.
105 * This errata impacts IGD assignment on Cantiga systems
106 * and can potentially cause VT-d operations to hang.
107 * The workaround is to access an IGD PCI config register
108 * to get IGD out of low power state before VT-d translation
109 * enable/disable and IOTLB flushes.
110 */
112 /*
113 * map IGD MMIO+0x2000 page to allow Xen access to IGD 3D register.
114 */
115 static void *map_igd_reg(void)
116 {
117 u64 igd_mmio, igd_reg;
119 if ( !is_cantiga_b3 && !is_snb_gfx )
120 return NULL;
122 if ( igd_reg_va )
123 return igd_reg_va;
125 /* get IGD mmio address in PCI BAR */
126 igd_mmio = ((u64)pci_conf_read32(0, IGD_DEV, 0, 0x14) << 32) +
127 pci_conf_read32(0, IGD_DEV, 0, 0x10);
129 /* offset of IGD regster we want to access is in 0x2000 range */
130 igd_reg = (igd_mmio & IGD_BAR_MASK) + 0x2000;
132 /* ioremap this physical page */
133 #if defined(CONFIG_X86)
134 set_fixmap_nocache(FIX_IGD_MMIO, igd_reg);
135 igd_reg_va = (u8 *)fix_to_virt(FIX_IGD_MMIO);
136 #else
137 igd_reg_va = ioremap_nocache(igd_reg, 0x100);
138 #endif
139 return igd_reg_va;
140 }
142 /*
143 * force IGD to exit low power mode by accessing a IGD 3D regsiter.
144 */
145 static int cantiga_vtd_ops_preamble(struct iommu* iommu)
146 {
147 struct intel_iommu *intel = iommu->intel;
148 struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
150 if ( !is_igd_drhd(drhd) || !is_cantiga_b3 )
151 return 0;
153 if ( !map_igd_reg() )
154 return 0;
156 /*
157 * read IGD register at IGD MMIO + 0x20A4 to force IGD
158 * to exit low power state. Since map_igd_reg()
159 * already mapped page starting 0x2000, we just need to
160 * add page offset 0x0A4 to virtual address base.
161 */
162 return ( *((volatile int *)(igd_reg_va + 0x0A4)) );
163 }
165 /*
166 * Sandybridge RC6 power management inhibit state erratum.
167 * This can cause power high power consumption.
168 * Workaround is to prevent graphics get into RC6
169 * state when doing VT-d IOTLB operations, do the VT-d
170 * IOTLB operation, and then re-enable RC6 state.
171 */
172 static void snb_vtd_ops_preamble(struct iommu* iommu)
173 {
174 struct intel_iommu *intel = iommu->intel;
175 struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
176 s_time_t start_time;
178 if ( !is_igd_drhd(drhd) || !is_snb_gfx )
179 return;
181 if ( !map_igd_reg() )
182 return;
184 *((volatile u32 *)(igd_reg_va + 0x54)) = 0x000FFFFF;
185 *((volatile u32 *)(igd_reg_va + 0x700)) = 0;
187 start_time = NOW();
188 while ( (*((volatile u32 *)(igd_reg_va + 0x2AC)) & 0xF) != 0 )
189 {
190 if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
191 {
192 dprintk(XENLOG_INFO VTDPREFIX,
193 "snb_vtd_ops_preamble: failed to disable idle handshake\n");
194 break;
195 }
196 cpu_relax();
197 }
199 *((volatile u32*)(igd_reg_va + 0x50)) = 0x10001;
200 }
202 static void snb_vtd_ops_postamble(struct iommu* iommu)
203 {
204 struct intel_iommu *intel = iommu->intel;
205 struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
207 if ( !is_igd_drhd(drhd) || !is_snb_gfx )
208 return;
210 if ( !map_igd_reg() )
211 return;
213 *((volatile u32 *)(igd_reg_va + 0x54)) = 0xA;
214 *((volatile u32 *)(igd_reg_va + 0x50)) = 0x10000;
215 }
217 /*
218 * call before VT-d translation enable and IOTLB flush operations.
219 */
220 void vtd_ops_preamble_quirk(struct iommu* iommu)
221 {
222 cantiga_vtd_ops_preamble(iommu);
223 snb_vtd_ops_preamble(iommu);
224 }
226 /*
227 * call after VT-d translation enable and IOTLB flush operations.
228 */
229 void vtd_ops_postamble_quirk(struct iommu* iommu)
230 {
231 snb_vtd_ops_postamble(iommu);
232 }
234 /* initialize platform identification flags */
235 void __init platform_quirks_init(void)
236 {
237 ioh_id = pci_conf_read32(0, IOH_DEV, 0, 0);
238 igd_id = pci_conf_read32(0, IGD_DEV, 0, 0);
240 /* Mobile 4 Series Chipset neglects to set RWBF capability. */
241 if ( ioh_id == 0x2a408086 )
242 {
243 dprintk(XENLOG_INFO VTDPREFIX, "DMAR: Forcing write-buffer flush\n");
244 rwbf_quirk = 1;
245 }
247 /* initialize cantiga B3 identification */
248 cantiga_b3_errata_init();
250 snb_errata_init();
252 /* ioremap IGD MMIO+0x2000 page */
253 map_igd_reg();
254 }
256 /*
257 * QUIRK to workaround wifi direct assignment issue. This issue
258 * impacts only cases where Intel integrated wifi device is directly
259 * is directly assigned to a guest.
260 *
261 * The workaround is to map ME phantom device 0:3.7 or 0:22.7
262 * to the ME vt-d engine if detect the user is trying to directly
263 * assigning Intel integrated wifi device to a guest.
264 */
266 static void map_me_phantom_function(struct domain *domain, u32 dev, int map)
267 {
268 struct acpi_drhd_unit *drhd;
269 struct pci_dev *pdev;
271 /* find ME VT-d engine base on a real ME device */
272 pdev = pci_get_pdev(0, PCI_DEVFN(dev, 0));
273 drhd = acpi_find_matched_drhd_unit(pdev);
275 /* map or unmap ME phantom function */
276 if ( map )
277 domain_context_mapping_one(domain, drhd->iommu, 0,
278 PCI_DEVFN(dev, 7));
279 else
280 domain_context_unmap_one(domain, drhd->iommu, 0,
281 PCI_DEVFN(dev, 7));
282 }
284 void me_wifi_quirk(struct domain *domain, u8 bus, u8 devfn, int map)
285 {
286 u32 id;
288 id = pci_conf_read32(0, 0, 0, 0);
289 if ( IS_CTG(id) )
290 {
291 /* quit if ME does not exist */
292 if ( pci_conf_read32(0, 3, 0, 0) == 0xffffffff )
293 return;
295 /* if device is WLAN device, map ME phantom device 0:3.7 */
296 id = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
297 switch (id)
298 {
299 case 0x42328086:
300 case 0x42358086:
301 case 0x42368086:
302 case 0x42378086:
303 case 0x423a8086:
304 case 0x423b8086:
305 case 0x423c8086:
306 case 0x423d8086:
307 map_me_phantom_function(domain, 3, map);
308 break;
309 default:
310 break;
311 }
312 }
313 else if ( IS_ILK(id) || IS_CPT(id) )
314 {
315 /* quit if ME does not exist */
316 if ( pci_conf_read32(0, 22, 0, 0) == 0xffffffff )
317 return;
319 /* if device is WLAN device, map ME phantom device 0:22.7 */
320 id = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
321 switch (id)
322 {
323 case 0x00878086: /* Kilmer Peak */
324 case 0x00898086:
325 case 0x00828086: /* Taylor Peak */
326 case 0x00858086:
327 case 0x008F8086: /* Rainbow Peak */
328 case 0x00908086:
329 case 0x00918086:
330 case 0x42388086: /* Puma Peak */
331 case 0x422b8086:
332 case 0x422c8086:
333 map_me_phantom_function(domain, 22, map);
334 break;
335 default:
336 break;
337 }
338 }
339 }
341 /*
342 * Mask reporting Intel VT-d faults to IOH core logic:
343 * - Some platform escalates VT-d faults to platform errors
344 * - This can cause system failure upon non-fatal VT-d faults
345 * - Potential security issue if malicious guest trigger VT-d faults
346 */
347 void pci_vtd_quirk(struct pci_dev *pdev)
348 {
349 int bus = pdev->bus;
350 int dev = PCI_SLOT(pdev->devfn);
351 int func = PCI_FUNC(pdev->devfn);
352 int id, val;
354 id = pci_conf_read32(bus, dev, func, 0);
355 if ( id == 0x342e8086 || id == 0x3c288086 )
356 {
357 val = pci_conf_read32(bus, dev, func, 0x1AC);
358 pci_conf_write32(bus, dev, func, 0x1AC, val | (1 << 31));
359 }
360 }