vgt owns the hardware interrupt of the GPU, to satisfy the interrupt requirement from both host side and guest side (e.g. host may have MI_USER_INTERRUPT disabled, while a VM may have it enabled). Sometimes vgt may also need to emulate a virtual interrupt to the host, w/o a hardware interrupt actually triggered. So we need to split the handling between physical interrupts to vgt and virtual interrupts to host i915. Regarding to above requirements, this patch registers a vgt interrupt handler when vgt is enabled, while letting original i915 interrupt handler instead carried in a tasklet. Whenever a virtual interrupt needs to be injected to host i915, tasklet_schedule gets called. Signed-off-by: Jike Song <jike.song@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++++ drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_vgt.h | 20 ++++++++++++++++++++ drivers/gpu/drm/i915/vgt/vgt.c | 22 ++++++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 742fe8a..e33455a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1668,6 +1668,12 @@ struct drm_i915_private { struct vlv_s0ix_state vlv_s0ix_state; struct { + struct tasklet_struct host_irq_task; + irqreturn_t (*host_isr)(int, void *); + void (*host_irq_uninstall)(struct drm_device *); + } igvt; + + struct { /* * Raw watermark latency values: * in 0.1us units for WM0, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 080981b..df7c868 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -36,6 +36,7 @@ #include "i915_drv.h" #include "i915_trace.h" #include "intel_drv.h" +#include "i915_vgt.h" static const u32 hpd_ibx[] = { [HPD_CRT] = SDE_CRT_HOTPLUG, @@ -4650,6 +4651,30 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) intel_runtime_pm_put(dev_priv); } +static void vgt_host_isr_wrapper(unsigned long data) +{ + struct drm_device *dev = (struct drm_device *)data; + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->igvt.host_isr(dev->pdev->irq, dev); +} + +void vgt_schedule_host_isr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + tasklet_schedule(&dev_priv->igvt.host_irq_task); +} + +static void vgt_irq_uninstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + tasklet_kill(&dev_priv->igvt.host_irq_task); + dev_priv->igvt.host_irq_uninstall(dev); + vgt_fini_irq(dev->pdev); +} + void intel_irq_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4756,6 +4781,16 @@ void intel_irq_init(struct drm_device *dev) dev->driver->enable_vblank = i915_enable_vblank; dev->driver->disable_vblank = i915_disable_vblank; } + + if (i915.enable_vgt) { + vgt_init_irq(dev->pdev, dev); + dev_priv->igvt.host_isr = dev->driver->irq_handler; + dev->driver->irq_handler = vgt_interrupt; + dev_priv->igvt.host_irq_uninstall = dev->driver->irq_uninstall; + dev->driver->irq_uninstall = vgt_irq_uninstall; + tasklet_init(&dev_priv->igvt.host_irq_task, + vgt_host_isr_wrapper, (unsigned long)dev); + } } void intel_hpd_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_vgt.h b/drivers/gpu/drm/i915/i915_vgt.h index 03e7f00..553f920 100644 --- a/drivers/gpu/drm/i915/i915_vgt.h +++ b/drivers/gpu/drm/i915/i915_vgt.h @@ -1,6 +1,9 @@ #ifndef _I915_VGT_H_ #define _I915_VGT_H_ +#include <linux/interrupt.h> + +struct drm_device; struct drm_i915_private; #ifdef CONFIG_I915_IGVT @@ -9,6 +12,10 @@ bool i915_start_vgt(struct pci_dev *); void i915_vgt_record_priv(struct drm_i915_private *); bool vgt_emulate_host_read(u32, void *, int, bool, bool); bool vgt_emulate_host_write(u32, void *, int, bool, bool); +void vgt_schedule_host_isr(struct drm_device *); +void vgt_init_irq(struct pci_dev *, struct drm_device *); +void vgt_fini_irq(struct pci_dev *); +irqreturn_t vgt_interrupt(int, void *); #else /* !CONFIG_I915_IGVT */ @@ -33,6 +40,19 @@ static inline bool vgt_emulate_host_write(u32 reg, void *val, int len, return false; } +static inline void vgt_init_irq(struct pci_dev *pdev, struct drm_device *dev) +{ +} + +static inline void vgt_fini_irq(struct pci_dev *pdev) +{ +} + +static inline irqreturn_t vgt_interrupt(int irq, void *data) +{ + return IRQ_NONE; +} + #endif /* CONFIG_I915_IGVT */ #endif diff --git a/drivers/gpu/drm/i915/vgt/vgt.c b/drivers/gpu/drm/i915/vgt/vgt.c index f33baf3..dab4bfc 100644 --- a/drivers/gpu/drm/i915/vgt/vgt.c +++ b/drivers/gpu/drm/i915/vgt/vgt.c @@ -1,6 +1,7 @@ #include <linux/module.h> #include <linux/kthread.h> #include <linux/pci.h> +#include <linux/interrupt.h> #include "../i915_drv.h" #include "vgt.h" @@ -121,3 +122,24 @@ void i915_vgt_record_priv(struct drm_i915_private *priv) { dev_priv = priv; } + +static void vgt_host_irq(struct drm_device *dev) +{ + vgt_schedule_host_isr(dev); +} + +void vgt_init_irq(struct pci_dev *pdev, struct drm_device *dev) +{ + /* TODO: initialize vgt-specific irq handlings after vgt integration */ +} + +void vgt_fini_irq(struct pci_dev *pdev) +{ + /* TODO: cleanup vgt-specific irq handlings after vgt integration */ +} + +irqreturn_t vgt_interrupt(int irq, void *data) +{ + vgt_host_irq(data); + return IRQ_HANDLED; +} -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx