[PATCH] can: sja1000: kvaser_pci: fix duplicate PCI I/O unmapping

From: Guangshuo Li

Date: Tue Sep 15 2026 - 13:29:44 EST


kvaser_pci_init_one() maps the PCI I/O regions with pci_iomap(), while
kvaser_pci_del_chan() also unmaps the same mappings as part of channel
cleanup.

If kvaser_pci_add_chan() fails after the master device has been
initialized, the probe error path calls kvaser_pci_del_chan(), which
unmaps the PCI I/O regions, and then falls through to failure_iounmap,
where the same mappings are unmapped again.

Move the PCI I/O unmapping out of kvaser_pci_del_chan(). Let the probe
error path release the mappings through failure_iounmap and explicitly
release them in kvaser_pci_remove_one() after channel cleanup. This
ensures that each PCI I/O mapping is released exactly once.

This issue was found by manual code inspection.

Fixes: 3878fb6fdbce ("The patch adds support for the PCI cards: PCIcan and PCIcanx (1, 2 or 4 channel) from Kvaser (http://www.kvaser.com).")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
drivers/net/can/sja1000/kvaser_pci.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index 95fe9ee1ce32..b21ca65d2daa 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -186,10 +186,6 @@ static void kvaser_pci_del_chan(struct net_device *dev)
}
unregister_sja1000dev(dev);

- pci_iounmap(board->pci_dev, priv->reg_base);
- pci_iounmap(board->pci_dev, board->conf_addr);
- pci_iounmap(board->pci_dev, board->res_addr);
-
free_sja1000dev(dev);
}

@@ -367,9 +363,18 @@ static int kvaser_pci_init_one(struct pci_dev *pdev,
static void kvaser_pci_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct sja1000_priv *priv = netdev_priv(dev);
+ struct kvaser_pci *board = priv->priv;
+ void __iomem *base_addr = priv->reg_base;
+ void __iomem *conf_addr = board->conf_addr;
+ void __iomem *res_addr = board->res_addr;

kvaser_pci_del_chan(dev);

+ pci_iounmap(pdev, conf_addr);
+ pci_iounmap(pdev, res_addr);
+ pci_iounmap(pdev, base_addr);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
}
--
2.43.0