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