1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * direct.c - Low-level direct PCI config space access
4  */
5 
6 #include <linux/pci.h>
7 #include <linux/init.h>
8 #include <linux/dmi.h>
9 #include <asm/pci_x86.h>
10 
11 /*
12  * Functions for accessing PCI base (first 256 bytes) and extended
13  * (4096 bytes per PCI function) configuration space with type 1
14  * accesses.
15  */
16 
17 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
18 	(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
19 	| (devfn << 8) | (reg & 0xFC))
20 
pci_conf1_read(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 * value)21 static int pci_conf1_read(unsigned int seg, unsigned int bus,
22 			  unsigned int devfn, int reg, int len, u32 *value)
23 {
24 	unsigned long flags;
25 
26 	if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) {
27 		*value = -1;
28 		return -EINVAL;
29 	}
30 
31 	raw_spin_lock_irqsave(&pci_config_lock, flags);
32 
33 	outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
34 
35 	switch (len) {
36 	case 1:
37 		*value = inb(0xCFC + (reg & 3));
38 		break;
39 	case 2:
40 		*value = inw(0xCFC + (reg & 2));
41 		break;
42 	case 4:
43 		*value = inl(0xCFC);
44 		break;
45 	}
46 
47 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
48 
49 	return 0;
50 }
51 
pci_conf1_write(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 value)52 static int pci_conf1_write(unsigned int seg, unsigned int bus,
53 			   unsigned int devfn, int reg, int len, u32 value)
54 {
55 	unsigned long flags;
56 
57 	if (seg || (bus > 255) || (devfn > 255) || (reg > 4095))
58 		return -EINVAL;
59 
60 	raw_spin_lock_irqsave(&pci_config_lock, flags);
61 
62 	outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
63 
64 	switch (len) {
65 	case 1:
66 		outb((u8)value, 0xCFC + (reg & 3));
67 		break;
68 	case 2:
69 		outw((u16)value, 0xCFC + (reg & 2));
70 		break;
71 	case 4:
72 		outl((u32)value, 0xCFC);
73 		break;
74 	}
75 
76 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
77 
78 	return 0;
79 }
80 
81 #undef PCI_CONF1_ADDRESS
82 
83 const struct pci_raw_ops pci_direct_conf1 = {
84 	.read =		pci_conf1_read,
85 	.write =	pci_conf1_write,
86 };
87 
88 
89 /*
90  * Functions for accessing PCI configuration space with type 2 accesses
91  */
92 
93 #define PCI_CONF2_ADDRESS(dev, reg)	(u16)(0xC000 | (dev << 8) | reg)
94 
pci_conf2_read(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 * value)95 static int pci_conf2_read(unsigned int seg, unsigned int bus,
96 			  unsigned int devfn, int reg, int len, u32 *value)
97 {
98 	unsigned long flags;
99 	int dev, fn;
100 
101 	WARN_ON(seg);
102 	if ((bus > 255) || (devfn > 255) || (reg > 255)) {
103 		*value = -1;
104 		return -EINVAL;
105 	}
106 
107 	dev = PCI_SLOT(devfn);
108 	fn = PCI_FUNC(devfn);
109 
110 	if (dev & 0x10)
111 		return PCIBIOS_DEVICE_NOT_FOUND;
112 
113 	raw_spin_lock_irqsave(&pci_config_lock, flags);
114 
115 	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
116 	outb((u8)bus, 0xCFA);
117 
118 	switch (len) {
119 	case 1:
120 		*value = inb(PCI_CONF2_ADDRESS(dev, reg));
121 		break;
122 	case 2:
123 		*value = inw(PCI_CONF2_ADDRESS(dev, reg));
124 		break;
125 	case 4:
126 		*value = inl(PCI_CONF2_ADDRESS(dev, reg));
127 		break;
128 	}
129 
130 	outb(0, 0xCF8);
131 
132 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
133 
134 	return 0;
135 }
136 
pci_conf2_write(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 value)137 static int pci_conf2_write(unsigned int seg, unsigned int bus,
138 			   unsigned int devfn, int reg, int len, u32 value)
139 {
140 	unsigned long flags;
141 	int dev, fn;
142 
143 	WARN_ON(seg);
144 	if ((bus > 255) || (devfn > 255) || (reg > 255))
145 		return -EINVAL;
146 
147 	dev = PCI_SLOT(devfn);
148 	fn = PCI_FUNC(devfn);
149 
150 	if (dev & 0x10)
151 		return PCIBIOS_DEVICE_NOT_FOUND;
152 
153 	raw_spin_lock_irqsave(&pci_config_lock, flags);
154 
155 	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
156 	outb((u8)bus, 0xCFA);
157 
158 	switch (len) {
159 	case 1:
160 		outb((u8)value, PCI_CONF2_ADDRESS(dev, reg));
161 		break;
162 	case 2:
163 		outw((u16)value, PCI_CONF2_ADDRESS(dev, reg));
164 		break;
165 	case 4:
166 		outl((u32)value, PCI_CONF2_ADDRESS(dev, reg));
167 		break;
168 	}
169 
170 	outb(0, 0xCF8);
171 
172 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
173 
174 	return 0;
175 }
176 
177 #undef PCI_CONF2_ADDRESS
178 
179 static const struct pci_raw_ops pci_direct_conf2 = {
180 	.read =		pci_conf2_read,
181 	.write =	pci_conf2_write,
182 };
183 
184 
185 /*
186  * Before we decide to use direct hardware access mechanisms, we try to do some
187  * trivial checks to ensure it at least _seems_ to be working -- we just test
188  * whether bus 00 contains a host bridge (this is similar to checking
189  * techniques used in XFree86, but ours should be more reliable since we
190  * attempt to make use of direct access hints provided by the PCI BIOS).
191  *
192  * This should be close to trivial, but it isn't, because there are buggy
193  * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
194  */
pci_sanity_check(const struct pci_raw_ops * o)195 static int __init pci_sanity_check(const struct pci_raw_ops *o)
196 {
197 	u32 x = 0;
198 	int devfn;
199 
200 	if (pci_probe & PCI_NO_CHECKS)
201 		return 1;
202 	/* Assume Type 1 works for newer systems.
203 	   This handles machines that don't have anything on PCI Bus 0. */
204 	if (dmi_get_bios_year() >= 2001)
205 		return 1;
206 
207 	for (devfn = 0; devfn < 0x100; devfn++) {
208 		if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x))
209 			continue;
210 		if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)
211 			return 1;
212 
213 		if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x))
214 			continue;
215 		if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)
216 			return 1;
217 	}
218 
219 	DBG(KERN_WARNING "PCI: Sanity check failed\n");
220 	return 0;
221 }
222 
pci_check_type1(void)223 static int __init pci_check_type1(void)
224 {
225 	unsigned long flags;
226 	unsigned int tmp;
227 	int works = 0;
228 
229 	local_irq_save(flags);
230 
231 	outb(0x01, 0xCFB);
232 	tmp = inl(0xCF8);
233 	outl(0x80000000, 0xCF8);
234 	if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) {
235 		works = 1;
236 	}
237 	outl(tmp, 0xCF8);
238 	local_irq_restore(flags);
239 
240 	return works;
241 }
242 
pci_check_type2(void)243 static int __init pci_check_type2(void)
244 {
245 	unsigned long flags;
246 	int works = 0;
247 
248 	local_irq_save(flags);
249 
250 	outb(0x00, 0xCFB);
251 	outb(0x00, 0xCF8);
252 	outb(0x00, 0xCFA);
253 	if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 &&
254 	    pci_sanity_check(&pci_direct_conf2)) {
255 		works = 1;
256 	}
257 
258 	local_irq_restore(flags);
259 
260 	return works;
261 }
262 
pci_direct_init(int type)263 void __init pci_direct_init(int type)
264 {
265 	if (type == 0)
266 		return;
267 	printk(KERN_INFO "PCI: Using configuration type %d for base access\n",
268 		 type);
269 	if (type == 1) {
270 		raw_pci_ops = &pci_direct_conf1;
271 		if (raw_pci_ext_ops)
272 			return;
273 		if (!(pci_probe & PCI_HAS_IO_ECS))
274 			return;
275 		printk(KERN_INFO "PCI: Using configuration type 1 "
276 		       "for extended access\n");
277 		raw_pci_ext_ops = &pci_direct_conf1;
278 		return;
279 	}
280 	raw_pci_ops = &pci_direct_conf2;
281 }
282 
pci_direct_probe(void)283 int __init pci_direct_probe(void)
284 {
285 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
286 		goto type2;
287 	if (!request_region(0xCF8, 8, "PCI conf1"))
288 		goto type2;
289 
290 	if (pci_check_type1()) {
291 		raw_pci_ops = &pci_direct_conf1;
292 		port_cf9_safe = true;
293 		return 1;
294 	}
295 	release_region(0xCF8, 8);
296 
297  type2:
298 	if ((pci_probe & PCI_PROBE_CONF2) == 0)
299 		return 0;
300 	if (!request_region(0xCF8, 4, "PCI conf2"))
301 		return 0;
302 	if (!request_region(0xC000, 0x1000, "PCI conf2"))
303 		goto fail2;
304 
305 	if (pci_check_type2()) {
306 		raw_pci_ops = &pci_direct_conf2;
307 		port_cf9_safe = true;
308 		return 2;
309 	}
310 
311 	release_region(0xC000, 0x1000);
312  fail2:
313 	release_region(0xCF8, 4);
314 	return 0;
315 }
316