blob: e3b7c14e619fdf6cf40823d1c4f802e1e4acb7cb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux ARCnet driver - COM20020 PCI support
3 * Contemporary Controls PCI20 and SOHARD SH-ARC PCI
Joe Perchescb334642015-05-05 10:05:47 -07004 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Written 1994-1999 by Avery Pennarun,
6 * based on an ISA version by David Woodhouse.
7 * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
8 * Derived from skeleton.c by Donald Becker.
9 *
10 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
11 * for sponsoring the further development of this driver.
12 *
13 * **********************
14 *
15 * The original copyright of skeleton.c was as follows:
16 *
17 * skeleton.c Written 1993 by Donald Becker.
18 * Copyright 1993 United States Government as represented by the
19 * Director, National Security Agency. This software may only be used
20 * and distributed according to the terms of the GNU General Public License as
21 * modified by SRC, incorporated herein by reference.
22 *
23 * **********************
24 *
25 * For more details, see drivers/net/arcnet.c
26 *
27 * **********************
28 */
Joe Perches05a24b22015-05-05 10:05:56 -070029
30#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/kernel.h>
35#include <linux/types.h>
36#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/errno.h>
38#include <linux/netdevice.h>
39#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000040#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/pci.h>
Michael Grzeschikc51da422014-09-29 11:55:37 +020042#include <linux/list.h>
Joe Perches5e7ef912015-05-05 10:05:51 -070043#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Joe Perches26c6d282015-05-05 10:06:03 -070045#include "arcdevice.h"
46#include "com20020.h"
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048/* Module parameters */
49
50static int node;
51static char device[9]; /* use eg. device="arc1" to change name */
52static int timeout = 3;
53static int backplane;
54static int clockp;
55static int clockm;
56
57module_param(node, int, 0);
58module_param_string(device, device, sizeof(device), 0);
59module_param(timeout, int, 0);
60module_param(backplane, int, 0);
61module_param(clockp, int, 0);
62module_param(clockm, int, 0);
63MODULE_LICENSE("GPL");
64
Michael Grzeschikc51da422014-09-29 11:55:37 +020065static void com20020pci_remove(struct pci_dev *pdev);
66
Joe Perchesd6d7d3e2015-05-05 10:06:02 -070067static int com20020pci_probe(struct pci_dev *pdev,
68 const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +020070 struct com20020_pci_card_info *ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 struct net_device *dev;
72 struct arcnet_local *lp;
Michael Grzeschikc51da422014-09-29 11:55:37 +020073 struct com20020_priv *priv;
74 int i, ioaddr, ret;
75 struct resource *r;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77 if (pci_enable_device(pdev))
78 return -EIO;
Stephen Hemmingera1799af2009-01-09 13:01:10 +000079
Michael Grzeschikc51da422014-09-29 11:55:37 +020080 priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
81 GFP_KERNEL);
Kiran Padwale8a308a2015-02-05 17:01:37 +053082 if (!priv)
83 return -ENOMEM;
84
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +020085 ci = (struct com20020_pci_card_info *)id->driver_data;
Michael Grzeschikc51da422014-09-29 11:55:37 +020086 priv->ci = ci;
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +020087
Michael Grzeschikc51da422014-09-29 11:55:37 +020088 INIT_LIST_HEAD(&priv->list_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Michael Grzeschikc51da422014-09-29 11:55:37 +020090 for (i = 0; i < ci->devcount; i++) {
91 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
92 struct com20020_dev *card;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Michael Grzeschikc51da422014-09-29 11:55:37 +020094 dev = alloc_arcdev(device);
95 if (!dev) {
96 ret = -ENOMEM;
97 goto out_port;
98 }
Michael Grzeschikae8ede62015-03-20 15:22:24 +010099 dev->dev_port = i;
Michael Grzeschikc51da422014-09-29 11:55:37 +0200100
101 dev->netdev_ops = &com20020_netdev_ops;
102
103 lp = netdev_priv(dev);
104
Joe Perchesa34c0932015-05-05 10:05:55 -0700105 arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
Michael Grzeschikc51da422014-09-29 11:55:37 +0200106 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
107
108 r = devm_request_region(&pdev->dev, ioaddr, cm->size,
109 "com20020-pci");
110 if (!r) {
Joe Perches05a24b22015-05-05 10:05:56 -0700111 pr_err("IO region %xh-%xh already allocated\n",
Michael Grzeschikc51da422014-09-29 11:55:37 +0200112 ioaddr, ioaddr + cm->size - 1);
113 ret = -EBUSY;
114 goto out_port;
115 }
116
117 /* Dummy access after Reset
118 * ARCNET controller needs
119 * this access to detect bustype
120 */
Joe Perches0fec6512015-05-05 10:06:06 -0700121 arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
122 arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
Michael Grzeschikc51da422014-09-29 11:55:37 +0200123
124 dev->base_addr = ioaddr;
125 dev->dev_addr[0] = node;
126 dev->irq = pdev->irq;
127 lp->card_name = "PCI COM20020";
128 lp->card_flags = ci->flags;
129 lp->backplane = backplane;
130 lp->clockp = clockp & 7;
131 lp->clockm = clockm & 3;
132 lp->timeout = timeout;
133 lp->hw.owner = THIS_MODULE;
134
Joe Perches0fec6512015-05-05 10:06:06 -0700135 if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
Michael Grzeschikc51da422014-09-29 11:55:37 +0200136 pr_err("IO address %Xh is empty!\n", ioaddr);
137 ret = -EIO;
138 goto out_port;
139 }
140 if (com20020_check(dev)) {
141 ret = -EIO;
142 goto out_port;
143 }
144
145 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
146 GFP_KERNEL);
Joe Perches5628d982015-05-05 10:05:58 -0700147 if (!card)
Michael Grzeschikc51da422014-09-29 11:55:37 +0200148 return -ENOMEM;
Michael Grzeschikc51da422014-09-29 11:55:37 +0200149
150 card->index = i;
151 card->pci_priv = priv;
152 card->dev = dev;
153
154 dev_set_drvdata(&dev->dev, card);
155
156 ret = com20020_found(dev, IRQF_SHARED);
157 if (ret)
158 goto out_port;
159
160 list_add(&card->list, &priv->list_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
162
Michael Grzeschikc51da422014-09-29 11:55:37 +0200163 pci_set_drvdata(pdev, priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
165 return 0;
166
167out_port:
Michael Grzeschikc51da422014-09-29 11:55:37 +0200168 com20020pci_remove(pdev);
169 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170}
171
Bill Pemberton7c47bab2012-12-03 09:22:43 -0500172static void com20020pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
Michael Grzeschikc51da422014-09-29 11:55:37 +0200174 struct com20020_dev *card, *tmpcard;
175 struct com20020_priv *priv;
176
177 priv = pci_get_drvdata(pdev);
178
179 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
180 struct net_device *dev = card->dev;
181
182 unregister_netdev(dev);
183 free_irq(dev->irq, dev);
184 free_netdev(dev);
185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200188static struct com20020_pci_card_info card_info_10mbit = {
189 .name = "ARC-PCI",
190 .devcount = 1,
191 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100192 {
193 .bar = 2,
194 .offset = 0x00,
195 .size = 0x08,
196 },
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200197 },
198 .flags = ARC_CAN_10MBIT,
199};
200
201static struct com20020_pci_card_info card_info_5mbit = {
202 .name = "ARC-PCI",
203 .devcount = 1,
204 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100205 {
206 .bar = 2,
207 .offset = 0x00,
208 .size = 0x08,
209 },
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200210 },
211 .flags = ARC_IS_5MBIT,
212};
213
214static struct com20020_pci_card_info card_info_sohard = {
215 .name = "PLX-PCI",
216 .devcount = 1,
217 /* SOHARD needs PCI base addr 4 */
218 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100219 {
220 .bar = 4,
221 .offset = 0x00,
222 .size = 0x08
223 },
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200224 },
225 .flags = ARC_CAN_10MBIT,
226};
227
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100228static struct com20020_pci_card_info card_info_eae_arc1 = {
229 .name = "EAE PLX-PCI ARC1",
230 .devcount = 1,
231 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100232 {
233 .bar = 2,
234 .offset = 0x00,
235 .size = 0x08,
236 },
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100237 },
238 .flags = ARC_CAN_10MBIT,
239};
240
241static struct com20020_pci_card_info card_info_eae_ma1 = {
242 .name = "EAE PLX-PCI MA1",
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200243 .devcount = 2,
244 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100245 {
246 .bar = 2,
247 .offset = 0x00,
248 .size = 0x08,
249 }, {
250 .bar = 2,
251 .offset = 0x08,
252 .size = 0x08,
253 }
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200254 },
255 .flags = ARC_CAN_10MBIT,
256};
257
Benoit Taine9baa3c32014-08-08 15:56:03 +0200258static const struct pci_device_id com20020pci_id_table[] = {
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200259 {
260 0x1571, 0xa001,
261 PCI_ANY_ID, PCI_ANY_ID,
262 0, 0,
263 0,
264 },
265 {
266 0x1571, 0xa002,
267 PCI_ANY_ID, PCI_ANY_ID,
268 0, 0,
269 0,
270 },
271 {
272 0x1571, 0xa003,
273 PCI_ANY_ID, PCI_ANY_ID,
274 0, 0,
275 0
276 },
277 {
278 0x1571, 0xa004,
279 PCI_ANY_ID, PCI_ANY_ID,
280 0, 0,
281 0,
282 },
283 {
284 0x1571, 0xa005,
285 PCI_ANY_ID, PCI_ANY_ID,
286 0, 0,
287 0
288 },
289 {
290 0x1571, 0xa006,
291 PCI_ANY_ID, PCI_ANY_ID,
292 0, 0,
293 0
294 },
295 {
296 0x1571, 0xa007,
297 PCI_ANY_ID, PCI_ANY_ID,
298 0, 0,
299 0
300 },
301 {
302 0x1571, 0xa008,
303 PCI_ANY_ID, PCI_ANY_ID,
304 0, 0,
305 0
306 },
307 {
308 0x1571, 0xa009,
309 PCI_ANY_ID, PCI_ANY_ID,
310 0, 0,
311 (kernel_ulong_t)&card_info_5mbit
312 },
313 {
314 0x1571, 0xa00a,
315 PCI_ANY_ID, PCI_ANY_ID,
316 0, 0,
317 (kernel_ulong_t)&card_info_5mbit
318 },
319 {
320 0x1571, 0xa00b,
321 PCI_ANY_ID, PCI_ANY_ID,
322 0, 0,
323 (kernel_ulong_t)&card_info_5mbit
324 },
325 {
326 0x1571, 0xa00c,
327 PCI_ANY_ID, PCI_ANY_ID,
328 0, 0,
329 (kernel_ulong_t)&card_info_5mbit
330 },
331 {
332 0x1571, 0xa00d,
333 PCI_ANY_ID, PCI_ANY_ID,
334 0, 0,
335 (kernel_ulong_t)&card_info_5mbit
336 },
337 {
338 0x1571, 0xa00e,
339 PCI_ANY_ID, PCI_ANY_ID,
340 0, 0,
341 (kernel_ulong_t)&card_info_5mbit
342 },
343 {
344 0x1571, 0xa201,
345 PCI_ANY_ID, PCI_ANY_ID,
346 0, 0,
347 (kernel_ulong_t)&card_info_10mbit
348 },
349 {
350 0x1571, 0xa202,
351 PCI_ANY_ID, PCI_ANY_ID,
352 0, 0,
353 (kernel_ulong_t)&card_info_10mbit
354 },
355 {
356 0x1571, 0xa203,
357 PCI_ANY_ID, PCI_ANY_ID,
358 0, 0,
359 (kernel_ulong_t)&card_info_10mbit
360 },
361 {
362 0x1571, 0xa204,
363 PCI_ANY_ID, PCI_ANY_ID,
364 0, 0,
365 (kernel_ulong_t)&card_info_10mbit
366 },
367 {
368 0x1571, 0xa205,
369 PCI_ANY_ID, PCI_ANY_ID,
370 0, 0,
371 (kernel_ulong_t)&card_info_10mbit
372 },
373 {
374 0x1571, 0xa206,
375 PCI_ANY_ID, PCI_ANY_ID,
376 0, 0,
377 (kernel_ulong_t)&card_info_10mbit
378 },
379 {
380 0x10B5, 0x9030,
381 0x10B5, 0x2978,
382 0, 0,
383 (kernel_ulong_t)&card_info_sohard
384 },
385 {
386 0x10B5, 0x9050,
387 0x10B5, 0x2273,
388 0, 0,
389 (kernel_ulong_t)&card_info_sohard
390 },
391 {
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200392 0x10B5, 0x9050,
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100393 0x10B5, 0x3263,
394 0, 0,
395 (kernel_ulong_t)&card_info_eae_arc1
396 },
397 {
398 0x10B5, 0x9050,
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200399 0x10B5, 0x3292,
400 0, 0,
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100401 (kernel_ulong_t)&card_info_eae_ma1
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200402 },
403 {
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200404 0x14BA, 0x6000,
405 PCI_ANY_ID, PCI_ANY_ID,
406 0, 0,
407 (kernel_ulong_t)&card_info_10mbit
408 },
409 {
410 0x10B5, 0x2200,
411 PCI_ANY_ID, PCI_ANY_ID,
412 0, 0,
413 (kernel_ulong_t)&card_info_10mbit
414 },
415 { 0, }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416};
417
418MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
419
420static struct pci_driver com20020pci_driver = {
421 .name = "com20020",
422 .id_table = com20020pci_id_table,
423 .probe = com20020pci_probe,
Bill Pemberton7c47bab2012-12-03 09:22:43 -0500424 .remove = com20020pci_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425};
426
427static int __init com20020pci_init(void)
428{
Joe Perches72aeea42015-05-05 10:05:54 -0700429 if (BUGLVL(D_NORMAL))
Joe Perches05a24b22015-05-05 10:05:56 -0700430 pr_info("%s\n", "COM20020 PCI support");
Jeff Garzik29917622006-08-19 17:48:59 -0400431 return pci_register_driver(&com20020pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432}
433
434static void __exit com20020pci_cleanup(void)
435{
436 pci_unregister_driver(&com20020pci_driver);
437}
438
439module_init(com20020pci_init)
440module_exit(com20020pci_cleanup)