[Intel-gfx] [RFC PATCH 7/8] drm/i915: vgt irq mediation - via a tasklet based mechanism
Jike Song
jike.song at intel.com
Tue Sep 30 12:05:37 CEST 2014
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 at intel.com>
---
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
More information about the Intel-gfx
mailing list