source: rtems/cpukit/libpci/pci_cfg_read.c

Last change on this file was 1b33b9d, checked in by Joel Sherrill <joel@…>, on 03/18/22 at 15:03:47

cpukit/libpci: Change license to BSD-2

Updates #3053.

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