Skip to content

Commit 0746ae1

Browse files
paliLorenzo Pieralisi
authored andcommitted
PCI: mvebu: Add support for compiling driver as module
Now when driver uses devm_pci_remap_iospace() function, it is possible implement ->remove() callback for unbinding device from driver. Implement mvebu_pcie_remove() callback with proper cleanup phase, drop driver's suppress_bind_attrs flag and switch type of CONFIG_PCI_MVEBU option from bool to tristate. This allows to compile pci-mvebu.c driver as loadable module pci-mvebu.ko with ability to unload it. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Pali Rohár <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent 859186e commit 0746ae1

File tree

2 files changed

+77
-16
lines changed

2 files changed

+77
-16
lines changed

drivers/pci/controller/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ menu "PCI controller drivers"
44
depends on PCI
55

66
config PCI_MVEBU
7-
bool "Marvell EBU PCIe controller"
7+
tristate "Marvell EBU PCIe controller"
88
depends on ARCH_MVEBU || ARCH_DOVE || COMPILE_TEST
99
depends on MVEBU_MBUS
1010
depends on ARM

drivers/pci/controller/pci-mvebu.c

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include <linux/kernel.h>
9+
#include <linux/module.h>
910
#include <linux/pci.h>
1011
#include <linux/clk.h>
1112
#include <linux/delay.h>
@@ -154,22 +155,13 @@ static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr)
154155
mvebu_writel(port, stat, PCIE_STAT_OFF);
155156
}
156157

157-
/*
158-
* Setup PCIE BARs and Address Decode Wins:
159-
* BAR[0] -> internal registers (needed for MSI)
160-
* BAR[1] -> covers all DRAM banks
161-
* BAR[2] -> Disabled
162-
* WIN[0-3] -> DRAM bank[0-3]
163-
*/
164-
static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
158+
static void mvebu_pcie_disable_wins(struct mvebu_pcie_port *port)
165159
{
166-
const struct mbus_dram_target_info *dram;
167-
u32 size;
168160
int i;
169161

170-
dram = mv_mbus_dram_info();
162+
mvebu_writel(port, 0, PCIE_BAR_LO_OFF(0));
163+
mvebu_writel(port, 0, PCIE_BAR_HI_OFF(0));
171164

172-
/* First, disable and clear BARs and windows. */
173165
for (i = 1; i < 3; i++) {
174166
mvebu_writel(port, 0, PCIE_BAR_CTRL_OFF(i));
175167
mvebu_writel(port, 0, PCIE_BAR_LO_OFF(i));
@@ -185,6 +177,25 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
185177
mvebu_writel(port, 0, PCIE_WIN5_CTRL_OFF);
186178
mvebu_writel(port, 0, PCIE_WIN5_BASE_OFF);
187179
mvebu_writel(port, 0, PCIE_WIN5_REMAP_OFF);
180+
}
181+
182+
/*
183+
* Setup PCIE BARs and Address Decode Wins:
184+
* BAR[0] -> internal registers (needed for MSI)
185+
* BAR[1] -> covers all DRAM banks
186+
* BAR[2] -> Disabled
187+
* WIN[0-3] -> DRAM bank[0-3]
188+
*/
189+
static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
190+
{
191+
const struct mbus_dram_target_info *dram;
192+
u32 size;
193+
int i;
194+
195+
dram = mv_mbus_dram_info();
196+
197+
/* First, disable and clear BARs and windows. */
198+
mvebu_pcie_disable_wins(port);
188199

189200
/* Setup windows for DDR banks. Count total DDR size on the fly. */
190201
size = 0;
@@ -1327,6 +1338,52 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
13271338
return pci_host_probe(bridge);
13281339
}
13291340

1341+
static int mvebu_pcie_remove(struct platform_device *pdev)
1342+
{
1343+
struct mvebu_pcie *pcie = platform_get_drvdata(pdev);
1344+
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
1345+
u32 cmd;
1346+
int i;
1347+
1348+
/* Remove PCI bus with all devices. */
1349+
pci_lock_rescan_remove();
1350+
pci_stop_root_bus(bridge->bus);
1351+
pci_remove_root_bus(bridge->bus);
1352+
pci_unlock_rescan_remove();
1353+
1354+
for (i = 0; i < pcie->nports; i++) {
1355+
struct mvebu_pcie_port *port = &pcie->ports[i];
1356+
1357+
if (!port->base)
1358+
continue;
1359+
1360+
/* Disable Root Bridge I/O space, memory space and bus mastering. */
1361+
cmd = mvebu_readl(port, PCIE_CMD_OFF);
1362+
cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
1363+
mvebu_writel(port, cmd, PCIE_CMD_OFF);
1364+
1365+
/* Mask all interrupt sources. */
1366+
mvebu_writel(port, 0, PCIE_MASK_OFF);
1367+
1368+
/* Free config space for emulated root bridge. */
1369+
pci_bridge_emul_cleanup(&port->bridge);
1370+
1371+
/* Disable and clear BARs and windows. */
1372+
mvebu_pcie_disable_wins(port);
1373+
1374+
/* Delete PCIe IO and MEM windows. */
1375+
if (port->iowin.size)
1376+
mvebu_pcie_del_windows(port, port->iowin.base, port->iowin.size);
1377+
if (port->memwin.size)
1378+
mvebu_pcie_del_windows(port, port->memwin.base, port->memwin.size);
1379+
1380+
/* Power down card and disable clocks. Must be the last step. */
1381+
mvebu_pcie_powerdown(port);
1382+
}
1383+
1384+
return 0;
1385+
}
1386+
13301387
static const struct of_device_id mvebu_pcie_of_match_table[] = {
13311388
{ .compatible = "marvell,armada-xp-pcie", },
13321389
{ .compatible = "marvell,armada-370-pcie", },
@@ -1343,10 +1400,14 @@ static struct platform_driver mvebu_pcie_driver = {
13431400
.driver = {
13441401
.name = "mvebu-pcie",
13451402
.of_match_table = mvebu_pcie_of_match_table,
1346-
/* driver unloading/unbinding currently not supported */
1347-
.suppress_bind_attrs = true,
13481403
.pm = &mvebu_pcie_pm_ops,
13491404
},
13501405
.probe = mvebu_pcie_probe,
1406+
.remove = mvebu_pcie_remove,
13511407
};
1352-
builtin_platform_driver(mvebu_pcie_driver);
1408+
module_platform_driver(mvebu_pcie_driver);
1409+
1410+
MODULE_AUTHOR("Thomas Petazzoni <[email protected]>");
1411+
MODULE_AUTHOR("Pali Rohár <[email protected]>");
1412+
MODULE_DESCRIPTION("Marvell EBU PCIe controller");
1413+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)