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