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