xref: /openbmc/linux/drivers/net/arcnet/com20020-pci.c (revision 372892ec1151c895c7dec362f3246f089690cfc7)
1 /*
2  * Linux ARCnet driver - COM20020 PCI support
3  * Contemporary Controls PCI20 and SOHARD SH-ARC PCI
4  *
5  * 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  */
29 
30 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
31 
32 #include <linux/module.h>
33 #include <linux/moduleparam.h>
34 #include <linux/kernel.h>
35 #include <linux/types.h>
36 #include <linux/ioport.h>
37 #include <linux/errno.h>
38 #include <linux/netdevice.h>
39 #include <linux/init.h>
40 #include <linux/interrupt.h>
41 #include <linux/pci.h>
42 #include <linux/list.h>
43 #include <linux/io.h>
44 
45 #include "arcdevice.h"
46 #include "com20020.h"
47 
48 /* Module parameters */
49 
50 static int node;
51 static char device[9];		/* use eg. device="arc1" to change name */
52 static int timeout = 3;
53 static int backplane;
54 static int clockp;
55 static int clockm;
56 
57 module_param(node, int, 0);
58 module_param_string(device, device, sizeof(device), 0);
59 module_param(timeout, int, 0);
60 module_param(backplane, int, 0);
61 module_param(clockp, int, 0);
62 module_param(clockm, int, 0);
63 MODULE_LICENSE("GPL");
64 
65 static void com20020pci_remove(struct pci_dev *pdev);
66 
67 static int com20020pci_probe(struct pci_dev *pdev,
68 			     const struct pci_device_id *id)
69 {
70 	struct com20020_pci_card_info *ci;
71 	struct net_device *dev;
72 	struct arcnet_local *lp;
73 	struct com20020_priv *priv;
74 	int i, ioaddr, ret;
75 	struct resource *r;
76 
77 	if (pci_enable_device(pdev))
78 		return -EIO;
79 
80 	priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
81 			    GFP_KERNEL);
82 	if (!priv)
83 		return -ENOMEM;
84 
85 	ci = (struct com20020_pci_card_info *)id->driver_data;
86 	priv->ci = ci;
87 
88 	INIT_LIST_HEAD(&priv->list_dev);
89 
90 	for (i = 0; i < ci->devcount; i++) {
91 		struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
92 		struct com20020_dev *card;
93 
94 		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 
104 		arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
105 		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) {
110 			pr_err("IO region %xh-%xh already allocated\n",
111 			       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 		 */
120 		arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
121 		arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
122 
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 
134 		if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
135 			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);
146 		if (!card)
147 			return -ENOMEM;
148 
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);
160 	}
161 
162 	pci_set_drvdata(pdev, priv);
163 
164 	return 0;
165 
166 out_port:
167 	com20020pci_remove(pdev);
168 	return ret;
169 }
170 
171 static void com20020pci_remove(struct pci_dev *pdev)
172 {
173 	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 	}
185 }
186 
187 static struct com20020_pci_card_info card_info_10mbit = {
188 	.name = "ARC-PCI",
189 	.devcount = 1,
190 	.chan_map_tbl = {
191 		{
192 			.bar = 2,
193 			.offset = 0x00,
194 			.size = 0x08,
195 		},
196 	},
197 	.flags = ARC_CAN_10MBIT,
198 };
199 
200 static struct com20020_pci_card_info card_info_5mbit = {
201 	.name = "ARC-PCI",
202 	.devcount = 1,
203 	.chan_map_tbl = {
204 		{
205 			.bar = 2,
206 			.offset = 0x00,
207 			.size = 0x08,
208 		},
209 	},
210 	.flags = ARC_IS_5MBIT,
211 };
212 
213 static 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 = {
218 		{
219 			.bar = 4,
220 			.offset = 0x00,
221 			.size = 0x08
222 		},
223 	},
224 	.flags = ARC_CAN_10MBIT,
225 };
226 
227 static struct com20020_pci_card_info card_info_eae_arc1 = {
228 	.name = "EAE PLX-PCI ARC1",
229 	.devcount = 1,
230 	.chan_map_tbl = {
231 		{
232 			.bar = 2,
233 			.offset = 0x00,
234 			.size = 0x08,
235 		},
236 	},
237 	.flags = ARC_CAN_10MBIT,
238 };
239 
240 static struct com20020_pci_card_info card_info_eae_ma1 = {
241 	.name = "EAE PLX-PCI MA1",
242 	.devcount = 2,
243 	.chan_map_tbl = {
244 		{
245 			.bar = 2,
246 			.offset = 0x00,
247 			.size = 0x08,
248 		}, {
249 			.bar = 2,
250 			.offset = 0x08,
251 			.size = 0x08,
252 		}
253 	},
254 	.flags = ARC_CAN_10MBIT,
255 };
256 
257 static const struct pci_device_id com20020pci_id_table[] = {
258 	{
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 	{
391 		0x10B5, 0x9050,
392 		0x10B5, 0x3263,
393 		0, 0,
394 		(kernel_ulong_t)&card_info_eae_arc1
395 	},
396 	{
397 		0x10B5, 0x9050,
398 		0x10B5, 0x3292,
399 		0, 0,
400 		(kernel_ulong_t)&card_info_eae_ma1
401 	},
402 	{
403 		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, }
415 };
416 
417 MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
418 
419 static struct pci_driver com20020pci_driver = {
420 	.name		= "com20020",
421 	.id_table	= com20020pci_id_table,
422 	.probe		= com20020pci_probe,
423 	.remove		= com20020pci_remove,
424 };
425 
426 static int __init com20020pci_init(void)
427 {
428 	if (BUGLVL(D_NORMAL))
429 		pr_info("%s\n", "COM20020 PCI support");
430 	return pci_register_driver(&com20020pci_driver);
431 }
432 
433 static void __exit com20020pci_cleanup(void)
434 {
435 	pci_unregister_driver(&com20020pci_driver);
436 }
437 
438 module_init(com20020pci_init)
439 module_exit(com20020pci_cleanup)
440