• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
pci_conf1_read(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 * value)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 (seg || (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 
pci_conf1_write(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 value)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 (seg || (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 const 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 
pci_conf2_read(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 * value)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 	WARN_ON(seg);
101 	if ((bus > 255) || (devfn > 255) || (reg > 255)) {
102 		*value = -1;
103 		return -EINVAL;
104 	}
105 
106 	dev = PCI_SLOT(devfn);
107 	fn = PCI_FUNC(devfn);
108 
109 	if (dev & 0x10)
110 		return PCIBIOS_DEVICE_NOT_FOUND;
111 
112 	raw_spin_lock_irqsave(&pci_config_lock, flags);
113 
114 	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
115 	outb((u8)bus, 0xCFA);
116 
117 	switch (len) {
118 	case 1:
119 		*value = inb(PCI_CONF2_ADDRESS(dev, reg));
120 		break;
121 	case 2:
122 		*value = inw(PCI_CONF2_ADDRESS(dev, reg));
123 		break;
124 	case 4:
125 		*value = inl(PCI_CONF2_ADDRESS(dev, reg));
126 		break;
127 	}
128 
129 	outb(0, 0xCF8);
130 
131 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
132 
133 	return 0;
134 }
135 
pci_conf2_write(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,u32 value)136 static int pci_conf2_write(unsigned int seg, unsigned int bus,
137 			   unsigned int devfn, int reg, int len, u32 value)
138 {
139 	unsigned long flags;
140 	int dev, fn;
141 
142 	WARN_ON(seg);
143 	if ((bus > 255) || (devfn > 255) || (reg > 255))
144 		return -EINVAL;
145 
146 	dev = PCI_SLOT(devfn);
147 	fn = PCI_FUNC(devfn);
148 
149 	if (dev & 0x10)
150 		return PCIBIOS_DEVICE_NOT_FOUND;
151 
152 	raw_spin_lock_irqsave(&pci_config_lock, flags);
153 
154 	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
155 	outb((u8)bus, 0xCFA);
156 
157 	switch (len) {
158 	case 1:
159 		outb((u8)value, PCI_CONF2_ADDRESS(dev, reg));
160 		break;
161 	case 2:
162 		outw((u16)value, PCI_CONF2_ADDRESS(dev, reg));
163 		break;
164 	case 4:
165 		outl((u32)value, PCI_CONF2_ADDRESS(dev, reg));
166 		break;
167 	}
168 
169 	outb(0, 0xCF8);
170 
171 	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
172 
173 	return 0;
174 }
175 
176 #undef PCI_CONF2_ADDRESS
177 
178 static const struct pci_raw_ops pci_direct_conf2 = {
179 	.read =		pci_conf2_read,
180 	.write =	pci_conf2_write,
181 };
182 
183 
184 /*
185  * Before we decide to use direct hardware access mechanisms, we try to do some
186  * trivial checks to ensure it at least _seems_ to be working -- we just test
187  * whether bus 00 contains a host bridge (this is similar to checking
188  * techniques used in XFree86, but ours should be more reliable since we
189  * attempt to make use of direct access hints provided by the PCI BIOS).
190  *
191  * This should be close to trivial, but it isn't, because there are buggy
192  * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
193  */
pci_sanity_check(const struct pci_raw_ops * o)194 static int __init pci_sanity_check(const struct pci_raw_ops *o)
195 {
196 	u32 x = 0;
197 	int year, devfn;
198 
199 	if (pci_probe & PCI_NO_CHECKS)
200 		return 1;
201 	/* Assume Type 1 works for newer systems.
202 	   This handles machines that don't have anything on PCI Bus 0. */
203 	dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL);
204 	if (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