From 3e7ceed2897512410cb06cad3b74b72f27dede8b Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Aug 2026 13:52:48 +0200 Subject: [PATCH] drivers/pci: enable upstream bridge forwarding PCI endpoints cannot perform memory transactions when a bridge in their hierarchy has memory forwarding or bus mastering disabled. Firmware may leave these bits clear when handing a device over after PXE boot. Enable both bits on every parent bridge before enabling the endpoint. Signed-off-by: raiden00pl Assisted-by: Claude Code --- drivers/pci/pci.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 257e349c638..e4d64acac90 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -425,6 +425,60 @@ static void pci_change_master(FAR struct pci_device_s *dev, bool enable) } } +/**************************************************************************** + * Name: pci_enable_parent_bridges + * + * Description: + * Enable memory forwarding and bus mastering on all bridges between a PCI + * device and the root bus. + * + ****************************************************************************/ + +static int pci_enable_parent_bridges(FAR struct pci_device_s *dev) +{ + FAR struct pci_device_s *bridge; + FAR struct pci_device_s *candidate; + FAR struct pci_bus_s *bus = dev->bus; + uint16_t command; + int ret; + + while (bus != NULL && bus->parent_bus != NULL) + { + bridge = NULL; + list_for_every_entry(&bus->parent_bus->devices, candidate, + struct pci_device_s, bus_list) + { + if (candidate->subordinate == bus) + { + bridge = candidate; + break; + } + } + + if (bridge == NULL) + { + return -ENODEV; + } + + ret = pci_read_config_word(bridge, PCI_COMMAND, &command); + if (ret < 0) + { + return ret; + } + + command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + ret = pci_write_config_word(bridge, PCI_COMMAND, command); + if (ret < 0) + { + return ret; + } + + bus = bus->parent_bus; + } + + return OK; +} + /**************************************************************************** * Name: pci_bus_find_start_cap * @@ -1649,6 +1703,13 @@ void pci_clear_master(FAR struct pci_device_s *dev) int pci_enable_device(FAR struct pci_device_s *dev) { uint32_t cmd; + int ret; + + ret = pci_enable_parent_bridges(dev); + if (ret < 0) + { + return ret; + } pci_read_config_dword(dev, PCI_COMMAND, &cmd); return pci_write_config_dword(dev, PCI_COMMAND,