summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Fatoum <ahmad@a3f.at>2021-04-16 08:24:34 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-05-03 14:06:30 +0200
commitc3a53742f3ae16443ee80dfe3c525a863c577e40 (patch)
treed7ca2dc4485bbe0a6cee9841eb189a320f6f8232
parentce65ca49fda3a849f80ddb7d8cafcf90ed765e2c (diff)
downloadbarebox-c3a53742f3ae16443ee80dfe3c525a863c577e40.tar.gz
barebox-c3a53742f3ae16443ee80dfe3c525a863c577e40.tar.xz
PCI: support PCI BIOS preassigned buses
When running under UEFI, barebox should no redo PCI enumeration, because the UEFI implementation will likely already have drivers that won't cope with e.g. BAR addresses changing. The user-visible effect of this is that likely the framebuffer will stop working because the UEFI driver won't be able to access it any longer. Support this configuration by changing the PCI code to consult the new pcibios_assign_all_busses(). When it's true, there is no change to previous behavior. When it's false, reconfiguration is omitted and instead current configuration is read back from the bus. Signed-off-by: Ahmad Fatoum <ahmad@a3f.at> Link: https://lore.barebox.org/20210416062436.332665-3-ahmad@a3f.at Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--arch/arm/include/asm/pci.h7
-rw-r--r--arch/mips/include/asm/pci.h7
-rw-r--r--drivers/pci/pci.c106
-rw-r--r--include/linux/pci.h3
4 files changed, 86 insertions, 37 deletions
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
new file mode 100644
index 0000000000..d7419cabe7
--- /dev/null
+++ b/arch/arm/include/asm/pci.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PCI_H
+#define __ASM_PCI_H
+
+#define pcibios_assign_all_busses() 1
+
+#endif
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
new file mode 100644
index 0000000000..d7419cabe7
--- /dev/null
+++ b/arch/mips/include/asm/pci.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PCI_H
+#define __ASM_PCI_H
+
+#define pcibios_assign_all_busses() 1
+
+#endif
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 945a983387..950c509447 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -51,25 +51,27 @@ void register_pci_controller(struct pci_controller *hose)
bus->resource[PCI_BUS_RESOURCE_MEM] = hose->mem_resource;
bus->resource[PCI_BUS_RESOURCE_MEM_PREF] = hose->mem_pref_resource;
bus->resource[PCI_BUS_RESOURCE_IO] = hose->io_resource;
- bus->number = bus_index++;
- if (hose->set_busno)
- hose->set_busno(hose, bus->number);
-
- if (bus->resource[PCI_BUS_RESOURCE_MEM])
- last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start;
- else
- last_mem = 0;
-
- if (bus->resource[PCI_BUS_RESOURCE_MEM_PREF])
- last_mem_pref = bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->start;
- else
- last_mem_pref = 0;
-
- if (bus->resource[PCI_BUS_RESOURCE_IO])
- last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start;
- else
- last_io = 0;
+ if (pcibios_assign_all_busses()) {
+ bus->number = bus_index++;
+ if (hose->set_busno)
+ hose->set_busno(hose, bus->number);
+
+ if (bus->resource[PCI_BUS_RESOURCE_MEM])
+ last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start;
+ else
+ last_mem = 0;
+
+ if (bus->resource[PCI_BUS_RESOURCE_MEM_PREF])
+ last_mem_pref = bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->start;
+ else
+ last_mem_pref = 0;
+
+ if (bus->resource[PCI_BUS_RESOURCE_IO])
+ last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start;
+ else
+ last_io = 0;
+ }
pci_scan_bus(bus);
pci_bus_register_devices(bus);
@@ -156,13 +158,16 @@ static void setup_device(struct pci_dev *dev, int max_bar)
u8 cmd;
pci_read_config_byte(dev, PCI_COMMAND, &cmd);
- pci_write_config_byte(dev, PCI_COMMAND,
- cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+
+ if (pcibios_assign_all_busses())
+ pci_write_config_byte(dev, PCI_COMMAND,
+ cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+
for (bar = 0; bar < max_bar; bar++) {
const int pci_base_address_0 = PCI_BASE_ADDRESS_0 + bar * 4;
const int pci_base_address_1 = PCI_BASE_ADDRESS_1 + bar * 4;
- resource_size_t *last_addr;
+ resource_size_t *last_addr, start;
u32 orig, mask, size;
unsigned long flags;
const char *kind;
@@ -207,32 +212,47 @@ static void setup_device(struct pci_dev *dev, int max_bar)
pr_debug("pbar%d: mask=%08x %s %d bytes\n", bar, mask, kind,
size);
- if (ALIGN(*last_addr, size) + size >
- dev->bus->resource[busres]->end) {
- pr_debug("BAR does not fit within bus %s res\n", kind);
- return;
+ if (pcibios_assign_all_busses()) {
+ if (ALIGN(*last_addr, size) + size >
+ dev->bus->resource[busres]->end) {
+ pr_debug("BAR does not fit within bus %s res\n", kind);
+ return;
+ }
+
+ *last_addr = ALIGN(*last_addr, size);
+ pci_write_config_dword(dev, pci_base_address_0, *last_addr);
+ if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ pci_write_config_dword(dev, pci_base_address_1, 0);
+ start = *last_addr;
+ *last_addr += size;
+ } else {
+ u32 tmp;
+ pci_read_config_dword(dev, pci_base_address_0, &tmp);
+ tmp &= mask & PCI_BASE_ADDRESS_SPACE_IO ? PCI_BASE_ADDRESS_IO_MASK
+ : PCI_BASE_ADDRESS_MEM_MASK;
+ start = tmp;
+
+ if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ pci_read_config_dword(dev, pci_base_address_1, &tmp);
+ start |= (u64)tmp << 32;
+ }
}
- *last_addr = ALIGN(*last_addr, size);
- pci_write_config_dword(dev, pci_base_address_0, *last_addr);
dev->resource[bar].flags = flags;
- dev->resource[bar].start = *last_addr;
- dev->resource[bar].end = dev->resource[bar].start + size - 1;
-
- pr_debug("pbar%d: allocated at %pa\n", bar, last_addr);
-
- *last_addr += size;
+ dev->resource[bar].start = start;
+ dev->resource[bar].end = start + size - 1;
if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) {
dev->resource[bar].flags |= IORESOURCE_MEM_64;
- pci_write_config_dword(dev, pci_base_address_1, 0);
bar++;
}
}
pci_fixup_device(pci_fixup_header, dev);
- pci_write_config_byte(dev, PCI_COMMAND, cmd);
+ if (pcibios_assign_all_busses())
+ pci_write_config_byte(dev, PCI_COMMAND, cmd);
+
list_add_tail(&dev->bus_list, &dev->bus->devices);
}
@@ -240,6 +260,12 @@ static void prescan_setup_bridge(struct pci_dev *dev)
{
u16 cmdstat;
+ if (!pcibios_assign_all_busses()) {
+ pci_read_config_byte(dev, PCI_PRIMARY_BUS, &dev->bus->number);
+ pci_read_config_byte(dev, PCI_SECONDARY_BUS, &dev->subordinate->number);
+ return;
+ }
+
pci_read_config_word(dev, PCI_COMMAND, &cmdstat);
/* Configure bus number registers */
@@ -283,6 +309,9 @@ static void prescan_setup_bridge(struct pci_dev *dev)
static void postscan_setup_bridge(struct pci_dev *dev)
{
+ if (!pcibios_assign_all_busses())
+ return;
+
/* limit subordinate to last used bus number */
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, bus_index - 1);
@@ -416,8 +445,11 @@ static unsigned int pci_scan_bus(struct pci_bus *bus)
bus->resource[PCI_BUS_RESOURCE_IO];
child_bus->parent = &dev->dev;
- child_bus->number = bus_index++;
- child_bus->primary = bus->number;
+
+ if (pcibios_assign_all_busses()) {
+ child_bus->number = bus_index++;
+ child_bus->primary = bus->number;
+ }
list_add_tail(&child_bus->node, &bus->children);
dev->subordinate = child_bus;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0c8fed7c8e..486d4251d4 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -29,6 +29,9 @@
#include <linux/pci_ids.h>
+/* Include architecture-dependent settings and functions */
+
+#include <asm/pci.h>
#define PCI_ANY_ID (~0)
#define PCI_FIND_CAP_TTL 48