[RFC PATCH 7/8] drm/i915: vgt irq mediation - via a tasklet based mechanism

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux