Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29830406 authored by Stephane Grosjean's avatar Stephane Grosjean Committed by Marc Kleine-Budde
Browse files

can: peak_pci: Fix the way channels are linked together



Change the way channels objects are linked together by peak_pci_probe()
avoiding any kernel oops when driver is removed. Side effect is that
the list is now browsed from last to first channel.

Signed-off-by: default avatarStephane Grosjean <s.grosjean@peak-system.com>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent d0a71a7e
Loading
Loading
Loading
Loading
+9 −14
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ MODULE_LICENSE("GPL v2");

struct peak_pci_chan {
	void __iomem *cfg_base;		/* Common for all channels */
	struct net_device *next_dev; /* Chain of network devices */
	struct net_device *prev_dev;	/* Chain of network devices */
	u16 icr_mask;			/* Interrupt mask for fast ack */
};

@@ -98,7 +98,7 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
{
	struct sja1000_priv *priv;
	struct peak_pci_chan *chan;
	struct net_device *dev, *dev0 = NULL;
	struct net_device *dev;
	void __iomem *cfg_base, *reg_base;
	u16 sub_sys_id, icr;
	int i, err, channels;
@@ -196,18 +196,14 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
		}

		/* Create chain of SJA1000 devices */
		if (i == 0)
			dev0 = dev;
		else
			chan->next_dev = dev;
		chan->prev_dev = pci_get_drvdata(pdev);
		pci_set_drvdata(pdev, dev);

		dev_info(&pdev->dev,
			 "%s at reg_base=0x%p cfg_base=0x%p irq=%d\n",
			 dev->name, priv->reg_base, chan->cfg_base, dev->irq);
	}

	pci_set_drvdata(pdev, dev0);

	/* Enable interrupts */
	writew(icr, cfg_base + PITA_ICR + 2);

@@ -217,12 +213,11 @@ failure_remove_channels:
	/* Disable interrupts */
	writew(0x0, cfg_base + PITA_ICR + 2);

	for (dev = dev0; dev; dev = chan->next_dev) {
	for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
		unregister_sja1000dev(dev);
		free_sja1000dev(dev);
		priv = netdev_priv(dev);
		chan = priv->priv;
		dev = chan->next_dev;
	}

	pci_iounmap(pdev, reg_base);
@@ -241,7 +236,7 @@ failure_disable_pci:

static void __devexit peak_pci_remove(struct pci_dev *pdev)
{
	struct net_device *dev = pci_get_drvdata(pdev); /* First device */
	struct net_device *dev = pci_get_drvdata(pdev); /* Last device */
	struct sja1000_priv *priv = netdev_priv(dev);
	struct peak_pci_chan *chan = priv->priv;
	void __iomem *cfg_base = chan->cfg_base;
@@ -255,7 +250,7 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
		dev_info(&pdev->dev, "removing device %s\n", dev->name);
		unregister_sja1000dev(dev);
		free_sja1000dev(dev);
		dev = chan->next_dev;
		dev = chan->prev_dev;
		if (!dev)
			break;
		priv = netdev_priv(dev);