~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/srv/pci/libpci/generic.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 -- Generic Direct Access Functions
 
3
 *
 
4
 *      Copyright (c) 1997--2000 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 <string.h>
 
12
 
 
13
#include "internal.h"
 
14
 
 
15
void pci_generic_scan_bus(struct pci_access *a, byte * busmap, int bus)
 
16
{
 
17
        int dev, multi, ht;
 
18
        struct pci_dev *t;
 
19
 
 
20
        a->debug("Scanning bus %02x for devices...\n", bus);
 
21
        if (busmap[bus]) {
 
22
                a->warning("Bus %02x seen twice (firmware bug). Ignored.",
 
23
                           bus);
 
24
                return;
 
25
        }
 
26
        busmap[bus] = 1;
 
27
        t = pci_alloc_dev(a);
 
28
        t->bus = bus;
 
29
        for (dev = 0; dev < 32; dev++) {
 
30
                t->dev = dev;
 
31
                multi = 0;
 
32
                for (t->func = 0; !t->func || (multi && t->func < 8);
 
33
                     t->func++) {
 
34
                        u32 vd = pci_read_long(t, PCI_VENDOR_ID);
 
35
                        struct pci_dev *d;
 
36
 
 
37
                        if (!vd || vd == 0xffffffff)
 
38
                                continue;
 
39
                        ht = pci_read_byte(t, PCI_HEADER_TYPE);
 
40
                        if (!t->func)
 
41
                                multi = ht & 0x80;
 
42
                        ht &= 0x7f;
 
43
                        d = pci_alloc_dev(a);
 
44
                        d->bus = t->bus;
 
45
                        d->dev = t->dev;
 
46
                        d->func = t->func;
 
47
                        d->vendor_id = vd & 0xffff;
 
48
                        d->device_id = vd >> 16U;
 
49
                        d->known_fields = PCI_FILL_IDENT;
 
50
                        d->hdrtype = ht;
 
51
                        pci_link_dev(a, d);
 
52
                        switch (ht) {
 
53
                        case PCI_HEADER_TYPE_NORMAL:
 
54
                                break;
 
55
                        case PCI_HEADER_TYPE_BRIDGE:
 
56
                        case PCI_HEADER_TYPE_CARDBUS:
 
57
                                pci_generic_scan_bus(a, busmap,
 
58
                                                     pci_read_byte(t,
 
59
                                                                   PCI_SECONDARY_BUS));
 
60
                                break;
 
61
                        default:
 
62
                                a->debug
 
63
                                    ("Device %04x:%02x:%02x.%d has unknown header type %02x.\n",
 
64
                                     d->domain, d->bus, d->dev, d->func,
 
65
                                     ht);
 
66
                        }
 
67
                }
 
68
        }
 
69
        pci_free_dev(t);
 
70
}
 
71
 
 
72
void pci_generic_scan(struct pci_access *a)
 
73
{
 
74
        byte busmap[256];
 
75
 
 
76
        bzero(busmap, sizeof(busmap));
 
77
        pci_generic_scan_bus(a, busmap, 0);
 
78
}
 
79
 
 
80
int pci_generic_fill_info(struct pci_dev *d, int flags)
 
81
{
 
82
        struct pci_access *a = d->access;
 
83
 
 
84
        if ((flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE))
 
85
            && d->hdrtype < 0)
 
86
                d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f;
 
87
        if (flags & PCI_FILL_IDENT) {
 
88
                d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
 
89
                d->device_id = pci_read_word(d, PCI_DEVICE_ID);
 
90
        }
 
91
        if (flags & PCI_FILL_IRQ)
 
92
                d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
 
93
        if (flags & PCI_FILL_BASES) {
 
94
                int cnt = 0, i;
 
95
                bzero(d->base_addr, sizeof(d->base_addr));
 
96
                switch (d->hdrtype) {
 
97
                case PCI_HEADER_TYPE_NORMAL:
 
98
                        cnt = 6;
 
99
                        break;
 
100
                case PCI_HEADER_TYPE_BRIDGE:
 
101
                        cnt = 2;
 
102
                        break;
 
103
                case PCI_HEADER_TYPE_CARDBUS:
 
104
                        cnt = 1;
 
105
                        break;
 
106
                }
 
107
                if (cnt) {
 
108
                        for (i = 0; i < cnt; i++) {
 
109
                                u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i * 4);
 
110
                                if (!x || x == (u32) ~ 0)
 
111
                                        continue;
 
112
                                if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
 
113
                                        d->base_addr[i] = x;
 
114
                                else {
 
115
                                        if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64)
 
116
                                                d->base_addr[i] = x;
 
117
                                        else if (i >= cnt - 1)
 
118
                                                a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.",
 
119
                                                     d->domain, d->bus,
 
120
                                                     d->dev, d->func, i);
 
121
                                        else {
 
122
                                                u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i) * 4);
 
123
#ifdef PCI_HAVE_64BIT_ADDRESS
 
124
                                                d->base_addr[i - 1] = x | (((pciaddr_t) y) << 32);
 
125
#else
 
126
                                                if (y)
 
127
                                                        a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.",
 
128
                                                             d->domain,
 
129
                                                             d->bus,
 
130
                                                             d->dev,
 
131
                                                             d->func);
 
132
                                                else
 
133
                                                        d->base_addr[i - 1] = x;
 
134
#endif
 
135
                                        }
 
136
                                }
 
137
                        }
 
138
                }
 
139
        }
 
140
        if (flags & PCI_FILL_ROM_BASE) {
 
141
                int reg = 0;
 
142
                d->rom_base_addr = 0;
 
143
                switch (d->hdrtype) {
 
144
                case PCI_HEADER_TYPE_NORMAL:
 
145
                        reg = PCI_ROM_ADDRESS;
 
146
                        break;
 
147
                case PCI_HEADER_TYPE_BRIDGE:
 
148
                        reg = PCI_ROM_ADDRESS1;
 
149
                        break;
 
150
                }
 
151
                if (reg) {
 
152
                        u32 u = pci_read_long(d, reg);
 
153
                        if (u != 0xffffffff)
 
154
                                d->rom_base_addr = u;
 
155
                }
 
156
        }
 
157
        return flags & ~PCI_FILL_SIZES;
 
158
}
 
159
 
 
160
static int
 
161
pci_generic_block_op(struct pci_dev *d, int pos, byte * buf, int len,
 
162
                     int (*r) (struct pci_dev * d, int pos, byte * buf,
 
163
                               int len))
 
164
{
 
165
        if ((pos & 1) && len >= 1) {
 
166
                if (!r(d, pos, buf, 1))
 
167
                        return 0;
 
168
                pos++;
 
169
                buf++;
 
170
                len--;
 
171
        }
 
172
        if ((pos & 3) && len >= 2) {
 
173
                if (!r(d, pos, buf, 2))
 
174
                        return 0;
 
175
                pos += 2;
 
176
                buf += 2;
 
177
                len -= 2;
 
178
        }
 
179
        while (len >= 4) {
 
180
                if (!r(d, pos, buf, 4))
 
181
                        return 0;
 
182
                pos += 4;
 
183
                buf += 4;
 
184
                len -= 4;
 
185
        }
 
186
        if (len >= 2) {
 
187
                if (!r(d, pos, buf, 2))
 
188
                        return 0;
 
189
                pos += 2;
 
190
                buf += 2;
 
191
                len -= 2;
 
192
        }
 
193
        if (len && !r(d, pos, buf, 1))
 
194
                return 0;
 
195
        return 1;
 
196
}
 
197
 
 
198
int pci_generic_block_read(struct pci_dev *d, int pos, byte * buf, int len)
 
199
{
 
200
        return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
 
201
}
 
202
 
 
203
int pci_generic_block_write(struct pci_dev *d, int pos, byte * buf, int len)
 
204
{
 
205
        return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
 
206
}