Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:20

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  Read current PCI configuration that bootloader or BIOS has already setup
0004  *  and initialize the PCI structures.
0005  *
0006  *  COPYRIGHT (c) 2010 Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #include <rtems.h>
0031 #include <stdlib.h>
0032 #include <rtems/bspIo.h>
0033 #include <pci/cfg.h>
0034 #include <pci/access.h>
0035 
0036 #include "pci_internal.h"
0037 
0038 /* PCI Library
0039  * (For debugging it might be good to use other functions or the driver's
0040  *  directly)
0041  */
0042 #define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
0043 #define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
0044 #define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
0045 #define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
0046 #define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
0047 #define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
0048 
0049 #ifdef DEBUG
0050 #define DBG(args...)    printk(args)
0051 #else
0052 #define DBG(args...)
0053 #endif
0054 
0055 /* The Host Bridge bus is initialized here */
0056 extern struct pci_bus pci_hb;
0057 
0058 static struct pci_dev *pci_dev_create(int isbus)
0059 {
0060     void *ptr;
0061     int size;
0062 
0063     if (isbus)
0064         size = sizeof(struct pci_bus);
0065     else
0066         size = sizeof(struct pci_dev);
0067 
0068     ptr = calloc(1, size);
0069     if (!ptr)
0070         rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
0071     return ptr;
0072 }
0073 
0074 /* Check if address is accessible from host */
0075 static int pci_read_addressable(struct pci_dev *dev, struct pci_res *res)
0076 {
0077     struct pci_bus *bus = dev->bus;
0078     int type = res->flags & PCI_RES_TYPE_MASK;
0079     struct pci_res *range0, *range1;
0080 
0081     if (type == PCI_BUS_IO && (bus->flags & PCI_BUS_IO) == 0)
0082         return 0;
0083 
0084     /* Assume that host bridge can access all */
0085     if (bus->pri == 0)
0086         return 1;
0087 
0088     range1 = NULL;
0089     switch (type) {
0090     case PCI_RES_IO:
0091         range0 = &bus->dev.resources[BRIDGE_RES_IO];
0092         break;
0093     case PCI_RES_MEM:
0094         range1 = &bus->dev.resources[BRIDGE_RES_MEM];
0095         /* Fall through */
0096     default:
0097     case PCI_RES_MEMIO:
0098         range0 = &bus->dev.resources[BRIDGE_RES_MEMIO];
0099         break;
0100     }
0101     if ((res->start >= range0->start) && (res->end <= range0->end)) {
0102         return pci_read_addressable(&bus->dev, range0);
0103     } else if (range1 && (res->start >= range1->start) &&
0104             (res->end <= range1->end)) {
0105         return pci_read_addressable(&bus->dev, range1);
0106     }
0107 
0108     return 0;
0109 }
0110 
0111 static void pci_read_bar(struct pci_dev *dev, int bar)
0112 {
0113     uint32_t orig, size, mask;
0114     struct pci_res *res = &dev->resources[bar];
0115     pci_dev_t pcidev = dev->busdevfun;
0116     int ofs;
0117 #ifdef DEBUG
0118     char *str;
0119 #define DBG_SET_STR(str, val) str = (val)
0120 #else
0121 #define DBG_SET_STR(str, val)
0122 #endif
0123 
0124     DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
0125         PCI_DEV_EXPAND(pcidev), bar);
0126 
0127     res->bar = bar;
0128     if (bar == DEV_RES_ROM) {
0129         if (dev->flags & PCI_DEV_BRIDGE)
0130             ofs = PCIR_BIOS_1;
0131         else
0132             ofs = PCIR_BIOS;
0133     } else {
0134         ofs = PCIR_BAR(0) + (bar << 2);
0135     }
0136 
0137     PCI_CFG_R32(pcidev, ofs, &orig);
0138     PCI_CFG_W32(pcidev, ofs, 0xffffffff);
0139     PCI_CFG_R32(pcidev, ofs, &size);
0140     PCI_CFG_W32(pcidev, ofs, orig);
0141 
0142     if (size == 0 || size == 0xffffffff)
0143         return;
0144     if (bar == DEV_RES_ROM) {
0145         mask = PCIM_BIOS_ADDR_MASK;
0146         DBG_SET_STR(str, "ROM");
0147         if (dev->bus->flags & PCI_BUS_MEM)
0148             res->flags = PCI_RES_MEM;
0149         else
0150             res->flags = PCI_RES_MEMIO;
0151     } else if (((size & 0x1) == 0) && (size & 0x6)) {
0152         /* unsupported Memory type */
0153         return;
0154     } else {
0155         mask = ~0xf;
0156         if (size & 0x1) {
0157             /* I/O */
0158             mask = ~0x3;
0159             res->flags = PCI_RES_IO;
0160             DBG_SET_STR(str, "I/O");
0161             if (size & 0xffff0000)
0162                 res->flags |= PCI_RES_IO32;
0163             /* Limit size of I/O space to 256 byte */
0164             size |= 0xffffff00;
0165             if ((dev->bus->flags & PCI_BUS_IO) == 0) {
0166                 res->flags |= PCI_RES_FAIL;
0167                 dev->flags |= PCI_DEV_RES_FAIL;
0168             }
0169         } else {
0170             /* Memory */
0171             if (size & 0x8) {
0172                 /* Prefetchable */
0173                 res->flags = PCI_RES_MEM;
0174                 DBG_SET_STR(str, "MEM");
0175             } else {
0176                 res->flags = PCI_RES_MEMIO;
0177                 DBG_SET_STR(str, "MEMIO");
0178             }
0179         }
0180     }
0181     res->start = orig & mask;
0182     size &= mask;
0183     res->size = ~size + 1;
0184     res->boundary = res->size;
0185     res->end = res->start +  res->size;
0186 
0187     DBG("Bus: %x, Slot: %x, function: %x, %s bar%d size: %x\n",
0188         PCI_DEV_EXPAND(pcidev), str, bar, res->size);
0189 
0190     /* Check if BAR is addressable by host */
0191     if (pci_read_addressable(dev, res) == 0) {
0192         /* No matching bridge window contains this BAR */
0193         res->flags |= PCI_RES_FAIL;
0194         dev->flags |= PCI_DEV_RES_FAIL;
0195     }
0196 }
0197 
0198 static void pci_read_devs(struct pci_bus *bus)
0199 {
0200     uint32_t id, tmp;
0201     uint16_t tmp16;
0202     uint8_t header;
0203     int slot, func, fail, i, maxbars, max_sord;
0204     struct pci_dev *dev, **listptr;
0205     struct pci_bus *bridge;
0206     pci_dev_t pcidev;
0207     struct pci_res *res;
0208 
0209     DBG("Scanning bus %d\n", bus->num);
0210 
0211     max_sord = bus->num;
0212     listptr = &bus->devs;
0213     for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
0214 
0215         /* Slot address */
0216         pcidev = PCI_DEV(bus->num, slot, 0);
0217 
0218         for (func = 0; func <= PCI_FUNCMAX; func++, pcidev++) {
0219 
0220             fail = PCI_CFG_R32(pcidev, PCIR_VENDOR, &id);
0221             if (fail || id == 0xffffffff || id == 0) {
0222                 /*
0223                  * This slot is empty
0224                  */
0225                 if (func == 0)
0226                     break;
0227                 else
0228                     continue;
0229             }
0230 
0231             DBG("Found PCIDEV 0x%x at (bus %x, slot %x, func %x)\n",
0232                             id, bus, slot, func);
0233 
0234             PCI_CFG_R32(pcidev, PCIR_REVID, &tmp);
0235             tmp >>= 16;
0236             dev = pci_dev_create(tmp == PCID_PCI2PCI_BRIDGE);
0237             *listptr = dev;
0238             listptr = &dev->next;
0239 
0240             dev->busdevfun = pcidev;
0241             dev->bus = bus;
0242             PCI_CFG_R16(pcidev, PCIR_VENDOR, &dev->vendor);
0243             PCI_CFG_R16(pcidev, PCIR_DEVICE, &dev->device);
0244             PCI_CFG_R32(pcidev, PCIR_REVID, &dev->classrev);
0245 
0246             if (tmp == PCID_PCI2PCI_BRIDGE) {
0247                 DBG("Found PCI-PCI Bridge 0x%x at "
0248                     "(bus %x, slot %x, func %x)\n",
0249                     id, bus, slot, func);
0250                 dev->flags = PCI_DEV_BRIDGE;
0251                 bridge = (struct pci_bus *)dev;
0252 
0253                 PCI_CFG_R32(pcidev, PCIR_PRIBUS_1, &tmp);
0254                 bridge->pri = tmp & 0xff;
0255                 bridge->num = (tmp >> 8) & 0xff;
0256                 bridge->sord = (tmp >> 16) & 0xff;
0257                 if (bridge->sord > max_sord)
0258                     max_sord = bridge->sord;
0259 
0260                 DBG("    Primary %x, Secondary %x, "
0261                     "Subordinate %x\n",
0262                     bridge->pri, bridge->num, bridge->sord);
0263 
0264                 /*** Probe Bridge Spaces ***/
0265 
0266                 /* MEMIO Window - always implemented */
0267                 bridge->flags = PCI_BUS_MEMIO;
0268                 res = &bridge->dev.resources[BRIDGE_RES_MEMIO];
0269                 res->flags = PCI_RES_MEMIO;
0270                 res->bar = BRIDGE_RES_MEMIO;
0271                 PCI_CFG_R32(pcidev, 0x20, &tmp);
0272                 res->start = (tmp & 0xfff0) << 16;
0273                 res->end = 1 + ((tmp & 0xfff00000) | 0xfffff);
0274                 if (res->end <= res->start) {
0275                     /* Window disabled */
0276                     res->end = res->start = 0;
0277                 }
0278                 res->size = res->end - res->start;
0279 
0280                 /* I/O Window - optional */
0281                 res = &bridge->dev.resources[BRIDGE_RES_IO];
0282                 res->bar = BRIDGE_RES_IO;
0283                 PCI_CFG_R32(pcidev, 0x30, &tmp);
0284                 PCI_CFG_R16(pcidev, 0x1c, &tmp16);
0285                 if (tmp != 0 || tmp16 != 0) {
0286                     bridge->flags |= PCI_BUS_IO;
0287                     res->flags = PCI_RES_IO;
0288                     if (tmp16 & 0x1) {
0289                         bridge->flags |= PCI_BUS_IO32;
0290                         res->flags |= PCI_RES_IO32;
0291                     }
0292 
0293                     res->start = (tmp & 0xffff) << 16 |
0294                             (tmp16 & 0xf0) << 8;
0295                     res->end = 1 + ((tmp & 0xffff0000) |
0296                             (tmp16 & 0xf000) |
0297                             0xfff);
0298                     if (res->end <= res->start) {
0299                         /* Window disabled */
0300                         res->end = res->start = 0;
0301                     }
0302                     res->size = res->end - res->start;
0303                 }
0304 
0305                 /* MEM Window - optional */
0306                 res = &bridge->dev.resources[BRIDGE_RES_MEM];
0307                 res->bar = BRIDGE_RES_MEM;
0308                 PCI_CFG_R32(pcidev, 0x24, &tmp);
0309                 if (tmp != 0) {
0310                     bridge->flags |= PCI_BUS_MEM;
0311                     res->flags = PCI_RES_MEM;
0312                     res->start = (tmp & 0xfff0) << 16;
0313                     res->end = 1 + ((tmp & 0xfff00000) |
0314                             0xfffff);
0315                     if (res->end <= res->start) {
0316                         /* Window disabled */
0317                         res->end = res->start = 0;
0318                     }
0319                     res->size = res->end - res->start;
0320                 }
0321 
0322                 /* Scan Secondary Bus */
0323                 pci_read_devs(bridge);
0324 
0325                 /* Only 2 BARs for Bridges */
0326                 maxbars = 2;
0327             } else {
0328                 /* Devices have subsytem device and vendor ID */
0329                 PCI_CFG_R16(pcidev, PCIR_SUBVEND_0,
0330                             &dev->subvendor);
0331                 PCI_CFG_R16(pcidev, PCIR_SUBDEV_0,
0332                             &dev->subdevice);
0333 
0334                 /* Normal PCI Device has max 6 BARs */
0335                 maxbars = 6;
0336             }
0337 
0338             /* Probe BARs */
0339             for (i = 0; i < maxbars; i++)
0340                 pci_read_bar(dev, i);
0341             pci_read_bar(dev, DEV_RES_ROM);
0342 
0343             /* Get System Interrupt/Vector for device.
0344              * 0 means no-IRQ
0345              */
0346             PCI_CFG_R8(pcidev, PCIR_INTLINE, &dev->sysirq);
0347 
0348             /* Stop if not a multi-function device */
0349             if (func == 0) {
0350                 pci_cfg_r8(pcidev, PCIR_HDRTYPE, &header);
0351                 if ((header & PCIM_MFDEV) == 0)
0352                     break;
0353             }
0354         }
0355     }
0356 
0357     if (bus->num == 0)
0358         bus->sord = max_sord;
0359 }
0360 
0361 int pci_config_read(void)
0362 {
0363     pci_system_type = PCI_SYSTEM_HOST;
0364 
0365     /* Find all devices and buses */
0366     pci_hb.flags = PCI_BUS_IO|PCI_BUS_MEMIO|PCI_BUS_MEM;
0367     pci_hb.dev.flags = PCI_DEV_BRIDGE;
0368     pci_read_devs(&pci_hb);
0369     pci_bus_cnt = pci_hb.sord + 1;
0370     if (pci_hb.devs == NULL)
0371         return 0;
0372 
0373     return 0;
0374 }