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