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 | |
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), port: 0xCF8); |
34 | |
35 | switch (len) { |
36 | case 1: |
37 | *value = inb(port: 0xCFC + (reg & 3)); |
38 | break; |
39 | case 2: |
40 | *value = inw(port: 0xCFC + (reg & 2)); |
41 | break; |
42 | case 4: |
43 | *value = inl(port: 0xCFC); |
44 | break; |
45 | } |
46 | |
47 | raw_spin_unlock_irqrestore(&pci_config_lock, flags); |
48 | |
49 | return 0; |
50 | } |
51 | |
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), port: 0xCF8); |
63 | |
64 | switch (len) { |
65 | case 1: |
66 | outb(value: (u8)value, port: 0xCFC + (reg & 3)); |
67 | break; |
68 | case 2: |
69 | outw(value: (u16)value, port: 0xCFC + (reg & 2)); |
70 | break; |
71 | case 4: |
72 | outl(value: (u32)value, port: 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 | |
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(value: (u8)(0xF0 | (fn << 1)), port: 0xCF8); |
116 | outb(value: (u8)bus, port: 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(value: 0, port: 0xCF8); |
131 | |
132 | raw_spin_unlock_irqrestore(&pci_config_lock, flags); |
133 | |
134 | return 0; |
135 | } |
136 | |
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(value: (u8)(0xF0 | (fn << 1)), port: 0xCF8); |
156 | outb(value: (u8)bus, port: 0xCFA); |
157 | |
158 | switch (len) { |
159 | case 1: |
160 | outb(value: (u8)value, PCI_CONF2_ADDRESS(dev, reg)); |
161 | break; |
162 | case 2: |
163 | outw(value: (u16)value, PCI_CONF2_ADDRESS(dev, reg)); |
164 | break; |
165 | case 4: |
166 | outl(value: (u32)value, PCI_CONF2_ADDRESS(dev, reg)); |
167 | break; |
168 | } |
169 | |
170 | outb(value: 0, port: 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 | */ |
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 | |
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(value: 0x01, port: 0xCFB); |
232 | tmp = inl(port: 0xCF8); |
233 | outl(value: 0x80000000, port: 0xCF8); |
234 | if (inl(port: 0xCF8) == 0x80000000 && pci_sanity_check(o: &pci_direct_conf1)) { |
235 | works = 1; |
236 | } |
237 | outl(value: tmp, port: 0xCF8); |
238 | local_irq_restore(flags); |
239 | |
240 | return works; |
241 | } |
242 | |
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(value: 0x00, port: 0xCFB); |
251 | outb(value: 0x00, port: 0xCF8); |
252 | outb(value: 0x00, port: 0xCFA); |
253 | if (inb(port: 0xCF8) == 0x00 && inb(port: 0xCFA) == 0x00 && |
254 | pci_sanity_check(o: &pci_direct_conf2)) { |
255 | works = 1; |
256 | } |
257 | |
258 | local_irq_restore(flags); |
259 | |
260 | return works; |
261 | } |
262 | |
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 | |
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 | |