Skip to content

Commit 91a8d79

Browse files
paliLorenzo Pieralisi
authored andcommitted
PCI: mvebu: Fix configuring secondary bus of PCIe Root Port via emulated bridge
It looks like that mvebu PCIe controller has for each PCIe link fully independent PCIe host bridge and so every PCIe Root Port is isolated not only on its own bus but also isolated from each others. But in past device tree structure was defined to put all PCIe Root Ports (as PCI Bridge devices) into one root bus 0 and this bus is emulated by pci-mvebu.c driver. Probably reason for this decision was incorrect understanding of PCIe topology of these Armada SoCs and also reason of misunderstanding how is PCIe controller generating Type 0 and Type 1 config requests (it is fully different compared to other drivers). Probably incorrect setup leaded to very surprised things like having PCIe Root Port (PCI Bridge device, with even incorrect Device Class set to Memory Controller) and the PCIe device behind the Root Port on the same PCI bus, which obviously was needed to somehow hack (as these two devices cannot be in reality on the same bus). Properly set mvebu local bus number and mvebu local device number based on PCI Bridge secondary bus number configuration. Also correctly report configured secondary bus number in config space. And explain in driver comment why this setup is correct. Link: https://lore.kernel.org/r/[email protected] Fixes: 1f08673 ("PCI: mvebu: Convert to PCI emulated bridge config space") Signed-off-by: Pali Rohár <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent f587775 commit 91a8d79

File tree

1 file changed

+97
-2
lines changed

1 file changed

+97
-2
lines changed

drivers/pci/controller/pci-mvebu.c

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port)
126126
return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
127127
}
128128

129+
static u8 mvebu_pcie_get_local_bus_nr(struct mvebu_pcie_port *port)
130+
{
131+
return (mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_BUS) >> 8;
132+
}
133+
129134
static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr)
130135
{
131136
u32 stat;
@@ -479,6 +484,20 @@ mvebu_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
479484
*value = mvebu_readl(port, PCIE_CMD_OFF);
480485
break;
481486

487+
case PCI_PRIMARY_BUS: {
488+
/*
489+
* From the whole 32bit register we support reading from HW only
490+
* secondary bus number which is mvebu local bus number.
491+
* Other bits are retrieved only from emulated config buffer.
492+
*/
493+
__le32 *cfgspace = (__le32 *)&bridge->conf;
494+
u32 val = le32_to_cpu(cfgspace[PCI_PRIMARY_BUS / 4]);
495+
val &= ~0xff00;
496+
val |= mvebu_pcie_get_local_bus_nr(port) << 8;
497+
*value = val;
498+
break;
499+
}
500+
482501
default:
483502
return PCI_BRIDGE_EMUL_NOT_HANDLED;
484503
}
@@ -583,7 +602,8 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
583602
break;
584603

585604
case PCI_PRIMARY_BUS:
586-
mvebu_pcie_set_local_bus_nr(port, conf->secondary_bus);
605+
if (mask & 0xff00)
606+
mvebu_pcie_set_local_bus_nr(port, conf->secondary_bus);
587607
break;
588608

589609
default:
@@ -1167,8 +1187,83 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
11671187
continue;
11681188
}
11691189

1190+
/*
1191+
* PCIe topology exported by mvebu hw is quite complicated. In
1192+
* reality has something like N fully independent host bridges
1193+
* where each host bridge has one PCIe Root Port (which acts as
1194+
* PCI Bridge device). Each host bridge has its own independent
1195+
* internal registers, independent access to PCI config space,
1196+
* independent interrupt lines, independent window and memory
1197+
* access configuration. But additionally there is some kind of
1198+
* peer-to-peer support between PCIe devices behind different
1199+
* host bridges limited just to forwarding of memory and I/O
1200+
* transactions (forwarding of error messages and config cycles
1201+
* is not supported). So we could say there are N independent
1202+
* PCIe Root Complexes.
1203+
*
1204+
* For this kind of setup DT should have been structured into
1205+
* N independent PCIe controllers / host bridges. But instead
1206+
* structure in past was defined to put PCIe Root Ports of all
1207+
* host bridges into one bus zero, like in classic multi-port
1208+
* Root Complex setup with just one host bridge.
1209+
*
1210+
* This means that pci-mvebu.c driver provides "virtual" bus 0
1211+
* on which registers all PCIe Root Ports (PCI Bridge devices)
1212+
* specified in DT by their BDF addresses and virtually routes
1213+
* PCI config access of each PCI bridge device to specific PCIe
1214+
* host bridge.
1215+
*
1216+
* Normally PCI Bridge should choose between Type 0 and Type 1
1217+
* config requests based on primary and secondary bus numbers
1218+
* configured on the bridge itself. But because mvebu PCI Bridge
1219+
* does not have registers for primary and secondary bus numbers
1220+
* in its config space, it determinates type of config requests
1221+
* via its own custom way.
1222+
*
1223+
* There are two options how mvebu determinate type of config
1224+
* request.
1225+
*
1226+
* 1. If Secondary Bus Number Enable bit is not set or is not
1227+
* available (applies for pre-XP PCIe controllers) then Type 0
1228+
* is used if target bus number equals Local Bus Number (bits
1229+
* [15:8] in register 0x1a04) and target device number differs
1230+
* from Local Device Number (bits [20:16] in register 0x1a04).
1231+
* Type 1 is used if target bus number differs from Local Bus
1232+
* Number. And when target bus number equals Local Bus Number
1233+
* and target device equals Local Device Number then request is
1234+
* routed to Local PCI Bridge (PCIe Root Port).
1235+
*
1236+
* 2. If Secondary Bus Number Enable bit is set (bit 7 in
1237+
* register 0x1a2c) then mvebu hw determinate type of config
1238+
* request like compliant PCI Bridge based on primary bus number
1239+
* which is configured via Local Bus Number (bits [15:8] in
1240+
* register 0x1a04) and secondary bus number which is configured
1241+
* via Secondary Bus Number (bits [7:0] in register 0x1a2c).
1242+
* Local PCI Bridge (PCIe Root Port) is available on primary bus
1243+
* as device with Local Device Number (bits [20:16] in register
1244+
* 0x1a04).
1245+
*
1246+
* Secondary Bus Number Enable bit is disabled by default and
1247+
* option 2. is not available on pre-XP PCIe controllers. Hence
1248+
* this driver always use option 1.
1249+
*
1250+
* Basically it means that primary and secondary buses shares
1251+
* one virtual number configured via Local Bus Number bits and
1252+
* Local Device Number bits determinates if accessing primary
1253+
* or secondary bus. Set Local Device Number to 1 and redirect
1254+
* all writes of PCI Bridge Secondary Bus Number register to
1255+
* Local Bus Number (bits [15:8] in register 0x1a04).
1256+
*
1257+
* So when accessing devices on buses behind secondary bus
1258+
* number it would work correctly. And also when accessing
1259+
* device 0 at secondary bus number via config space would be
1260+
* correctly routed to secondary bus. Due to issues described
1261+
* in mvebu_pcie_setup_hw(), PCI Bridges at primary bus (zero)
1262+
* are not accessed directly via PCI config space but rarher
1263+
* indirectly via kernel emulated PCI bridge driver.
1264+
*/
11701265
mvebu_pcie_setup_hw(port);
1171-
mvebu_pcie_set_local_dev_nr(port, 1);
1266+
mvebu_pcie_set_local_dev_nr(port, 0);
11721267
}
11731268

11741269
pcie->nports = i;

0 commit comments

Comments
 (0)