1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include "i915_drv.h"
35#include "gvt.h"
36
37enum {
38 INTEL_GVT_PCI_BAR_GTTMMIO = 0,
39 INTEL_GVT_PCI_BAR_APERTURE,
40 INTEL_GVT_PCI_BAR_PIO,
41 INTEL_GVT_PCI_BAR_MAX,
42};
43
44
45
46
47
48static const u8 pci_cfg_space_rw_bmp[PCI_INTERRUPT_LINE + 4] = {
49 [PCI_COMMAND] = 0xff, 0x07,
50 [PCI_STATUS] = 0x00, 0xf9,
51 [PCI_CACHE_LINE_SIZE] = 0xff,
52 [PCI_BASE_ADDRESS_0 ... PCI_CARDBUS_CIS - 1] = 0xff,
53 [PCI_ROM_ADDRESS] = 0x01, 0xf8, 0xff, 0xff,
54 [PCI_INTERRUPT_LINE] = 0xff,
55};
56
57
58
59
60
61
62
63
64static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off,
65 u8 *src, unsigned int bytes)
66{
67 u8 *cfg_base = vgpu_cfg_space(vgpu);
68 u8 mask, new, old;
69 int i = 0;
70
71 for (; i < bytes && (off + i < sizeof(pci_cfg_space_rw_bmp)); i++) {
72 mask = pci_cfg_space_rw_bmp[off + i];
73 old = cfg_base[off + i];
74 new = src[i] & mask;
75
76
77
78
79
80
81 if (off + i == PCI_STATUS + 1)
82 new = (~new & old) & mask;
83
84 cfg_base[off + i] = (old & ~mask) | new;
85 }
86
87
88 if (i < bytes)
89 memcpy(cfg_base + off + i, src + i, bytes - i);
90}
91
92
93
94
95
96
97
98int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
99 void *p_data, unsigned int bytes)
100{
101 if (WARN_ON(bytes > 4))
102 return -EINVAL;
103
104 if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ))
105 return -EINVAL;
106
107 memcpy(p_data, vgpu_cfg_space(vgpu) + offset, bytes);
108 return 0;
109}
110
111static int map_aperture(struct intel_vgpu *vgpu, bool map)
112{
113 u64 first_gfn, first_mfn;
114 u64 val;
115 int ret;
116
117 if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked)
118 return 0;
119
120 val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2];
121 if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
122 val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
123 else
124 val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
125
126 first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT;
127 first_mfn = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT;
128
129 ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn,
130 first_mfn,
131 vgpu_aperture_sz(vgpu) >>
132 PAGE_SHIFT, map);
133 if (ret)
134 return ret;
135
136 vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map;
137 return 0;
138}
139
140static int trap_gttmmio(struct intel_vgpu *vgpu, bool trap)
141{
142 u64 start, end;
143 u64 val;
144 int ret;
145
146 if (trap == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked)
147 return 0;
148
149 val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0];
150 if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
151 start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
152 else
153 start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
154
155 start &= ~GENMASK(3, 0);
156 end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1;
157
158 ret = intel_gvt_hypervisor_set_trap_area(vgpu, start, end, trap);
159 if (ret)
160 return ret;
161
162 vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap;
163 return 0;
164}
165
166static int emulate_pci_command_write(struct intel_vgpu *vgpu,
167 unsigned int offset, void *p_data, unsigned int bytes)
168{
169 u8 old = vgpu_cfg_space(vgpu)[offset];
170 u8 new = *(u8 *)p_data;
171 u8 changed = old ^ new;
172 int ret;
173
174 vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
175 if (!(changed & PCI_COMMAND_MEMORY))
176 return 0;
177
178 if (old & PCI_COMMAND_MEMORY) {
179 ret = trap_gttmmio(vgpu, false);
180 if (ret)
181 return ret;
182 ret = map_aperture(vgpu, false);
183 if (ret)
184 return ret;
185 } else {
186 ret = trap_gttmmio(vgpu, true);
187 if (ret)
188 return ret;
189 ret = map_aperture(vgpu, true);
190 if (ret)
191 return ret;
192 }
193
194 return 0;
195}
196
197static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
198 void *p_data, unsigned int bytes)
199{
200 u32 new = *(u32 *)(p_data);
201 bool lo = IS_ALIGNED(offset, 8);
202 u64 size;
203 int ret = 0;
204 bool mmio_enabled =
205 vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY;
206 struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar;
207
208
209
210
211
212
213
214
215 if (new == 0xffffffff) {
216 switch (offset) {
217 case PCI_BASE_ADDRESS_0:
218 case PCI_BASE_ADDRESS_1:
219 size = ~(bars[INTEL_GVT_PCI_BAR_GTTMMIO].size -1);
220 intel_vgpu_write_pci_bar(vgpu, offset,
221 size >> (lo ? 0 : 32), lo);
222
223
224
225
226 ret = trap_gttmmio(vgpu, false);
227 break;
228 case PCI_BASE_ADDRESS_2:
229 case PCI_BASE_ADDRESS_3:
230 size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1);
231 intel_vgpu_write_pci_bar(vgpu, offset,
232 size >> (lo ? 0 : 32), lo);
233 ret = map_aperture(vgpu, false);
234 break;
235 default:
236
237 intel_vgpu_write_pci_bar(vgpu, offset, 0x0, false);
238 }
239 } else {
240 switch (offset) {
241 case PCI_BASE_ADDRESS_0:
242 case PCI_BASE_ADDRESS_1:
243
244
245
246
247 trap_gttmmio(vgpu, false);
248 intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
249 ret = trap_gttmmio(vgpu, mmio_enabled);
250 break;
251 case PCI_BASE_ADDRESS_2:
252 case PCI_BASE_ADDRESS_3:
253 map_aperture(vgpu, false);
254 intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
255 ret = map_aperture(vgpu, mmio_enabled);
256 break;
257 default:
258 intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
259 }
260 }
261 return ret;
262}
263
264
265
266
267
268
269
270int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
271 void *p_data, unsigned int bytes)
272{
273 int ret;
274
275 if (WARN_ON(bytes > 4))
276 return -EINVAL;
277
278 if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ))
279 return -EINVAL;
280
281
282 if (IS_ALIGNED(offset, 2) && offset == PCI_COMMAND) {
283 if (WARN_ON(bytes > 2))
284 return -EINVAL;
285 return emulate_pci_command_write(vgpu, offset, p_data, bytes);
286 }
287
288 switch (rounddown(offset, 4)) {
289 case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
290 if (WARN_ON(!IS_ALIGNED(offset, 4)))
291 return -EINVAL;
292 return emulate_pci_bar_write(vgpu, offset, p_data, bytes);
293
294 case INTEL_GVT_PCI_SWSCI:
295 if (WARN_ON(!IS_ALIGNED(offset, 4)))
296 return -EINVAL;
297 ret = intel_vgpu_emulate_opregion_request(vgpu, *(u32 *)p_data);
298 if (ret)
299 return ret;
300 break;
301
302 case INTEL_GVT_PCI_OPREGION:
303 if (WARN_ON(!IS_ALIGNED(offset, 4)))
304 return -EINVAL;
305 ret = intel_vgpu_init_opregion(vgpu, *(u32 *)p_data);
306 if (ret)
307 return ret;
308
309 vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
310 break;
311 default:
312 vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
313 break;
314 }
315 return 0;
316}
317
318
319
320
321
322
323
324
325void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
326 bool primary)
327{
328 struct intel_gvt *gvt = vgpu->gvt;
329 const struct intel_gvt_device_info *info = &gvt->device_info;
330 u16 *gmch_ctl;
331
332 memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
333 info->cfg_space_size);
334
335 if (!primary) {
336 vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
337 INTEL_GVT_PCI_CLASS_VGA_OTHER;
338 vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
339 INTEL_GVT_PCI_CLASS_VGA_OTHER;
340 }
341
342
343 gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
344 *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
345
346 intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
347 gvt_aperture_pa_base(gvt), true);
348
349 vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
350 | PCI_COMMAND_MEMORY
351 | PCI_COMMAND_MASTER);
352
353
354
355 memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
356 memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
357 memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_4, 0, 8);
358 memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
359
360 vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size =
361 pci_resource_len(gvt->dev_priv->drm.pdev, 0);
362 vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =
363 pci_resource_len(gvt->dev_priv->drm.pdev, 2);
364}
365
366
367
368
369
370
371
372void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu)
373{
374 u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND];
375 bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] !=
376 INTEL_GVT_PCI_CLASS_VGA_OTHER;
377
378 if (cmd & PCI_COMMAND_MEMORY) {
379 trap_gttmmio(vgpu, false);
380 map_aperture(vgpu, false);
381 }
382
383
384
385
386
387
388 intel_vgpu_init_cfg_space(vgpu, primary);
389}
390