aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Grzeschik <m.grzeschik@pengutronix.de>2014-09-29 05:55:37 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-29 14:36:26 -0400
commitc51da42a6346c0c747e70a4f5ae873da1150a784 (patch)
treeb2a03fe83a1fc7f2cfb8ba864f8f93ce480e8261
parent8c14f9c70327a6fb75534c4c61d7ea9c82ccf78f (diff)
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 <m.grzeschik@pengutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/arcnet/com20020-pci.c149
-rw-r--r--drivers/net/arcnet/com20020_cs.c4
-rw-r--r--include/linux/com20020.h15
3 files changed, 109 insertions, 59 deletions
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 @@
38#include <linux/pci.h> 38#include <linux/pci.h>
39#include <linux/arcdevice.h> 39#include <linux/arcdevice.h>
40#include <linux/com20020.h> 40#include <linux/com20020.h>
41#include <linux/list.h>
41 42
42#include <asm/io.h> 43#include <asm/io.h>
43 44
@@ -61,85 +62,125 @@ module_param(clockp, int, 0);
61module_param(clockm, int, 0); 62module_param(clockm, int, 0);
62MODULE_LICENSE("GPL"); 63MODULE_LICENSE("GPL");
63 64
65static void com20020pci_remove(struct pci_dev *pdev);
66
64static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 67static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
65{ 68{
66 struct com20020_pci_channel_map *cm;
67 struct com20020_pci_card_info *ci; 69 struct com20020_pci_card_info *ci;
68 struct net_device *dev; 70 struct net_device *dev;
69 struct arcnet_local *lp; 71 struct arcnet_local *lp;
70 int ioaddr, err; 72 struct com20020_priv *priv;
73 int i, ioaddr, ret;
74 struct resource *r;
71 75
72 if (pci_enable_device(pdev)) 76 if (pci_enable_device(pdev))
73 return -EIO; 77 return -EIO;
74 dev = alloc_arcdev(device);
75 if (!dev)
76 return -ENOMEM;
77
78 dev->netdev_ops = &com20020_netdev_ops;
79 78
79 priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
80 GFP_KERNEL);
80 ci = (struct com20020_pci_card_info *)id->driver_data; 81 ci = (struct com20020_pci_card_info *)id->driver_data;
82 priv->ci = ci;
81 83
82 lp = netdev_priv(dev); 84 INIT_LIST_HEAD(&priv->list_dev);
83 85
84 pci_set_drvdata(pdev, dev);
85 86
86 cm = &ci->chan_map_tbl[0]; 87 for (i = 0; i < ci->devcount; i++) {
87 BUGMSG(D_NORMAL, "%s Controls\n", ci->name); 88 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
88 ioaddr = pci_resource_start(pdev, cm->bar); 89 struct com20020_dev *card;
89 90
90 if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { 91 dev = alloc_arcdev(device);
91 BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", 92 if (!dev) {
92 ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); 93 ret = -ENOMEM;
93 err = -EBUSY; 94 goto out_port;
94 goto out_dev; 95 }
95 }
96 96
97 // Dummy access after Reset 97 dev->netdev_ops = &com20020_netdev_ops;
98 // ARCNET controller needs this access to detect bustype 98
99 outb(0x00,ioaddr+1); 99 lp = netdev_priv(dev);
100 inb(ioaddr+1); 100
101 101 BUGMSG(D_NORMAL, "%s Controls\n", ci->name);
102 dev->base_addr = ioaddr; 102 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
103 dev->irq = pdev->irq; 103
104 dev->dev_addr[0] = node; 104 r = devm_request_region(&pdev->dev, ioaddr, cm->size,
105 lp->card_name = "PCI COM20020"; 105 "com20020-pci");
106 lp->card_flags = ci->flags; 106 if (!r) {
107 lp->backplane = backplane; 107 pr_err("IO region %xh-%xh already allocated.\n",
108 lp->clockp = clockp & 7; 108 ioaddr, ioaddr + cm->size - 1);
109 lp->clockm = clockm & 3; 109 ret = -EBUSY;
110 lp->timeout = timeout; 110 goto out_port;
111 lp->hw.owner = THIS_MODULE; 111 }
112 112
113 if (ASTATUS() == 0xFF) { 113 /* Dummy access after Reset
114 BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " 114 * ARCNET controller needs
115 "but seems empty!\n", ioaddr); 115 * this access to detect bustype
116 err = -EIO; 116 */
117 goto out_port; 117 outb(0x00, ioaddr + 1);
118 } 118 inb(ioaddr + 1);
119 if (com20020_check(dev)) { 119
120 err = -EIO; 120 dev->base_addr = ioaddr;
121 goto out_port; 121 dev->dev_addr[0] = node;
122 dev->irq = pdev->irq;
123 lp->card_name = "PCI COM20020";
124 lp->card_flags = ci->flags;
125 lp->backplane = backplane;
126 lp->clockp = clockp & 7;
127 lp->clockm = clockm & 3;
128 lp->timeout = timeout;
129 lp->hw.owner = THIS_MODULE;
130
131 if (ASTATUS() == 0xFF) {
132 pr_err("IO address %Xh is empty!\n", ioaddr);
133 ret = -EIO;
134 goto out_port;
135 }
136 if (com20020_check(dev)) {
137 ret = -EIO;
138 goto out_port;
139 }
140
141 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
142 GFP_KERNEL);
143 if (!card) {
144 pr_err("%s out of memory!\n", __func__);
145 return -ENOMEM;
146 }
147
148 card->index = i;
149 card->pci_priv = priv;
150 card->dev = dev;
151
152 dev_set_drvdata(&dev->dev, card);
153
154 ret = com20020_found(dev, IRQF_SHARED);
155 if (ret)
156 goto out_port;
157
158 list_add(&card->list, &priv->list_dev);
122 } 159 }
123 160
124 if ((err = com20020_found(dev, IRQF_SHARED)) != 0) 161 pci_set_drvdata(pdev, priv);
125 goto out_port;
126 162
127 return 0; 163 return 0;
128 164
129out_port: 165out_port:
130 release_region(ioaddr, ARCNET_TOTAL_SIZE); 166 com20020pci_remove(pdev);
131out_dev: 167 return ret;
132 free_netdev(dev);
133 return err;
134} 168}
135 169
136static void com20020pci_remove(struct pci_dev *pdev) 170static void com20020pci_remove(struct pci_dev *pdev)
137{ 171{
138 struct net_device *dev = pci_get_drvdata(pdev); 172 struct com20020_dev *card, *tmpcard;
139 unregister_netdev(dev); 173 struct com20020_priv *priv;
140 free_irq(dev->irq, dev); 174
141 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 175 priv = pci_get_drvdata(pdev);
142 free_netdev(dev); 176
177 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
178 struct net_device *dev = card->dev;
179
180 unregister_netdev(dev);
181 free_irq(dev->irq, dev);
182 free_netdev(dev);
183 }
143} 184}
144 185
145static struct com20020_pci_card_info card_info_10mbit = { 186static 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);
112 112
113/*====================================================================*/ 113/*====================================================================*/
114 114
115struct com20020_dev {
116 struct net_device *dev;
117};
118
119static int com20020_probe(struct pcmcia_device *p_dev) 115static int com20020_probe(struct pcmcia_device *p_dev)
120{ 116{
121 struct com20020_dev *info; 117 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;
41#define BUS_ALIGN 1 41#define BUS_ALIGN 1
42#endif 42#endif
43 43
44#define PLX_PCI_MAX_CARDS 1 44#define PLX_PCI_MAX_CARDS 2
45 45
46struct com20020_pci_channel_map { 46struct com20020_pci_channel_map {
47 u32 bar; 47 u32 bar;
@@ -58,6 +58,19 @@ struct com20020_pci_card_info {
58 unsigned int flags; 58 unsigned int flags;
59}; 59};
60 60
61struct com20020_priv {
62 struct com20020_pci_card_info *ci;
63 struct list_head list_dev;
64};
65
66struct com20020_dev {
67 struct list_head list;
68 struct net_device *dev;
69
70 struct com20020_priv *pci_priv;
71 int index;
72};
73
61#define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */ 74#define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */
62#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ 75#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */
63#define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */ 76#define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */