1 | /* |
2 | * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | * SOFTWARE. |
22 | * |
23 | * Authors: |
24 | * Kevin Tian <kevin.tian@intel.com> |
25 | * Zhi Wang <zhi.a.wang@intel.com> |
26 | * |
27 | * Contributors: |
28 | * Min he <min.he@intel.com> |
29 | * |
30 | */ |
31 | |
32 | #include <linux/eventfd.h> |
33 | |
34 | #include "i915_drv.h" |
35 | #include "i915_reg.h" |
36 | #include "gvt.h" |
37 | #include "trace.h" |
38 | |
39 | struct intel_gvt_irq_info { |
40 | char *name; |
41 | i915_reg_t reg_base; |
42 | enum intel_gvt_event_type bit_to_event[INTEL_GVT_IRQ_BITWIDTH]; |
43 | int group; |
44 | DECLARE_BITMAP(downstream_irq_bitmap, INTEL_GVT_IRQ_BITWIDTH); |
45 | bool has_upstream_irq; |
46 | }; |
47 | |
48 | struct intel_gvt_irq_map { |
49 | int up_irq_group; |
50 | int up_irq_bit; |
51 | int down_irq_group; |
52 | u32 down_irq_bitmask; |
53 | }; |
54 | |
55 | /* common offset among interrupt control registers */ |
56 | #define regbase_to_isr(base) (base) |
57 | #define regbase_to_imr(base) (base + 0x4) |
58 | #define regbase_to_iir(base) (base + 0x8) |
59 | #define regbase_to_ier(base) (base + 0xC) |
60 | |
61 | #define iir_to_regbase(iir) (iir - 0x8) |
62 | #define ier_to_regbase(ier) (ier - 0xC) |
63 | |
64 | #define get_event_virt_handler(irq, e) (irq->events[e].v_handler) |
65 | #define get_irq_info(irq, e) (irq->events[e].info) |
66 | |
67 | #define irq_to_gvt(irq) \ |
68 | container_of(irq, struct intel_gvt, irq) |
69 | |
70 | static void update_upstream_irq(struct intel_vgpu *vgpu, |
71 | struct intel_gvt_irq_info *info); |
72 | |
73 | static const char * const irq_name[INTEL_GVT_EVENT_MAX] = { |
74 | [RCS_MI_USER_INTERRUPT] = "Render CS MI USER INTERRUPT" , |
75 | [RCS_DEBUG] = "Render EU debug from SVG" , |
76 | [RCS_MMIO_SYNC_FLUSH] = "Render MMIO sync flush status" , |
77 | [RCS_CMD_STREAMER_ERR] = "Render CS error interrupt" , |
78 | [RCS_PIPE_CONTROL] = "Render PIPE CONTROL notify" , |
79 | [RCS_WATCHDOG_EXCEEDED] = "Render CS Watchdog counter exceeded" , |
80 | [RCS_PAGE_DIRECTORY_FAULT] = "Render page directory faults" , |
81 | [RCS_AS_CONTEXT_SWITCH] = "Render AS Context Switch Interrupt" , |
82 | |
83 | [VCS_MI_USER_INTERRUPT] = "Video CS MI USER INTERRUPT" , |
84 | [VCS_MMIO_SYNC_FLUSH] = "Video MMIO sync flush status" , |
85 | [VCS_CMD_STREAMER_ERR] = "Video CS error interrupt" , |
86 | [VCS_MI_FLUSH_DW] = "Video MI FLUSH DW notify" , |
87 | [VCS_WATCHDOG_EXCEEDED] = "Video CS Watchdog counter exceeded" , |
88 | [VCS_PAGE_DIRECTORY_FAULT] = "Video page directory faults" , |
89 | [VCS_AS_CONTEXT_SWITCH] = "Video AS Context Switch Interrupt" , |
90 | [VCS2_MI_USER_INTERRUPT] = "VCS2 Video CS MI USER INTERRUPT" , |
91 | [VCS2_MI_FLUSH_DW] = "VCS2 Video MI FLUSH DW notify" , |
92 | [VCS2_AS_CONTEXT_SWITCH] = "VCS2 Context Switch Interrupt" , |
93 | |
94 | [BCS_MI_USER_INTERRUPT] = "Blitter CS MI USER INTERRUPT" , |
95 | [BCS_MMIO_SYNC_FLUSH] = "Billter MMIO sync flush status" , |
96 | [BCS_CMD_STREAMER_ERR] = "Blitter CS error interrupt" , |
97 | [BCS_MI_FLUSH_DW] = "Blitter MI FLUSH DW notify" , |
98 | [BCS_PAGE_DIRECTORY_FAULT] = "Blitter page directory faults" , |
99 | [BCS_AS_CONTEXT_SWITCH] = "Blitter AS Context Switch Interrupt" , |
100 | |
101 | [VECS_MI_FLUSH_DW] = "Video Enhanced Streamer MI FLUSH DW notify" , |
102 | [VECS_AS_CONTEXT_SWITCH] = "VECS Context Switch Interrupt" , |
103 | |
104 | [PIPE_A_FIFO_UNDERRUN] = "Pipe A FIFO underrun" , |
105 | [PIPE_A_CRC_ERR] = "Pipe A CRC error" , |
106 | [PIPE_A_CRC_DONE] = "Pipe A CRC done" , |
107 | [PIPE_A_VSYNC] = "Pipe A vsync" , |
108 | [PIPE_A_LINE_COMPARE] = "Pipe A line compare" , |
109 | [PIPE_A_ODD_FIELD] = "Pipe A odd field" , |
110 | [PIPE_A_EVEN_FIELD] = "Pipe A even field" , |
111 | [PIPE_A_VBLANK] = "Pipe A vblank" , |
112 | [PIPE_B_FIFO_UNDERRUN] = "Pipe B FIFO underrun" , |
113 | [PIPE_B_CRC_ERR] = "Pipe B CRC error" , |
114 | [PIPE_B_CRC_DONE] = "Pipe B CRC done" , |
115 | [PIPE_B_VSYNC] = "Pipe B vsync" , |
116 | [PIPE_B_LINE_COMPARE] = "Pipe B line compare" , |
117 | [PIPE_B_ODD_FIELD] = "Pipe B odd field" , |
118 | [PIPE_B_EVEN_FIELD] = "Pipe B even field" , |
119 | [PIPE_B_VBLANK] = "Pipe B vblank" , |
120 | [PIPE_C_VBLANK] = "Pipe C vblank" , |
121 | [DPST_PHASE_IN] = "DPST phase in event" , |
122 | [DPST_HISTOGRAM] = "DPST histogram event" , |
123 | [GSE] = "GSE" , |
124 | [DP_A_HOTPLUG] = "DP A Hotplug" , |
125 | [AUX_CHANNEL_A] = "AUX Channel A" , |
126 | [PERF_COUNTER] = "Performance counter" , |
127 | [POISON] = "Poison" , |
128 | [GTT_FAULT] = "GTT fault" , |
129 | [PRIMARY_A_FLIP_DONE] = "Primary Plane A flip done" , |
130 | [PRIMARY_B_FLIP_DONE] = "Primary Plane B flip done" , |
131 | [PRIMARY_C_FLIP_DONE] = "Primary Plane C flip done" , |
132 | [SPRITE_A_FLIP_DONE] = "Sprite Plane A flip done" , |
133 | [SPRITE_B_FLIP_DONE] = "Sprite Plane B flip done" , |
134 | [SPRITE_C_FLIP_DONE] = "Sprite Plane C flip done" , |
135 | |
136 | [PCU_THERMAL] = "PCU Thermal Event" , |
137 | [PCU_PCODE2DRIVER_MAILBOX] = "PCU pcode2driver mailbox event" , |
138 | |
139 | [FDI_RX_INTERRUPTS_TRANSCODER_A] = "FDI RX Interrupts Combined A" , |
140 | [AUDIO_CP_CHANGE_TRANSCODER_A] = "Audio CP Change Transcoder A" , |
141 | [AUDIO_CP_REQUEST_TRANSCODER_A] = "Audio CP Request Transcoder A" , |
142 | [FDI_RX_INTERRUPTS_TRANSCODER_B] = "FDI RX Interrupts Combined B" , |
143 | [AUDIO_CP_CHANGE_TRANSCODER_B] = "Audio CP Change Transcoder B" , |
144 | [AUDIO_CP_REQUEST_TRANSCODER_B] = "Audio CP Request Transcoder B" , |
145 | [FDI_RX_INTERRUPTS_TRANSCODER_C] = "FDI RX Interrupts Combined C" , |
146 | [AUDIO_CP_CHANGE_TRANSCODER_C] = "Audio CP Change Transcoder C" , |
147 | [AUDIO_CP_REQUEST_TRANSCODER_C] = "Audio CP Request Transcoder C" , |
148 | [ERR_AND_DBG] = "South Error and Debug Interrupts Combined" , |
149 | [GMBUS] = "Gmbus" , |
150 | [SDVO_B_HOTPLUG] = "SDVO B hotplug" , |
151 | [CRT_HOTPLUG] = "CRT Hotplug" , |
152 | [DP_B_HOTPLUG] = "DisplayPort/HDMI/DVI B Hotplug" , |
153 | [DP_C_HOTPLUG] = "DisplayPort/HDMI/DVI C Hotplug" , |
154 | [DP_D_HOTPLUG] = "DisplayPort/HDMI/DVI D Hotplug" , |
155 | [AUX_CHANNEL_B] = "AUX Channel B" , |
156 | [AUX_CHANNEL_C] = "AUX Channel C" , |
157 | [AUX_CHANNEL_D] = "AUX Channel D" , |
158 | [AUDIO_POWER_STATE_CHANGE_B] = "Audio Power State change Port B" , |
159 | [AUDIO_POWER_STATE_CHANGE_C] = "Audio Power State change Port C" , |
160 | [AUDIO_POWER_STATE_CHANGE_D] = "Audio Power State change Port D" , |
161 | |
162 | [INTEL_GVT_EVENT_RESERVED] = "RESERVED EVENTS!!!" , |
163 | }; |
164 | |
165 | static inline struct intel_gvt_irq_info *regbase_to_irq_info( |
166 | struct intel_gvt *gvt, |
167 | unsigned int reg) |
168 | { |
169 | struct intel_gvt_irq *irq = &gvt->irq; |
170 | int i; |
171 | |
172 | for_each_set_bit(i, irq->irq_info_bitmap, INTEL_GVT_IRQ_INFO_MAX) { |
173 | if (i915_mmio_reg_offset(irq->info[i]->reg_base) == reg) |
174 | return irq->info[i]; |
175 | } |
176 | |
177 | return NULL; |
178 | } |
179 | |
180 | /** |
181 | * intel_vgpu_reg_imr_handler - Generic IMR register emulation write handler |
182 | * @vgpu: a vGPU |
183 | * @reg: register offset written by guest |
184 | * @p_data: register data written by guest |
185 | * @bytes: register data length |
186 | * |
187 | * This function is used to emulate the generic IMR register bit change |
188 | * behavior. |
189 | * |
190 | * Returns: |
191 | * Zero on success, negative error code if failed. |
192 | * |
193 | */ |
194 | int intel_vgpu_reg_imr_handler(struct intel_vgpu *vgpu, |
195 | unsigned int reg, void *p_data, unsigned int bytes) |
196 | { |
197 | struct intel_gvt *gvt = vgpu->gvt; |
198 | const struct intel_gvt_irq_ops *ops = gvt->irq.ops; |
199 | u32 imr = *(u32 *)p_data; |
200 | |
201 | trace_write_ir(id: vgpu->id, reg_name: "IMR" , reg, new_val: imr, vgpu_vreg(vgpu, reg), |
202 | changed: (vgpu_vreg(vgpu, reg) ^ imr)); |
203 | |
204 | vgpu_vreg(vgpu, reg) = imr; |
205 | |
206 | ops->check_pending_irq(vgpu); |
207 | |
208 | return 0; |
209 | } |
210 | |
211 | /** |
212 | * intel_vgpu_reg_master_irq_handler - master IRQ write emulation handler |
213 | * @vgpu: a vGPU |
214 | * @reg: register offset written by guest |
215 | * @p_data: register data written by guest |
216 | * @bytes: register data length |
217 | * |
218 | * This function is used to emulate the master IRQ register on gen8+. |
219 | * |
220 | * Returns: |
221 | * Zero on success, negative error code if failed. |
222 | * |
223 | */ |
224 | int intel_vgpu_reg_master_irq_handler(struct intel_vgpu *vgpu, |
225 | unsigned int reg, void *p_data, unsigned int bytes) |
226 | { |
227 | struct intel_gvt *gvt = vgpu->gvt; |
228 | const struct intel_gvt_irq_ops *ops = gvt->irq.ops; |
229 | u32 ier = *(u32 *)p_data; |
230 | u32 virtual_ier = vgpu_vreg(vgpu, reg); |
231 | |
232 | trace_write_ir(id: vgpu->id, reg_name: "MASTER_IRQ" , reg, new_val: ier, old_val: virtual_ier, |
233 | changed: (virtual_ier ^ ier)); |
234 | |
235 | /* |
236 | * GEN8_MASTER_IRQ is a special irq register, |
237 | * only bit 31 is allowed to be modified |
238 | * and treated as an IER bit. |
239 | */ |
240 | ier &= GEN8_MASTER_IRQ_CONTROL; |
241 | virtual_ier &= GEN8_MASTER_IRQ_CONTROL; |
242 | vgpu_vreg(vgpu, reg) &= ~GEN8_MASTER_IRQ_CONTROL; |
243 | vgpu_vreg(vgpu, reg) |= ier; |
244 | |
245 | ops->check_pending_irq(vgpu); |
246 | |
247 | return 0; |
248 | } |
249 | |
250 | /** |
251 | * intel_vgpu_reg_ier_handler - Generic IER write emulation handler |
252 | * @vgpu: a vGPU |
253 | * @reg: register offset written by guest |
254 | * @p_data: register data written by guest |
255 | * @bytes: register data length |
256 | * |
257 | * This function is used to emulate the generic IER register behavior. |
258 | * |
259 | * Returns: |
260 | * Zero on success, negative error code if failed. |
261 | * |
262 | */ |
263 | int intel_vgpu_reg_ier_handler(struct intel_vgpu *vgpu, |
264 | unsigned int reg, void *p_data, unsigned int bytes) |
265 | { |
266 | struct intel_gvt *gvt = vgpu->gvt; |
267 | struct drm_i915_private *i915 = gvt->gt->i915; |
268 | const struct intel_gvt_irq_ops *ops = gvt->irq.ops; |
269 | struct intel_gvt_irq_info *info; |
270 | u32 ier = *(u32 *)p_data; |
271 | |
272 | trace_write_ir(id: vgpu->id, reg_name: "IER" , reg, new_val: ier, vgpu_vreg(vgpu, reg), |
273 | changed: (vgpu_vreg(vgpu, reg) ^ ier)); |
274 | |
275 | vgpu_vreg(vgpu, reg) = ier; |
276 | |
277 | info = regbase_to_irq_info(gvt, ier_to_regbase(reg)); |
278 | if (drm_WARN_ON(&i915->drm, !info)) |
279 | return -EINVAL; |
280 | |
281 | if (info->has_upstream_irq) |
282 | update_upstream_irq(vgpu, info); |
283 | |
284 | ops->check_pending_irq(vgpu); |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | /** |
290 | * intel_vgpu_reg_iir_handler - Generic IIR write emulation handler |
291 | * @vgpu: a vGPU |
292 | * @reg: register offset written by guest |
293 | * @p_data: register data written by guest |
294 | * @bytes: register data length |
295 | * |
296 | * This function is used to emulate the generic IIR register behavior. |
297 | * |
298 | * Returns: |
299 | * Zero on success, negative error code if failed. |
300 | * |
301 | */ |
302 | int intel_vgpu_reg_iir_handler(struct intel_vgpu *vgpu, unsigned int reg, |
303 | void *p_data, unsigned int bytes) |
304 | { |
305 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
306 | struct intel_gvt_irq_info *info = regbase_to_irq_info(gvt: vgpu->gvt, |
307 | iir_to_regbase(reg)); |
308 | u32 iir = *(u32 *)p_data; |
309 | |
310 | trace_write_ir(id: vgpu->id, reg_name: "IIR" , reg, new_val: iir, vgpu_vreg(vgpu, reg), |
311 | changed: (vgpu_vreg(vgpu, reg) ^ iir)); |
312 | |
313 | if (drm_WARN_ON(&i915->drm, !info)) |
314 | return -EINVAL; |
315 | |
316 | vgpu_vreg(vgpu, reg) &= ~iir; |
317 | |
318 | if (info->has_upstream_irq) |
319 | update_upstream_irq(vgpu, info); |
320 | return 0; |
321 | } |
322 | |
323 | static struct intel_gvt_irq_map gen8_irq_map[] = { |
324 | { INTEL_GVT_IRQ_INFO_MASTER, 0, INTEL_GVT_IRQ_INFO_GT0, 0xffff }, |
325 | { INTEL_GVT_IRQ_INFO_MASTER, 1, INTEL_GVT_IRQ_INFO_GT0, 0xffff0000 }, |
326 | { INTEL_GVT_IRQ_INFO_MASTER, 2, INTEL_GVT_IRQ_INFO_GT1, 0xffff }, |
327 | { INTEL_GVT_IRQ_INFO_MASTER, 3, INTEL_GVT_IRQ_INFO_GT1, 0xffff0000 }, |
328 | { INTEL_GVT_IRQ_INFO_MASTER, 4, INTEL_GVT_IRQ_INFO_GT2, 0xffff }, |
329 | { INTEL_GVT_IRQ_INFO_MASTER, 6, INTEL_GVT_IRQ_INFO_GT3, 0xffff }, |
330 | { INTEL_GVT_IRQ_INFO_MASTER, 16, INTEL_GVT_IRQ_INFO_DE_PIPE_A, ~0 }, |
331 | { INTEL_GVT_IRQ_INFO_MASTER, 17, INTEL_GVT_IRQ_INFO_DE_PIPE_B, ~0 }, |
332 | { INTEL_GVT_IRQ_INFO_MASTER, 18, INTEL_GVT_IRQ_INFO_DE_PIPE_C, ~0 }, |
333 | { INTEL_GVT_IRQ_INFO_MASTER, 20, INTEL_GVT_IRQ_INFO_DE_PORT, ~0 }, |
334 | { INTEL_GVT_IRQ_INFO_MASTER, 22, INTEL_GVT_IRQ_INFO_DE_MISC, ~0 }, |
335 | { INTEL_GVT_IRQ_INFO_MASTER, 23, INTEL_GVT_IRQ_INFO_PCH, ~0 }, |
336 | { INTEL_GVT_IRQ_INFO_MASTER, 30, INTEL_GVT_IRQ_INFO_PCU, ~0 }, |
337 | { -1, -1, ~0 }, |
338 | }; |
339 | |
340 | static void update_upstream_irq(struct intel_vgpu *vgpu, |
341 | struct intel_gvt_irq_info *info) |
342 | { |
343 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
344 | struct intel_gvt_irq *irq = &vgpu->gvt->irq; |
345 | struct intel_gvt_irq_map *map = irq->irq_map; |
346 | struct intel_gvt_irq_info *up_irq_info = NULL; |
347 | u32 set_bits = 0; |
348 | u32 clear_bits = 0; |
349 | int bit; |
350 | u32 val = vgpu_vreg(vgpu, |
351 | regbase_to_iir(i915_mmio_reg_offset(info->reg_base))) |
352 | & vgpu_vreg(vgpu, |
353 | regbase_to_ier(i915_mmio_reg_offset(info->reg_base))); |
354 | |
355 | if (!info->has_upstream_irq) |
356 | return; |
357 | |
358 | for (map = irq->irq_map; map->up_irq_bit != -1; map++) { |
359 | if (info->group != map->down_irq_group) |
360 | continue; |
361 | |
362 | if (!up_irq_info) |
363 | up_irq_info = irq->info[map->up_irq_group]; |
364 | else |
365 | drm_WARN_ON(&i915->drm, up_irq_info != |
366 | irq->info[map->up_irq_group]); |
367 | |
368 | bit = map->up_irq_bit; |
369 | |
370 | if (val & map->down_irq_bitmask) |
371 | set_bits |= (1 << bit); |
372 | else |
373 | clear_bits |= (1 << bit); |
374 | } |
375 | |
376 | if (drm_WARN_ON(&i915->drm, !up_irq_info)) |
377 | return; |
378 | |
379 | if (up_irq_info->group == INTEL_GVT_IRQ_INFO_MASTER) { |
380 | u32 isr = i915_mmio_reg_offset(up_irq_info->reg_base); |
381 | |
382 | vgpu_vreg(vgpu, isr) &= ~clear_bits; |
383 | vgpu_vreg(vgpu, isr) |= set_bits; |
384 | } else { |
385 | u32 iir = regbase_to_iir( |
386 | i915_mmio_reg_offset(up_irq_info->reg_base)); |
387 | u32 imr = regbase_to_imr( |
388 | i915_mmio_reg_offset(up_irq_info->reg_base)); |
389 | |
390 | vgpu_vreg(vgpu, iir) |= (set_bits & ~vgpu_vreg(vgpu, imr)); |
391 | } |
392 | |
393 | if (up_irq_info->has_upstream_irq) |
394 | update_upstream_irq(vgpu, info: up_irq_info); |
395 | } |
396 | |
397 | static void init_irq_map(struct intel_gvt_irq *irq) |
398 | { |
399 | struct intel_gvt_irq_map *map; |
400 | struct intel_gvt_irq_info *up_info, *down_info; |
401 | int up_bit; |
402 | |
403 | for (map = irq->irq_map; map->up_irq_bit != -1; map++) { |
404 | up_info = irq->info[map->up_irq_group]; |
405 | up_bit = map->up_irq_bit; |
406 | down_info = irq->info[map->down_irq_group]; |
407 | |
408 | set_bit(nr: up_bit, addr: up_info->downstream_irq_bitmap); |
409 | down_info->has_upstream_irq = true; |
410 | |
411 | gvt_dbg_irq("[up] grp %d bit %d -> [down] grp %d bitmask %x\n" , |
412 | up_info->group, up_bit, |
413 | down_info->group, map->down_irq_bitmask); |
414 | } |
415 | } |
416 | |
417 | /* =======================vEvent injection===================== */ |
418 | |
419 | #define MSI_CAP_CONTROL(offset) (offset + 2) |
420 | #define MSI_CAP_ADDRESS(offset) (offset + 4) |
421 | #define MSI_CAP_DATA(offset) (offset + 8) |
422 | #define MSI_CAP_EN 0x1 |
423 | |
424 | static void inject_virtual_interrupt(struct intel_vgpu *vgpu) |
425 | { |
426 | unsigned long offset = vgpu->gvt->device_info.msi_cap_offset; |
427 | u16 control, data; |
428 | u32 addr; |
429 | |
430 | control = *(u16 *)(vgpu_cfg_space(vgpu) + MSI_CAP_CONTROL(offset)); |
431 | addr = *(u32 *)(vgpu_cfg_space(vgpu) + MSI_CAP_ADDRESS(offset)); |
432 | data = *(u16 *)(vgpu_cfg_space(vgpu) + MSI_CAP_DATA(offset)); |
433 | |
434 | /* Do not generate MSI if MSIEN is disabled */ |
435 | if (!(control & MSI_CAP_EN)) |
436 | return; |
437 | |
438 | if (WARN(control & GENMASK(15, 1), "only support one MSI format\n" )) |
439 | return; |
440 | |
441 | trace_inject_msi(id: vgpu->id, address: addr, data); |
442 | |
443 | /* |
444 | * When guest is powered off, msi_trigger is set to NULL, but vgpu's |
445 | * config and mmio register isn't restored to default during guest |
446 | * poweroff. If this vgpu is still used in next vm, this vgpu's pipe |
447 | * may be enabled, then once this vgpu is active, it will get inject |
448 | * vblank interrupt request. But msi_trigger is null until msi is |
449 | * enabled by guest. so if msi_trigger is null, success is still |
450 | * returned and don't inject interrupt into guest. |
451 | */ |
452 | if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) |
453 | return; |
454 | if (vgpu->msi_trigger) |
455 | eventfd_signal(ctx: vgpu->msi_trigger); |
456 | } |
457 | |
458 | static void propagate_event(struct intel_gvt_irq *irq, |
459 | enum intel_gvt_event_type event, struct intel_vgpu *vgpu) |
460 | { |
461 | struct intel_gvt_irq_info *info; |
462 | unsigned int reg_base; |
463 | int bit; |
464 | |
465 | info = get_irq_info(irq, event); |
466 | if (WARN_ON(!info)) |
467 | return; |
468 | |
469 | reg_base = i915_mmio_reg_offset(info->reg_base); |
470 | bit = irq->events[event].bit; |
471 | |
472 | if (!test_bit(bit, (void *)&vgpu_vreg(vgpu, |
473 | regbase_to_imr(reg_base)))) { |
474 | trace_propagate_event(id: vgpu->id, irq_name: irq_name[event], bit); |
475 | set_bit(nr: bit, addr: (void *)&vgpu_vreg(vgpu, |
476 | regbase_to_iir(reg_base))); |
477 | } |
478 | } |
479 | |
480 | /* =======================vEvent Handlers===================== */ |
481 | static void handle_default_event_virt(struct intel_gvt_irq *irq, |
482 | enum intel_gvt_event_type event, struct intel_vgpu *vgpu) |
483 | { |
484 | if (!vgpu->irq.irq_warn_once[event]) { |
485 | gvt_dbg_core("vgpu%d: IRQ receive event %d (%s)\n" , |
486 | vgpu->id, event, irq_name[event]); |
487 | vgpu->irq.irq_warn_once[event] = true; |
488 | } |
489 | propagate_event(irq, event, vgpu); |
490 | } |
491 | |
492 | /* =====================GEN specific logic======================= */ |
493 | /* GEN8 interrupt routines. */ |
494 | |
495 | #define DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(regname, regbase) \ |
496 | static struct intel_gvt_irq_info gen8_##regname##_info = { \ |
497 | .name = #regname"-IRQ", \ |
498 | .reg_base = (regbase), \ |
499 | .bit_to_event = {[0 ... INTEL_GVT_IRQ_BITWIDTH-1] = \ |
500 | INTEL_GVT_EVENT_RESERVED}, \ |
501 | } |
502 | |
503 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt0, GEN8_GT_ISR(0)); |
504 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt1, GEN8_GT_ISR(1)); |
505 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt2, GEN8_GT_ISR(2)); |
506 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt3, GEN8_GT_ISR(3)); |
507 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_pipe_a, GEN8_DE_PIPE_ISR(PIPE_A)); |
508 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_pipe_b, GEN8_DE_PIPE_ISR(PIPE_B)); |
509 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_pipe_c, GEN8_DE_PIPE_ISR(PIPE_C)); |
510 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_port, GEN8_DE_PORT_ISR); |
511 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_misc, GEN8_DE_MISC_ISR); |
512 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(pcu, GEN8_PCU_ISR); |
513 | DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(master, GEN8_MASTER_IRQ); |
514 | |
515 | static struct intel_gvt_irq_info gvt_base_pch_info = { |
516 | .name = "PCH-IRQ" , |
517 | .reg_base = SDEISR, |
518 | .bit_to_event = {[0 ... INTEL_GVT_IRQ_BITWIDTH-1] = |
519 | INTEL_GVT_EVENT_RESERVED}, |
520 | }; |
521 | |
522 | static void gen8_check_pending_irq(struct intel_vgpu *vgpu) |
523 | { |
524 | struct intel_gvt_irq *irq = &vgpu->gvt->irq; |
525 | int i; |
526 | |
527 | if (!(vgpu_vreg(vgpu, i915_mmio_reg_offset(GEN8_MASTER_IRQ)) & |
528 | GEN8_MASTER_IRQ_CONTROL)) |
529 | return; |
530 | |
531 | for_each_set_bit(i, irq->irq_info_bitmap, INTEL_GVT_IRQ_INFO_MAX) { |
532 | struct intel_gvt_irq_info *info = irq->info[i]; |
533 | u32 reg_base; |
534 | |
535 | if (!info->has_upstream_irq) |
536 | continue; |
537 | |
538 | reg_base = i915_mmio_reg_offset(info->reg_base); |
539 | if ((vgpu_vreg(vgpu, regbase_to_iir(reg_base)) |
540 | & vgpu_vreg(vgpu, regbase_to_ier(reg_base)))) |
541 | update_upstream_irq(vgpu, info); |
542 | } |
543 | |
544 | if (vgpu_vreg(vgpu, i915_mmio_reg_offset(GEN8_MASTER_IRQ)) |
545 | & ~GEN8_MASTER_IRQ_CONTROL) |
546 | inject_virtual_interrupt(vgpu); |
547 | } |
548 | |
549 | static void gen8_init_irq( |
550 | struct intel_gvt_irq *irq) |
551 | { |
552 | struct intel_gvt *gvt = irq_to_gvt(irq); |
553 | |
554 | #define SET_BIT_INFO(s, b, e, i) \ |
555 | do { \ |
556 | s->events[e].bit = b; \ |
557 | s->events[e].info = s->info[i]; \ |
558 | s->info[i]->bit_to_event[b] = e;\ |
559 | } while (0) |
560 | |
561 | #define SET_IRQ_GROUP(s, g, i) \ |
562 | do { \ |
563 | s->info[g] = i; \ |
564 | (i)->group = g; \ |
565 | set_bit(g, s->irq_info_bitmap); \ |
566 | } while (0) |
567 | |
568 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_MASTER, &gen8_master_info); |
569 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT0, &gen8_gt0_info); |
570 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT1, &gen8_gt1_info); |
571 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT2, &gen8_gt2_info); |
572 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT3, &gen8_gt3_info); |
573 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PIPE_A, &gen8_de_pipe_a_info); |
574 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PIPE_B, &gen8_de_pipe_b_info); |
575 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PIPE_C, &gen8_de_pipe_c_info); |
576 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PORT, &gen8_de_port_info); |
577 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_MISC, &gen8_de_misc_info); |
578 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_PCU, &gen8_pcu_info); |
579 | SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_PCH, &gvt_base_pch_info); |
580 | |
581 | /* GEN8 level 2 interrupts. */ |
582 | |
583 | /* GEN8 interrupt GT0 events */ |
584 | SET_BIT_INFO(irq, 0, RCS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT0); |
585 | SET_BIT_INFO(irq, 4, RCS_PIPE_CONTROL, INTEL_GVT_IRQ_INFO_GT0); |
586 | SET_BIT_INFO(irq, 8, RCS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT0); |
587 | |
588 | SET_BIT_INFO(irq, 16, BCS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT0); |
589 | SET_BIT_INFO(irq, 20, BCS_MI_FLUSH_DW, INTEL_GVT_IRQ_INFO_GT0); |
590 | SET_BIT_INFO(irq, 24, BCS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT0); |
591 | |
592 | /* GEN8 interrupt GT1 events */ |
593 | SET_BIT_INFO(irq, 0, VCS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT1); |
594 | SET_BIT_INFO(irq, 4, VCS_MI_FLUSH_DW, INTEL_GVT_IRQ_INFO_GT1); |
595 | SET_BIT_INFO(irq, 8, VCS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT1); |
596 | |
597 | if (HAS_ENGINE(gvt->gt, VCS1)) { |
598 | SET_BIT_INFO(irq, 16, VCS2_MI_USER_INTERRUPT, |
599 | INTEL_GVT_IRQ_INFO_GT1); |
600 | SET_BIT_INFO(irq, 20, VCS2_MI_FLUSH_DW, |
601 | INTEL_GVT_IRQ_INFO_GT1); |
602 | SET_BIT_INFO(irq, 24, VCS2_AS_CONTEXT_SWITCH, |
603 | INTEL_GVT_IRQ_INFO_GT1); |
604 | } |
605 | |
606 | /* GEN8 interrupt GT3 events */ |
607 | SET_BIT_INFO(irq, 0, VECS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT3); |
608 | SET_BIT_INFO(irq, 4, VECS_MI_FLUSH_DW, INTEL_GVT_IRQ_INFO_GT3); |
609 | SET_BIT_INFO(irq, 8, VECS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT3); |
610 | |
611 | SET_BIT_INFO(irq, 0, PIPE_A_VBLANK, INTEL_GVT_IRQ_INFO_DE_PIPE_A); |
612 | SET_BIT_INFO(irq, 0, PIPE_B_VBLANK, INTEL_GVT_IRQ_INFO_DE_PIPE_B); |
613 | SET_BIT_INFO(irq, 0, PIPE_C_VBLANK, INTEL_GVT_IRQ_INFO_DE_PIPE_C); |
614 | |
615 | /* GEN8 interrupt DE PORT events */ |
616 | SET_BIT_INFO(irq, 0, AUX_CHANNEL_A, INTEL_GVT_IRQ_INFO_DE_PORT); |
617 | SET_BIT_INFO(irq, 3, DP_A_HOTPLUG, INTEL_GVT_IRQ_INFO_DE_PORT); |
618 | |
619 | /* GEN8 interrupt DE MISC events */ |
620 | SET_BIT_INFO(irq, 0, GSE, INTEL_GVT_IRQ_INFO_DE_MISC); |
621 | |
622 | /* PCH events */ |
623 | SET_BIT_INFO(irq, 17, GMBUS, INTEL_GVT_IRQ_INFO_PCH); |
624 | SET_BIT_INFO(irq, 19, CRT_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH); |
625 | SET_BIT_INFO(irq, 21, DP_B_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH); |
626 | SET_BIT_INFO(irq, 22, DP_C_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH); |
627 | SET_BIT_INFO(irq, 23, DP_D_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH); |
628 | |
629 | if (IS_BROADWELL(gvt->gt->i915)) { |
630 | SET_BIT_INFO(irq, 25, AUX_CHANNEL_B, INTEL_GVT_IRQ_INFO_PCH); |
631 | SET_BIT_INFO(irq, 26, AUX_CHANNEL_C, INTEL_GVT_IRQ_INFO_PCH); |
632 | SET_BIT_INFO(irq, 27, AUX_CHANNEL_D, INTEL_GVT_IRQ_INFO_PCH); |
633 | |
634 | SET_BIT_INFO(irq, 4, PRIMARY_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A); |
635 | SET_BIT_INFO(irq, 5, SPRITE_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A); |
636 | |
637 | SET_BIT_INFO(irq, 4, PRIMARY_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B); |
638 | SET_BIT_INFO(irq, 5, SPRITE_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B); |
639 | |
640 | SET_BIT_INFO(irq, 4, PRIMARY_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C); |
641 | SET_BIT_INFO(irq, 5, SPRITE_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C); |
642 | } else if (GRAPHICS_VER(gvt->gt->i915) >= 9) { |
643 | SET_BIT_INFO(irq, 25, AUX_CHANNEL_B, INTEL_GVT_IRQ_INFO_DE_PORT); |
644 | SET_BIT_INFO(irq, 26, AUX_CHANNEL_C, INTEL_GVT_IRQ_INFO_DE_PORT); |
645 | SET_BIT_INFO(irq, 27, AUX_CHANNEL_D, INTEL_GVT_IRQ_INFO_DE_PORT); |
646 | |
647 | SET_BIT_INFO(irq, 3, PRIMARY_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A); |
648 | SET_BIT_INFO(irq, 3, PRIMARY_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B); |
649 | SET_BIT_INFO(irq, 3, PRIMARY_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C); |
650 | |
651 | SET_BIT_INFO(irq, 4, SPRITE_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A); |
652 | SET_BIT_INFO(irq, 4, SPRITE_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B); |
653 | SET_BIT_INFO(irq, 4, SPRITE_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C); |
654 | } |
655 | |
656 | /* GEN8 interrupt PCU events */ |
657 | SET_BIT_INFO(irq, 24, PCU_THERMAL, INTEL_GVT_IRQ_INFO_PCU); |
658 | SET_BIT_INFO(irq, 25, PCU_PCODE2DRIVER_MAILBOX, INTEL_GVT_IRQ_INFO_PCU); |
659 | } |
660 | |
661 | static const struct intel_gvt_irq_ops gen8_irq_ops = { |
662 | .init_irq = gen8_init_irq, |
663 | .check_pending_irq = gen8_check_pending_irq, |
664 | }; |
665 | |
666 | /** |
667 | * intel_vgpu_trigger_virtual_event - Trigger a virtual event for a vGPU |
668 | * @vgpu: a vGPU |
669 | * @event: interrupt event |
670 | * |
671 | * This function is used to trigger a virtual interrupt event for vGPU. |
672 | * The caller provides the event to be triggered, the framework itself |
673 | * will emulate the IRQ register bit change. |
674 | * |
675 | */ |
676 | void intel_vgpu_trigger_virtual_event(struct intel_vgpu *vgpu, |
677 | enum intel_gvt_event_type event) |
678 | { |
679 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
680 | struct intel_gvt *gvt = vgpu->gvt; |
681 | struct intel_gvt_irq *irq = &gvt->irq; |
682 | gvt_event_virt_handler_t handler; |
683 | const struct intel_gvt_irq_ops *ops = gvt->irq.ops; |
684 | |
685 | handler = get_event_virt_handler(irq, event); |
686 | drm_WARN_ON(&i915->drm, !handler); |
687 | |
688 | handler(irq, event, vgpu); |
689 | |
690 | ops->check_pending_irq(vgpu); |
691 | } |
692 | |
693 | static void init_events( |
694 | struct intel_gvt_irq *irq) |
695 | { |
696 | int i; |
697 | |
698 | for (i = 0; i < INTEL_GVT_EVENT_MAX; i++) { |
699 | irq->events[i].info = NULL; |
700 | irq->events[i].v_handler = handle_default_event_virt; |
701 | } |
702 | } |
703 | |
704 | /** |
705 | * intel_gvt_init_irq - initialize GVT-g IRQ emulation subsystem |
706 | * @gvt: a GVT device |
707 | * |
708 | * This function is called at driver loading stage, to initialize the GVT-g IRQ |
709 | * emulation subsystem. |
710 | * |
711 | * Returns: |
712 | * Zero on success, negative error code if failed. |
713 | */ |
714 | int intel_gvt_init_irq(struct intel_gvt *gvt) |
715 | { |
716 | struct intel_gvt_irq *irq = &gvt->irq; |
717 | |
718 | gvt_dbg_core("init irq framework\n" ); |
719 | |
720 | irq->ops = &gen8_irq_ops; |
721 | irq->irq_map = gen8_irq_map; |
722 | |
723 | /* common event initialization */ |
724 | init_events(irq); |
725 | |
726 | /* gen specific initialization */ |
727 | irq->ops->init_irq(irq); |
728 | |
729 | init_irq_map(irq); |
730 | |
731 | return 0; |
732 | } |
733 | |