/* SPDX-License-Identifier: BSD-2-Clause */ /* PCI Print Current Configuration To Terminal * * COPYRIGHT (c) 2010 Cobham Gaisler AB. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include /* PCI Access Library shortcuts */ #define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args) #define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args) #define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args) #define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args) #define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args) #define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args) void pci_print_dev(pci_dev_t dev) { int maxbars, pos, romadrs; uint32_t tmp, tmp2, id; uint16_t irq; uint8_t irq_pin; char *str, *str2; uint32_t base, limit; maxbars = 6; romadrs = 0x30; str = ""; PCI_CFG_R32(dev, PCIR_REVID, &tmp); tmp >>= 16; if (tmp == PCID_PCI2PCI_BRIDGE) { maxbars = 2; romadrs = 0x38; str = "(BRIDGE)"; } PCI_CFG_R32(dev, PCIR_VENDOR, &id); printf("\nBus %x Slot %x function: %x [0x%x] %s\n", PCI_DEV_EXPAND(dev), dev, str); printf("\tVendor id: 0x%" PRIx32 ", device id: 0x%" PRIx32 "\n", id & 0xffff, id >> 16); if (maxbars == 2) { PCI_CFG_R32(dev, PCIR_PRIBUS_1, &tmp); printf("\tPrimary: %" PRIx32 " Secondary: %" PRIx32 " Subordinate: %" PRIx32 "\n", tmp & 0xff, (tmp >> 8) & 0xff, (tmp >> 16) & 0xff); } PCI_CFG_R16(dev, PCIR_INTLINE, &irq); irq_pin = irq >> 8; if ((irq_pin > 0) && (irq_pin < 5)) printf("\tIRQ INT%c# LINE: %d\n", (irq_pin - 1) + 'A', (irq & 0xff)); /* Print standard BARs */ for (pos = 0; pos < maxbars; pos++) { PCI_CFG_R32(dev, PCIR_BAR(0) + pos*4, &tmp); PCI_CFG_W32(dev, PCIR_BAR(0) + pos*4, 0xffffffff); PCI_CFG_R32(dev, PCIR_BAR(0) + pos*4, &tmp2); PCI_CFG_W32(dev, PCIR_BAR(0) + pos*4, tmp); if (tmp2 != 0 && tmp2 != 0xffffffff && ((tmp2 & 0x1) || ((tmp2 & 0x6) == 0))) { uint32_t mask = ~0xf; if ((tmp2 & 0x1) == 1) { /* I/O Bar */ mask = ~3; tmp2 = tmp2 | 0xffffff00; } tmp2 &= mask; tmp2 = ~tmp2+1; /* Size of BAR */ if (tmp2 < 0x1000) { str = "B"; } else if (tmp2 < 0x100000) { str = "kB"; tmp2 = tmp2 / 1024; } else { str = "MB"; tmp2 = tmp2 / (1024*1024); } printf("\tBAR %d: %" PRIx32 " [%" PRIu32 "%s]\n", pos, tmp, tmp2, str); } } /* Print ROM BARs */ PCI_CFG_R32(dev, romadrs, &tmp); PCI_CFG_W32(dev, romadrs, 0xffffffff); PCI_CFG_R32(dev, romadrs, &tmp2); PCI_CFG_W32(dev, romadrs, tmp); if (tmp2 & 1) { /* ROM BAR available */ tmp2 &= PCIM_BIOS_ADDR_MASK; tmp2 = (~tmp2 + 1); /* Size of BAR */ if (tmp2 < 0x1000) { str = "B"; } else if (tmp2 < 0x100000) { str = "kB"; tmp2 = tmp2 / 1024; } else { str = "MB"; tmp2 = tmp2 / (1024*1024); } str2 = tmp & 1 ? "ENABLED" : "DISABLED"; printf("\tROM: %08" PRIx32 " [%" PRIu32 "%s] (%s)\n", tmp, tmp2, str, str2); } /* Print Bridge addresses */ if (maxbars == 2) { tmp = 0; PCI_CFG_R32(dev, 0x1C, &tmp); if (tmp != 0) { base = (tmp & 0x00f0) << 8; limit = (tmp & 0xf000) | 0xfff; PCI_CFG_R32(dev, 0x30, &tmp); base |= (tmp & 0xffff) << 16; limit |= (tmp & 0xffff0000); str = "ENABLED"; if (limit < base) str = "DISABLED"; printf("\tI/O: BASE: 0x%08" PRIx32 ", LIMIT: 0x%08" PRIx32 " (%s)\n", base, limit, str); } PCI_CFG_R32(dev, 0x20, &tmp); if (tmp != 0) { base = (tmp & 0xfff0) << 16; limit = (tmp & 0xfff00000) | 0xfffff; str = "ENABLED"; if (limit < base) str = "DISABLED"; printf("\tMEMIO: BASE: 0x%08" PRIx32 ", LIMIT: 0x%08" PRIx32 " (%s)\n", base, limit, str); } PCI_CFG_R32(dev, 0x24, &tmp); if (tmp != 0) { base = (tmp & 0xfff0) << 16; limit = (tmp & 0xfff00000) | 0xfffff; str = "ENABLED"; if (limit < base) str = "DISABLED"; printf("\tMEM: BASE: 0x%08" PRIx32 ", LIMIT: 0x%08" PRIx32 " (%s)\n", base, limit, str); } } printf("\n"); } void pci_print_device(int bus, int slot, int function) { pci_print_dev(PCI_DEV(bus, slot, function)); } void pci_print(void) { int fail, bus, slot, func; pci_dev_t dev; uint8_t header; uint32_t id; printf("\nPCI devices found and configured:\n"); for (bus = 0; bus < pci_bus_count(); bus++) { for (slot = 0; slot <= PCI_SLOTMAX; slot++) { for (func=0; func <= PCI_FUNCMAX; func++) { dev = PCI_DEV(bus, slot, func); fail = PCI_CFG_R32(dev, PCIR_VENDOR, &id); if (!fail && id != PCI_INVALID_VENDORDEVICEID && id != 0) { pci_print_dev(dev); /* Stop if not a multi-function device */ if (func == 0) { PCI_CFG_R8(dev, PCIR_HDRTYPE, &header); if ((header & PCIM_MFDEV) == 0) break; } } else if (func == 0) break; } } } printf("\n"); }