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 <raiden00@railab.me>
Assisted-by: Claude Code
This commit is contained in:
raiden00pl 2026-08-22 13:52:48 +02:00 committed by Xiang Xiao
parent c81cc02e83
commit 3e7ceed289

View file

@ -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,