aboutsummarylogtreecommitdiffstats
path: root/i915-vga-arbiter.patch
blob: 71ea831045ea46a6bdce445c4093cb4cf8524122 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
From 5918c8e3a6d12e391f05ea85b24a19a899dd16b1 Mon Sep 17 00:00:00 2001
From: Mark Weiman <mark.weiman@markzz.com>
Date: Fri, 20 Apr 2018 13:16:39 -0400
Subject: [PATCH] i915: Add module option to support VGA arbiter on HD devices
 (4.16)

This is an updated version of Alex Williamson's patch from:
https://lkml.org/lkml/2014/5/9/517
I don't have i915 graphics, so this is completely untested.

Original commit message follows:
---
Commit 81b5c7bc found that the current VGA arbiter support in i915
only works for ancient GMCH-based IGD devices and attempted to update
support for newer HD devices.  Unfortunately newer devices cannot
completely opt-out of VGA arbitration like the old devices could.
The VGA I/O space cannot be disabled internally.  The only way to
route VGA I/O elsewhere is by disabling I/O at the device PCI command
register.  This means that with commit 81b5c7bc and multiple VGA
adapters, the VGA arbiter will report that multiple VGA devices are
participating in arbitration, Xorg will notice this and disable DRI.
Therefore, 81b5c7bc was reverted because DRI is more important than
being correct.

There is however an actual need for i915 to correctly participate in
VGA arbitration; VGA device assignment.  If we want to use VFIO to
assign a VGA device to a virtual machine, we need to be able to
access the VGA resources of that device.  By adding an i915 module
option we can allow i915 to continue with its charade by default, but
also allow an easy path for users who require working VGA arbitration.
Hopefully Xorg can someday be taught to behave better with multiple
VGA devices.

This also rolls in reverted commit 6e1b4fda, which corrected an
ordering issue with 81b5c7bc by delaying the disabling of VGA memory
until after vgacon->fbcon handoff.

Signed-off-by: Mark Weiman <mark.weiman@markzz.com>
---
 drivers/gpu/drm/i915/i915_drv.c      | 22 ++++++++++++++++---
 drivers/gpu/drm/i915/i915_params.c   |  3 +++
 drivers/gpu/drm/i915/i915_params.h   |  1 +
 drivers/gpu/drm/i915/intel_display.c | 33 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |  1 +
 5 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 2f5209de0391..7c875c651236 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -647,10 +647,20 @@ static int i915_load_modeset_init(struct drm_device *dev)
 	 * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA),
 	 * then we do not take part in VGA arbitration and the
 	 * vga_client_register() fails with -ENODEV.
+	 *
+	 * NB. The set_decode callback here actually works on GMCH
+	 * devices, on newer HD devices we can only disable VGA MMIO space.
+	 * Disabling VGA I/O space requires disabling I/O in the PCI command
+	 * register.  Nonetheless, we like to pretend that we participate in
+	 * VGA arbitration and can dynamically disable VGA I/O space because
+	 * this makes X happy, even though it's a complete lie.
 	 */
-	ret = vga_client_register(pdev, dev_priv, NULL, i915_vga_set_decode);
-	if (ret && ret != -ENODEV)
-		goto out;
+	if (!i915_modparams.enable_hd_vgaarb || !HAS_PCH_SPLIT(dev_priv)) {
+		ret = vga_client_register(pdev, dev, NULL,
+					  i915_vga_set_decode);
+		if (ret && ret != -ENODEV)
+			goto out;
+	}
 
 	intel_register_dsm_handler();
 
@@ -692,6 +702,12 @@ static int i915_load_modeset_init(struct drm_device *dev)
 	if (ret)
 		goto cleanup_gem;
 
+	/*
+	 * Must do this after fbcon init so that
+	 * vgacon_save_screen() works during the handover.
+	 */
+	i915_disable_vga_mem(dev_priv);
+
 	/* Only enable hotplug handling once the fbdev is fully set up. */
 	intel_hpd_init(dev_priv);
 
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index b5f3eb4fa8a3..8fe95b729c22 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -133,6 +133,9 @@ i915_param_named(disable_display, bool, 0400,
 i915_param_named_unsafe(enable_cmd_parser, bool, 0400,
 	"Enable command parsing (true=enabled [default], false=disabled)");
 
+i915_param_named(enable_hd_vgaarb, bool, 0444,
+	"Enable support for VGA arbitration on Intel HD IGD. (default: false)");
+
 i915_param_named(mmio_debug, int, 0600,
 	"Enable the MMIO debug code for the first N failures (default: off). "
 	"This may negatively affect performance.");
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index c96360398072..f76b34e91ea0 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -58,6 +58,7 @@ struct drm_printer;
 	/* leave bools at the end to not create holes */ \
 	param(bool, alpha_support, IS_ENABLED(CONFIG_DRM_I915_ALPHA_SUPPORT)) \
 	param(bool, enable_cmd_parser, true) \
+	param(bool, enable_hd_vgaarb, false) \
 	param(bool, enable_hangcheck, true) \
 	param(bool, fastboot, false) \
 	param(bool, prefault_disable, false) \
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f288bcc7be22..9d6e3d35a2ff 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -14335,6 +14335,36 @@ static void i915_disable_vga(struct drm_i915_private *dev_priv)
 	POSTING_READ(vga_reg);
 }
 
+static void i915_enable_vga_mem(struct drm_i915_private *dev_priv)
+{
+	struct pci_dev *pdev = dev_priv->drm.pdev;
+
+	/* Enable VGA memory on Intel HD */
+	if (i915_modparams.enable_hd_vgaarb && HAS_PCH_SPLIT(dev_priv)) {
+		vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
+		outb(inb(VGA_MSR_READ) | VGA_MSR_MEM_EN, VGA_MSR_WRITE);
+		vga_set_legacy_decoding(pdev, VGA_RSRC_LEGACY_IO |
+						VGA_RSRC_LEGACY_MEM |
+						VGA_RSRC_NORMAL_IO |
+						VGA_RSRC_NORMAL_MEM);
+		vga_put(pdev, VGA_RSRC_LEGACY_IO);
+	}
+}
+
+void i915_disable_vga_mem(struct drm_i915_private *dev_priv)
+{
+	struct pci_dev *pdev = dev_priv->drm.pdev;
+	/* Disable VGA memory on Intel HD */
+	if (i915_modparams.enable_hd_vgaarb && HAS_PCH_SPLIT(dev_priv)) {
+		vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
+		outb(inb(VGA_MSR_READ) & ~VGA_MSR_MEM_EN, VGA_MSR_WRITE);
+		vga_set_legacy_decoding(pdev, VGA_RSRC_LEGACY_IO |
+						   VGA_RSRC_NORMAL_IO |
+						   VGA_RSRC_NORMAL_MEM);
+		vga_put(pdev, VGA_RSRC_LEGACY_IO);
+	}
+}
+
 void intel_modeset_init_hw(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
@@ -14854,6 +14884,7 @@ void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv)
 	if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
 		DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
 		i915_disable_vga(dev_priv);
+		i915_disable_vga_mem(dev_priv);
 	}
 }
 
@@ -15225,6 +15256,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
 
+	i915_enable_vga_mem(dev_priv);
+
 	flush_work(&dev_priv->atomic_helper.free_work);
 	WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list));
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 30f791f89d64..a922629bf376 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1348,6 +1348,7 @@ int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
 			   const char *name, u32 reg);
 void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv);
 void lpt_disable_iclkip(struct drm_i915_private *dev_priv);
+extern void i915_disable_vga_mem(struct drm_i915_private *dev_priv);
 void intel_init_display_hooks(struct drm_i915_private *dev_priv);
 unsigned int intel_fb_xy_to_linear(int x, int y,
 				   const struct intel_plane_state *state,
-- 
2.17.0