Some single-function devices will respond to all sub-functions - and
this confuses things. So, when scanning the PCI bus make sure to
only touch function 0 on single-function devices.
Since the bus scanning code is necessarily complex now, we might as
well implement max bus detection inline with all pci scans. So,
there is no need to scan for the max bus at startup.
}
} else {
// Find and deploy PCI roms.
}
} else {
// Find and deploy PCI roms.
- int max = GET_VAR(CS, MaxBDF);
- int bdf;
- for (bdf=0; bdf < max; bdf++) {
+ int bdf, max;
+ foreachpci(bdf, max, 0) {
u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
if (v == 0x0000 || v == 0xffff || v == PCI_CLASS_DISPLAY_VGA)
continue;
u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
if (v == 0x0000 || v == 0xffff || v == PCI_CLASS_DISPLAY_VGA)
continue;
//
// This file may be distributed under the terms of the GNU GPLv3 license.
//
// This file may be distributed under the terms of the GNU GPLv3 license.
-#include "pci.h" // MaxBDF
+#include "pci.h" // pci_config_writel
#include "ioport.h" // outl
#include "util.h" // dprintf
#include "config.h" // CONFIG_*
#include "ioport.h" // outl
#include "util.h" // dprintf
#include "config.h" // CONFIG_*
return inb(PORT_PCI_DATA + (addr & 3));
}
return inb(PORT_PCI_DATA + (addr & 3));
}
-#if MODE16
-int MaxBDF VISIBLE16 = 0x0100;
-#endif
-
-// Find the maximum bus number.
-void
-pci_bus_setup()
+int
+pci_next(int bdf, int *pmax)
- dprintf(3, "Scan for max PCI bus\n");
+ if (pci_bdf_to_fn(bdf) == 1
+ && (pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0)
+ // Last found device wasn't a multi-function device - skip to
+ // the next device.
+ bdf += 7;
- int max = 0x0100;
- int bdf;
- for (bdf=0; bdf < max; bdf++) {
- u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
- if (v == 0xffffffff || v == 0x00000000
- || v == 0x0000ffff || v == 0xffff0000)
- // No device present.
- continue;
- v = pci_config_readb(bdf, PCI_HEADER_TYPE);
- v &= 0x7f;
- if (v != PCI_HEADER_TYPE_BRIDGE && v != PCI_HEADER_TYPE_CARDBUS)
- // Not a bridge
- continue;
+ int max = *pmax;
+ for (;;) {
+ if (bdf >= max)
+ return -1;
+
+ u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
+ if (v != 0x0000 && v != 0xffff)
+ // Device is present.
+ break;
+
+ if (pci_bdf_to_fn(bdf) == 0)
+ bdf += 8;
+ else
+ bdf += 1;
+ }
+
+ // Check if found device is a bridge.
+ u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
+ v &= 0x7f;
+ if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
int newmax = (v & 0xff00) + 0x0100;
if (newmax > max)
v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
int newmax = (v & 0xff00) + 0x0100;
if (newmax > max)
- SET_VAR(CS, MaxBDF, max);
- dprintf(1, "Found %d PCI buses\n", pci_bdf_to_bus(max));
}
// Search for a device with the specified vendor and device ids.
}
// Search for a device with the specified vendor and device ids.
pci_find_device(u16 vendid, u16 devid, int start_bdf)
{
u32 id = (devid << 16) | vendid;
pci_find_device(u16 vendid, u16 devid, int start_bdf)
{
u32 id = (devid << 16) | vendid;
- int max = GET_VAR(CS, MaxBDF);
- int bdf;
- for (bdf=start_bdf; bdf < max; bdf++) {
+ int bdf, max;
+ foreachpci(bdf, max, start_bdf) {
u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
if (v != id)
continue;
u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
if (v != id)
continue;
int
pci_find_classprog(u32 classprog, int start_bdf)
{
int
pci_find_classprog(u32 classprog, int start_bdf)
{
- int max = GET_VAR(CS, MaxBDF);
- int bdf;
- for (bdf=start_bdf; bdf < max; bdf++) {
+ int bdf, max;
+ foreachpci(bdf, max, start_bdf) {
u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
if ((v>>8) != classprog)
continue;
u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
if ((v>>8) != classprog)
continue;
int
pci_find_class(u16 classid, int start_bdf)
{
int
pci_find_class(u16 classid, int start_bdf)
{
- int max = GET_VAR(CS, MaxBDF);
- int bdf;
- for (bdf=start_bdf; bdf < max; bdf++) {
+ int bdf, max;
+ foreachpci(bdf, max, start_bdf) {
u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
if (v != classid)
continue;
u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
if (v != classid)
continue;
u16 pci_config_readw(u16 bdf, u32 addr);
u8 pci_config_readb(u16 bdf, u32 addr);
u16 pci_config_readw(u16 bdf, u32 addr);
u8 pci_config_readb(u16 bdf, u32 addr);
int pci_find_device(u16 vendid, u16 devid, int start_bdf);
int pci_find_classprog(u32 classprog, int start_bdf);
int pci_find_class(u16 classid, int start_bdf);
int pci_find_device(u16 vendid, u16 devid, int start_bdf);
int pci_find_classprog(u32 classprog, int start_bdf);
int pci_find_class(u16 classid, int start_bdf);
+int pci_next(int bdf, int *pmax);
+#define foreachpci(BDF, MAX, START) \
+ for (MAX=0x0100, BDF=pci_next((START), &MAX) \
+ ; BDF >= 0 \
+ ; BDF=pci_next(BDF+1, &MAX))
// pirtable.c
void create_pirtable();
// pirtable.c
void create_pirtable();
static void
handle_1ab101(struct bregs *regs)
{
static void
handle_1ab101(struct bregs *regs)
{
+ // Find max bus.
+ int bdf, max;
+ foreachpci(bdf, max, 0) {
+ }
+
regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
regs->bx = 0x0210; // PCI version 2.10
regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
regs->bx = 0x0210; // PCI version 2.10
- regs->cl = pci_bdf_to_bus(GET_VAR(CS, MaxBDF) - 1);
+ regs->cl = pci_bdf_to_bus(max - 1);
regs->edx = 0x20494350; // "PCI "
// XXX - bochs bios code sets edi to point to 32bit code - but no
// reference to this in spec.
regs->edx = 0x20494350; // "PCI "
// XXX - bochs bios code sets edi to point to 32bit code - but no
// reference to this in spec.
-static void pci_for_each_device(void (*init_func)(u16 bdf))
-{
- int max = GET_VAR(CS, MaxBDF);
- int bdf;
- for (bdf = 0; bdf < max; bdf++) {
- u16 vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
- u16 device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
- if (vendor_id != 0xffff || device_id != 0xffff)
- init_func(bdf);
- }
-}
-
void
pci_bios_setup(void)
{
void
pci_bios_setup(void)
{
if (pci_bios_bigmem_addr < 0x90000000)
pci_bios_bigmem_addr = 0x90000000;
if (pci_bios_bigmem_addr < 0x90000000)
pci_bios_bigmem_addr = 0x90000000;
- pci_for_each_device(pci_bios_init_bridges);
-
- pci_for_each_device(pci_bios_init_device);
+ int bdf, max;
+ foreachpci(bdf, max, 0) {
+ pci_bios_init_bridges(bdf);
+ }
+ foreachpci(bdf, max, 0) {
+ pci_bios_init_device(bdf);
+ }
timer_setup();
mathcp_setup();
timer_setup();
mathcp_setup();
smp_probe_setup();
memmap_setup();
smp_probe_setup();
memmap_setup();