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

4.115
Last change on this file since f4bf22c was f4bf22c, checked in by Daniel Hellstrom <daniel@…>, on 04/08/15 at 08:51:45

LIBPCI: new implementation private header file

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