Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

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