1*677dec6eSriastradh /*	$NetBSD: interrupt.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $	*/
21571a7a1Sriastradh 
31571a7a1Sriastradh /*
41571a7a1Sriastradh  * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
51571a7a1Sriastradh  *
61571a7a1Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
71571a7a1Sriastradh  * copy of this software and associated documentation files (the "Software"),
81571a7a1Sriastradh  * to deal in the Software without restriction, including without limitation
91571a7a1Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101571a7a1Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
111571a7a1Sriastradh  * Software is furnished to do so, subject to the following conditions:
121571a7a1Sriastradh  *
131571a7a1Sriastradh  * The above copyright notice and this permission notice (including the next
141571a7a1Sriastradh  * paragraph) shall be included in all copies or substantial portions of the
151571a7a1Sriastradh  * Software.
161571a7a1Sriastradh  *
171571a7a1Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181571a7a1Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191571a7a1Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
201571a7a1Sriastradh  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
211571a7a1Sriastradh  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221571a7a1Sriastradh  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
231571a7a1Sriastradh  * SOFTWARE.
241571a7a1Sriastradh  *
251571a7a1Sriastradh  * Authors:
261571a7a1Sriastradh  *    Kevin Tian <kevin.tian@intel.com>
271571a7a1Sriastradh  *    Zhi Wang <zhi.a.wang@intel.com>
281571a7a1Sriastradh  *
291571a7a1Sriastradh  * Contributors:
301571a7a1Sriastradh  *    Min he <min.he@intel.com>
311571a7a1Sriastradh  *
321571a7a1Sriastradh  */
331571a7a1Sriastradh 
341571a7a1Sriastradh #include <sys/cdefs.h>
35*677dec6eSriastradh __KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $");
361571a7a1Sriastradh 
371571a7a1Sriastradh #include "i915_drv.h"
381571a7a1Sriastradh #include "gvt.h"
391571a7a1Sriastradh #include "trace.h"
401571a7a1Sriastradh 
411571a7a1Sriastradh /* common offset among interrupt control registers */
421571a7a1Sriastradh #define regbase_to_isr(base)	(base)
431571a7a1Sriastradh #define regbase_to_imr(base)	(base + 0x4)
441571a7a1Sriastradh #define regbase_to_iir(base)	(base + 0x8)
451571a7a1Sriastradh #define regbase_to_ier(base)	(base + 0xC)
461571a7a1Sriastradh 
471571a7a1Sriastradh #define iir_to_regbase(iir)    (iir - 0x8)
481571a7a1Sriastradh #define ier_to_regbase(ier)    (ier - 0xC)
491571a7a1Sriastradh 
501571a7a1Sriastradh #define get_event_virt_handler(irq, e)	(irq->events[e].v_handler)
511571a7a1Sriastradh #define get_irq_info(irq, e)		(irq->events[e].info)
521571a7a1Sriastradh 
531571a7a1Sriastradh #define irq_to_gvt(irq) \
541571a7a1Sriastradh 	container_of(irq, struct intel_gvt, irq)
551571a7a1Sriastradh 
561571a7a1Sriastradh static void update_upstream_irq(struct intel_vgpu *vgpu,
571571a7a1Sriastradh 		struct intel_gvt_irq_info *info);
581571a7a1Sriastradh 
591571a7a1Sriastradh static const char * const irq_name[INTEL_GVT_EVENT_MAX] = {
601571a7a1Sriastradh 	[RCS_MI_USER_INTERRUPT] = "Render CS MI USER INTERRUPT",
611571a7a1Sriastradh 	[RCS_DEBUG] = "Render EU debug from SVG",
621571a7a1Sriastradh 	[RCS_MMIO_SYNC_FLUSH] = "Render MMIO sync flush status",
631571a7a1Sriastradh 	[RCS_CMD_STREAMER_ERR] = "Render CS error interrupt",
641571a7a1Sriastradh 	[RCS_PIPE_CONTROL] = "Render PIPE CONTROL notify",
651571a7a1Sriastradh 	[RCS_WATCHDOG_EXCEEDED] = "Render CS Watchdog counter exceeded",
661571a7a1Sriastradh 	[RCS_PAGE_DIRECTORY_FAULT] = "Render page directory faults",
671571a7a1Sriastradh 	[RCS_AS_CONTEXT_SWITCH] = "Render AS Context Switch Interrupt",
681571a7a1Sriastradh 
691571a7a1Sriastradh 	[VCS_MI_USER_INTERRUPT] = "Video CS MI USER INTERRUPT",
701571a7a1Sriastradh 	[VCS_MMIO_SYNC_FLUSH] = "Video MMIO sync flush status",
711571a7a1Sriastradh 	[VCS_CMD_STREAMER_ERR] = "Video CS error interrupt",
721571a7a1Sriastradh 	[VCS_MI_FLUSH_DW] = "Video MI FLUSH DW notify",
731571a7a1Sriastradh 	[VCS_WATCHDOG_EXCEEDED] = "Video CS Watchdog counter exceeded",
741571a7a1Sriastradh 	[VCS_PAGE_DIRECTORY_FAULT] = "Video page directory faults",
751571a7a1Sriastradh 	[VCS_AS_CONTEXT_SWITCH] = "Video AS Context Switch Interrupt",
761571a7a1Sriastradh 	[VCS2_MI_USER_INTERRUPT] = "VCS2 Video CS MI USER INTERRUPT",
771571a7a1Sriastradh 	[VCS2_MI_FLUSH_DW] = "VCS2 Video MI FLUSH DW notify",
781571a7a1Sriastradh 	[VCS2_AS_CONTEXT_SWITCH] = "VCS2 Context Switch Interrupt",
791571a7a1Sriastradh 
801571a7a1Sriastradh 	[BCS_MI_USER_INTERRUPT] = "Blitter CS MI USER INTERRUPT",
811571a7a1Sriastradh 	[BCS_MMIO_SYNC_FLUSH] = "Billter MMIO sync flush status",
821571a7a1Sriastradh 	[BCS_CMD_STREAMER_ERR] = "Blitter CS error interrupt",
831571a7a1Sriastradh 	[BCS_MI_FLUSH_DW] = "Blitter MI FLUSH DW notify",
841571a7a1Sriastradh 	[BCS_PAGE_DIRECTORY_FAULT] = "Blitter page directory faults",
851571a7a1Sriastradh 	[BCS_AS_CONTEXT_SWITCH] = "Blitter AS Context Switch Interrupt",
861571a7a1Sriastradh 
871571a7a1Sriastradh 	[VECS_MI_FLUSH_DW] = "Video Enhanced Streamer MI FLUSH DW notify",
881571a7a1Sriastradh 	[VECS_AS_CONTEXT_SWITCH] = "VECS Context Switch Interrupt",
891571a7a1Sriastradh 
901571a7a1Sriastradh 	[PIPE_A_FIFO_UNDERRUN] = "Pipe A FIFO underrun",
911571a7a1Sriastradh 	[PIPE_A_CRC_ERR] = "Pipe A CRC error",
921571a7a1Sriastradh 	[PIPE_A_CRC_DONE] = "Pipe A CRC done",
931571a7a1Sriastradh 	[PIPE_A_VSYNC] = "Pipe A vsync",
941571a7a1Sriastradh 	[PIPE_A_LINE_COMPARE] = "Pipe A line compare",
951571a7a1Sriastradh 	[PIPE_A_ODD_FIELD] = "Pipe A odd field",
961571a7a1Sriastradh 	[PIPE_A_EVEN_FIELD] = "Pipe A even field",
971571a7a1Sriastradh 	[PIPE_A_VBLANK] = "Pipe A vblank",
981571a7a1Sriastradh 	[PIPE_B_FIFO_UNDERRUN] = "Pipe B FIFO underrun",
991571a7a1Sriastradh 	[PIPE_B_CRC_ERR] = "Pipe B CRC error",
1001571a7a1Sriastradh 	[PIPE_B_CRC_DONE] = "Pipe B CRC done",
1011571a7a1Sriastradh 	[PIPE_B_VSYNC] = "Pipe B vsync",
1021571a7a1Sriastradh 	[PIPE_B_LINE_COMPARE] = "Pipe B line compare",
1031571a7a1Sriastradh 	[PIPE_B_ODD_FIELD] = "Pipe B odd field",
1041571a7a1Sriastradh 	[PIPE_B_EVEN_FIELD] = "Pipe B even field",
1051571a7a1Sriastradh 	[PIPE_B_VBLANK] = "Pipe B vblank",
1061571a7a1Sriastradh 	[PIPE_C_VBLANK] = "Pipe C vblank",
1071571a7a1Sriastradh 	[DPST_PHASE_IN] = "DPST phase in event",
1081571a7a1Sriastradh 	[DPST_HISTOGRAM] = "DPST histogram event",
1091571a7a1Sriastradh 	[GSE] = "GSE",
1101571a7a1Sriastradh 	[DP_A_HOTPLUG] = "DP A Hotplug",
1111571a7a1Sriastradh 	[AUX_CHANNEL_A] = "AUX Channel A",
1121571a7a1Sriastradh 	[PERF_COUNTER] = "Performance counter",
1131571a7a1Sriastradh 	[POISON] = "Poison",
1141571a7a1Sriastradh 	[GTT_FAULT] = "GTT fault",
1151571a7a1Sriastradh 	[PRIMARY_A_FLIP_DONE] = "Primary Plane A flip done",
1161571a7a1Sriastradh 	[PRIMARY_B_FLIP_DONE] = "Primary Plane B flip done",
1171571a7a1Sriastradh 	[PRIMARY_C_FLIP_DONE] = "Primary Plane C flip done",
1181571a7a1Sriastradh 	[SPRITE_A_FLIP_DONE] = "Sprite Plane A flip done",
1191571a7a1Sriastradh 	[SPRITE_B_FLIP_DONE] = "Sprite Plane B flip done",
1201571a7a1Sriastradh 	[SPRITE_C_FLIP_DONE] = "Sprite Plane C flip done",
1211571a7a1Sriastradh 
1221571a7a1Sriastradh 	[PCU_THERMAL] = "PCU Thermal Event",
1231571a7a1Sriastradh 	[PCU_PCODE2DRIVER_MAILBOX] = "PCU pcode2driver mailbox event",
1241571a7a1Sriastradh 
1251571a7a1Sriastradh 	[FDI_RX_INTERRUPTS_TRANSCODER_A] = "FDI RX Interrupts Combined A",
1261571a7a1Sriastradh 	[AUDIO_CP_CHANGE_TRANSCODER_A] = "Audio CP Change Transcoder A",
1271571a7a1Sriastradh 	[AUDIO_CP_REQUEST_TRANSCODER_A] = "Audio CP Request Transcoder A",
1281571a7a1Sriastradh 	[FDI_RX_INTERRUPTS_TRANSCODER_B] = "FDI RX Interrupts Combined B",
1291571a7a1Sriastradh 	[AUDIO_CP_CHANGE_TRANSCODER_B] = "Audio CP Change Transcoder B",
1301571a7a1Sriastradh 	[AUDIO_CP_REQUEST_TRANSCODER_B] = "Audio CP Request Transcoder B",
1311571a7a1Sriastradh 	[FDI_RX_INTERRUPTS_TRANSCODER_C] = "FDI RX Interrupts Combined C",
1321571a7a1Sriastradh 	[AUDIO_CP_CHANGE_TRANSCODER_C] = "Audio CP Change Transcoder C",
1331571a7a1Sriastradh 	[AUDIO_CP_REQUEST_TRANSCODER_C] = "Audio CP Request Transcoder C",
1341571a7a1Sriastradh 	[ERR_AND_DBG] = "South Error and Debug Interrupts Combined",
1351571a7a1Sriastradh 	[GMBUS] = "Gmbus",
1361571a7a1Sriastradh 	[SDVO_B_HOTPLUG] = "SDVO B hotplug",
1371571a7a1Sriastradh 	[CRT_HOTPLUG] = "CRT Hotplug",
1381571a7a1Sriastradh 	[DP_B_HOTPLUG] = "DisplayPort/HDMI/DVI B Hotplug",
1391571a7a1Sriastradh 	[DP_C_HOTPLUG] = "DisplayPort/HDMI/DVI C Hotplug",
1401571a7a1Sriastradh 	[DP_D_HOTPLUG] = "DisplayPort/HDMI/DVI D Hotplug",
1411571a7a1Sriastradh 	[AUX_CHANNEL_B] = "AUX Channel B",
1421571a7a1Sriastradh 	[AUX_CHANNEL_C] = "AUX Channel C",
1431571a7a1Sriastradh 	[AUX_CHANNEL_D] = "AUX Channel D",
1441571a7a1Sriastradh 	[AUDIO_POWER_STATE_CHANGE_B] = "Audio Power State change Port B",
1451571a7a1Sriastradh 	[AUDIO_POWER_STATE_CHANGE_C] = "Audio Power State change Port C",
1461571a7a1Sriastradh 	[AUDIO_POWER_STATE_CHANGE_D] = "Audio Power State change Port D",
1471571a7a1Sriastradh 
1481571a7a1Sriastradh 	[INTEL_GVT_EVENT_RESERVED] = "RESERVED EVENTS!!!",
1491571a7a1Sriastradh };
1501571a7a1Sriastradh 
regbase_to_irq_info(struct intel_gvt * gvt,unsigned int reg)1511571a7a1Sriastradh static inline struct intel_gvt_irq_info *regbase_to_irq_info(
1521571a7a1Sriastradh 		struct intel_gvt *gvt,
1531571a7a1Sriastradh 		unsigned int reg)
1541571a7a1Sriastradh {
1551571a7a1Sriastradh 	struct intel_gvt_irq *irq = &gvt->irq;
1561571a7a1Sriastradh 	int i;
1571571a7a1Sriastradh 
1581571a7a1Sriastradh 	for_each_set_bit(i, irq->irq_info_bitmap, INTEL_GVT_IRQ_INFO_MAX) {
1591571a7a1Sriastradh 		if (i915_mmio_reg_offset(irq->info[i]->reg_base) == reg)
1601571a7a1Sriastradh 			return irq->info[i];
1611571a7a1Sriastradh 	}
1621571a7a1Sriastradh 
1631571a7a1Sriastradh 	return NULL;
1641571a7a1Sriastradh }
1651571a7a1Sriastradh 
1661571a7a1Sriastradh /**
1671571a7a1Sriastradh  * intel_vgpu_reg_imr_handler - Generic IMR register emulation write handler
1681571a7a1Sriastradh  * @vgpu: a vGPU
1691571a7a1Sriastradh  * @reg: register offset written by guest
1701571a7a1Sriastradh  * @p_data: register data written by guest
1711571a7a1Sriastradh  * @bytes: register data length
1721571a7a1Sriastradh  *
1731571a7a1Sriastradh  * This function is used to emulate the generic IMR register bit change
1741571a7a1Sriastradh  * behavior.
1751571a7a1Sriastradh  *
1761571a7a1Sriastradh  * Returns:
1771571a7a1Sriastradh  * Zero on success, negative error code if failed.
1781571a7a1Sriastradh  *
1791571a7a1Sriastradh  */
intel_vgpu_reg_imr_handler(struct intel_vgpu * vgpu,unsigned int reg,void * p_data,unsigned int bytes)1801571a7a1Sriastradh int intel_vgpu_reg_imr_handler(struct intel_vgpu *vgpu,
1811571a7a1Sriastradh 	unsigned int reg, void *p_data, unsigned int bytes)
1821571a7a1Sriastradh {
1831571a7a1Sriastradh 	struct intel_gvt *gvt = vgpu->gvt;
1841571a7a1Sriastradh 	struct intel_gvt_irq_ops *ops = gvt->irq.ops;
1851571a7a1Sriastradh 	u32 imr = *(u32 *)p_data;
1861571a7a1Sriastradh 
1871571a7a1Sriastradh 	trace_write_ir(vgpu->id, "IMR", reg, imr, vgpu_vreg(vgpu, reg),
1881571a7a1Sriastradh 		       (vgpu_vreg(vgpu, reg) ^ imr));
1891571a7a1Sriastradh 
1901571a7a1Sriastradh 	vgpu_vreg(vgpu, reg) = imr;
1911571a7a1Sriastradh 
1921571a7a1Sriastradh 	ops->check_pending_irq(vgpu);
1931571a7a1Sriastradh 
1941571a7a1Sriastradh 	return 0;
1951571a7a1Sriastradh }
1961571a7a1Sriastradh 
1971571a7a1Sriastradh /**
1981571a7a1Sriastradh  * intel_vgpu_reg_master_irq_handler - master IRQ write emulation handler
1991571a7a1Sriastradh  * @vgpu: a vGPU
2001571a7a1Sriastradh  * @reg: register offset written by guest
2011571a7a1Sriastradh  * @p_data: register data written by guest
2021571a7a1Sriastradh  * @bytes: register data length
2031571a7a1Sriastradh  *
2041571a7a1Sriastradh  * This function is used to emulate the master IRQ register on gen8+.
2051571a7a1Sriastradh  *
2061571a7a1Sriastradh  * Returns:
2071571a7a1Sriastradh  * Zero on success, negative error code if failed.
2081571a7a1Sriastradh  *
2091571a7a1Sriastradh  */
intel_vgpu_reg_master_irq_handler(struct intel_vgpu * vgpu,unsigned int reg,void * p_data,unsigned int bytes)2101571a7a1Sriastradh int intel_vgpu_reg_master_irq_handler(struct intel_vgpu *vgpu,
2111571a7a1Sriastradh 	unsigned int reg, void *p_data, unsigned int bytes)
2121571a7a1Sriastradh {
2131571a7a1Sriastradh 	struct intel_gvt *gvt = vgpu->gvt;
2141571a7a1Sriastradh 	struct intel_gvt_irq_ops *ops = gvt->irq.ops;
2151571a7a1Sriastradh 	u32 ier = *(u32 *)p_data;
2161571a7a1Sriastradh 	u32 virtual_ier = vgpu_vreg(vgpu, reg);
2171571a7a1Sriastradh 
2181571a7a1Sriastradh 	trace_write_ir(vgpu->id, "MASTER_IRQ", reg, ier, virtual_ier,
2191571a7a1Sriastradh 		       (virtual_ier ^ ier));
2201571a7a1Sriastradh 
2211571a7a1Sriastradh 	/*
2221571a7a1Sriastradh 	 * GEN8_MASTER_IRQ is a special irq register,
2231571a7a1Sriastradh 	 * only bit 31 is allowed to be modified
2241571a7a1Sriastradh 	 * and treated as an IER bit.
2251571a7a1Sriastradh 	 */
2261571a7a1Sriastradh 	ier &= GEN8_MASTER_IRQ_CONTROL;
2271571a7a1Sriastradh 	virtual_ier &= GEN8_MASTER_IRQ_CONTROL;
2281571a7a1Sriastradh 	vgpu_vreg(vgpu, reg) &= ~GEN8_MASTER_IRQ_CONTROL;
2291571a7a1Sriastradh 	vgpu_vreg(vgpu, reg) |= ier;
2301571a7a1Sriastradh 
2311571a7a1Sriastradh 	ops->check_pending_irq(vgpu);
2321571a7a1Sriastradh 
2331571a7a1Sriastradh 	return 0;
2341571a7a1Sriastradh }
2351571a7a1Sriastradh 
2361571a7a1Sriastradh /**
2371571a7a1Sriastradh  * intel_vgpu_reg_ier_handler - Generic IER write emulation handler
2381571a7a1Sriastradh  * @vgpu: a vGPU
2391571a7a1Sriastradh  * @reg: register offset written by guest
2401571a7a1Sriastradh  * @p_data: register data written by guest
2411571a7a1Sriastradh  * @bytes: register data length
2421571a7a1Sriastradh  *
2431571a7a1Sriastradh  * This function is used to emulate the generic IER register behavior.
2441571a7a1Sriastradh  *
2451571a7a1Sriastradh  * Returns:
2461571a7a1Sriastradh  * Zero on success, negative error code if failed.
2471571a7a1Sriastradh  *
2481571a7a1Sriastradh  */
intel_vgpu_reg_ier_handler(struct intel_vgpu * vgpu,unsigned int reg,void * p_data,unsigned int bytes)2491571a7a1Sriastradh int intel_vgpu_reg_ier_handler(struct intel_vgpu *vgpu,
2501571a7a1Sriastradh 	unsigned int reg, void *p_data, unsigned int bytes)
2511571a7a1Sriastradh {
2521571a7a1Sriastradh 	struct intel_gvt *gvt = vgpu->gvt;
2531571a7a1Sriastradh 	struct intel_gvt_irq_ops *ops = gvt->irq.ops;
2541571a7a1Sriastradh 	struct intel_gvt_irq_info *info;
2551571a7a1Sriastradh 	u32 ier = *(u32 *)p_data;
2561571a7a1Sriastradh 
2571571a7a1Sriastradh 	trace_write_ir(vgpu->id, "IER", reg, ier, vgpu_vreg(vgpu, reg),
2581571a7a1Sriastradh 		       (vgpu_vreg(vgpu, reg) ^ ier));
2591571a7a1Sriastradh 
2601571a7a1Sriastradh 	vgpu_vreg(vgpu, reg) = ier;
2611571a7a1Sriastradh 
2621571a7a1Sriastradh 	info = regbase_to_irq_info(gvt, ier_to_regbase(reg));
2631571a7a1Sriastradh 	if (WARN_ON(!info))
2641571a7a1Sriastradh 		return -EINVAL;
2651571a7a1Sriastradh 
2661571a7a1Sriastradh 	if (info->has_upstream_irq)
2671571a7a1Sriastradh 		update_upstream_irq(vgpu, info);
2681571a7a1Sriastradh 
2691571a7a1Sriastradh 	ops->check_pending_irq(vgpu);
2701571a7a1Sriastradh 
2711571a7a1Sriastradh 	return 0;
2721571a7a1Sriastradh }
2731571a7a1Sriastradh 
2741571a7a1Sriastradh /**
2751571a7a1Sriastradh  * intel_vgpu_reg_iir_handler - Generic IIR write emulation handler
2761571a7a1Sriastradh  * @vgpu: a vGPU
2771571a7a1Sriastradh  * @reg: register offset written by guest
2781571a7a1Sriastradh  * @p_data: register data written by guest
2791571a7a1Sriastradh  * @bytes: register data length
2801571a7a1Sriastradh  *
2811571a7a1Sriastradh  * This function is used to emulate the generic IIR register behavior.
2821571a7a1Sriastradh  *
2831571a7a1Sriastradh  * Returns:
2841571a7a1Sriastradh  * Zero on success, negative error code if failed.
2851571a7a1Sriastradh  *
2861571a7a1Sriastradh  */
intel_vgpu_reg_iir_handler(struct intel_vgpu * vgpu,unsigned int reg,void * p_data,unsigned int bytes)2871571a7a1Sriastradh int intel_vgpu_reg_iir_handler(struct intel_vgpu *vgpu, unsigned int reg,
2881571a7a1Sriastradh 	void *p_data, unsigned int bytes)
2891571a7a1Sriastradh {
2901571a7a1Sriastradh 	struct intel_gvt_irq_info *info = regbase_to_irq_info(vgpu->gvt,
2911571a7a1Sriastradh 		iir_to_regbase(reg));
2921571a7a1Sriastradh 	u32 iir = *(u32 *)p_data;
2931571a7a1Sriastradh 
2941571a7a1Sriastradh 	trace_write_ir(vgpu->id, "IIR", reg, iir, vgpu_vreg(vgpu, reg),
2951571a7a1Sriastradh 		       (vgpu_vreg(vgpu, reg) ^ iir));
2961571a7a1Sriastradh 
2971571a7a1Sriastradh 	if (WARN_ON(!info))
2981571a7a1Sriastradh 		return -EINVAL;
2991571a7a1Sriastradh 
3001571a7a1Sriastradh 	vgpu_vreg(vgpu, reg) &= ~iir;
3011571a7a1Sriastradh 
3021571a7a1Sriastradh 	if (info->has_upstream_irq)
3031571a7a1Sriastradh 		update_upstream_irq(vgpu, info);
3041571a7a1Sriastradh 	return 0;
3051571a7a1Sriastradh }
3061571a7a1Sriastradh 
3071571a7a1Sriastradh static struct intel_gvt_irq_map gen8_irq_map[] = {
3081571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 0, INTEL_GVT_IRQ_INFO_GT0, 0xffff },
3091571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 1, INTEL_GVT_IRQ_INFO_GT0, 0xffff0000 },
3101571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 2, INTEL_GVT_IRQ_INFO_GT1, 0xffff },
3111571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 3, INTEL_GVT_IRQ_INFO_GT1, 0xffff0000 },
3121571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 4, INTEL_GVT_IRQ_INFO_GT2, 0xffff },
3131571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 6, INTEL_GVT_IRQ_INFO_GT3, 0xffff },
3141571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 16, INTEL_GVT_IRQ_INFO_DE_PIPE_A, ~0 },
3151571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 17, INTEL_GVT_IRQ_INFO_DE_PIPE_B, ~0 },
3161571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 18, INTEL_GVT_IRQ_INFO_DE_PIPE_C, ~0 },
3171571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 20, INTEL_GVT_IRQ_INFO_DE_PORT, ~0 },
3181571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 22, INTEL_GVT_IRQ_INFO_DE_MISC, ~0 },
3191571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 23, INTEL_GVT_IRQ_INFO_PCH, ~0 },
3201571a7a1Sriastradh 	{ INTEL_GVT_IRQ_INFO_MASTER, 30, INTEL_GVT_IRQ_INFO_PCU, ~0 },
3211571a7a1Sriastradh 	{ -1, -1, ~0 },
3221571a7a1Sriastradh };
3231571a7a1Sriastradh 
update_upstream_irq(struct intel_vgpu * vgpu,struct intel_gvt_irq_info * info)3241571a7a1Sriastradh static void update_upstream_irq(struct intel_vgpu *vgpu,
3251571a7a1Sriastradh 		struct intel_gvt_irq_info *info)
3261571a7a1Sriastradh {
3271571a7a1Sriastradh 	struct intel_gvt_irq *irq = &vgpu->gvt->irq;
3281571a7a1Sriastradh 	struct intel_gvt_irq_map *map = irq->irq_map;
3291571a7a1Sriastradh 	struct intel_gvt_irq_info *up_irq_info = NULL;
3301571a7a1Sriastradh 	u32 set_bits = 0;
3311571a7a1Sriastradh 	u32 clear_bits = 0;
3321571a7a1Sriastradh 	int bit;
3331571a7a1Sriastradh 	u32 val = vgpu_vreg(vgpu,
3341571a7a1Sriastradh 			regbase_to_iir(i915_mmio_reg_offset(info->reg_base)))
3351571a7a1Sriastradh 		& vgpu_vreg(vgpu,
3361571a7a1Sriastradh 			regbase_to_ier(i915_mmio_reg_offset(info->reg_base)));
3371571a7a1Sriastradh 
3381571a7a1Sriastradh 	if (!info->has_upstream_irq)
3391571a7a1Sriastradh 		return;
3401571a7a1Sriastradh 
3411571a7a1Sriastradh 	for (map = irq->irq_map; map->up_irq_bit != -1; map++) {
3421571a7a1Sriastradh 		if (info->group != map->down_irq_group)
3431571a7a1Sriastradh 			continue;
3441571a7a1Sriastradh 
3451571a7a1Sriastradh 		if (!up_irq_info)
3461571a7a1Sriastradh 			up_irq_info = irq->info[map->up_irq_group];
3471571a7a1Sriastradh 		else
3481571a7a1Sriastradh 			WARN_ON(up_irq_info != irq->info[map->up_irq_group]);
3491571a7a1Sriastradh 
3501571a7a1Sriastradh 		bit = map->up_irq_bit;
3511571a7a1Sriastradh 
3521571a7a1Sriastradh 		if (val & map->down_irq_bitmask)
3531571a7a1Sriastradh 			set_bits |= (1 << bit);
3541571a7a1Sriastradh 		else
3551571a7a1Sriastradh 			clear_bits |= (1 << bit);
3561571a7a1Sriastradh 	}
3571571a7a1Sriastradh 
3581571a7a1Sriastradh 	if (WARN_ON(!up_irq_info))
3591571a7a1Sriastradh 		return;
3601571a7a1Sriastradh 
3611571a7a1Sriastradh 	if (up_irq_info->group == INTEL_GVT_IRQ_INFO_MASTER) {
3621571a7a1Sriastradh 		u32 isr = i915_mmio_reg_offset(up_irq_info->reg_base);
3631571a7a1Sriastradh 
3641571a7a1Sriastradh 		vgpu_vreg(vgpu, isr) &= ~clear_bits;
3651571a7a1Sriastradh 		vgpu_vreg(vgpu, isr) |= set_bits;
3661571a7a1Sriastradh 	} else {
3671571a7a1Sriastradh 		u32 iir = regbase_to_iir(
3681571a7a1Sriastradh 			i915_mmio_reg_offset(up_irq_info->reg_base));
3691571a7a1Sriastradh 		u32 imr = regbase_to_imr(
3701571a7a1Sriastradh 			i915_mmio_reg_offset(up_irq_info->reg_base));
3711571a7a1Sriastradh 
3721571a7a1Sriastradh 		vgpu_vreg(vgpu, iir) |= (set_bits & ~vgpu_vreg(vgpu, imr));
3731571a7a1Sriastradh 	}
3741571a7a1Sriastradh 
3751571a7a1Sriastradh 	if (up_irq_info->has_upstream_irq)
3761571a7a1Sriastradh 		update_upstream_irq(vgpu, up_irq_info);
3771571a7a1Sriastradh }
3781571a7a1Sriastradh 
init_irq_map(struct intel_gvt_irq * irq)3791571a7a1Sriastradh static void init_irq_map(struct intel_gvt_irq *irq)
3801571a7a1Sriastradh {
3811571a7a1Sriastradh 	struct intel_gvt_irq_map *map;
3821571a7a1Sriastradh 	struct intel_gvt_irq_info *up_info, *down_info;
3831571a7a1Sriastradh 	int up_bit;
3841571a7a1Sriastradh 
3851571a7a1Sriastradh 	for (map = irq->irq_map; map->up_irq_bit != -1; map++) {
3861571a7a1Sriastradh 		up_info = irq->info[map->up_irq_group];
3871571a7a1Sriastradh 		up_bit = map->up_irq_bit;
3881571a7a1Sriastradh 		down_info = irq->info[map->down_irq_group];
3891571a7a1Sriastradh 
3901571a7a1Sriastradh 		set_bit(up_bit, up_info->downstream_irq_bitmap);
3911571a7a1Sriastradh 		down_info->has_upstream_irq = true;
3921571a7a1Sriastradh 
3931571a7a1Sriastradh 		gvt_dbg_irq("[up] grp %d bit %d -> [down] grp %d bitmask %x\n",
3941571a7a1Sriastradh 			up_info->group, up_bit,
3951571a7a1Sriastradh 			down_info->group, map->down_irq_bitmask);
3961571a7a1Sriastradh 	}
3971571a7a1Sriastradh }
3981571a7a1Sriastradh 
3991571a7a1Sriastradh /* =======================vEvent injection===================== */
inject_virtual_interrupt(struct intel_vgpu * vgpu)4001571a7a1Sriastradh static int inject_virtual_interrupt(struct intel_vgpu *vgpu)
4011571a7a1Sriastradh {
4021571a7a1Sriastradh 	return intel_gvt_hypervisor_inject_msi(vgpu);
4031571a7a1Sriastradh }
4041571a7a1Sriastradh 
propagate_event(struct intel_gvt_irq * irq,enum intel_gvt_event_type event,struct intel_vgpu * vgpu)4051571a7a1Sriastradh static void propagate_event(struct intel_gvt_irq *irq,
4061571a7a1Sriastradh 	enum intel_gvt_event_type event, struct intel_vgpu *vgpu)
4071571a7a1Sriastradh {
4081571a7a1Sriastradh 	struct intel_gvt_irq_info *info;
4091571a7a1Sriastradh 	unsigned int reg_base;
4101571a7a1Sriastradh 	int bit;
4111571a7a1Sriastradh 
4121571a7a1Sriastradh 	info = get_irq_info(irq, event);
4131571a7a1Sriastradh 	if (WARN_ON(!info))
4141571a7a1Sriastradh 		return;
4151571a7a1Sriastradh 
4161571a7a1Sriastradh 	reg_base = i915_mmio_reg_offset(info->reg_base);
4171571a7a1Sriastradh 	bit = irq->events[event].bit;
4181571a7a1Sriastradh 
4191571a7a1Sriastradh 	if (!test_bit(bit, (void *)&vgpu_vreg(vgpu,
4201571a7a1Sriastradh 					regbase_to_imr(reg_base)))) {
4211571a7a1Sriastradh 		trace_propagate_event(vgpu->id, irq_name[event], bit);
4221571a7a1Sriastradh 		set_bit(bit, (void *)&vgpu_vreg(vgpu,
4231571a7a1Sriastradh 					regbase_to_iir(reg_base)));
4241571a7a1Sriastradh 	}
4251571a7a1Sriastradh }
4261571a7a1Sriastradh 
4271571a7a1Sriastradh /* =======================vEvent Handlers===================== */
handle_default_event_virt(struct intel_gvt_irq * irq,enum intel_gvt_event_type event,struct intel_vgpu * vgpu)4281571a7a1Sriastradh static void handle_default_event_virt(struct intel_gvt_irq *irq,
4291571a7a1Sriastradh 	enum intel_gvt_event_type event, struct intel_vgpu *vgpu)
4301571a7a1Sriastradh {
4311571a7a1Sriastradh 	if (!vgpu->irq.irq_warn_once[event]) {
4321571a7a1Sriastradh 		gvt_dbg_core("vgpu%d: IRQ receive event %d (%s)\n",
4331571a7a1Sriastradh 			vgpu->id, event, irq_name[event]);
4341571a7a1Sriastradh 		vgpu->irq.irq_warn_once[event] = true;
4351571a7a1Sriastradh 	}
4361571a7a1Sriastradh 	propagate_event(irq, event, vgpu);
4371571a7a1Sriastradh }
4381571a7a1Sriastradh 
4391571a7a1Sriastradh /* =====================GEN specific logic======================= */
4401571a7a1Sriastradh /* GEN8 interrupt routines. */
4411571a7a1Sriastradh 
4421571a7a1Sriastradh #define DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(regname, regbase) \
4431571a7a1Sriastradh static struct intel_gvt_irq_info gen8_##regname##_info = { \
4441571a7a1Sriastradh 	.name = #regname"-IRQ", \
4451571a7a1Sriastradh 	.reg_base = (regbase), \
4461571a7a1Sriastradh 	.bit_to_event = {[0 ... INTEL_GVT_IRQ_BITWIDTH-1] = \
4471571a7a1Sriastradh 		INTEL_GVT_EVENT_RESERVED}, \
4481571a7a1Sriastradh }
4491571a7a1Sriastradh 
4501571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt0, GEN8_GT_ISR(0));
4511571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt1, GEN8_GT_ISR(1));
4521571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt2, GEN8_GT_ISR(2));
4531571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(gt3, GEN8_GT_ISR(3));
4541571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_pipe_a, GEN8_DE_PIPE_ISR(PIPE_A));
4551571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_pipe_b, GEN8_DE_PIPE_ISR(PIPE_B));
4561571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_pipe_c, GEN8_DE_PIPE_ISR(PIPE_C));
4571571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_port, GEN8_DE_PORT_ISR);
4581571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(de_misc, GEN8_DE_MISC_ISR);
4591571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(pcu, GEN8_PCU_ISR);
4601571a7a1Sriastradh DEFINE_GVT_GEN8_INTEL_GVT_IRQ_INFO(master, GEN8_MASTER_IRQ);
4611571a7a1Sriastradh 
4621571a7a1Sriastradh static struct intel_gvt_irq_info gvt_base_pch_info = {
4631571a7a1Sriastradh 	.name = "PCH-IRQ",
4641571a7a1Sriastradh 	.reg_base = SDEISR,
4651571a7a1Sriastradh 	.bit_to_event = {[0 ... INTEL_GVT_IRQ_BITWIDTH-1] =
4661571a7a1Sriastradh 		INTEL_GVT_EVENT_RESERVED},
4671571a7a1Sriastradh };
4681571a7a1Sriastradh 
gen8_check_pending_irq(struct intel_vgpu * vgpu)4691571a7a1Sriastradh static void gen8_check_pending_irq(struct intel_vgpu *vgpu)
4701571a7a1Sriastradh {
4711571a7a1Sriastradh 	struct intel_gvt_irq *irq = &vgpu->gvt->irq;
4721571a7a1Sriastradh 	int i;
4731571a7a1Sriastradh 
4741571a7a1Sriastradh 	if (!(vgpu_vreg(vgpu, i915_mmio_reg_offset(GEN8_MASTER_IRQ)) &
4751571a7a1Sriastradh 				GEN8_MASTER_IRQ_CONTROL))
4761571a7a1Sriastradh 		return;
4771571a7a1Sriastradh 
4781571a7a1Sriastradh 	for_each_set_bit(i, irq->irq_info_bitmap, INTEL_GVT_IRQ_INFO_MAX) {
4791571a7a1Sriastradh 		struct intel_gvt_irq_info *info = irq->info[i];
4801571a7a1Sriastradh 		u32 reg_base;
4811571a7a1Sriastradh 
4821571a7a1Sriastradh 		if (!info->has_upstream_irq)
4831571a7a1Sriastradh 			continue;
4841571a7a1Sriastradh 
4851571a7a1Sriastradh 		reg_base = i915_mmio_reg_offset(info->reg_base);
4861571a7a1Sriastradh 		if ((vgpu_vreg(vgpu, regbase_to_iir(reg_base))
4871571a7a1Sriastradh 				& vgpu_vreg(vgpu, regbase_to_ier(reg_base))))
4881571a7a1Sriastradh 			update_upstream_irq(vgpu, info);
4891571a7a1Sriastradh 	}
4901571a7a1Sriastradh 
4911571a7a1Sriastradh 	if (vgpu_vreg(vgpu, i915_mmio_reg_offset(GEN8_MASTER_IRQ))
4921571a7a1Sriastradh 			& ~GEN8_MASTER_IRQ_CONTROL)
4931571a7a1Sriastradh 		inject_virtual_interrupt(vgpu);
4941571a7a1Sriastradh }
4951571a7a1Sriastradh 
gen8_init_irq(struct intel_gvt_irq * irq)4961571a7a1Sriastradh static void gen8_init_irq(
4971571a7a1Sriastradh 		struct intel_gvt_irq *irq)
4981571a7a1Sriastradh {
4991571a7a1Sriastradh 	struct intel_gvt *gvt = irq_to_gvt(irq);
5001571a7a1Sriastradh 
5011571a7a1Sriastradh #define SET_BIT_INFO(s, b, e, i)		\
5021571a7a1Sriastradh 	do {					\
5031571a7a1Sriastradh 		s->events[e].bit = b;		\
5041571a7a1Sriastradh 		s->events[e].info = s->info[i];	\
5051571a7a1Sriastradh 		s->info[i]->bit_to_event[b] = e;\
5061571a7a1Sriastradh 	} while (0)
5071571a7a1Sriastradh 
5081571a7a1Sriastradh #define SET_IRQ_GROUP(s, g, i) \
5091571a7a1Sriastradh 	do { \
5101571a7a1Sriastradh 		s->info[g] = i; \
5111571a7a1Sriastradh 		(i)->group = g; \
5121571a7a1Sriastradh 		set_bit(g, s->irq_info_bitmap); \
5131571a7a1Sriastradh 	} while (0)
5141571a7a1Sriastradh 
5151571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_MASTER, &gen8_master_info);
5161571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT0, &gen8_gt0_info);
5171571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT1, &gen8_gt1_info);
5181571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT2, &gen8_gt2_info);
5191571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_GT3, &gen8_gt3_info);
5201571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PIPE_A, &gen8_de_pipe_a_info);
5211571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PIPE_B, &gen8_de_pipe_b_info);
5221571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PIPE_C, &gen8_de_pipe_c_info);
5231571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_PORT, &gen8_de_port_info);
5241571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_DE_MISC, &gen8_de_misc_info);
5251571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_PCU, &gen8_pcu_info);
5261571a7a1Sriastradh 	SET_IRQ_GROUP(irq, INTEL_GVT_IRQ_INFO_PCH, &gvt_base_pch_info);
5271571a7a1Sriastradh 
5281571a7a1Sriastradh 	/* GEN8 level 2 interrupts. */
5291571a7a1Sriastradh 
5301571a7a1Sriastradh 	/* GEN8 interrupt GT0 events */
5311571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, RCS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT0);
5321571a7a1Sriastradh 	SET_BIT_INFO(irq, 4, RCS_PIPE_CONTROL, INTEL_GVT_IRQ_INFO_GT0);
5331571a7a1Sriastradh 	SET_BIT_INFO(irq, 8, RCS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT0);
5341571a7a1Sriastradh 
5351571a7a1Sriastradh 	SET_BIT_INFO(irq, 16, BCS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT0);
5361571a7a1Sriastradh 	SET_BIT_INFO(irq, 20, BCS_MI_FLUSH_DW, INTEL_GVT_IRQ_INFO_GT0);
5371571a7a1Sriastradh 	SET_BIT_INFO(irq, 24, BCS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT0);
5381571a7a1Sriastradh 
5391571a7a1Sriastradh 	/* GEN8 interrupt GT1 events */
5401571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, VCS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT1);
5411571a7a1Sriastradh 	SET_BIT_INFO(irq, 4, VCS_MI_FLUSH_DW, INTEL_GVT_IRQ_INFO_GT1);
5421571a7a1Sriastradh 	SET_BIT_INFO(irq, 8, VCS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT1);
5431571a7a1Sriastradh 
5441571a7a1Sriastradh 	if (HAS_ENGINE(gvt->dev_priv, VCS1)) {
5451571a7a1Sriastradh 		SET_BIT_INFO(irq, 16, VCS2_MI_USER_INTERRUPT,
5461571a7a1Sriastradh 			INTEL_GVT_IRQ_INFO_GT1);
5471571a7a1Sriastradh 		SET_BIT_INFO(irq, 20, VCS2_MI_FLUSH_DW,
5481571a7a1Sriastradh 			INTEL_GVT_IRQ_INFO_GT1);
5491571a7a1Sriastradh 		SET_BIT_INFO(irq, 24, VCS2_AS_CONTEXT_SWITCH,
5501571a7a1Sriastradh 			INTEL_GVT_IRQ_INFO_GT1);
5511571a7a1Sriastradh 	}
5521571a7a1Sriastradh 
5531571a7a1Sriastradh 	/* GEN8 interrupt GT3 events */
5541571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, VECS_MI_USER_INTERRUPT, INTEL_GVT_IRQ_INFO_GT3);
5551571a7a1Sriastradh 	SET_BIT_INFO(irq, 4, VECS_MI_FLUSH_DW, INTEL_GVT_IRQ_INFO_GT3);
5561571a7a1Sriastradh 	SET_BIT_INFO(irq, 8, VECS_AS_CONTEXT_SWITCH, INTEL_GVT_IRQ_INFO_GT3);
5571571a7a1Sriastradh 
5581571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, PIPE_A_VBLANK, INTEL_GVT_IRQ_INFO_DE_PIPE_A);
5591571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, PIPE_B_VBLANK, INTEL_GVT_IRQ_INFO_DE_PIPE_B);
5601571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, PIPE_C_VBLANK, INTEL_GVT_IRQ_INFO_DE_PIPE_C);
5611571a7a1Sriastradh 
5621571a7a1Sriastradh 	/* GEN8 interrupt DE PORT events */
5631571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, AUX_CHANNEL_A, INTEL_GVT_IRQ_INFO_DE_PORT);
5641571a7a1Sriastradh 	SET_BIT_INFO(irq, 3, DP_A_HOTPLUG, INTEL_GVT_IRQ_INFO_DE_PORT);
5651571a7a1Sriastradh 
5661571a7a1Sriastradh 	/* GEN8 interrupt DE MISC events */
5671571a7a1Sriastradh 	SET_BIT_INFO(irq, 0, GSE, INTEL_GVT_IRQ_INFO_DE_MISC);
5681571a7a1Sriastradh 
5691571a7a1Sriastradh 	/* PCH events */
5701571a7a1Sriastradh 	SET_BIT_INFO(irq, 17, GMBUS, INTEL_GVT_IRQ_INFO_PCH);
5711571a7a1Sriastradh 	SET_BIT_INFO(irq, 19, CRT_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH);
5721571a7a1Sriastradh 	SET_BIT_INFO(irq, 21, DP_B_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH);
5731571a7a1Sriastradh 	SET_BIT_INFO(irq, 22, DP_C_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH);
5741571a7a1Sriastradh 	SET_BIT_INFO(irq, 23, DP_D_HOTPLUG, INTEL_GVT_IRQ_INFO_PCH);
5751571a7a1Sriastradh 
5761571a7a1Sriastradh 	if (IS_BROADWELL(gvt->dev_priv)) {
5771571a7a1Sriastradh 		SET_BIT_INFO(irq, 25, AUX_CHANNEL_B, INTEL_GVT_IRQ_INFO_PCH);
5781571a7a1Sriastradh 		SET_BIT_INFO(irq, 26, AUX_CHANNEL_C, INTEL_GVT_IRQ_INFO_PCH);
5791571a7a1Sriastradh 		SET_BIT_INFO(irq, 27, AUX_CHANNEL_D, INTEL_GVT_IRQ_INFO_PCH);
5801571a7a1Sriastradh 
5811571a7a1Sriastradh 		SET_BIT_INFO(irq, 4, PRIMARY_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A);
5821571a7a1Sriastradh 		SET_BIT_INFO(irq, 5, SPRITE_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A);
5831571a7a1Sriastradh 
5841571a7a1Sriastradh 		SET_BIT_INFO(irq, 4, PRIMARY_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B);
5851571a7a1Sriastradh 		SET_BIT_INFO(irq, 5, SPRITE_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B);
5861571a7a1Sriastradh 
5871571a7a1Sriastradh 		SET_BIT_INFO(irq, 4, PRIMARY_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C);
5881571a7a1Sriastradh 		SET_BIT_INFO(irq, 5, SPRITE_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C);
5891571a7a1Sriastradh 	} else if (INTEL_GEN(gvt->dev_priv) >= 9) {
5901571a7a1Sriastradh 		SET_BIT_INFO(irq, 25, AUX_CHANNEL_B, INTEL_GVT_IRQ_INFO_DE_PORT);
5911571a7a1Sriastradh 		SET_BIT_INFO(irq, 26, AUX_CHANNEL_C, INTEL_GVT_IRQ_INFO_DE_PORT);
5921571a7a1Sriastradh 		SET_BIT_INFO(irq, 27, AUX_CHANNEL_D, INTEL_GVT_IRQ_INFO_DE_PORT);
5931571a7a1Sriastradh 
5941571a7a1Sriastradh 		SET_BIT_INFO(irq, 3, PRIMARY_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A);
5951571a7a1Sriastradh 		SET_BIT_INFO(irq, 3, PRIMARY_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B);
5961571a7a1Sriastradh 		SET_BIT_INFO(irq, 3, PRIMARY_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C);
5971571a7a1Sriastradh 
5981571a7a1Sriastradh 		SET_BIT_INFO(irq, 4, SPRITE_A_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_A);
5991571a7a1Sriastradh 		SET_BIT_INFO(irq, 4, SPRITE_B_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_B);
6001571a7a1Sriastradh 		SET_BIT_INFO(irq, 4, SPRITE_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C);
6011571a7a1Sriastradh 	}
6021571a7a1Sriastradh 
6031571a7a1Sriastradh 	/* GEN8 interrupt PCU events */
6041571a7a1Sriastradh 	SET_BIT_INFO(irq, 24, PCU_THERMAL, INTEL_GVT_IRQ_INFO_PCU);
6051571a7a1Sriastradh 	SET_BIT_INFO(irq, 25, PCU_PCODE2DRIVER_MAILBOX, INTEL_GVT_IRQ_INFO_PCU);
6061571a7a1Sriastradh }
6071571a7a1Sriastradh 
6081571a7a1Sriastradh static struct intel_gvt_irq_ops gen8_irq_ops = {
6091571a7a1Sriastradh 	.init_irq = gen8_init_irq,
6101571a7a1Sriastradh 	.check_pending_irq = gen8_check_pending_irq,
6111571a7a1Sriastradh };
6121571a7a1Sriastradh 
6131571a7a1Sriastradh /**
6141571a7a1Sriastradh  * intel_vgpu_trigger_virtual_event - Trigger a virtual event for a vGPU
6151571a7a1Sriastradh  * @vgpu: a vGPU
6161571a7a1Sriastradh  * @event: interrupt event
6171571a7a1Sriastradh  *
6181571a7a1Sriastradh  * This function is used to trigger a virtual interrupt event for vGPU.
6191571a7a1Sriastradh  * The caller provides the event to be triggered, the framework itself
6201571a7a1Sriastradh  * will emulate the IRQ register bit change.
6211571a7a1Sriastradh  *
6221571a7a1Sriastradh  */
intel_vgpu_trigger_virtual_event(struct intel_vgpu * vgpu,enum intel_gvt_event_type event)6231571a7a1Sriastradh void intel_vgpu_trigger_virtual_event(struct intel_vgpu *vgpu,
6241571a7a1Sriastradh 	enum intel_gvt_event_type event)
6251571a7a1Sriastradh {
6261571a7a1Sriastradh 	struct intel_gvt *gvt = vgpu->gvt;
6271571a7a1Sriastradh 	struct intel_gvt_irq *irq = &gvt->irq;
6281571a7a1Sriastradh 	gvt_event_virt_handler_t handler;
6291571a7a1Sriastradh 	struct intel_gvt_irq_ops *ops = gvt->irq.ops;
6301571a7a1Sriastradh 
6311571a7a1Sriastradh 	handler = get_event_virt_handler(irq, event);
6321571a7a1Sriastradh 	WARN_ON(!handler);
6331571a7a1Sriastradh 
6341571a7a1Sriastradh 	handler(irq, event, vgpu);
6351571a7a1Sriastradh 
6361571a7a1Sriastradh 	ops->check_pending_irq(vgpu);
6371571a7a1Sriastradh }
6381571a7a1Sriastradh 
init_events(struct intel_gvt_irq * irq)6391571a7a1Sriastradh static void init_events(
6401571a7a1Sriastradh 	struct intel_gvt_irq *irq)
6411571a7a1Sriastradh {
6421571a7a1Sriastradh 	int i;
6431571a7a1Sriastradh 
6441571a7a1Sriastradh 	for (i = 0; i < INTEL_GVT_EVENT_MAX; i++) {
6451571a7a1Sriastradh 		irq->events[i].info = NULL;
6461571a7a1Sriastradh 		irq->events[i].v_handler = handle_default_event_virt;
6471571a7a1Sriastradh 	}
6481571a7a1Sriastradh }
6491571a7a1Sriastradh 
vblank_timer_fn(struct hrtimer * data)6501571a7a1Sriastradh static enum hrtimer_restart vblank_timer_fn(struct hrtimer *data)
6511571a7a1Sriastradh {
6521571a7a1Sriastradh 	struct intel_gvt_vblank_timer *vblank_timer;
6531571a7a1Sriastradh 	struct intel_gvt_irq *irq;
6541571a7a1Sriastradh 	struct intel_gvt *gvt;
6551571a7a1Sriastradh 
6561571a7a1Sriastradh 	vblank_timer = container_of(data, struct intel_gvt_vblank_timer, timer);
6571571a7a1Sriastradh 	irq = container_of(vblank_timer, struct intel_gvt_irq, vblank_timer);
6581571a7a1Sriastradh 	gvt = container_of(irq, struct intel_gvt, irq);
6591571a7a1Sriastradh 
6601571a7a1Sriastradh 	intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EMULATE_VBLANK);
6611571a7a1Sriastradh 	hrtimer_add_expires_ns(&vblank_timer->timer, vblank_timer->period);
6621571a7a1Sriastradh 	return HRTIMER_RESTART;
6631571a7a1Sriastradh }
6641571a7a1Sriastradh 
6651571a7a1Sriastradh /**
6661571a7a1Sriastradh  * intel_gvt_clean_irq - clean up GVT-g IRQ emulation subsystem
6671571a7a1Sriastradh  * @gvt: a GVT device
6681571a7a1Sriastradh  *
6691571a7a1Sriastradh  * This function is called at driver unloading stage, to clean up GVT-g IRQ
6701571a7a1Sriastradh  * emulation subsystem.
6711571a7a1Sriastradh  *
6721571a7a1Sriastradh  */
intel_gvt_clean_irq(struct intel_gvt * gvt)6731571a7a1Sriastradh void intel_gvt_clean_irq(struct intel_gvt *gvt)
6741571a7a1Sriastradh {
6751571a7a1Sriastradh 	struct intel_gvt_irq *irq = &gvt->irq;
6761571a7a1Sriastradh 
6771571a7a1Sriastradh 	hrtimer_cancel(&irq->vblank_timer.timer);
6781571a7a1Sriastradh }
6791571a7a1Sriastradh 
6801571a7a1Sriastradh #define VBLANK_TIMER_PERIOD 16000000
6811571a7a1Sriastradh 
6821571a7a1Sriastradh /**
6831571a7a1Sriastradh  * intel_gvt_init_irq - initialize GVT-g IRQ emulation subsystem
6841571a7a1Sriastradh  * @gvt: a GVT device
6851571a7a1Sriastradh  *
6861571a7a1Sriastradh  * This function is called at driver loading stage, to initialize the GVT-g IRQ
6871571a7a1Sriastradh  * emulation subsystem.
6881571a7a1Sriastradh  *
6891571a7a1Sriastradh  * Returns:
6901571a7a1Sriastradh  * Zero on success, negative error code if failed.
6911571a7a1Sriastradh  */
intel_gvt_init_irq(struct intel_gvt * gvt)6921571a7a1Sriastradh int intel_gvt_init_irq(struct intel_gvt *gvt)
6931571a7a1Sriastradh {
6941571a7a1Sriastradh 	struct intel_gvt_irq *irq = &gvt->irq;
6951571a7a1Sriastradh 	struct intel_gvt_vblank_timer *vblank_timer = &irq->vblank_timer;
6961571a7a1Sriastradh 
6971571a7a1Sriastradh 	gvt_dbg_core("init irq framework\n");
6981571a7a1Sriastradh 
6991571a7a1Sriastradh 	irq->ops = &gen8_irq_ops;
7001571a7a1Sriastradh 	irq->irq_map = gen8_irq_map;
7011571a7a1Sriastradh 
7021571a7a1Sriastradh 	/* common event initialization */
7031571a7a1Sriastradh 	init_events(irq);
7041571a7a1Sriastradh 
7051571a7a1Sriastradh 	/* gen specific initialization */
7061571a7a1Sriastradh 	irq->ops->init_irq(irq);
7071571a7a1Sriastradh 
7081571a7a1Sriastradh 	init_irq_map(irq);
7091571a7a1Sriastradh 
7101571a7a1Sriastradh 	hrtimer_init(&vblank_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
7111571a7a1Sriastradh 	vblank_timer->timer.function = vblank_timer_fn;
7121571a7a1Sriastradh 	vblank_timer->period = VBLANK_TIMER_PERIOD;
7131571a7a1Sriastradh 
7141571a7a1Sriastradh 	return 0;
7151571a7a1Sriastradh }
716