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
intel_stolen_base_gen3(int domain,int bus,int slot,int func)71 intel_stolen_base_gen3(int domain, int bus, int slot, int func)
72 {
73 uint32_t ctrl;
74 vm_paddr_t val;
75
76 ctrl = pci_cfgregread(domain, bus, slot, func, INTEL_BSM, 4);
77 val = ctrl & INTEL_BSM_MASK;
78 return (val);
79 }
80
81 static vm_paddr_t
intel_stolen_base_gen11(int domain,int bus,int slot,int func)82 intel_stolen_base_gen11(int domain, int bus, int slot, int func)
83 {
84 uint32_t ctrl;
85 vm_paddr_t val;
86
87 ctrl = pci_cfgregread(domain, bus, slot, func, INTEL_GEN11_BSM_DW0, 4);
88 val = ctrl & INTEL_BSM_MASK;
89 val |= (uint64_t)pci_cfgregread(
90 domain, bus, slot, func, INTEL_GEN11_BSM_DW1, 4) << 32;
91 return (val);
92 }
93
94 static vm_paddr_t
intel_stolen_size_gen3(int domain,int bus,int slot,int func)95 intel_stolen_size_gen3(int domain, int bus, int slot, int func)
96 {
97 uint32_t ctrl;
98 vm_paddr_t val;
99
100 ctrl = pci_cfgregread(0, 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
intel_stolen_size_gen6(int domain,int bus,int slot,int func)135 intel_stolen_size_gen6(int domain, int bus, int slot, int func)
136 {
137 uint32_t ctrl;
138 vm_paddr_t val;
139
140 ctrl = pci_cfgregread(domain, 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
intel_stolen_size_gen8(int domain,int bus,int slot,int func)146 intel_stolen_size_gen8(int domain, int bus, int slot, int func)
147 {
148 uint32_t ctrl;
149 vm_paddr_t val;
150
151 ctrl = pci_cfgregread(domain, 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
intel_stolen_size_chv(int domain,int bus,int slot,int func)157 intel_stolen_size_chv(int domain, int bus, int slot, int func)
158 {
159 uint32_t ctrl;
160 vm_paddr_t val;
161
162 ctrl = pci_cfgregread(domain, 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
intel_stolen_size_gen9(int domain,int bus,int slot,int func)179 intel_stolen_size_gen9(int domain, int bus, int slot, int func)
180 {
181 uint32_t ctrl;
182 vm_paddr_t val;
183
184 ctrl = pci_cfgregread(domain, 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 domain, int bus, int slot, int func);
196 vm_paddr_t (*size)(int domain, 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_ADLN_IDS(&intel_stolen_ops_gen11),
264 INTEL_RPLS_IDS(&intel_stolen_ops_gen11),
265 INTEL_RPLP_IDS(&intel_stolen_ops_gen11),
266 };
267
268 /*
269 * Buggy BIOS don't reserve memory for the GPU properly and the OS
270 * can claim it before the GPU driver is loaded. This function will
271 * check the registers for base and size of this memory and reserve
272 * it for the GPU driver.
273 * gen3 (2004) and newer devices are supported. Support for older hw
274 * can be ported from Linux if needed.
275 */
276 static void
intel_graphics_stolen(void)277 intel_graphics_stolen(void)
278 {
279 const struct intel_stolen_ops *ops;
280 uint32_t vendor, device, class;
281 int i;
282
283 /* XXX: Scan bus instead of assuming 0:0:2:0? */
284 const int domain = 0;
285 const int bus = 0;
286 const int slot = 2;
287 const int func = 0;
288
289 if (pci_cfgregopen() == 0)
290 return;
291
292 vendor = pci_cfgregread(domain, bus, slot, func, PCIR_VENDOR, 2);
293 if (vendor != PCI_VENDOR_INTEL)
294 return;
295
296 class = pci_cfgregread(domain, bus, slot, func, PCIR_SUBCLASS, 2);
297 if (class != PCI_CLASS_VGA)
298 return;
299
300 device = pci_cfgregread(domain, bus, slot, func, PCIR_DEVICE, 2);
301 if (device == 0xFFFF)
302 return;
303
304 for (i = 0; i < nitems(intel_ids); i++) {
305 if (intel_ids[i].device != device)
306 continue;
307 ops = intel_ids[i].data;
308 intel_graphics_stolen_base = ops->base(domain, bus, slot, func);
309 intel_graphics_stolen_size = ops->size(domain, bus, slot, func);
310 break;
311 }
312
313 /* XXX: enable this once the KPI is available */
314 /* phys_avail_reserve(intel_graphics_stolen_base, */
315 /* intel_graphics_stolen_base + intel_graphics_stolen_size); */
316 }
317
318 void
pci_early_quirks(void)319 pci_early_quirks(void)
320 {
321
322 TSENTER();
323 intel_graphics_stolen();
324 TSEXIT();
325 }
326