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