From 8c14f9c70327a6fb75534c4c61d7ea9c82ccf78f Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 29 Sep 2014 11:55:36 +0200 Subject: ARCNET: add com20020 PCI IDs with metadata This patch adds metadata for the com20020 to prepare for devices with multiple io address areas with multi card interfaces. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- include/linux/com20020.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include/linux/com20020.h') diff --git a/include/linux/com20020.h b/include/linux/com20020.h index 5dcfb944b6ce..6a1ceca61e7f 100644 --- a/include/linux/com20020.h +++ b/include/linux/com20020.h @@ -41,6 +41,22 @@ extern const struct net_device_ops com20020_netdev_ops; #define BUS_ALIGN 1 #endif +#define PLX_PCI_MAX_CARDS 1 + +struct com20020_pci_channel_map { + u32 bar; + u32 offset; + u32 size; /* 0x00 - auto, e.g. length of entire bar */ +}; + +struct com20020_pci_card_info { + const char *name; + int devcount; + + struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; + + unsigned int flags; +}; #define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */ #define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ -- cgit v1.2.3-70-g09d2 From c51da42a6346c0c747e70a4f5ae873da1150a784 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 29 Sep 2014 11:55:37 +0200 Subject: 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: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 149 ++++++++++++++++++++++++-------------- drivers/net/arcnet/com20020_cs.c | 4 - include/linux/com20020.h | 15 +++- 3 files changed, 109 insertions(+), 59 deletions(-) (limited to 'include/linux/com20020.h') diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index f9e55527739d..fe87576bae3c 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -61,85 +62,125 @@ module_param(clockp, int, 0); module_param(clockm, int, 0); 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) { - struct com20020_pci_channel_map *cm; struct com20020_pci_card_info *ci; struct net_device *dev; struct arcnet_local *lp; - int ioaddr, err; + struct com20020_priv *priv; + int i, ioaddr, ret; + struct resource *r; if (pci_enable_device(pdev)) return -EIO; - dev = alloc_arcdev(device); - if (!dev) - return -ENOMEM; - - dev->netdev_ops = &com20020_netdev_ops; + priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), + GFP_KERNEL); ci = (struct com20020_pci_card_info *)id->driver_data; + priv->ci = ci; - lp = netdev_priv(dev); + INIT_LIST_HEAD(&priv->list_dev); - pci_set_drvdata(pdev, dev); - cm = &ci->chan_map_tbl[0]; - BUGMSG(D_NORMAL, "%s Controls\n", ci->name); - ioaddr = pci_resource_start(pdev, cm->bar); + for (i = 0; i < ci->devcount; i++) { + struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; + struct com20020_dev *card; - if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { - BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", - ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - err = -EBUSY; - goto out_dev; - } + dev = alloc_arcdev(device); + if (!dev) { + ret = -ENOMEM; + goto out_port; + } - // Dummy access after Reset - // ARCNET controller needs this access to detect bustype - outb(0x00,ioaddr+1); - inb(ioaddr+1); - - dev->base_addr = ioaddr; - dev->irq = pdev->irq; - dev->dev_addr[0] = node; - lp->card_name = "PCI COM20020"; - lp->card_flags = ci->flags; - lp->backplane = backplane; - lp->clockp = clockp & 7; - lp->clockm = clockm & 3; - lp->timeout = timeout; - lp->hw.owner = THIS_MODULE; - - if (ASTATUS() == 0xFF) { - BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " - "but seems empty!\n", ioaddr); - err = -EIO; - goto out_port; - } - if (com20020_check(dev)) { - err = -EIO; - goto out_port; + dev->netdev_ops = &com20020_netdev_ops; + + lp = netdev_priv(dev); + + BUGMSG(D_NORMAL, "%s Controls\n", ci->name); + ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset; + + r = devm_request_region(&pdev->dev, ioaddr, cm->size, + "com20020-pci"); + if (!r) { + pr_err("IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + cm->size - 1); + ret = -EBUSY; + goto out_port; + } + + /* Dummy access after Reset + * ARCNET controller needs + * this access to detect bustype + */ + outb(0x00, ioaddr + 1); + inb(ioaddr + 1); + + dev->base_addr = ioaddr; + dev->dev_addr[0] = node; + dev->irq = pdev->irq; + lp->card_name = "PCI COM20020"; + lp->card_flags = ci->flags; + lp->backplane = backplane; + lp->clockp = clockp & 7; + lp->clockm = clockm & 3; + lp->timeout = timeout; + lp->hw.owner = THIS_MODULE; + + if (ASTATUS() == 0xFF) { + pr_err("IO address %Xh is empty!\n", ioaddr); + ret = -EIO; + goto out_port; + } + if (com20020_check(dev)) { + ret = -EIO; + goto out_port; + } + + 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; + + list_add(&card->list, &priv->list_dev); } - if ((err = com20020_found(dev, IRQF_SHARED)) != 0) - goto out_port; + pci_set_drvdata(pdev, priv); return 0; out_port: - release_region(ioaddr, ARCNET_TOTAL_SIZE); -out_dev: - free_netdev(dev); - return err; + com20020pci_remove(pdev); + return ret; } static void com20020pci_remove(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - unregister_netdev(dev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - free_netdev(dev); + 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); + free_irq(dev->irq, dev); + free_netdev(dev); + } } static struct com20020_pci_card_info card_info_10mbit = { diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c index 1a790a20210d..057d9582132a 100644 --- a/drivers/net/arcnet/com20020_cs.c +++ b/drivers/net/arcnet/com20020_cs.c @@ -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) { struct com20020_dev *info; diff --git a/include/linux/com20020.h b/include/linux/com20020.h index 6a1ceca61e7f..85898995b234 100644 --- a/include/linux/com20020.h +++ b/include/linux/com20020.h @@ -41,7 +41,7 @@ extern const struct net_device_ops com20020_netdev_ops; #define BUS_ALIGN 1 #endif -#define PLX_PCI_MAX_CARDS 1 +#define PLX_PCI_MAX_CARDS 2 struct com20020_pci_channel_map { u32 bar; @@ -58,6 +58,19 @@ struct com20020_pci_card_info { 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 _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ #define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */ -- cgit v1.2.3-70-g09d2