~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to uspace/srv/pci/libpci/i386-ports.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      The PCI Library -- Direct Configuration access via i386 Ports
 
3
 *
 
4
 *      Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz>
 
5
 *
 
6
 *      May 8, 2006 - Modified and ported to HelenOS by Jakub Jermar.
 
7
 *
 
8
 *      Can be freely distributed and used under the terms of the GNU GPL.
 
9
 */
 
10
 
 
11
#include <unistd.h>
 
12
 
 
13
#include "internal.h"
 
14
 
 
15
static inline void outb(u8 b, u16 port)
 
16
{
 
17
        asm volatile ("outb %0, %1\n" :: "a" (b), "d" (port));
 
18
}
 
19
 
 
20
static inline void outw(u16 w, u16 port)
 
21
{
 
22
        asm volatile ("outw %0, %1\n" :: "a" (w), "d" (port));
 
23
}
 
24
 
 
25
static inline void outl(u32 l, u16 port)
 
26
{
 
27
        asm volatile ("outl %0, %1\n" :: "a" (l), "d" (port));
 
28
}
 
29
 
 
30
static inline u8 inb(u16 port)
 
31
{
 
32
        u8 val;
 
33
 
 
34
        asm volatile ("inb %1, %0 \n" : "=a" (val) : "d"(port));
 
35
        return val;
 
36
}
 
37
 
 
38
static inline u16 inw(u16 port)
 
39
{
 
40
        u16 val;
 
41
 
 
42
        asm volatile ("inw %1, %0 \n" : "=a" (val) : "d"(port));
 
43
        return val;
 
44
}
 
45
 
 
46
static inline u32 inl(u16 port)
 
47
{
 
48
        u32 val;
 
49
 
 
50
        asm volatile ("inl %1, %0 \n" : "=a" (val) : "d"(port));
 
51
        return val;
 
52
}
 
53
 
 
54
static void conf12_init(struct pci_access *a)
 
55
{
 
56
}
 
57
 
 
58
static void conf12_cleanup(struct pci_access *a UNUSED)
 
59
{
 
60
}
 
61
 
 
62
/*
 
63
 * Before we decide to use direct hardware access mechanisms, we try to do some
 
64
 * trivial checks to ensure it at least _seems_ to be working -- we just test
 
65
 * whether bus 00 contains a host bridge (this is similar to checking
 
66
 * techniques used in XFree86, but ours should be more reliable since we
 
67
 * attempt to make use of direct access hints provided by the PCI BIOS).
 
68
 *
 
69
 * This should be close to trivial, but it isn't, because there are buggy
 
70
 * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
 
71
 */
 
72
 
 
73
static int intel_sanity_check(struct pci_access *a, struct pci_methods *m)
 
74
{
 
75
        struct pci_dev d;
 
76
 
 
77
        a->debug("...sanity check");
 
78
        d.bus = 0;
 
79
        d.func = 0;
 
80
        for (d.dev = 0; d.dev < 32; d.dev++) {
 
81
                u16 class, vendor;
 
82
                if ((m->read(&d, PCI_CLASS_DEVICE, (byte *) & class,
 
83
                         sizeof(class))
 
84
                    && (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST)
 
85
                        || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)))
 
86
                    || (m->read(&d, PCI_VENDOR_ID, (byte *) & vendor,
 
87
                               sizeof(vendor))
 
88
                    && (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL)
 
89
                        || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ)))) {
 
90
                        a->debug("...outside the Asylum at 0/%02x/0",
 
91
                                 d.dev);
 
92
                        return 1;
 
93
                }
 
94
        }
 
95
        a->debug("...insane");
 
96
        return 0;
 
97
}
 
98
 
 
99
/*
 
100
 *      Configuration type 1
 
101
 */
 
102
 
 
103
#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
 
104
 
 
105
static int conf1_detect(struct pci_access *a)
 
106
{
 
107
        unsigned int tmp;
 
108
        int res = 0;
 
109
 
 
110
        outb(0x01, 0xCFB);
 
111
        tmp = inl(0xCF8);
 
112
        outl(0x80000000, 0xCF8);
 
113
        if (inl(0xCF8) == 0x80000000)
 
114
                res = 1;
 
115
        outl(tmp, 0xCF8);
 
116
        if (res)
 
117
                res = intel_sanity_check(a, &pm_intel_conf1);
 
118
        return res;
 
119
}
 
120
 
 
121
static int conf1_read(struct pci_dev *d, int pos, byte * buf, int len)
 
122
{
 
123
        int addr = 0xcfc + (pos & 3);
 
124
 
 
125
        if (pos >= 256)
 
126
                return 0;
 
127
 
 
128
        outl(0x80000000 | ((d->bus & 0xff) << 16) |
 
129
             (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8);
 
130
 
 
131
        switch (len) {
 
132
        case 1:
 
133
                buf[0] = inb(addr);
 
134
                break;
 
135
        case 2:
 
136
                ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
 
137
                break;
 
138
        case 4:
 
139
                ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
 
140
                break;
 
141
        default:
 
142
                return pci_generic_block_read(d, pos, buf, len);
 
143
        }
 
144
        return 1;
 
145
}
 
146
 
 
147
static int conf1_write(struct pci_dev *d, int pos, byte * buf, int len)
 
148
{
 
149
        int addr = 0xcfc + (pos & 3);
 
150
 
 
151
        if (pos >= 256)
 
152
                return 0;
 
153
 
 
154
        outl(0x80000000 | ((d->bus & 0xff) << 16) |
 
155
             (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8);
 
156
 
 
157
        switch (len) {
 
158
        case 1:
 
159
                outb(buf[0], addr);
 
160
                break;
 
161
        case 2:
 
162
                outw(le16_to_cpu(((u16 *) buf)[0]), addr);
 
163
                break;
 
164
        case 4:
 
165
                outl(le32_to_cpu(((u32 *) buf)[0]), addr);
 
166
                break;
 
167
        default:
 
168
                return pci_generic_block_write(d, pos, buf, len);
 
169
        }
 
170
        return 1;
 
171
}
 
172
 
 
173
/*
 
174
 *      Configuration type 2. Obsolete and brain-damaged, but existing.
 
175
 */
 
176
 
 
177
static int conf2_detect(struct pci_access *a)
 
178
{
 
179
        /* This is ugly and tends to produce false positives. Beware. */
 
180
        outb(0x00, 0xCFB);
 
181
        outb(0x00, 0xCF8);
 
182
        outb(0x00, 0xCFA);
 
183
        if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
 
184
                return intel_sanity_check(a, &pm_intel_conf2);
 
185
        else
 
186
                return 0;
 
187
}
 
188
 
 
189
static int conf2_read(struct pci_dev *d, int pos, byte * buf, int len)
 
190
{
 
191
        int addr = 0xc000 | (d->dev << 8) | pos;
 
192
 
 
193
        if (pos >= 256)
 
194
                return 0;
 
195
 
 
196
        if (d->dev >= 16)
 
197
                /* conf2 supports only 16 devices per bus */
 
198
                return 0;
 
199
        outb((d->func << 1) | 0xf0, 0xcf8);
 
200
        outb(d->bus, 0xcfa);
 
201
        switch (len) {
 
202
        case 1:
 
203
                buf[0] = inb(addr);
 
204
                break;
 
205
        case 2:
 
206
                ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
 
207
                break;
 
208
        case 4:
 
209
                ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
 
210
                break;
 
211
        default:
 
212
                outb(0, 0xcf8);
 
213
                return pci_generic_block_read(d, pos, buf, len);
 
214
        }
 
215
        outb(0, 0xcf8);
 
216
        return 1;
 
217
}
 
218
 
 
219
static int conf2_write(struct pci_dev *d, int pos, byte * buf, int len)
 
220
{
 
221
        int addr = 0xc000 | (d->dev << 8) | pos;
 
222
 
 
223
        if (pos >= 256)
 
224
                return 0;
 
225
 
 
226
        if (d->dev >= 16)
 
227
                d->access->error("conf2_write: only first 16 devices exist.");
 
228
        outb((d->func << 1) | 0xf0, 0xcf8);
 
229
        outb(d->bus, 0xcfa);
 
230
        switch (len) {
 
231
        case 1:
 
232
                outb(buf[0], addr);
 
233
                break;
 
234
        case 2:
 
235
                outw(le16_to_cpu(*(u16 *) buf), addr);
 
236
                break;
 
237
        case 4:
 
238
                outl(le32_to_cpu(*(u32 *) buf), addr);
 
239
                break;
 
240
        default:
 
241
                outb(0, 0xcf8);
 
242
                return pci_generic_block_write(d, pos, buf, len);
 
243
        }
 
244
        outb(0, 0xcf8);
 
245
        return 1;
 
246
}
 
247
 
 
248
struct pci_methods pm_intel_conf1 = {
 
249
        "Intel-conf1",
 
250
        NULL,                   /* config */
 
251
        conf1_detect,
 
252
        conf12_init,
 
253
        conf12_cleanup,
 
254
        pci_generic_scan,
 
255
        pci_generic_fill_info,
 
256
        conf1_read,
 
257
        conf1_write,
 
258
        NULL,                   /* init_dev */
 
259
        NULL                    /* cleanup_dev */
 
260
};
 
261
 
 
262
struct pci_methods pm_intel_conf2 = {
 
263
        "Intel-conf2",
 
264
        NULL,                   /* config */
 
265
        conf2_detect,
 
266
        conf12_init,
 
267
        conf12_cleanup,
 
268
        pci_generic_scan,
 
269
        pci_generic_fill_info,
 
270
        conf2_read,
 
271
        conf2_write,
 
272
        NULL,                   /* init_dev */
 
273
        NULL                    /* cleanup_dev */
 
274
};