blob: a12bf83be7502dd6e4262907a45dc05efb090b80 [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 }
99
100 dev->netdev_ops = &com20020_netdev_ops;
101
102 lp = netdev_priv(dev);
103
Joe Perchesa34c0932015-05-05 10:05:55 -0700104 arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
Michael Grzeschikc51da422014-09-29 11:55:37 +0200105 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
106
107 r = devm_request_region(&pdev->dev, ioaddr, cm->size,
108 "com20020-pci");
109 if (!r) {
Joe Perches05a24b22015-05-05 10:05:56 -0700110 pr_err("IO region %xh-%xh already allocated\n",
Michael Grzeschikc51da422014-09-29 11:55:37 +0200111 ioaddr, ioaddr + cm->size - 1);
112 ret = -EBUSY;
113 goto out_port;
114 }
115
116 /* Dummy access after Reset
117 * ARCNET controller needs
118 * this access to detect bustype
119 */
Joe Perches0fec6512015-05-05 10:06:06 -0700120 arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
121 arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
Michael Grzeschikc51da422014-09-29 11:55:37 +0200122
123 dev->base_addr = ioaddr;
124 dev->dev_addr[0] = node;
125 dev->irq = pdev->irq;
126 lp->card_name = "PCI COM20020";
127 lp->card_flags = ci->flags;
128 lp->backplane = backplane;
129 lp->clockp = clockp & 7;
130 lp->clockm = clockm & 3;
131 lp->timeout = timeout;
132 lp->hw.owner = THIS_MODULE;
133
Joe Perches0fec6512015-05-05 10:06:06 -0700134 if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
Michael Grzeschikc51da422014-09-29 11:55:37 +0200135 pr_err("IO address %Xh is empty!\n", ioaddr);
136 ret = -EIO;
137 goto out_port;
138 }
139 if (com20020_check(dev)) {
140 ret = -EIO;
141 goto out_port;
142 }
143
144 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
145 GFP_KERNEL);
Joe Perches5628d982015-05-05 10:05:58 -0700146 if (!card)
Michael Grzeschikc51da422014-09-29 11:55:37 +0200147 return -ENOMEM;
Michael Grzeschikc51da422014-09-29 11:55:37 +0200148
149 card->index = i;
150 card->pci_priv = priv;
151 card->dev = dev;
152
153 dev_set_drvdata(&dev->dev, card);
154
155 ret = com20020_found(dev, IRQF_SHARED);
156 if (ret)
157 goto out_port;
158
159 list_add(&card->list, &priv->list_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161
Michael Grzeschikc51da422014-09-29 11:55:37 +0200162 pci_set_drvdata(pdev, priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 return 0;
165
166out_port:
Michael Grzeschikc51da422014-09-29 11:55:37 +0200167 com20020pci_remove(pdev);
168 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169}
170
Bill Pemberton7c47bab2012-12-03 09:22:43 -0500171static void com20020pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
Michael Grzeschikc51da422014-09-29 11:55:37 +0200173 struct com20020_dev *card, *tmpcard;
174 struct com20020_priv *priv;
175
176 priv = pci_get_drvdata(pdev);
177
178 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
179 struct net_device *dev = card->dev;
180
181 unregister_netdev(dev);
182 free_irq(dev->irq, dev);
183 free_netdev(dev);
184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200187static struct com20020_pci_card_info card_info_10mbit = {
188 .name = "ARC-PCI",
189 .devcount = 1,
190 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100191 {
192 .bar = 2,
193 .offset = 0x00,
194 .size = 0x08,
195 },
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200196 },
197 .flags = ARC_CAN_10MBIT,
198};
199
200static struct com20020_pci_card_info card_info_5mbit = {
201 .name = "ARC-PCI",
202 .devcount = 1,
203 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100204 {
205 .bar = 2,
206 .offset = 0x00,
207 .size = 0x08,
208 },
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200209 },
210 .flags = ARC_IS_5MBIT,
211};
212
213static struct com20020_pci_card_info card_info_sohard = {
214 .name = "PLX-PCI",
215 .devcount = 1,
216 /* SOHARD needs PCI base addr 4 */
217 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100218 {
219 .bar = 4,
220 .offset = 0x00,
221 .size = 0x08
222 },
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200223 },
224 .flags = ARC_CAN_10MBIT,
225};
226
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100227static struct com20020_pci_card_info card_info_eae_arc1 = {
228 .name = "EAE PLX-PCI ARC1",
229 .devcount = 1,
230 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100231 {
232 .bar = 2,
233 .offset = 0x00,
234 .size = 0x08,
235 },
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100236 },
237 .flags = ARC_CAN_10MBIT,
238};
239
240static struct com20020_pci_card_info card_info_eae_ma1 = {
241 .name = "EAE PLX-PCI MA1",
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200242 .devcount = 2,
243 .chan_map_tbl = {
Michael Grzeschik54a84c62015-03-20 15:22:02 +0100244 {
245 .bar = 2,
246 .offset = 0x00,
247 .size = 0x08,
248 }, {
249 .bar = 2,
250 .offset = 0x08,
251 .size = 0x08,
252 }
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200253 },
254 .flags = ARC_CAN_10MBIT,
255};
256
Benoit Taine9baa3c32014-08-08 15:56:03 +0200257static const struct pci_device_id com20020pci_id_table[] = {
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200258 {
259 0x1571, 0xa001,
260 PCI_ANY_ID, PCI_ANY_ID,
261 0, 0,
262 0,
263 },
264 {
265 0x1571, 0xa002,
266 PCI_ANY_ID, PCI_ANY_ID,
267 0, 0,
268 0,
269 },
270 {
271 0x1571, 0xa003,
272 PCI_ANY_ID, PCI_ANY_ID,
273 0, 0,
274 0
275 },
276 {
277 0x1571, 0xa004,
278 PCI_ANY_ID, PCI_ANY_ID,
279 0, 0,
280 0,
281 },
282 {
283 0x1571, 0xa005,
284 PCI_ANY_ID, PCI_ANY_ID,
285 0, 0,
286 0
287 },
288 {
289 0x1571, 0xa006,
290 PCI_ANY_ID, PCI_ANY_ID,
291 0, 0,
292 0
293 },
294 {
295 0x1571, 0xa007,
296 PCI_ANY_ID, PCI_ANY_ID,
297 0, 0,
298 0
299 },
300 {
301 0x1571, 0xa008,
302 PCI_ANY_ID, PCI_ANY_ID,
303 0, 0,
304 0
305 },
306 {
307 0x1571, 0xa009,
308 PCI_ANY_ID, PCI_ANY_ID,
309 0, 0,
310 (kernel_ulong_t)&card_info_5mbit
311 },
312 {
313 0x1571, 0xa00a,
314 PCI_ANY_ID, PCI_ANY_ID,
315 0, 0,
316 (kernel_ulong_t)&card_info_5mbit
317 },
318 {
319 0x1571, 0xa00b,
320 PCI_ANY_ID, PCI_ANY_ID,
321 0, 0,
322 (kernel_ulong_t)&card_info_5mbit
323 },
324 {
325 0x1571, 0xa00c,
326 PCI_ANY_ID, PCI_ANY_ID,
327 0, 0,
328 (kernel_ulong_t)&card_info_5mbit
329 },
330 {
331 0x1571, 0xa00d,
332 PCI_ANY_ID, PCI_ANY_ID,
333 0, 0,
334 (kernel_ulong_t)&card_info_5mbit
335 },
336 {
337 0x1571, 0xa00e,
338 PCI_ANY_ID, PCI_ANY_ID,
339 0, 0,
340 (kernel_ulong_t)&card_info_5mbit
341 },
342 {
343 0x1571, 0xa201,
344 PCI_ANY_ID, PCI_ANY_ID,
345 0, 0,
346 (kernel_ulong_t)&card_info_10mbit
347 },
348 {
349 0x1571, 0xa202,
350 PCI_ANY_ID, PCI_ANY_ID,
351 0, 0,
352 (kernel_ulong_t)&card_info_10mbit
353 },
354 {
355 0x1571, 0xa203,
356 PCI_ANY_ID, PCI_ANY_ID,
357 0, 0,
358 (kernel_ulong_t)&card_info_10mbit
359 },
360 {
361 0x1571, 0xa204,
362 PCI_ANY_ID, PCI_ANY_ID,
363 0, 0,
364 (kernel_ulong_t)&card_info_10mbit
365 },
366 {
367 0x1571, 0xa205,
368 PCI_ANY_ID, PCI_ANY_ID,
369 0, 0,
370 (kernel_ulong_t)&card_info_10mbit
371 },
372 {
373 0x1571, 0xa206,
374 PCI_ANY_ID, PCI_ANY_ID,
375 0, 0,
376 (kernel_ulong_t)&card_info_10mbit
377 },
378 {
379 0x10B5, 0x9030,
380 0x10B5, 0x2978,
381 0, 0,
382 (kernel_ulong_t)&card_info_sohard
383 },
384 {
385 0x10B5, 0x9050,
386 0x10B5, 0x2273,
387 0, 0,
388 (kernel_ulong_t)&card_info_sohard
389 },
390 {
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200391 0x10B5, 0x9050,
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100392 0x10B5, 0x3263,
393 0, 0,
394 (kernel_ulong_t)&card_info_eae_arc1
395 },
396 {
397 0x10B5, 0x9050,
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200398 0x10B5, 0x3292,
399 0, 0,
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100400 (kernel_ulong_t)&card_info_eae_ma1
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200401 },
402 {
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200403 0x14BA, 0x6000,
404 PCI_ANY_ID, PCI_ANY_ID,
405 0, 0,
406 (kernel_ulong_t)&card_info_10mbit
407 },
408 {
409 0x10B5, 0x2200,
410 PCI_ANY_ID, PCI_ANY_ID,
411 0, 0,
412 (kernel_ulong_t)&card_info_10mbit
413 },
414 { 0, }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415};
416
417MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
418
419static struct pci_driver com20020pci_driver = {
420 .name = "com20020",
421 .id_table = com20020pci_id_table,
422 .probe = com20020pci_probe,
Bill Pemberton7c47bab2012-12-03 09:22:43 -0500423 .remove = com20020pci_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424};
425
426static int __init com20020pci_init(void)
427{
Joe Perches72aeea42015-05-05 10:05:54 -0700428 if (BUGLVL(D_NORMAL))
Joe Perches05a24b22015-05-05 10:05:56 -0700429 pr_info("%s\n", "COM20020 PCI support");
Jeff Garzik29917622006-08-19 17:48:59 -0400430 return pci_register_driver(&com20020pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431}
432
433static void __exit com20020pci_cleanup(void)
434{
435 pci_unregister_driver(&com20020pci_driver);
436}
437
438module_init(com20020pci_init)
439module_exit(com20020pci_cleanup)