1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 #include <sys/tslog.h> 37 38 #include <vm/vm.h> 39 /* XXX: enable this once the KPI is available */ 40 /* #include <x86/physmem.h> */ 41 #include <machine/pci_cfgreg.h> 42 #include <machine/md_var.h> 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcireg.h> 45 46 #include <x86/pci/pci_early_quirks.h> 47 48 #define MiB(v) ((unsigned long)(v) << 20) 49 50 struct pci_device_id { 51 uint32_t vendor; 52 uint32_t device; 53 const struct intel_stolen_ops *data; 54 }; 55 56 /* 57 * These global variables are read by LinuxKPI. 58 * LinuxKPI provide this information to the i915 driver. 59 */ 60 vm_paddr_t intel_graphics_stolen_base = 0; 61 vm_paddr_t intel_graphics_stolen_size = 0; 62 SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_base, CTLFLAG_RD, 63 &intel_graphics_stolen_base, 0, 64 "Base address of the intel graphics stolen memory."); 65 SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_size, CTLFLAG_RD, 66 &intel_graphics_stolen_size, 0, 67 "Size of the intel graphics stolen memory."); 68 69 /* 70 * Intel early quirks functions 71 */ 72 static vm_paddr_t 73 intel_stolen_base_gen3(int bus, int slot, int func) 74 { 75 uint32_t ctrl; 76 vm_paddr_t val; 77 78 ctrl = pci_cfgregread(bus, slot, func, INTEL_BSM, 4); 79 val = ctrl & INTEL_BSM_MASK; 80 return (val); 81 } 82 83 static vm_paddr_t 84 intel_stolen_base_gen11(int bus, int slot, int func) 85 { 86 uint32_t ctrl; 87 vm_paddr_t val; 88 89 ctrl = pci_cfgregread(bus, slot, func, INTEL_GEN11_BSM_DW0, 4); 90 val = ctrl & INTEL_BSM_MASK; 91 val |= (uint64_t)pci_cfgregread( 92 bus, slot, func, INTEL_GEN11_BSM_DW1, 4) << 32; 93 return (val); 94 } 95 96 static vm_paddr_t 97 intel_stolen_size_gen3(int bus, int slot, int func) 98 { 99 uint32_t ctrl; 100 vm_paddr_t val; 101 102 ctrl = pci_cfgregread(0, 0, 0, I830_GMCH_CTRL, 2); 103 val = ctrl & I855_GMCH_GMS_MASK; 104 105 switch (val) { 106 case I855_GMCH_GMS_STOLEN_1M: 107 return (MiB(1)); 108 case I855_GMCH_GMS_STOLEN_4M: 109 return (MiB(4)); 110 case I855_GMCH_GMS_STOLEN_8M: 111 return (MiB(8)); 112 case I855_GMCH_GMS_STOLEN_16M: 113 return (MiB(16)); 114 case I855_GMCH_GMS_STOLEN_32M: 115 return (MiB(32)); 116 case I915_GMCH_GMS_STOLEN_48M: 117 return (MiB(48)); 118 case I915_GMCH_GMS_STOLEN_64M: 119 return (MiB(64)); 120 case G33_GMCH_GMS_STOLEN_128M: 121 return (MiB(128)); 122 case G33_GMCH_GMS_STOLEN_256M: 123 return (MiB(256)); 124 case INTEL_GMCH_GMS_STOLEN_96M: 125 return (MiB(96)); 126 case INTEL_GMCH_GMS_STOLEN_160M: 127 return (MiB(160)); 128 case INTEL_GMCH_GMS_STOLEN_224M: 129 return (MiB(224)); 130 case INTEL_GMCH_GMS_STOLEN_352M: 131 return (MiB(352)); 132 } 133 return (0); 134 } 135 136 static vm_paddr_t 137 intel_stolen_size_gen6(int bus, int slot, int func) 138 { 139 uint32_t ctrl; 140 vm_paddr_t val; 141 142 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 143 val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; 144 return (val * MiB(32)); 145 } 146 147 static vm_paddr_t 148 intel_stolen_size_gen8(int bus, int slot, int func) 149 { 150 uint32_t ctrl; 151 vm_paddr_t val; 152 153 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 154 val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; 155 return (val * MiB(32)); 156 } 157 158 static vm_paddr_t 159 intel_stolen_size_chv(int bus, int slot, int func) 160 { 161 uint32_t ctrl; 162 vm_paddr_t val; 163 164 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 165 val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; 166 167 /* 168 * 0x0 to 0x10: 32MB increments starting at 0MB 169 * 0x11 to 0x16: 4MB increments starting at 8MB 170 * 0x17 to 0x1d: 4MB increments start at 36MB 171 */ 172 if (val < 0x11) 173 return (val * MiB(32)); 174 else if (val < 0x17) 175 return ((val - 0x11) * MiB(4) + MiB(8)); 176 else 177 return ((val - 0x17) * MiB(4) + MiB(36)); 178 } 179 180 static vm_paddr_t 181 intel_stolen_size_gen9(int bus, int slot, int func) 182 { 183 uint32_t ctrl; 184 vm_paddr_t val; 185 186 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 187 val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; 188 189 /* 0x0 to 0xEF: 32MB increments starting at 0MB */ 190 /* 0xF0 to 0xFE: 4MB increments starting at 4MB */ 191 if (val < 0xF0) 192 return (val * MiB(32)); 193 return ((val - 0xF0) * MiB(4) + MiB(4)); 194 } 195 196 struct intel_stolen_ops { 197 vm_paddr_t (*base)(int bus, int slot, int func); 198 vm_paddr_t (*size)(int bus, int slot, int func); 199 }; 200 201 static const struct intel_stolen_ops intel_stolen_ops_gen3 = { 202 .base = intel_stolen_base_gen3, 203 .size = intel_stolen_size_gen3, 204 }; 205 206 static const struct intel_stolen_ops intel_stolen_ops_gen6 = { 207 .base = intel_stolen_base_gen3, 208 .size = intel_stolen_size_gen6, 209 }; 210 211 static const struct intel_stolen_ops intel_stolen_ops_gen8 = { 212 .base = intel_stolen_base_gen3, 213 .size = intel_stolen_size_gen8, 214 }; 215 216 static const struct intel_stolen_ops intel_stolen_ops_gen9 = { 217 .base = intel_stolen_base_gen3, 218 .size = intel_stolen_size_gen9, 219 }; 220 221 static const struct intel_stolen_ops intel_stolen_ops_chv = { 222 .base = intel_stolen_base_gen3, 223 .size = intel_stolen_size_chv, 224 }; 225 226 static const struct intel_stolen_ops intel_stolen_ops_gen11 = { 227 .base = intel_stolen_base_gen11, 228 .size = intel_stolen_size_gen9, 229 }; 230 231 static const struct pci_device_id intel_ids[] = { 232 INTEL_I915G_IDS(&intel_stolen_ops_gen3), 233 INTEL_I915GM_IDS(&intel_stolen_ops_gen3), 234 INTEL_I945G_IDS(&intel_stolen_ops_gen3), 235 INTEL_I945GM_IDS(&intel_stolen_ops_gen3), 236 INTEL_VLV_IDS(&intel_stolen_ops_gen6), 237 INTEL_PINEVIEW_IDS(&intel_stolen_ops_gen3), 238 INTEL_I965G_IDS(&intel_stolen_ops_gen3), 239 INTEL_G33_IDS(&intel_stolen_ops_gen3), 240 INTEL_I965GM_IDS(&intel_stolen_ops_gen3), 241 INTEL_GM45_IDS(&intel_stolen_ops_gen3), 242 INTEL_G45_IDS(&intel_stolen_ops_gen3), 243 INTEL_IRONLAKE_D_IDS(&intel_stolen_ops_gen3), 244 INTEL_IRONLAKE_M_IDS(&intel_stolen_ops_gen3), 245 INTEL_SNB_D_IDS(&intel_stolen_ops_gen6), 246 INTEL_SNB_M_IDS(&intel_stolen_ops_gen6), 247 INTEL_IVB_M_IDS(&intel_stolen_ops_gen6), 248 INTEL_IVB_D_IDS(&intel_stolen_ops_gen6), 249 INTEL_HSW_IDS(&intel_stolen_ops_gen6), 250 INTEL_BDW_IDS(&intel_stolen_ops_gen8), 251 INTEL_CHV_IDS(&intel_stolen_ops_chv), 252 INTEL_SKL_IDS(&intel_stolen_ops_gen9), 253 INTEL_BXT_IDS(&intel_stolen_ops_gen9), 254 INTEL_KBL_IDS(&intel_stolen_ops_gen9), 255 INTEL_CFL_IDS(&intel_stolen_ops_gen9), 256 INTEL_GLK_IDS(&intel_stolen_ops_gen9), 257 INTEL_CNL_IDS(&intel_stolen_ops_gen9), 258 INTEL_ICL_11_IDS(&intel_stolen_ops_gen11), 259 INTEL_EHL_IDS(&intel_stolen_ops_gen11), 260 INTEL_JSL_IDS(&intel_stolen_ops_gen11), 261 INTEL_TGL_12_IDS(&intel_stolen_ops_gen11), 262 INTEL_RKL_IDS(&intel_stolen_ops_gen11), 263 INTEL_ADLS_IDS(&intel_stolen_ops_gen11), 264 INTEL_ADLP_IDS(&intel_stolen_ops_gen11), 265 INTEL_RPLS_IDS(&intel_stolen_ops_gen11), 266 }; 267 268 /* 269 * Buggy BIOS don't reserve memory for the GPU properly and the OS 270 * can claim it before the GPU driver is loaded. This function will 271 * check the registers for base and size of this memory and reserve 272 * it for the GPU driver. 273 * gen3 (2004) and newer devices are supported. Support for older hw 274 * can be ported from Linux if needed. 275 */ 276 static void 277 intel_graphics_stolen(void) 278 { 279 const struct intel_stolen_ops *ops; 280 uint32_t vendor, device, class; 281 int i; 282 283 /* XXX: Scan bus instead of assuming 0:2:0? */ 284 const int bus = 0; 285 const int slot = 2; 286 const int func = 0; 287 288 if (pci_cfgregopen() == 0) 289 return; 290 291 vendor = pci_cfgregread(bus, slot, func, PCIR_VENDOR, 2); 292 if (vendor != PCI_VENDOR_INTEL) 293 return; 294 295 class = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 2); 296 if (class != PCI_CLASS_VGA) 297 return; 298 299 device = pci_cfgregread(bus, slot, func, PCIR_DEVICE, 2); 300 if (device == 0xFFFF) 301 return; 302 303 for (i = 0; i < nitems(intel_ids); i++) { 304 if (intel_ids[i].device != device) 305 continue; 306 ops = intel_ids[i].data; 307 intel_graphics_stolen_base = ops->base(bus, slot, func); 308 intel_graphics_stolen_size = ops->size(bus, slot, func); 309 break; 310 } 311 312 /* XXX: enable this once the KPI is available */ 313 /* phys_avail_reserve(intel_graphics_stolen_base, */ 314 /* intel_graphics_stolen_base + intel_graphics_stolen_size); */ 315 } 316 317 void 318 pci_early_quirks(void) 319 { 320 321 TSENTER(); 322 intel_graphics_stolen(); 323 TSEXIT(); 324 } 325