Commit c51da42a authored by Michael Grzeschik's avatar Michael Grzeschik Committed by David S. Miller

ARCNET: add support for multi interfaces on com20020

The com20020-pci driver is currently designed to instance
one netdev with one pci device. This patch adds support to
instance many cards with one pci device, depending on the device
data in the private data.
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8c14f9c7
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/arcdevice.h> #include <linux/arcdevice.h>
#include <linux/com20020.h> #include <linux/com20020.h>
#include <linux/list.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -61,47 +62,64 @@ module_param(clockp, int, 0); ...@@ -61,47 +62,64 @@ module_param(clockp, int, 0);
module_param(clockm, int, 0); module_param(clockm, int, 0);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static void com20020pci_remove(struct pci_dev *pdev);
static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct com20020_pci_channel_map *cm;
struct com20020_pci_card_info *ci; struct com20020_pci_card_info *ci;
struct net_device *dev; struct net_device *dev;
struct arcnet_local *lp; struct arcnet_local *lp;
int ioaddr, err; struct com20020_priv *priv;
int i, ioaddr, ret;
struct resource *r;
if (pci_enable_device(pdev)) if (pci_enable_device(pdev))
return -EIO; return -EIO;
priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
GFP_KERNEL);
ci = (struct com20020_pci_card_info *)id->driver_data;
priv->ci = ci;
INIT_LIST_HEAD(&priv->list_dev);
for (i = 0; i < ci->devcount; i++) {
struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
struct com20020_dev *card;
dev = alloc_arcdev(device); dev = alloc_arcdev(device);
if (!dev) if (!dev) {
return -ENOMEM; ret = -ENOMEM;
goto out_port;
}
dev->netdev_ops = &com20020_netdev_ops; dev->netdev_ops = &com20020_netdev_ops;
ci = (struct com20020_pci_card_info *)id->driver_data;
lp = netdev_priv(dev); lp = netdev_priv(dev);
pci_set_drvdata(pdev, dev);
cm = &ci->chan_map_tbl[0];
BUGMSG(D_NORMAL, "%s Controls\n", ci->name); BUGMSG(D_NORMAL, "%s Controls\n", ci->name);
ioaddr = pci_resource_start(pdev, cm->bar); ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { r = devm_request_region(&pdev->dev, ioaddr, cm->size,
BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", "com20020-pci");
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); if (!r) {
err = -EBUSY; pr_err("IO region %xh-%xh already allocated.\n",
goto out_dev; ioaddr, ioaddr + cm->size - 1);
ret = -EBUSY;
goto out_port;
} }
// Dummy access after Reset /* Dummy access after Reset
// ARCNET controller needs this access to detect bustype * ARCNET controller needs
outb(0x00,ioaddr+1); * this access to detect bustype
inb(ioaddr+1); */
outb(0x00, ioaddr + 1);
inb(ioaddr + 1);
dev->base_addr = ioaddr; dev->base_addr = ioaddr;
dev->irq = pdev->irq;
dev->dev_addr[0] = node; dev->dev_addr[0] = node;
dev->irq = pdev->irq;
lp->card_name = "PCI COM20020"; lp->card_name = "PCI COM20020";
lp->card_flags = ci->flags; lp->card_flags = ci->flags;
lp->backplane = backplane; lp->backplane = backplane;
...@@ -111,35 +129,58 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i ...@@ -111,35 +129,58 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
lp->hw.owner = THIS_MODULE; lp->hw.owner = THIS_MODULE;
if (ASTATUS() == 0xFF) { if (ASTATUS() == 0xFF) {
BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " pr_err("IO address %Xh is empty!\n", ioaddr);
"but seems empty!\n", ioaddr); ret = -EIO;
err = -EIO;
goto out_port; goto out_port;
} }
if (com20020_check(dev)) { if (com20020_check(dev)) {
err = -EIO; ret = -EIO;
goto out_port; goto out_port;
} }
if ((err = com20020_found(dev, IRQF_SHARED)) != 0) card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
GFP_KERNEL);
if (!card) {
pr_err("%s out of memory!\n", __func__);
return -ENOMEM;
}
card->index = i;
card->pci_priv = priv;
card->dev = dev;
dev_set_drvdata(&dev->dev, card);
ret = com20020_found(dev, IRQF_SHARED);
if (ret)
goto out_port; goto out_port;
list_add(&card->list, &priv->list_dev);
}
pci_set_drvdata(pdev, priv);
return 0; return 0;
out_port: out_port:
release_region(ioaddr, ARCNET_TOTAL_SIZE); com20020pci_remove(pdev);
out_dev: return ret;
free_netdev(dev);
return err;
} }
static void com20020pci_remove(struct pci_dev *pdev) static void com20020pci_remove(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct com20020_dev *card, *tmpcard;
struct com20020_priv *priv;
priv = pci_get_drvdata(pdev);
list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
struct net_device *dev = card->dev;
unregister_netdev(dev); unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
free_netdev(dev); free_netdev(dev);
}
} }
static struct com20020_pci_card_info card_info_10mbit = { static struct com20020_pci_card_info card_info_10mbit = {
......
...@@ -112,10 +112,6 @@ static void com20020_detach(struct pcmcia_device *p_dev); ...@@ -112,10 +112,6 @@ static void com20020_detach(struct pcmcia_device *p_dev);
/*====================================================================*/ /*====================================================================*/
struct com20020_dev {
struct net_device *dev;
};
static int com20020_probe(struct pcmcia_device *p_dev) static int com20020_probe(struct pcmcia_device *p_dev)
{ {
struct com20020_dev *info; struct com20020_dev *info;
......
...@@ -41,7 +41,7 @@ extern const struct net_device_ops com20020_netdev_ops; ...@@ -41,7 +41,7 @@ extern const struct net_device_ops com20020_netdev_ops;
#define BUS_ALIGN 1 #define BUS_ALIGN 1
#endif #endif
#define PLX_PCI_MAX_CARDS 1 #define PLX_PCI_MAX_CARDS 2
struct com20020_pci_channel_map { struct com20020_pci_channel_map {
u32 bar; u32 bar;
...@@ -58,6 +58,19 @@ struct com20020_pci_card_info { ...@@ -58,6 +58,19 @@ struct com20020_pci_card_info {
unsigned int flags; unsigned int flags;
}; };
struct com20020_priv {
struct com20020_pci_card_info *ci;
struct list_head list_dev;
};
struct com20020_dev {
struct list_head list;
struct net_device *dev;
struct com20020_priv *pci_priv;
int index;
};
#define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */ #define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */
#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ #define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */
#define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */ #define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment