aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes at virtuousgeek.org>2009-06-05 10:41:29 -0400
committerEric Anholt <eric@anholt.net>2009-06-09 14:15:07 -0400
commitd765898970f35acef960581f678b9da9d5c779fa (patch)
tree07465dd7221dfef8624c9f2982e3cd2c01bf4775
parent1b8e69662e1a086878bf930a6042daf7f8a076cc (diff)
drm/i915: enable MCHBAR if needed
Using the new PNP resource checking code, this patch allows the i915 driver to allocate MCHBAR space if needed and use the BAR to determine current memory settings. [apw@canonical.com: moved to the new generic PNP resource interface] Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Andy Whitcroft <apw@canonical.com> Signed-off-by: Eric Anholt <eric@anholt.net> failure to update-index after git-am --reject to hand-apply Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c145
2 files changed, 147 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index db81f5513daa..6a471458d61a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -150,6 +150,8 @@ typedef struct drm_i915_private {
150 drm_local_map_t hws_map; 150 drm_local_map_t hws_map;
151 struct drm_gem_object *hws_obj; 151 struct drm_gem_object *hws_obj;
152 152
153 struct resource mch_res;
154
153 unsigned int cpp; 155 unsigned int cpp;
154 int back_offset; 156 int back_offset;
155 int front_offset; 157 int front_offset;
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 07d976bf4931..9a05cadaa4ad 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -25,6 +25,8 @@
25 * 25 *
26 */ 26 */
27 27
28#include <linux/acpi.h>
29#include <linux/pnp.h>
28#include "linux/string.h" 30#include "linux/string.h"
29#include "linux/bitops.h" 31#include "linux/bitops.h"
30#include "drmP.h" 32#include "drmP.h"
@@ -81,6 +83,143 @@
81 * to match what the GPU expects. 83 * to match what the GPU expects.
82 */ 84 */
83 85
86#define MCHBAR_I915 0x44
87#define MCHBAR_I965 0x48
88#define MCHBAR_SIZE (4*4096)
89
90#define DEVEN_REG 0x54
91#define DEVEN_MCHBAR_EN (1 << 28)
92
93/* Allocate space for the MCH regs if needed, return nonzero on error */
94static int
95intel_alloc_mchbar_resource(struct drm_device *dev)
96{
97 struct pci_dev *bridge_dev;
98 drm_i915_private_t *dev_priv = dev->dev_private;
99 int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
100 u32 temp_lo, temp_hi = 0;
101 u64 mchbar_addr;
102 int ret = 0;
103
104 bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
105 if (!bridge_dev) {
106 DRM_DEBUG("no bridge dev?!\n");
107 ret = -ENODEV;
108 goto out;
109 }
110
111 if (IS_I965G(dev))
112 pci_read_config_dword(bridge_dev, reg + 4, &temp_hi);
113 pci_read_config_dword(bridge_dev, reg, &temp_lo);
114 mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
115
116 /* If ACPI doesn't have it, assume we need to allocate it ourselves */
117 if (mchbar_addr &&
118 pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
119 ret = 0;
120 goto out_put;
121 }
122
123 /* Get some space for it */
124 ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
125 MCHBAR_SIZE, MCHBAR_SIZE,
126 PCIBIOS_MIN_MEM,
127 0, pcibios_align_resource,
128 bridge_dev);
129 if (ret) {
130 DRM_DEBUG("failed bus alloc: %d\n", ret);
131 dev_priv->mch_res.start = 0;
132 goto out_put;
133 }
134
135 if (IS_I965G(dev))
136 pci_write_config_dword(bridge_dev, reg + 4,
137 upper_32_bits(dev_priv->mch_res.start));
138
139 pci_write_config_dword(bridge_dev, reg,
140 lower_32_bits(dev_priv->mch_res.start));
141out_put:
142 pci_dev_put(bridge_dev);
143out:
144 return ret;
145}
146
147/* Setup MCHBAR if possible, return true if we should disable it again */
148static bool
149intel_setup_mchbar(struct drm_device *dev)
150{
151 struct pci_dev *bridge_dev;
152 int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
153 u32 temp;
154 bool need_disable = false, enabled;
155
156 bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
157 if (!bridge_dev) {
158 DRM_DEBUG("no bridge dev?!\n");
159 goto out;
160 }
161
162 if (IS_I915G(dev) || IS_I915GM(dev)) {
163 pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
164 enabled = !!(temp & DEVEN_MCHBAR_EN);
165 } else {
166 pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
167 enabled = temp & 1;
168 }
169
170 /* If it's already enabled, don't have to do anything */
171 if (enabled)
172 goto out_put;
173
174 if (intel_alloc_mchbar_resource(dev))
175 goto out_put;
176
177 need_disable = true;
178
179 /* Space is allocated or reserved, so enable it. */
180 if (IS_I915G(dev) || IS_I915GM(dev)) {
181 pci_write_config_dword(bridge_dev, DEVEN_REG,
182 temp | DEVEN_MCHBAR_EN);
183 } else {
184 pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
185 pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1);
186 }
187out_put:
188 pci_dev_put(bridge_dev);
189out:
190 return need_disable;
191}
192
193static void
194intel_teardown_mchbar(struct drm_device *dev, bool disable)
195{
196 drm_i915_private_t *dev_priv = dev->dev_private;
197 struct pci_dev *bridge_dev;
198 int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
199 u32 temp;
200
201 bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
202 if (!bridge_dev) {
203 DRM_DEBUG("no bridge dev?!\n");
204 return;
205 }
206
207 if (disable) {
208 if (IS_I915G(dev) || IS_I915GM(dev)) {
209 pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
210 temp &= ~DEVEN_MCHBAR_EN;
211 pci_write_config_dword(bridge_dev, DEVEN_REG, temp);
212 } else {
213 pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
214 temp &= ~1;
215 pci_write_config_dword(bridge_dev, mchbar_reg, temp);
216 }
217 }
218
219 if (dev_priv->mch_res.start)
220 release_resource(&dev_priv->mch_res);
221}
222
84/** 223/**
85 * Detects bit 6 swizzling of address lookup between IGD access and CPU 224 * Detects bit 6 swizzling of address lookup between IGD access and CPU
86 * access through main memory. 225 * access through main memory.
@@ -91,6 +230,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
91 drm_i915_private_t *dev_priv = dev->dev_private; 230 drm_i915_private_t *dev_priv = dev->dev_private;
92 uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; 231 uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
93 uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; 232 uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
233 bool need_disable;
94 234
95 if (!IS_I9XX(dev)) { 235 if (!IS_I9XX(dev)) {
96 /* As far as we know, the 865 doesn't have these bit 6 236 /* As far as we know, the 865 doesn't have these bit 6
@@ -101,6 +241,9 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
101 } else if (IS_MOBILE(dev)) { 241 } else if (IS_MOBILE(dev)) {
102 uint32_t dcc; 242 uint32_t dcc;
103 243
244 /* Try to make sure MCHBAR is enabled before poking at it */
245 need_disable = intel_setup_mchbar(dev);
246
104 /* On mobile 9xx chipsets, channel interleave by the CPU is 247 /* On mobile 9xx chipsets, channel interleave by the CPU is
105 * determined by DCC. For single-channel, neither the CPU 248 * determined by DCC. For single-channel, neither the CPU
106 * nor the GPU do swizzling. For dual channel interleaved, 249 * nor the GPU do swizzling. For dual channel interleaved,
@@ -140,6 +283,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
140 swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; 283 swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
141 swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; 284 swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
142 } 285 }
286
287 intel_teardown_mchbar(dev, need_disable);
143 } else { 288 } else {
144 /* The 965, G33, and newer, have a very flexible memory 289 /* The 965, G33, and newer, have a very flexible memory
145 * configuration. It will enable dual-channel mode 290 * configuration. It will enable dual-channel mode