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
intel_stolen_base_gen3(int domain,int bus,int slot,int func)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
intel_stolen_base_gen11(int domain,int bus,int slot,int func)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
intel_stolen_size_gen3(int domain,int bus,int slot,int func)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
intel_stolen_size_gen6(int domain,int bus,int slot,int func)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
intel_stolen_size_gen8(int domain,int bus,int slot,int func)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
intel_stolen_size_chv(int domain,int bus,int slot,int func)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
intel_stolen_size_gen9(int domain,int bus,int slot,int func)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_ADLN_IDS(&intel_stolen_ops_gen11),
263 INTEL_RPLS_IDS(&intel_stolen_ops_gen11),
264 INTEL_RPLP_IDS(&intel_stolen_ops_gen11),
265 };
266
267 /*
268 * Buggy BIOS don't reserve memory for the GPU properly and the OS
269 * can claim it before the GPU driver is loaded. This function will
270 * check the registers for base and size of this memory and reserve
271 * it for the GPU driver.
272 * gen3 (2004) and newer devices are supported. Support for older hw
273 * can be ported from Linux if needed.
274 */
275 static void
intel_graphics_stolen(void)276 intel_graphics_stolen(void)
277 {
278 const struct intel_stolen_ops *ops;
279 uint32_t vendor, device, class;
280 int i;
281
282 /* XXX: Scan bus instead of assuming 0:0:2:0? */
283 const int domain = 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(domain, bus, slot, func, PCIR_VENDOR, 2);
292 if (vendor != PCI_VENDOR_INTEL)
293 return;
294
295 class = pci_cfgregread(domain, bus, slot, func, PCIR_SUBCLASS, 2);
296 if (class != PCI_CLASS_VGA)
297 return;
298
299 device = pci_cfgregread(domain, 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(domain, bus, slot, func);
308 intel_graphics_stolen_size = ops->size(domain, 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
pci_early_quirks(void)318 pci_early_quirks(void)
319 {
320
321 TSENTER();
322 intel_graphics_stolen();
323 TSEXIT();
324 }
325