This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 3e7ceed2897512410cb06cad3b74b72f27dede8b
Author: raiden00pl <[email protected]>
AuthorDate: Sat Aug 22 13:52:48 2026 +0200

    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 <[email protected]>
    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,

Reply via email to