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