1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018 Johannes Lundberg 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bus.h> 34 #include <sys/kernel.h> 35 #include <sys/sysctl.h> 36 37 #include <vm/vm.h> 38 /* XXX: enable this once the KPI is available */ 39 /* #include <x86/physmem.h> */ 40 #include <machine/pci_cfgreg.h> 41 #include <machine/md_var.h> 42 #include <dev/pci/pcivar.h> 43 #include <dev/pci/pcireg.h> 44 45 #include <x86/pci/pci_early_quirks.h> 46 47 #define MiB(v) ((unsigned long)(v) << 20) 48 49 struct pci_device_id { 50 uint32_t vendor; 51 uint32_t device; 52 const struct intel_stolen_ops *data; 53 }; 54 55 /* 56 * These global variables are read by LinuxKPI. 57 * LinuxKPI provide this information to the i915 driver. 58 */ 59 vm_paddr_t intel_graphics_stolen_base = 0; 60 vm_paddr_t intel_graphics_stolen_size = 0; 61 SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_base, CTLFLAG_RD, 62 &intel_graphics_stolen_base, 0, 63 "Base address of the intel graphics stolen memory."); 64 SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_size, CTLFLAG_RD, 65 &intel_graphics_stolen_size, 0, 66 "Size of the intel graphics stolen memory."); 67 68 /* 69 * Intel early quirks functions 70 */ 71 static vm_paddr_t 72 intel_stolen_base_gen3(int bus, int slot, int func) 73 { 74 uint32_t ctrl; 75 vm_paddr_t val; 76 77 ctrl = pci_cfgregread(bus, slot, func, INTEL_BSM, 4); 78 val = ctrl & INTEL_BSM_MASK; 79 return (val); 80 } 81 82 static vm_paddr_t 83 intel_stolen_base_gen11(int bus, int slot, int func) 84 { 85 uint32_t ctrl; 86 vm_paddr_t val; 87 88 ctrl = pci_cfgregread(bus, slot, func, INTEL_GEN11_BSM_DW0, 4); 89 val = ctrl & INTEL_BSM_MASK; 90 val |= (uint64_t)pci_cfgregread( 91 bus, slot, func, INTEL_GEN11_BSM_DW1, 4) << 32; 92 return (val); 93 } 94 95 static vm_paddr_t 96 intel_stolen_size_gen3(int bus, int slot, int func) 97 { 98 uint32_t ctrl; 99 vm_paddr_t val; 100 101 ctrl = pci_cfgregread(0, 0, 0, I830_GMCH_CTRL, 2); 102 val = ctrl & I855_GMCH_GMS_MASK; 103 104 switch (val) { 105 case I855_GMCH_GMS_STOLEN_1M: 106 return (MiB(1)); 107 case I855_GMCH_GMS_STOLEN_4M: 108 return (MiB(4)); 109 case I855_GMCH_GMS_STOLEN_8M: 110 return (MiB(8)); 111 case I855_GMCH_GMS_STOLEN_16M: 112 return (MiB(16)); 113 case I855_GMCH_GMS_STOLEN_32M: 114 return (MiB(32)); 115 case I915_GMCH_GMS_STOLEN_48M: 116 return (MiB(48)); 117 case I915_GMCH_GMS_STOLEN_64M: 118 return (MiB(64)); 119 case G33_GMCH_GMS_STOLEN_128M: 120 return (MiB(128)); 121 case G33_GMCH_GMS_STOLEN_256M: 122 return (MiB(256)); 123 case INTEL_GMCH_GMS_STOLEN_96M: 124 return (MiB(96)); 125 case INTEL_GMCH_GMS_STOLEN_160M: 126 return (MiB(160)); 127 case INTEL_GMCH_GMS_STOLEN_224M: 128 return (MiB(224)); 129 case INTEL_GMCH_GMS_STOLEN_352M: 130 return (MiB(352)); 131 } 132 return (0); 133 } 134 135 static vm_paddr_t 136 intel_stolen_size_gen6(int bus, int slot, int func) 137 { 138 uint32_t ctrl; 139 vm_paddr_t val; 140 141 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 142 val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; 143 return (val * MiB(32)); 144 } 145 146 static vm_paddr_t 147 intel_stolen_size_gen8(int bus, int slot, int func) 148 { 149 uint32_t ctrl; 150 vm_paddr_t val; 151 152 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 153 val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; 154 return (val * MiB(32)); 155 } 156 157 static vm_paddr_t 158 intel_stolen_size_chv(int bus, int slot, int func) 159 { 160 uint32_t ctrl; 161 vm_paddr_t val; 162 163 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 164 val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; 165 166 /* 167 * 0x0 to 0x10: 32MB increments starting at 0MB 168 * 0x11 to 0x16: 4MB increments starting at 8MB 169 * 0x17 to 0x1d: 4MB increments start at 36MB 170 */ 171 if (val < 0x11) 172 return (val * MiB(32)); 173 else if (val < 0x17) 174 return ((val - 0x11) * MiB(4) + MiB(8)); 175 else 176 return ((val - 0x17) * MiB(4) + MiB(36)); 177 } 178 179 static vm_paddr_t 180 intel_stolen_size_gen9(int bus, int slot, int func) 181 { 182 uint32_t ctrl; 183 vm_paddr_t val; 184 185 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 186 val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; 187 188 /* 0x0 to 0xEF: 32MB increments starting at 0MB */ 189 /* 0xF0 to 0xFE: 4MB increments starting at 4MB */ 190 if (val < 0xF0) 191 return (val * MiB(32)); 192 return ((val - 0xF0) * MiB(4) + MiB(4)); 193 } 194 195 struct intel_stolen_ops { 196 vm_paddr_t (*base)(int bus, int slot, int func); 197 vm_paddr_t (*size)(int bus, int slot, int func); 198 }; 199 200 static const struct intel_stolen_ops intel_stolen_ops_gen3 = { 201 .base = intel_stolen_base_gen3, 202 .size = intel_stolen_size_gen3, 203 }; 204 205 static const struct intel_stolen_ops intel_stolen_ops_gen6 = { 206 .base = intel_stolen_base_gen3, 207 .size = intel_stolen_size_gen6, 208 }; 209 210 static const struct intel_stolen_ops intel_stolen_ops_gen8 = { 211 .base = intel_stolen_base_gen3, 212 .size = intel_stolen_size_gen8, 213 }; 214 215 static const struct intel_stolen_ops intel_stolen_ops_gen9 = { 216 .base = intel_stolen_base_gen3, 217 .size = intel_stolen_size_gen9, 218 }; 219 220 static const struct intel_stolen_ops intel_stolen_ops_chv = { 221 .base = intel_stolen_base_gen3, 222 .size = intel_stolen_size_chv, 223 }; 224 225 static const struct intel_stolen_ops intel_stolen_ops_gen11 = { 226 .base = intel_stolen_base_gen11, 227 .size = intel_stolen_size_gen9, 228 }; 229 230 static const struct pci_device_id intel_ids[] = { 231 INTEL_I915G_IDS(&intel_stolen_ops_gen3), 232 INTEL_I915GM_IDS(&intel_stolen_ops_gen3), 233 INTEL_I945G_IDS(&intel_stolen_ops_gen3), 234 INTEL_I945GM_IDS(&intel_stolen_ops_gen3), 235 INTEL_VLV_IDS(&intel_stolen_ops_gen6), 236 INTEL_PINEVIEW_IDS(&intel_stolen_ops_gen3), 237 INTEL_I965G_IDS(&intel_stolen_ops_gen3), 238 INTEL_G33_IDS(&intel_stolen_ops_gen3), 239 INTEL_I965GM_IDS(&intel_stolen_ops_gen3), 240 INTEL_GM45_IDS(&intel_stolen_ops_gen3), 241 INTEL_G45_IDS(&intel_stolen_ops_gen3), 242 INTEL_IRONLAKE_D_IDS(&intel_stolen_ops_gen3), 243 INTEL_IRONLAKE_M_IDS(&intel_stolen_ops_gen3), 244 INTEL_SNB_D_IDS(&intel_stolen_ops_gen6), 245 INTEL_SNB_M_IDS(&intel_stolen_ops_gen6), 246 INTEL_IVB_M_IDS(&intel_stolen_ops_gen6), 247 INTEL_IVB_D_IDS(&intel_stolen_ops_gen6), 248 INTEL_HSW_IDS(&intel_stolen_ops_gen6), 249 INTEL_BDW_IDS(&intel_stolen_ops_gen8), 250 INTEL_CHV_IDS(&intel_stolen_ops_chv), 251 INTEL_SKL_IDS(&intel_stolen_ops_gen9), 252 INTEL_BXT_IDS(&intel_stolen_ops_gen9), 253 INTEL_KBL_IDS(&intel_stolen_ops_gen9), 254 INTEL_CFL_IDS(&intel_stolen_ops_gen9), 255 INTEL_GLK_IDS(&intel_stolen_ops_gen9), 256 INTEL_CNL_IDS(&intel_stolen_ops_gen9), 257 INTEL_ICL_11_IDS(&intel_stolen_ops_gen11), 258 INTEL_EHL_IDS(&intel_stolen_ops_gen11), 259 INTEL_JSL_IDS(&intel_stolen_ops_gen11), 260 INTEL_TGL_12_IDS(&intel_stolen_ops_gen11), 261 INTEL_RKL_IDS(&intel_stolen_ops_gen11), 262 INTEL_ADLS_IDS(&intel_stolen_ops_gen11), 263 INTEL_ADLP_IDS(&intel_stolen_ops_gen11), 264 INTEL_RPLS_IDS(&intel_stolen_ops_gen11), 265 }; 266 267 /* 268 * Buggy BIOS don't reserve memory for the GPU properly and the OS 269 * can claim it before the GPU driver is loaded. This function will 270 * check the registers for base and size of this memory and reserve 271 * it for the GPU driver. 272 * gen3 (2004) and newer devices are supported. Support for older hw 273 * can be ported from Linux if needed. 274 */ 275 static void 276 intel_graphics_stolen(void) 277 { 278 const struct intel_stolen_ops *ops; 279 uint32_t vendor, device, class; 280 int i; 281 282 /* XXX: Scan bus instead of assuming 0:2:0? */ 283 const int bus = 0; 284 const int slot = 2; 285 const int func = 0; 286 287 if (pci_cfgregopen() == 0) 288 return; 289 290 vendor = pci_cfgregread(bus, slot, func, PCIR_VENDOR, 2); 291 if (vendor != PCI_VENDOR_INTEL) 292 return; 293 294 class = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 2); 295 if (class != PCI_CLASS_VGA) 296 return; 297 298 device = pci_cfgregread(bus, slot, func, PCIR_DEVICE, 2); 299 if (device == 0xFFFF) 300 return; 301 302 for (i = 0; i < nitems(intel_ids); i++) { 303 if (intel_ids[i].device != device) 304 continue; 305 ops = intel_ids[i].data; 306 intel_graphics_stolen_base = ops->base(bus, slot, func); 307 intel_graphics_stolen_size = ops->size(bus, slot, func); 308 break; 309 } 310 311 /* XXX: enable this once the KPI is available */ 312 /* phys_avail_reserve(intel_graphics_stolen_base, */ 313 /* intel_graphics_stolen_base + intel_graphics_stolen_size); */ 314 } 315 316 void 317 pci_early_quirks(void) 318 { 319 320 intel_graphics_stolen(); 321 } 322