diff --git a/src/arch/i386/lib/pci_ops_auto.c b/src/arch/i386/lib/pci_ops_auto.c index b757e608fc..f453d47826 100644 --- a/src/arch/i386/lib/pci_ops_auto.c +++ b/src/arch/i386/lib/pci_ops_auto.c @@ -41,6 +41,8 @@ static int pci_sanity_check(const struct pci_bus_operations *o) return 0; } +struct pci_bus_operations *pci_bus_fallback_ops = NULL; + const struct pci_bus_operations *pci_check_direct(void) { unsigned int tmp; @@ -81,11 +83,18 @@ const struct pci_bus_operations *pci_check_direct(void) return NULL; } +const struct pci_bus_operations *pci_remember_direct(void) +{ + if (!pci_bus_fallback_ops) + pci_bus_fallback_ops = pci_check_direct(); + return pci_bus_fallback_ops; +} + /** Set the method to be used for PCI, type I or type II */ void pci_set_method(device_t dev) { printk_info("Finding PCI configuration type.\n"); - dev->ops->ops_pci_bus = pci_check_direct(); + dev->ops->ops_pci_bus = pci_remember_direct(); post_code(0x5f); } diff --git a/src/devices/pci_ops.c b/src/devices/pci_ops.c index 6029d757ef..6ade5e0c3c 100644 --- a/src/devices/pci_ops.c +++ b/src/devices/pci_ops.c @@ -25,6 +25,9 @@ #include #include +/* The only consumer of the return value of get_pbus() is ops_pci_bus(). + * ops_pci_bus() can handle being passed NULL and auto-picks working ops. + */ static struct bus *get_pbus(device_t dev) { struct bus *pbus = NULL; @@ -44,8 +47,9 @@ static struct bus *get_pbus(device_t dev) pbus = pbus->dev->bus; } if (!pbus || !pbus->dev || !pbus->dev->ops || !pbus->dev->ops->ops_pci_bus) { - printk_emerg("%s: Cannot find pci bus operations.\n", dev_path(dev)); - die(""); + /* This can happen before the device tree is set up completely. */ + //printk_emerg("%s: Cannot find pci bus operations.\n", dev_path(dev)); + pbus = NULL; } return pbus; } diff --git a/src/include/device/pci.h b/src/include/device/pci.h index df9e80dbbb..60cf4aa35c 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -97,6 +97,8 @@ static inline const struct pci_bus_operations *ops_pci_bus(struct bus *bus) if (bus && bus->dev && bus->dev->ops) { bops = bus->dev->ops->ops_pci_bus; } + if (!bops) + bops = pci_remember_direct(); return bops; } diff --git a/src/include/device/pci_ops.h b/src/include/device/pci_ops.h index da7e6c5d17..13eee9d4a9 100644 --- a/src/include/device/pci_ops.h +++ b/src/include/device/pci_ops.h @@ -21,4 +21,7 @@ void pci_mmio_write_config16(device_t dev, unsigned where, uint16_t val); void pci_mmio_write_config32(device_t dev, unsigned where, uint32_t val); #endif +/* This function lives in pci_ops_auto.c */ +const struct pci_bus_operations *pci_remember_direct(void); + #endif /* PCI_OPS_H */