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