i915_gem_stolen.c revision 296548
1/* 2 * Copyright �� 2008-2012 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Eric Anholt <eric@anholt.net> 25 * Chris Wilson <chris@chris-wilson.co.uk> 26 * 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: head/sys/dev/drm2/i915/i915_gem_stolen.c 296548 2016-03-08 20:33:02Z dumbbell $"); 31 32#include <dev/drm2/drmP.h> 33#include <dev/drm2/i915/i915_drm.h> 34#include <dev/drm2/i915/i915_drv.h> 35 36/* 37 * The BIOS typically reserves some of the system's memory for the exclusive 38 * use of the integrated graphics. This memory is no longer available for 39 * use by the OS and so the user finds that his system has less memory 40 * available than he put in. We refer to this memory as stolen. 41 * 42 * The BIOS will allocate its framebuffer from the stolen memory. Our 43 * goal is try to reuse that object for our own fbcon which must always 44 * be available for panics. Anything else we can reuse the stolen memory 45 * for is a boon. 46 */ 47 48static unsigned long i915_stolen_to_physical(struct drm_device *dev) 49{ 50 u32 base; 51 52 /* On the machines I have tested the Graphics Base of Stolen Memory 53 * is unreliable, so on those compute the base by subtracting the 54 * stolen memory from the Top of Low Usable DRAM which is where the 55 * BIOS places the graphics stolen memory. 56 * 57 * On gen2, the layout is slightly different with the Graphics Segment 58 * immediately following Top of Memory (or Top of Usable DRAM). Note 59 * it appears that TOUD is only reported by 865g, so we just use the 60 * top of memory as determined by the e820 probe. 61 * 62 * XXX gen2 requires an unavailable symbol and 945gm fails with 63 * its value of TOLUD. 64 */ 65 base = 0; 66 if (INTEL_INFO(dev)->gen >= 6) { 67 /* Read Base Data of Stolen Memory Register (BDSM) directly. 68 * Note that there is also a MCHBAR miror at 0x1080c0 or 69 * we could use device 2:0x5c instead. 70 */ 71 pci_read_config_dword(dev->dev, 0xB0, &base); 72 base &= ~4095; /* lower bits used for locking register */ 73 } else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { 74 /* Read Graphics Base of Stolen Memory directly */ 75 pci_read_config_dword(dev->dev, 0xA4, &base); 76#if 0 77 } else if (IS_GEN3(dev)) { 78 u8 val; 79 /* Stolen is immediately below Top of Low Usable DRAM */ 80 pci_read_config_byte(pdev, 0x9c, &val); 81 base = val >> 3 << 27; 82 base -= dev_priv->mm.gtt->stolen_size; 83 } else { 84 /* Stolen is immediately above Top of Memory */ 85 base = max_low_pfn_mapped << PAGE_SHIFT; 86#endif 87 } 88 89 return base; 90} 91 92static void i915_warn_stolen(struct drm_device *dev) 93{ 94 DRM_INFO("not enough stolen space for compressed buffer, disabling\n"); 95 DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n"); 96} 97 98static void i915_setup_compression(struct drm_device *dev, int size) 99{ 100 struct drm_i915_private *dev_priv = dev->dev_private; 101 struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb); 102 unsigned long cfb_base; 103 unsigned long ll_base = 0; 104 105 /* Just in case the BIOS is doing something questionable. */ 106 intel_disable_fbc(dev); 107 108 compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0); 109 if (compressed_fb) 110 compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); 111 if (!compressed_fb) 112 goto err; 113 114 cfb_base = dev_priv->mm.stolen_base + compressed_fb->start; 115 if (!cfb_base) 116 goto err_fb; 117 118 if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) { 119 compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen, 120 4096, 4096, 0); 121 if (compressed_llb) 122 compressed_llb = drm_mm_get_block(compressed_llb, 123 4096, 4096); 124 if (!compressed_llb) 125 goto err_fb; 126 127 ll_base = dev_priv->mm.stolen_base + compressed_llb->start; 128 if (!ll_base) 129 goto err_llb; 130 } 131 132 dev_priv->cfb_size = size; 133 134 dev_priv->compressed_fb = compressed_fb; 135 if (HAS_PCH_SPLIT(dev)) 136 I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); 137 else if (IS_GM45(dev)) { 138 I915_WRITE(DPFC_CB_BASE, compressed_fb->start); 139 } else { 140 I915_WRITE(FBC_CFB_BASE, cfb_base); 141 I915_WRITE(FBC_LL_BASE, ll_base); 142 dev_priv->compressed_llb = compressed_llb; 143 } 144 145 DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", 146 (long)cfb_base, (long)ll_base, size >> 20); 147 return; 148 149err_llb: 150 drm_mm_put_block(compressed_llb); 151err_fb: 152 drm_mm_put_block(compressed_fb); 153err: 154 dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; 155 i915_warn_stolen(dev); 156} 157 158static void i915_cleanup_compression(struct drm_device *dev) 159{ 160 struct drm_i915_private *dev_priv = dev->dev_private; 161 162 drm_mm_put_block(dev_priv->compressed_fb); 163 if (dev_priv->compressed_llb) 164 drm_mm_put_block(dev_priv->compressed_llb); 165} 166 167void i915_gem_cleanup_stolen(struct drm_device *dev) 168{ 169 if (I915_HAS_FBC(dev) && i915_powersave) 170 i915_cleanup_compression(dev); 171} 172 173int i915_gem_init_stolen(struct drm_device *dev) 174{ 175 struct drm_i915_private *dev_priv = dev->dev_private; 176 unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size; 177 178 dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); 179 if (dev_priv->mm.stolen_base == 0) 180 return 0; 181 182 DRM_DEBUG_KMS("found %d bytes of stolen memory at %08lx\n", 183 dev_priv->mm.gtt->stolen_size, dev_priv->mm.stolen_base); 184 185 /* Basic memrange allocator for stolen space */ 186 drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); 187 188 /* Try to set up FBC with a reasonable compressed buffer size */ 189 if (I915_HAS_FBC(dev) && i915_powersave) { 190 int cfb_size; 191 192 /* Leave 1M for line length buffer & misc. */ 193 194 /* Try to get a 32M buffer... */ 195 if (prealloc_size > (36*1024*1024)) 196 cfb_size = 32*1024*1024; 197 else /* fall back to 7/8 of the stolen space */ 198 cfb_size = prealloc_size * 7 / 8; 199 i915_setup_compression(dev, cfb_size); 200 } 201 202 return 0; 203} 204