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_size_gen3(int bus, int slot, int func) 76 { 77 uint32_t ctrl; 78 vm_paddr_t val; 79 80 ctrl = pci_cfgregread(0, 0, 0, I830_GMCH_CTRL, 2); 81 val = ctrl & I855_GMCH_GMS_MASK; 82 83 switch (val) { 84 case I855_GMCH_GMS_STOLEN_1M: 85 return (MiB(1)); 86 case I855_GMCH_GMS_STOLEN_4M: 87 return (MiB(4)); 88 case I855_GMCH_GMS_STOLEN_8M: 89 return (MiB(8)); 90 case I855_GMCH_GMS_STOLEN_16M: 91 return (MiB(16)); 92 case I855_GMCH_GMS_STOLEN_32M: 93 return (MiB(32)); 94 case I915_GMCH_GMS_STOLEN_48M: 95 return (MiB(48)); 96 case I915_GMCH_GMS_STOLEN_64M: 97 return (MiB(64)); 98 case G33_GMCH_GMS_STOLEN_128M: 99 return (MiB(128)); 100 case G33_GMCH_GMS_STOLEN_256M: 101 return (MiB(256)); 102 case INTEL_GMCH_GMS_STOLEN_96M: 103 return (MiB(96)); 104 case INTEL_GMCH_GMS_STOLEN_160M: 105 return (MiB(160)); 106 case INTEL_GMCH_GMS_STOLEN_224M: 107 return (MiB(224)); 108 case INTEL_GMCH_GMS_STOLEN_352M: 109 return (MiB(352)); 110 } 111 return (0); 112 } 113 114 static vm_paddr_t 115 intel_stolen_size_gen6(int bus, int slot, int func) 116 { 117 uint32_t ctrl; 118 vm_paddr_t val; 119 120 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 121 val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; 122 return (val * MiB(32)); 123 } 124 125 static vm_paddr_t 126 intel_stolen_size_gen8(int bus, int slot, int func) 127 { 128 uint32_t ctrl; 129 vm_paddr_t val; 130 131 ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); 132 val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; 133 return (val * MiB(32)); 134 } 135 136 static vm_paddr_t 137 intel_stolen_size_chv(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 145 /* 146 * 0x0 to 0x10: 32MB increments starting at 0MB 147 * 0x11 to 0x16: 4MB increments starting at 8MB 148 * 0x17 to 0x1d: 4MB increments start at 36MB 149 */ 150 if (val < 0x11) 151 return (val * MiB(32)); 152 else if (val < 0x17) 153 return ((val - 0x11) * MiB(4) + MiB(8)); 154 else 155 return ((val - 0x17) * MiB(4) + MiB(36)); 156 } 157 158 static vm_paddr_t 159 intel_stolen_size_gen9(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 >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; 166 167 /* 0x0 to 0xEF: 32MB increments starting at 0MB */ 168 /* 0xF0 to 0xFE: 4MB increments starting at 4MB */ 169 if (val < 0xF0) 170 return (val * MiB(32)); 171 return ((val - 0xF0) * MiB(4) + MiB(4)); 172 } 173 174 struct intel_stolen_ops { 175 vm_paddr_t (*base)(int bus, int slot, int func); 176 vm_paddr_t (*size)(int bus, int slot, int func); 177 }; 178 179 static const struct intel_stolen_ops intel_stolen_ops_gen3 = { 180 .base = intel_stolen_base_gen3, 181 .size = intel_stolen_size_gen3, 182 }; 183 184 static const struct intel_stolen_ops intel_stolen_ops_gen6 = { 185 .base = intel_stolen_base_gen3, 186 .size = intel_stolen_size_gen6, 187 }; 188 189 static const struct intel_stolen_ops intel_stolen_ops_gen8 = { 190 .base = intel_stolen_base_gen3, 191 .size = intel_stolen_size_gen8, 192 }; 193 194 static const struct intel_stolen_ops intel_stolen_ops_gen9 = { 195 .base = intel_stolen_base_gen3, 196 .size = intel_stolen_size_gen9, 197 }; 198 199 static const struct intel_stolen_ops intel_stolen_ops_chv = { 200 .base = intel_stolen_base_gen3, 201 .size = intel_stolen_size_chv, 202 }; 203 204 static const struct pci_device_id intel_ids[] = { 205 INTEL_I915G_IDS(&intel_stolen_ops_gen3), 206 INTEL_I915GM_IDS(&intel_stolen_ops_gen3), 207 INTEL_I945G_IDS(&intel_stolen_ops_gen3), 208 INTEL_I945GM_IDS(&intel_stolen_ops_gen3), 209 INTEL_VLV_IDS(&intel_stolen_ops_gen6), 210 INTEL_PINEVIEW_IDS(&intel_stolen_ops_gen3), 211 INTEL_I965G_IDS(&intel_stolen_ops_gen3), 212 INTEL_G33_IDS(&intel_stolen_ops_gen3), 213 INTEL_I965GM_IDS(&intel_stolen_ops_gen3), 214 INTEL_GM45_IDS(&intel_stolen_ops_gen3), 215 INTEL_G45_IDS(&intel_stolen_ops_gen3), 216 INTEL_IRONLAKE_D_IDS(&intel_stolen_ops_gen3), 217 INTEL_IRONLAKE_M_IDS(&intel_stolen_ops_gen3), 218 INTEL_SNB_D_IDS(&intel_stolen_ops_gen6), 219 INTEL_SNB_M_IDS(&intel_stolen_ops_gen6), 220 INTEL_IVB_M_IDS(&intel_stolen_ops_gen6), 221 INTEL_IVB_D_IDS(&intel_stolen_ops_gen6), 222 INTEL_HSW_IDS(&intel_stolen_ops_gen6), 223 INTEL_BDW_IDS(&intel_stolen_ops_gen8), 224 INTEL_CHV_IDS(&intel_stolen_ops_chv), 225 INTEL_SKL_IDS(&intel_stolen_ops_gen9), 226 INTEL_BXT_IDS(&intel_stolen_ops_gen9), 227 INTEL_KBL_IDS(&intel_stolen_ops_gen9), 228 INTEL_CFL_IDS(&intel_stolen_ops_gen9), 229 INTEL_GLK_IDS(&intel_stolen_ops_gen9), 230 INTEL_CNL_IDS(&intel_stolen_ops_gen9), 231 }; 232 233 /* 234 * Buggy BIOS don't reserve memory for the GPU properly and the OS 235 * can claim it before the GPU driver is loaded. This function will 236 * check the registers for base and size of this memory and reserve 237 * it for the GPU driver. 238 * gen3 (2004) and newer devices are supported. Support for older hw 239 * can be ported from Linux if needed. 240 */ 241 static void 242 intel_graphics_stolen(void) 243 { 244 const struct intel_stolen_ops *ops; 245 uint32_t vendor, device, class; 246 int i; 247 248 /* XXX: Scan bus instead of assuming 0:2:0? */ 249 const int bus = 0; 250 const int slot = 2; 251 const int func = 0; 252 253 if (pci_cfgregopen() == 0) 254 return; 255 256 vendor = pci_cfgregread(bus, slot, func, PCIR_VENDOR, 2); 257 if (vendor != PCI_VENDOR_INTEL) 258 return; 259 260 class = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 2); 261 if (class != PCI_CLASS_VGA) 262 return; 263 264 device = pci_cfgregread(bus, slot, func, PCIR_DEVICE, 2); 265 if (device == 0xFFFF) 266 return; 267 268 for (i = 0; i < nitems(intel_ids); i++) { 269 if (intel_ids[i].device != device) 270 continue; 271 ops = intel_ids[i].data; 272 intel_graphics_stolen_base = ops->base(bus, slot, func); 273 intel_graphics_stolen_size = ops->size(bus, slot, func); 274 break; 275 } 276 277 /* XXX: enable this once the KPI is available */ 278 /* phys_avail_reserve(intel_graphics_stolen_base, */ 279 /* intel_graphics_stolen_base + intel_graphics_stolen_size); */ 280 } 281 282 void 283 pci_early_quirks(void) 284 { 285 286 intel_graphics_stolen(); 287 } 288