xref: /freebsd/sys/x86/pci/pci_early_quirks.c (revision 66fd12cf4896eb08ad8e7a2627537f84ead84dd3)
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 __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 <sys/sysctl.h>
36 #include <sys/tslog.h>
37 
38 #include <vm/vm.h>
39 /* XXX: enable this once the KPI is available */
40 /* #include <x86/physmem.h> */
41 #include <machine/pci_cfgreg.h>
42 #include <machine/md_var.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45 
46 #include <x86/pci/pci_early_quirks.h>
47 
48 #define	MiB(v) ((unsigned long)(v) << 20)
49 
50 struct pci_device_id {
51 	uint32_t	vendor;
52 	uint32_t	device;
53 	const struct intel_stolen_ops *data;
54 };
55 
56 /*
57  * These global variables are read by LinuxKPI.
58  * LinuxKPI provide this information to the i915 driver.
59  */
60 vm_paddr_t intel_graphics_stolen_base = 0;
61 vm_paddr_t intel_graphics_stolen_size = 0;
62 SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_base, CTLFLAG_RD,
63     &intel_graphics_stolen_base, 0,
64     "Base address of the intel graphics stolen memory.");
65 SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_size, CTLFLAG_RD,
66     &intel_graphics_stolen_size, 0,
67     "Size of the intel graphics stolen memory.");
68 
69 /*
70  * Intel early quirks functions
71  */
72 static vm_paddr_t
73 intel_stolen_base_gen3(int bus, int slot, int func)
74 {
75 	uint32_t ctrl;
76 	vm_paddr_t val;
77 
78 	ctrl = pci_cfgregread(bus, slot, func, INTEL_BSM, 4);
79 	val = ctrl & INTEL_BSM_MASK;
80 	return (val);
81 }
82 
83 static vm_paddr_t
84 intel_stolen_base_gen11(int bus, int slot, int func)
85 {
86 	uint32_t ctrl;
87 	vm_paddr_t val;
88 
89 	ctrl = pci_cfgregread(bus, slot, func, INTEL_GEN11_BSM_DW0, 4);
90 	val = ctrl & INTEL_BSM_MASK;
91 	val |= (uint64_t)pci_cfgregread(
92 	    bus, slot, func, INTEL_GEN11_BSM_DW1, 4) << 32;
93 	return (val);
94 }
95 
96 static vm_paddr_t
97 intel_stolen_size_gen3(int bus, int slot, int func)
98 {
99 	uint32_t ctrl;
100 	vm_paddr_t val;
101 
102 	ctrl = pci_cfgregread(0, 0, 0, I830_GMCH_CTRL, 2);
103 	val = ctrl & I855_GMCH_GMS_MASK;
104 
105 	switch (val) {
106 	case I855_GMCH_GMS_STOLEN_1M:
107 		return (MiB(1));
108 	case I855_GMCH_GMS_STOLEN_4M:
109 		return (MiB(4));
110 	case I855_GMCH_GMS_STOLEN_8M:
111 		return (MiB(8));
112 	case I855_GMCH_GMS_STOLEN_16M:
113 		return (MiB(16));
114 	case I855_GMCH_GMS_STOLEN_32M:
115 		return (MiB(32));
116 	case I915_GMCH_GMS_STOLEN_48M:
117 		return (MiB(48));
118 	case I915_GMCH_GMS_STOLEN_64M:
119 		return (MiB(64));
120 	case G33_GMCH_GMS_STOLEN_128M:
121 		return (MiB(128));
122 	case G33_GMCH_GMS_STOLEN_256M:
123 		return (MiB(256));
124 	case INTEL_GMCH_GMS_STOLEN_96M:
125 		return (MiB(96));
126 	case INTEL_GMCH_GMS_STOLEN_160M:
127 		return (MiB(160));
128 	case INTEL_GMCH_GMS_STOLEN_224M:
129 		return (MiB(224));
130 	case INTEL_GMCH_GMS_STOLEN_352M:
131 		return (MiB(352));
132 	}
133 	return (0);
134 }
135 
136 static vm_paddr_t
137 intel_stolen_size_gen6(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 	return (val * MiB(32));
145 }
146 
147 static vm_paddr_t
148 intel_stolen_size_gen8(int bus, int slot, int func)
149 {
150 	uint32_t ctrl;
151 	vm_paddr_t val;
152 
153 	ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2);
154 	val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
155 	return (val * MiB(32));
156 }
157 
158 static vm_paddr_t
159 intel_stolen_size_chv(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 >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
166 
167 	/*
168 	 * 0x0  to 0x10: 32MB increments starting at 0MB
169 	 * 0x11 to 0x16: 4MB increments starting at 8MB
170 	 * 0x17 to 0x1d: 4MB increments start at 36MB
171 	 */
172 	if (val < 0x11)
173 		return (val * MiB(32));
174 	else if (val < 0x17)
175 		return ((val - 0x11) * MiB(4) + MiB(8));
176 	else
177 		return ((val - 0x17) * MiB(4) + MiB(36));
178 }
179 
180 static vm_paddr_t
181 intel_stolen_size_gen9(int bus, int slot, int func)
182 {
183 	uint32_t ctrl;
184 	vm_paddr_t val;
185 
186 	ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2);
187 	val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
188 
189 	/* 0x0  to 0xEF: 32MB increments starting at 0MB */
190 	/* 0xF0 to 0xFE: 4MB increments starting at 4MB */
191 	if (val < 0xF0)
192 		return (val * MiB(32));
193 	return ((val - 0xF0) * MiB(4) + MiB(4));
194 }
195 
196 struct intel_stolen_ops {
197 	vm_paddr_t (*base)(int bus, int slot, int func);
198 	vm_paddr_t (*size)(int bus, int slot, int func);
199 };
200 
201 static const struct intel_stolen_ops intel_stolen_ops_gen3 = {
202 	.base = intel_stolen_base_gen3,
203 	.size = intel_stolen_size_gen3,
204 };
205 
206 static const struct intel_stolen_ops intel_stolen_ops_gen6 = {
207 	.base = intel_stolen_base_gen3,
208 	.size = intel_stolen_size_gen6,
209 };
210 
211 static const struct intel_stolen_ops intel_stolen_ops_gen8 = {
212 	.base = intel_stolen_base_gen3,
213 	.size = intel_stolen_size_gen8,
214 };
215 
216 static const struct intel_stolen_ops intel_stolen_ops_gen9 = {
217 	.base = intel_stolen_base_gen3,
218 	.size = intel_stolen_size_gen9,
219 };
220 
221 static const struct intel_stolen_ops intel_stolen_ops_chv = {
222 	.base = intel_stolen_base_gen3,
223 	.size = intel_stolen_size_chv,
224 };
225 
226 static const struct intel_stolen_ops intel_stolen_ops_gen11 = {
227 	.base = intel_stolen_base_gen11,
228 	.size = intel_stolen_size_gen9,
229 };
230 
231 static const struct pci_device_id intel_ids[] = {
232 	INTEL_I915G_IDS(&intel_stolen_ops_gen3),
233 	INTEL_I915GM_IDS(&intel_stolen_ops_gen3),
234 	INTEL_I945G_IDS(&intel_stolen_ops_gen3),
235 	INTEL_I945GM_IDS(&intel_stolen_ops_gen3),
236 	INTEL_VLV_IDS(&intel_stolen_ops_gen6),
237 	INTEL_PINEVIEW_IDS(&intel_stolen_ops_gen3),
238 	INTEL_I965G_IDS(&intel_stolen_ops_gen3),
239 	INTEL_G33_IDS(&intel_stolen_ops_gen3),
240 	INTEL_I965GM_IDS(&intel_stolen_ops_gen3),
241 	INTEL_GM45_IDS(&intel_stolen_ops_gen3),
242 	INTEL_G45_IDS(&intel_stolen_ops_gen3),
243 	INTEL_IRONLAKE_D_IDS(&intel_stolen_ops_gen3),
244 	INTEL_IRONLAKE_M_IDS(&intel_stolen_ops_gen3),
245 	INTEL_SNB_D_IDS(&intel_stolen_ops_gen6),
246 	INTEL_SNB_M_IDS(&intel_stolen_ops_gen6),
247 	INTEL_IVB_M_IDS(&intel_stolen_ops_gen6),
248 	INTEL_IVB_D_IDS(&intel_stolen_ops_gen6),
249 	INTEL_HSW_IDS(&intel_stolen_ops_gen6),
250 	INTEL_BDW_IDS(&intel_stolen_ops_gen8),
251 	INTEL_CHV_IDS(&intel_stolen_ops_chv),
252 	INTEL_SKL_IDS(&intel_stolen_ops_gen9),
253 	INTEL_BXT_IDS(&intel_stolen_ops_gen9),
254 	INTEL_KBL_IDS(&intel_stolen_ops_gen9),
255 	INTEL_CFL_IDS(&intel_stolen_ops_gen9),
256 	INTEL_GLK_IDS(&intel_stolen_ops_gen9),
257 	INTEL_CNL_IDS(&intel_stolen_ops_gen9),
258 	INTEL_ICL_11_IDS(&intel_stolen_ops_gen11),
259 	INTEL_EHL_IDS(&intel_stolen_ops_gen11),
260 	INTEL_JSL_IDS(&intel_stolen_ops_gen11),
261 	INTEL_TGL_12_IDS(&intel_stolen_ops_gen11),
262 	INTEL_RKL_IDS(&intel_stolen_ops_gen11),
263 	INTEL_ADLS_IDS(&intel_stolen_ops_gen11),
264 	INTEL_ADLP_IDS(&intel_stolen_ops_gen11),
265 	INTEL_RPLS_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
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:2: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(bus, slot, func, PCIR_VENDOR, 2);
292 	if (vendor != PCI_VENDOR_INTEL)
293 		return;
294 
295 	class = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 2);
296 	if (class != PCI_CLASS_VGA)
297 		return;
298 
299 	device = pci_cfgregread(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(bus, slot, func);
308 		intel_graphics_stolen_size = ops->size(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
318 pci_early_quirks(void)
319 {
320 
321 	TSENTER();
322 	intel_graphics_stolen();
323 	TSEXIT();
324 }
325