aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-11-15 06:32:18 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-11-30 17:22:53 -0500
commite12a2d53ae45a69aea499b64f75e7222cca0f12f (patch)
treeaa636f33e9f51b17ed62a821b9872e58d80f8f52 /drivers
parent9e8944ab564f2e3dde90a518cd32048c58918608 (diff)
drm/i915: Fix detection of base of stolen memory
The routine to query the base of stolen memory was using the wrong registers and the wrong encodings on virtually every platform. It was not until the G33 refresh, that a PCI config register was introduced that explicitly said where the stolen memory was. Prior to 865G there was not even a register that said where the end of usable low memory was and where the stolen memory began (or ended depending upon chipset). Before then, one has to look at the BIOS memory maps to find the Top of Memory. Alas that is not exported by arch/x86 and so we have to resort to disabling stolen memory on gen2 for the time being. Then SandyBridge enlarged the PCI register to a full 32-bits and change the encoding of the address, so even though we happened to be querying the right register, we read the wrong bits and ended up using address 0 for our stolen data, i.e. notably FBC. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c81
2 files changed, 42 insertions, 40 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 31ab43b79736..21360a7e2c8f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -765,6 +765,7 @@ typedef struct drm_i915_private {
765 unsigned long gtt_start; 765 unsigned long gtt_start;
766 unsigned long gtt_mappable_end; 766 unsigned long gtt_mappable_end;
767 unsigned long gtt_end; 767 unsigned long gtt_end;
768 unsigned long stolen_base; /* limited to low memory (32-bit) */
768 769
769 struct io_mapping *gtt_mapping; 770 struct io_mapping *gtt_mapping;
770 phys_addr_t gtt_base_addr; 771 phys_addr_t gtt_base_addr;
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 8e91083b126f..be24312cd32f 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -42,56 +42,50 @@
42 * for is a boon. 42 * for is a boon.
43 */ 43 */
44 44
45#define PTE_ADDRESS_MASK 0xfffff000 45static unsigned long i915_stolen_to_physical(struct drm_device *dev)
46#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
47#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
48#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
49#define PTE_MAPPING_TYPE_CACHED (3 << 1)
50#define PTE_MAPPING_TYPE_MASK (3 << 1)
51#define PTE_VALID (1 << 0)
52
53/**
54 * i915_stolen_to_phys - take an offset into stolen memory and turn it into
55 * a physical one
56 * @dev: drm device
57 * @offset: address to translate
58 *
59 * Some chip functions require allocations from stolen space and need the
60 * physical address of the memory in question.
61 */
62static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset)
63{ 46{
64 struct drm_i915_private *dev_priv = dev->dev_private; 47 struct drm_i915_private *dev_priv = dev->dev_private;
65 struct pci_dev *pdev = dev_priv->bridge_dev; 48 struct pci_dev *pdev = dev_priv->bridge_dev;
66 u32 base; 49 u32 base;
67 50
68#if 0
69 /* On the machines I have tested the Graphics Base of Stolen Memory 51 /* On the machines I have tested the Graphics Base of Stolen Memory
70 * is unreliable, so compute the base by subtracting the stolen memory 52 * is unreliable, so on those compute the base by subtracting the
71 * from the Top of Low Usable DRAM which is where the BIOS places 53 * stolen memory from the Top of Low Usable DRAM which is where the
72 * the graphics stolen memory. 54 * BIOS places the graphics stolen memory.
55 *
56 * On gen2, the layout is slightly different with the Graphics Segment
57 * immediately following Top of Memory (or Top of Usable DRAM). Note
58 * it appears that TOUD is only reported by 865g, so we just use the
59 * top of memory as determined by the e820 probe.
60 *
61 * XXX gen2 requires an unavailable symbol and 945gm fails with
62 * its value of TOLUD.
73 */ 63 */
74 if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { 64 base = 0;
75 /* top 32bits are reserved = 0 */ 65 if (INTEL_INFO(dev)->gen >= 6) {
66 /* Read Base Data of Stolen Memory Register (BDSM) directly.
67 * Note that there is also a MCHBAR miror at 0x1080c0 or
68 * we could use device 2:0x5c instead.
69 */
70 pci_read_config_dword(pdev, 0xB0, &base);
71 base &= ~4095; /* lower bits used for locking register */
72 } else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
73 /* Read Graphics Base of Stolen Memory directly */
76 pci_read_config_dword(pdev, 0xA4, &base); 74 pci_read_config_dword(pdev, 0xA4, &base);
77 } else { 75#if 0
78 /* XXX presume 8xx is the same as i915 */ 76 } else if (IS_GEN3(dev)) {
79 pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base);
80 }
81#else
82 if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
83 u16 val;
84 pci_read_config_word(pdev, 0xb0, &val);
85 base = val >> 4 << 20;
86 } else {
87 u8 val; 77 u8 val;
78 /* Stolen is immediately below Top of Low Usable DRAM */
88 pci_read_config_byte(pdev, 0x9c, &val); 79 pci_read_config_byte(pdev, 0x9c, &val);
89 base = val >> 3 << 27; 80 base = val >> 3 << 27;
90 } 81 base -= dev_priv->mm.gtt->stolen_size;
91 base -= dev_priv->mm.gtt->stolen_size; 82 } else {
83 /* Stolen is immediately above Top of Memory */
84 base = max_low_pfn_mapped << PAGE_SHIFT;
92#endif 85#endif
86 }
93 87
94 return base + offset; 88 return base;
95} 89}
96 90
97static void i915_warn_stolen(struct drm_device *dev) 91static void i915_warn_stolen(struct drm_device *dev)
@@ -116,7 +110,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
116 if (!compressed_fb) 110 if (!compressed_fb)
117 goto err; 111 goto err;
118 112
119 cfb_base = i915_stolen_to_phys(dev, compressed_fb->start); 113 cfb_base = dev_priv->mm.stolen_base + compressed_fb->start;
120 if (!cfb_base) 114 if (!cfb_base)
121 goto err_fb; 115 goto err_fb;
122 116
@@ -129,7 +123,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
129 if (!compressed_llb) 123 if (!compressed_llb)
130 goto err_fb; 124 goto err_fb;
131 125
132 ll_base = i915_stolen_to_phys(dev, compressed_llb->start); 126 ll_base = dev_priv->mm.stolen_base + compressed_llb->start;
133 if (!ll_base) 127 if (!ll_base)
134 goto err_llb; 128 goto err_llb;
135 } 129 }
@@ -148,7 +142,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
148 } 142 }
149 143
150 DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", 144 DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
151 cfb_base, ll_base, size >> 20); 145 (long)cfb_base, (long)ll_base, size >> 20);
152 return; 146 return;
153 147
154err_llb: 148err_llb:
@@ -180,6 +174,13 @@ int i915_gem_init_stolen(struct drm_device *dev)
180 struct drm_i915_private *dev_priv = dev->dev_private; 174 struct drm_i915_private *dev_priv = dev->dev_private;
181 unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size; 175 unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size;
182 176
177 dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
178 if (dev_priv->mm.stolen_base == 0)
179 return 0;
180
181 DRM_DEBUG_KMS("found %d bytes of stolen memory at %08lx\n",
182 dev_priv->mm.gtt->stolen_size, dev_priv->mm.stolen_base);
183
183 /* Basic memrange allocator for stolen space */ 184 /* Basic memrange allocator for stolen space */
184 drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); 185 drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
185 186