Skip to content

Commit 20ce0c2

Browse files
Krishna Kumarmpe
authored andcommitted
powerpc/pci: Hotplug driver bridge support
There is an issue with the hotplug operation when it's done on the bridge/switch slot. The bridge-port and devices behind the bridge, which become offline by hot-unplug operation, don't get hot-plugged/enabled by doing hot-plug operation on that slot. Only the first port of the bridge gets enabled and the remaining port/devices remain unplugged. The hot plug/unplug operation is done by the hotplug driver (drivers/pci/ hotplug/pnv_php.c). This behavior is due to missing code for the switch/bridge. The existing driver depends on pci_hp_add_devices() function for device enablement. This function calls pci_scan_slot() on only one device-node/port of the bridge, not on all the siblings' device-node/port. The missing code needs to be added which will find all the sibling device-nodes/bridge-ports and will run explicit pci_scan_slot() on those. A new function has been added for this purpose which is invoked from pci_hp_add_devices(). This new function traverse_siblings_and_scan_slot() gets all the sibling bridge-ports by traversal and explicitly invokes pci_scan_slot() on them. Tested-by: Shawn Anastasio <[email protected]> Signed-off-by: Krishna Kumar <[email protected]> [mpe: Move the code into pci-hotplug.c] Signed-off-by: Michael Ellerman <[email protected]> Link: https://msgid.link/[email protected]
1 parent 335e35b commit 20ce0c2

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

arch/powerpc/kernel/pci-hotplug.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ void pci_hp_remove_devices(struct pci_bus *bus)
9393
}
9494
EXPORT_SYMBOL_GPL(pci_hp_remove_devices);
9595

96+
static void traverse_siblings_and_scan_slot(struct device_node *start, struct pci_bus *bus)
97+
{
98+
struct device_node *dn;
99+
int slotno;
100+
101+
u32 class = 0;
102+
103+
if (!of_property_read_u32(start->child, "class-code", &class)) {
104+
/* Call of pci_scan_slot for non-bridge/EP case */
105+
if (!((class >> 8) == PCI_CLASS_BRIDGE_PCI)) {
106+
slotno = PCI_SLOT(PCI_DN(start->child)->devfn);
107+
pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
108+
return;
109+
}
110+
}
111+
112+
/* Iterate all siblings */
113+
for_each_child_of_node(start, dn) {
114+
class = 0;
115+
116+
if (!of_property_read_u32(start->child, "class-code", &class)) {
117+
/* Call of pci_scan_slot on each sibling-nodes/bridge-ports */
118+
if ((class >> 8) == PCI_CLASS_BRIDGE_PCI) {
119+
slotno = PCI_SLOT(PCI_DN(dn)->devfn);
120+
pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
121+
}
122+
}
123+
}
124+
}
125+
96126
/**
97127
* pci_hp_add_devices - adds new pci devices to bus
98128
* @bus: the indicated PCI bus
@@ -106,7 +136,7 @@ EXPORT_SYMBOL_GPL(pci_hp_remove_devices);
106136
*/
107137
void pci_hp_add_devices(struct pci_bus *bus)
108138
{
109-
int slotno, mode, max;
139+
int mode, max;
110140
struct pci_dev *dev;
111141
struct pci_controller *phb;
112142
struct device_node *dn = pci_bus_to_OF_node(bus);
@@ -129,8 +159,7 @@ void pci_hp_add_devices(struct pci_bus *bus)
129159
* order for fully rescan all the way down to pick them up.
130160
* They can have been removed during partial hotplug.
131161
*/
132-
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
133-
pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
162+
traverse_siblings_and_scan_slot(dn, bus);
134163
max = bus->busn_res.start;
135164
/*
136165
* Scan bridges that are already configured. We don't touch

0 commit comments

Comments
 (0)