source: rtems/cpukit/libpci/pci_cfg_read.c @ f9fbb333

Last change on this file since f9fbb333 was f9fbb333, checked in by Daniel Hellstrom <daniel@…>, on Aug 30, 2017 at 9:01:38 AM

libpci: fix pci device allocation

The refactoring of pci_dev_create() was incorrect since the code relied on
different defines before including pci/cfg.h. This reverts back to the
original code having two pci_dev_create() one in auto and one in read library.
confdefs.h selectes between the two libraries so both there is no link
conflict.

Updates #3029

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