source: rtems/cpukit/libpci/pci_cfg_read.c @ 39937b6c

4.115
Last change on this file since 39937b6c was c1c37a1, checked in by Daniel Hellstrom <daniel@…>, on 04/07/15 at 12:25:49

LIBPCI: converted to BSD header

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*  Read current PCI configuration that bootloader or BIOS has already setup
2 *  and initialize the PCI structures.
3 *
4 *  COPYRIGHT (c) 2010 Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.com/license/LICENSE.
9 */
10
11#include <rtems.h>
12#include <stdlib.h>
13#include <rtems/bspIo.h>
14#include <pci/cfg.h>
15#include <pci/access.h>
16
17/* PCI Library
18 * (For debugging it might be good to use other functions or the driver's
19 *  directly)
20 */
21#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
22#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
23#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
24#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
25#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
26#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
27
28#ifdef DEBUG
29#define DBG(args...)    printk(args)
30#else
31#define DBG(args...)
32#endif
33
34/* Number of buses */
35extern int pci_bus_cnt;
36
37/* The Host Bridge bus is initialized here */
38extern struct pci_bus pci_hb;
39
40static struct pci_dev *pci_dev_create(int isbus)
41{
42        void *ptr;
43        int size;
44
45        if (isbus)
46                size = sizeof(struct pci_bus);
47        else
48                size = sizeof(struct pci_dev);
49
50        ptr = malloc(size);
51        if (!ptr)
52                rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
53        memset(ptr, 0, size);
54        return ptr;
55}
56
57/* Check if address is accessible from host */
58static int pci_read_addressable(struct pci_dev *dev, struct pci_res *res)
59{
60        struct pci_bus *bus = dev->bus;
61        int type = res->flags & PCI_RES_TYPE_MASK;
62        struct pci_res *range0, *range1;
63
64        if (type == PCI_BUS_IO && (bus->flags & PCI_BUS_IO) == 0)
65                return 0;
66
67        /* Assume that host bridge can access all */
68        if (bus->pri == 0)
69                return 1;
70
71        range1 = NULL;
72        switch (type) {
73        case PCI_RES_IO:
74                range0 = &bus->dev.resources[BRIDGE_RES_IO];
75                break;
76        case PCI_RES_MEM:
77                range1 = &bus->dev.resources[BRIDGE_RES_MEM];
78        default:
79        case PCI_RES_MEMIO:
80                range0 = &bus->dev.resources[BRIDGE_RES_MEMIO];
81                break;
82        }
83        if ((res->start >= range0->start) && (res->end <= range0->end)) {
84                return pci_read_addressable(&bus->dev, range0);
85        } else if (range1 && (res->start >= range1->start) &&
86                        (res->end <= range1->end)) {
87                return pci_read_addressable(&bus->dev, range1);
88        }
89
90        return 0;
91}
92
93static void pci_read_bar(struct pci_dev *dev, int bar)
94{
95        uint32_t orig, size, mask;
96        struct pci_res *res = &dev->resources[bar];
97        pci_dev_t pcidev = dev->busdevfun;
98        int ofs;
99#ifdef DEBUG
100        char *str;
101#define DBG_SET_STR(str, val) str = (val)
102#else
103#define DBG_SET_STR(str, val)
104#endif
105
106        DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
107                PCI_DEV_EXPAND(pcidev), bar);
108
109        res->bar = bar;
110        if (bar == DEV_RES_ROM) {
111                if (dev->flags & PCI_DEV_BRIDGE)
112                        ofs = PCIR_BIOS_1;
113                else
114                        ofs = PCIR_BIOS;
115        } else {
116                ofs = PCIR_BAR(0) + (bar << 2);
117        }
118
119        PCI_CFG_R32(pcidev, ofs, &orig);
120        PCI_CFG_W32(pcidev, ofs, 0xffffffff);
121        PCI_CFG_R32(pcidev, ofs, &size);
122        PCI_CFG_W32(pcidev, ofs, orig);
123
124        if (size == 0 || size == 0xffffffff)
125                return;
126        if (bar == DEV_RES_ROM) {
127                mask = PCIM_BIOS_ADDR_MASK;
128                DBG_SET_STR(str, "ROM");
129                if (dev->bus->flags & PCI_BUS_MEM)
130                        res->flags = PCI_RES_MEM;
131                else
132                        res->flags = PCI_RES_MEMIO;
133        } else if (((size & 0x1) == 0) && (size & 0x6)) {
134                /* unsupported Memory type */
135                return;
136        } else {
137                mask = ~0xf;
138                if (size & 0x1) {
139                        /* I/O */
140                        mask = ~0x3;
141                        res->flags = PCI_RES_IO;
142                        DBG_SET_STR(str, "I/O");
143                        if (size & 0xffff0000)
144                                res->flags |= PCI_RES_IO32;
145                        /* Limit size of I/O space to 256 byte */
146                        size |= 0xffffff00;
147                        if ((dev->bus->flags & PCI_BUS_IO) == 0) {
148                                res->flags |= PCI_RES_FAIL;
149                                dev->flags |= PCI_DEV_RES_FAIL;
150                        }
151                } else {
152                        /* Memory */
153                        if (size & 0x8) {
154                                /* Prefetchable */
155                                res->flags = PCI_RES_MEM;
156                                DBG_SET_STR(str, "MEM");
157                        } else {
158                                res->flags = PCI_RES_MEMIO;
159                                DBG_SET_STR(str, "MEMIO");
160                        }
161                }
162        }
163        res->start = orig & mask;
164        size &= mask;
165        res->size = ~size + 1;
166        res->boundary = res->size;
167        res->end = res->start +  res->size;
168
169        DBG("Bus: %x, Slot: %x, function: %x, %s bar%d size: %x\n",
170                PCI_DEV_EXPAND(pcidev), str, bar, res->size);
171
172        /* Check if BAR is addressable by host */
173        if (pci_read_addressable(dev, res) == 0) {
174                /* No matching bridge window contains this BAR */
175                res->flags |= PCI_RES_FAIL;
176                dev->flags |= PCI_DEV_RES_FAIL;
177        }
178}
179
180static void pci_read_devs(struct pci_bus *bus)
181{
182        uint32_t id, tmp;
183        uint16_t tmp16;
184        uint8_t header;
185        int slot, func, fail, i, maxbars, max_sord;
186        struct pci_dev *dev, **listptr;
187        struct pci_bus *bridge;
188        pci_dev_t pcidev;
189        struct pci_res *res;
190
191        DBG("Scanning bus %d\n", bus->num);
192
193        max_sord = bus->num;
194        listptr = &bus->devs;
195        for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
196
197                /* Slot address */
198                pcidev = PCI_DEV(bus->num, slot, 0);
199
200                for (func = 0; func <= PCI_FUNCMAX; func++, pcidev++) {
201
202                        fail = PCI_CFG_R32(pcidev, PCIR_VENDOR, &id);
203                        if (fail || id == 0xffffffff || id == 0) {
204                                /*
205                                 * This slot is empty
206                                 */
207                                if (func == 0)
208                                        break;
209                                else
210                                        continue;
211                        }
212
213                        DBG("Found PCIDEV 0x%x at (bus %x, slot %x, func %x)\n",
214                                                        id, bus, slot, func);
215
216                        PCI_CFG_R32(pcidev, PCIR_REVID, &tmp);
217                        tmp >>= 16;
218                        dev = pci_dev_create(tmp == PCID_PCI2PCI_BRIDGE);
219                        *listptr = dev;
220                        listptr = &dev->next;
221
222                        dev->busdevfun = pcidev;
223                        dev->bus = bus;
224                        PCI_CFG_R16(pcidev, PCIR_VENDOR, &dev->vendor);
225                        PCI_CFG_R16(pcidev, PCIR_DEVICE, &dev->device);
226                        PCI_CFG_R32(pcidev, PCIR_REVID, &dev->classrev);
227
228                        if (tmp == PCID_PCI2PCI_BRIDGE) {
229                                DBG("Found PCI-PCI Bridge 0x%x at "
230                                    "(bus %x, slot %x, func %x)\n",
231                                    id, bus, slot, func);
232                                dev->flags = PCI_DEV_BRIDGE;
233                                bridge = (struct pci_bus *)dev;
234
235                                PCI_CFG_R32(pcidev, PCIR_PRIBUS_1, &tmp);
236                                bridge->pri = tmp & 0xff;
237                                bridge->num = (tmp >> 8) & 0xff;
238                                bridge->sord = (tmp >> 16) & 0xff;
239                                if (bridge->sord > max_sord)
240                                        max_sord = bridge->sord;
241
242                                DBG("    Primary %x, Secondary %x, "
243                                    "Subordinate %x\n",
244                                    bridge->pri, bridge->num, bridge->sord);
245
246                                /*** Probe Bridge Spaces ***/
247
248                                /* MEMIO Window - always implemented */
249                                bridge->flags = PCI_BUS_MEMIO;
250                                res = &bridge->dev.resources[BRIDGE_RES_MEMIO];
251                                res->flags = PCI_RES_MEMIO;
252                                res->bar = BRIDGE_RES_MEMIO;
253                                PCI_CFG_R32(pcidev, 0x20, &tmp);
254                                res->start = (tmp & 0xfff0) << 16;
255                                res->end = 1 + ((tmp & 0xfff00000) | 0xfffff);
256                                if (res->end <= res->start) {
257                                        /* Window disabled */
258                                        res->end = res->start = 0;
259                                }
260                                res->size = res->end - res->start;
261
262                                /* I/O Window - optional */
263                                res = &bridge->dev.resources[BRIDGE_RES_IO];
264                                res->bar = BRIDGE_RES_IO;
265                                PCI_CFG_R32(pcidev, 0x30, &tmp);
266                                PCI_CFG_R16(pcidev, 0x1c, &tmp16);
267                                if (tmp != 0 || tmp16 != 0) {
268                                        bridge->flags |= PCI_BUS_IO;
269                                        res->flags = PCI_RES_IO;
270                                        if (tmp16 & 0x1) {
271                                                bridge->flags |= PCI_BUS_IO32;
272                                                res->flags |= PCI_RES_IO32;
273                                        }
274
275                                        res->start = (tmp & 0xffff) << 16 |
276                                                        (tmp16 & 0xf0) << 8;
277                                        res->end = 1 + ((tmp & 0xffff0000) |
278                                                        (tmp16 & 0xf000) |
279                                                        0xfff);
280                                        if (res->end <= res->start) {
281                                                /* Window disabled */
282                                                res->end = res->start = 0;
283                                        }
284                                        res->size = res->end - res->start;
285                                }
286
287                                /* MEM Window - optional */
288                                res = &bridge->dev.resources[BRIDGE_RES_MEM];
289                                res->bar = BRIDGE_RES_MEM;
290                                PCI_CFG_R32(pcidev, 0x24, &tmp);
291                                if (tmp != 0) {
292                                        bridge->flags |= PCI_BUS_MEM;
293                                        res->flags = PCI_RES_MEM;
294                                        res->start = (tmp & 0xfff0) << 16;
295                                        res->end = 1 + ((tmp & 0xfff00000) |
296                                                        0xfffff);
297                                        if (res->end <= res->start) {
298                                                /* Window disabled */
299                                                res->end = res->start = 0;
300                                        }
301                                        res->size = res->end - res->start;
302                                }
303
304                                /* Scan Secondary Bus */
305                                pci_read_devs(bridge);
306
307                                /* Only 2 BARs for Bridges */
308                                maxbars = 2;
309                        } else {
310                                /* Devices have subsytem device and vendor ID */
311                                PCI_CFG_R16(pcidev, PCIR_SUBVEND_0,
312                                                        &dev->subvendor);
313                                PCI_CFG_R16(pcidev, PCIR_SUBDEV_0,
314                                                        &dev->subdevice);
315
316                                /* Normal PCI Device has max 6 BARs */
317                                maxbars = 6;
318                        }
319
320                        /* Probe BARs */
321                        for (i = 0; i < maxbars; i++)
322                                pci_read_bar(dev, i);
323                        pci_read_bar(dev, DEV_RES_ROM);
324
325                        /* Get System Interrupt/Vector for device.
326                         * 0 means no-IRQ
327                         */
328                        PCI_CFG_R8(pcidev, PCIR_INTLINE, &dev->sysirq);
329
330                        /* Stop if not a multi-function device */
331                        if (func == 0) {
332                                pci_cfg_r8(pcidev, PCIR_HDRTYPE, &header);
333                                if ((header & PCIM_MFDEV) == 0)
334                                        break;
335                        }
336                }
337        }
338
339        if (bus->num == 0)
340                bus->sord = max_sord;
341}
342
343int pci_config_read(void)
344{
345        pci_system_type = PCI_SYSTEM_HOST;
346
347        /* Find all devices and buses */
348        pci_hb.flags = PCI_BUS_IO|PCI_BUS_MEMIO|PCI_BUS_MEM;
349        pci_hb.dev.flags = PCI_DEV_BRIDGE;
350        pci_read_devs(&pci_hb);
351        pci_bus_cnt = pci_hb.sord + 1;
352        if (pci_hb.devs == NULL)
353                return 0;
354
355        return 0;
356}
Note: See TracBrowser for help on using the repository browser.