Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- drivers/pci.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/pci.h | 5 +++++ 2 files changed, 48 insertions(+)
diff --git a/drivers/pci.c b/drivers/pci.c index e203aa4..eafec32 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -1283,6 +1283,8 @@ static void ob_configure_pci_bridge(pci_addr addr, unsigned long *io_base, int primary_bus, pci_config_t *config) { + unsigned long old_mem_base, old_io_base; + uint16_t cmd; phandle_t ph;
config->primary_bus = primary_bus; @@ -1302,6 +1304,29 @@ static void ob_configure_pci_bridge(pci_addr addr, ph = find_dev(config->path); set_int_property(ph, "bus-range", *bus_num);
+ /* Always expose the legacy ioports on the first PCI bridge. If we + must have legacy devices behind a PCI bridge then they must be + on the first one discovered to ensure that the ioports will work. */ + if (*io_base < 0x1000) { + *io_base = 0x0; + } + + /* Align mem_base up to nearest MB, io_base up to nearest 4K */ + old_mem_base = (*mem_base + 0xfffff - 1) & ~(0xfffff - 1); + *mem_base = old_mem_base; + old_io_base = (*io_base + 0xfff - 1) & ~(0xfff - 1); + *io_base = old_io_base; + + /* Set the base limit registers */ + pci_config_write16(addr, PCI_MEMORY_BASE, ((*mem_base >> 16) & ~(0xf))); + pci_config_write8(addr, PCI_IO_BASE, ((*io_base >> 8) & ~(0xf))); + + /* Always ensure legacy ioports are accessible during enumeration. + Some drivers (e.g. IDE) will attempt ioport access as part of + the configuration process, so we allow them during the secondary + bus scan and then set the correct IO limit below. */ + pci_config_write8(addr, PCI_IO_LIMIT, (((*io_base + 0xffff - 1) >> 8) & ~(0xf))); + /* make pci bridge parent device, prepare for recursion */
ob_scan_pci_bus(bus_num, mem_base, io_base, @@ -1315,6 +1340,24 @@ static void ob_configure_pci_bridge(pci_addr addr, config->path, config->primary_bus, config->secondary_bus, config->subordinate_bus);
+ /* Align mem_base up to nearest MB, io_base up to nearest 4K */ + *mem_base = (*mem_base + 0xfffff - 1) & ~(0xfffff - 1); + *io_base = (*io_base + 0xfff - 1) & ~(0xfff - 1); + + /* Set the limit registers */ + pci_config_write16(addr, PCI_MEMORY_LIMIT, (((*mem_base - 1) >> 16) & ~(0xf))); + pci_config_write8(addr, PCI_IO_LIMIT, (((*io_base - 1) >> 8) & ~(0xf))); + + /* Disable unused address spaces */ + cmd = pci_config_read16(addr, PCI_COMMAND); + if (*mem_base == old_mem_base) { + pci_config_write16(addr, PCI_COMMAND, (cmd & ~PCI_COMMAND_MEMORY)); + } + + if (*io_base == old_io_base) { + pci_config_write16(addr, PCI_COMMAND, (cmd & ~PCI_COMMAND_IO)); + } + pci_set_bus_range(config); }
diff --git a/drivers/pci.h b/drivers/pci.h index d5aa5f8..ea70e8a 100644 --- a/drivers/pci.h +++ b/drivers/pci.h @@ -46,6 +46,11 @@ #define PCI_BASE_ADDR_4 0x20 #define PCI_BASE_ADDR_5 0x24
+#define PCI_IO_BASE 0x1c +#define PCI_IO_LIMIT 0x1d +#define PCI_MEMORY_BASE 0x20 +#define PCI_MEMORY_LIMIT 0x22 + #define PCI_SUBSYSTEM_VENDOR_ID 0x2c #define PCI_SUBSYSTEM_ID 0x2e