• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/x86/pci/
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
20static 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
51static 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
82struct 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
94static 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
135static 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
176struct 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 */
192static 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
221static 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
241static 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
261void __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
281int __init pci_direct_probe(void)
282{
283	struct resource *region, *region2;
284
285	if ((pci_probe & PCI_PROBE_CONF1) == 0)
286		goto type2;
287	region = request_region(0xCF8, 8, "PCI conf1");
288	if (!region)
289		goto type2;
290
291	if (pci_check_type1()) {
292		raw_pci_ops = &pci_direct_conf1;
293		port_cf9_safe = true;
294		return 1;
295	}
296	release_resource(region);
297
298 type2:
299	if ((pci_probe & PCI_PROBE_CONF2) == 0)
300		return 0;
301	region = request_region(0xCF8, 4, "PCI conf2");
302	if (!region)
303		return 0;
304	region2 = request_region(0xC000, 0x1000, "PCI conf2");
305	if (!region2)
306		goto fail2;
307
308	if (pci_check_type2()) {
309		raw_pci_ops = &pci_direct_conf2;
310		port_cf9_safe = true;
311		return 2;
312	}
313
314	release_resource(region2);
315 fail2:
316	release_resource(region);
317	return 0;
318}
319