blob: dc85282193bf2e415ec18249d58fa8e58098a858 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 A PCMCIA token-ring driver for IBM-based cards
4
5 This driver supports the IBM PCMCIA Token-Ring Card.
6 Written by Steve Kipisz, kipisz@vnet.ibm.com or
7 bungy@ibm.net
8
9 Written 1995,1996.
10
11 This code is based on pcnet_cs.c from David Hinds.
12
13 V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
14
15 Linux V2.2.x presented significant changes to the underlying
16 ibmtr.c code. Mainly the code became a lot more organized and
17 modular.
18
19 This caused the old PCMCIA Token Ring driver to give up and go
20 home early. Instead of just patching the old code to make it
21 work, the PCMCIA code has been streamlined, updated and possibly
22 improved.
23
24 This code now only contains code required for the Card Services.
25 All we do here is set the card up enough so that the real ibmtr.c
26 driver can find it and work with it properly.
27
28 i.e. We set up the io port, irq, mmio memory and shared ram
29 memory. This enables ibmtr_probe in ibmtr.c to find the card and
30 configure it as though it was a normal ISA and/or PnP card.
31
32 CHANGES
33
34 v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
35 Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
36
37 v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
38 Updated to version 2.2.7 to match the first version of the kernel
39 that the modification to ibmtr.c were incorporated into.
40
41 v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com)
42 Address translation feature of PCMCIA controller is usable so
43 memory windows can be placed in High memory (meaning above
44 0xFFFFF.)
45
46======================================================================*/
47
Joe Perches636b8112010-08-12 12:22:51 +000048#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/init.h>
52#include <linux/ptrace.h>
53#include <linux/slab.h>
54#include <linux/string.h>
55#include <linux/timer.h>
56#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/netdevice.h>
58#include <linux/trdevice.h>
59#include <linux/ibmtr.h>
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <pcmcia/cs.h>
62#include <pcmcia/cistpl.h>
63#include <pcmcia/ds.h>
64
65#include <asm/uaccess.h>
66#include <asm/io.h>
67#include <asm/system.h>
68
69#define PCMCIA
70#include "../tokenring/ibmtr.c"
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73/*====================================================================*/
74
75/* Parameters that can be set with 'insmod' */
76
77/* MMIO base address */
78static u_long mmiobase = 0xce000;
79
80/* SRAM base address */
81static u_long srambase = 0xd0000;
82
83/* SRAM size 8,16,32,64 */
84static u_long sramsize = 64;
85
86/* Ringspeed 4,16 */
87static int ringspeed = 16;
88
89module_param(mmiobase, ulong, 0);
90module_param(srambase, ulong, 0);
91module_param(sramsize, ulong, 0);
92module_param(ringspeed, int, 0);
93MODULE_LICENSE("GPL");
94
95/*====================================================================*/
96
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020097static int ibmtr_config(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020099static void ibmtr_release(struct pcmcia_device *link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100100static void ibmtr_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102/*====================================================================*/
103
104typedef struct ibmtr_dev_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100105 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 window_handle_t sram_win_handle;
108 struct tok_info *ti;
109} ibmtr_dev_t;
110
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100111static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
112 ibmtr_dev_t *info = dev_id;
113 struct net_device *dev = info->dev;
114 return tok_interrupt(irq, dev);
115};
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*======================================================================
118
119 ibmtr_attach() creates an "instance" of the driver, allocating
120 local data structures for one device. The device is registered
121 with Card Services.
122
123======================================================================*/
124
Al Viroabf04372007-03-14 09:04:21 +0000125static int __devinit ibmtr_attach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
127 ibmtr_dev_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 struct net_device *dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200129
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200130 dev_dbg(&link->dev, "ibmtr_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 /* Create new token-ring device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700133 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100134 if (!info) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 dev = alloc_trdev(sizeof(struct tok_info));
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100136 if (!dev) {
137 kfree(info);
138 return -ENOMEM;
139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200141 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 link->priv = info;
143 info->ti = netdev_priv(dev);
144
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200145 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
146 link->resource[0]->end = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 link->conf.IntType = INT_MEMORY_AND_IO;
149 link->conf.Present = PRESENT_OPTION;
150
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100151 info->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200153 return ibmtr_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154} /* ibmtr_attach */
155
156/*======================================================================
157
158 This deletes a driver "instance". The device is de-registered
159 with Card Services. If it has been released, all local data
160 structures are freed. Otherwise, the structures will be freed
161 when the device is released.
162
163======================================================================*/
164
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200165static void ibmtr_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166{
167 struct ibmtr_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100168 struct net_device *dev = info->dev;
Paul Walmsley5bebf822007-05-09 10:47:16 -0600169 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200171 dev_dbg(&link->dev, "ibmtr_detach\n");
Paul Walmsley5bebf822007-05-09 10:47:16 -0600172
173 /*
174 * When the card removal interrupt hits tok_interrupt(),
175 * bail out early, so we don't crash the machine
176 */
177 ti->sram_phys |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100179 unregister_netdev(dev);
Paul Walmsley5bebf822007-05-09 10:47:16 -0600180
181 del_timer_sync(&(ti->tr_timer));
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100182
183 ibmtr_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100186 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187} /* ibmtr_detach */
188
189/*======================================================================
190
191 ibmtr_config() is scheduled to run after a CARD_INSERTION event
192 is received, to configure the PCMCIA socket, and to make the
193 token-ring device available to the system.
194
195======================================================================*/
196
Al Viroabf04372007-03-14 09:04:21 +0000197static int __devinit ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 ibmtr_dev_t *info = link->priv;
200 struct net_device *dev = info->dev;
201 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 win_req_t req;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200203 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200205 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 link->conf.ConfigIndex = 0x61;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200208 link->io_lines = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210 /* Determine if this is PRIMARY or ALTERNATE. */
211
212 /* Try PRIMARY card at 0xA20-0xA23 */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200213 link->resource[0]->start = 0xA20;
214 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200215 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200217 link->resource[0]->start = 0xA24;
218 ret = pcmcia_request_io(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200219 if (ret)
220 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200222 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Dominik Brodowskieb141202010-03-07 12:21:16 +0100224 ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200225 if (ret)
226 goto failed;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100227 dev->irq = link->irq;
228 ti->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
230
231 /* Allocate the MMIO memory window */
232 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
233 req.Attributes |= WIN_USE_WAIT;
234 req.Base = 0;
235 req.Size = 0x2000;
236 req.AccessSpeed = 250;
Dominik Brodowski6838b032009-11-03 01:31:52 +0100237 ret = pcmcia_request_window(link, &req, &link->win);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200238 if (ret)
239 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200241 ret = pcmcia_map_mem_page(link, link->win, mmiobase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200242 if (ret)
243 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 ti->mmio = ioremap(req.Base, req.Size);
245
246 /* Allocate the SRAM memory window */
247 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
248 req.Attributes |= WIN_USE_WAIT;
249 req.Base = 0;
250 req.Size = sramsize * 1024;
251 req.AccessSpeed = 250;
Dominik Brodowski6838b032009-11-03 01:31:52 +0100252 ret = pcmcia_request_window(link, &req, &info->sram_win_handle);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200253 if (ret)
254 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200256 ret = pcmcia_map_mem_page(link, info->sram_win_handle, srambase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200257 if (ret)
258 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200260 ti->sram_base = srambase >> 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 ti->sram_virt = ioremap(req.Base, req.Size);
262 ti->sram_phys = req.Base;
263
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200264 ret = pcmcia_request_configuration(link, &link->conf);
265 if (ret)
266 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 /* Set up the Token-Ring Controller Configuration Register and
269 turn on the card. Check the "Local Area Network Credit Card
270 Adapters Technical Reference" SC30-3585 for this info. */
271 ibmtr_hw_setup(dev, mmiobase);
272
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100273 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 i = ibmtr_probe_card(dev);
276 if (i != 0) {
Joe Perches636b8112010-08-12 12:22:51 +0000277 pr_notice("register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 goto failed;
279 }
280
Joe Perches636b8112010-08-12 12:22:51 +0000281 netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
282 dev->base_addr, dev->irq,
283 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
284 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200285 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287failed:
288 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200289 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290} /* ibmtr_config */
291
292/*======================================================================
293
294 After a card is removed, ibmtr_release() will unregister the net
295 device, and release the PCMCIA configuration. If the device is
296 still open, this will be postponed until it is closed.
297
298======================================================================*/
299
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200300static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100302 ibmtr_dev_t *info = link->priv;
303 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200305 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100307 if (link->win) {
308 struct tok_info *ti = netdev_priv(dev);
309 iounmap(ti->mmio);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100310 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200311 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200314static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100315{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100316 ibmtr_dev_t *info = link->priv;
317 struct net_device *dev = info->dev;
318
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100319 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100320 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100321
322 return 0;
323}
324
Al Viro8814b502008-11-22 17:35:44 +0000325static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100326{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100327 ibmtr_dev_t *info = link->priv;
328 struct net_device *dev = info->dev;
329
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100330 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100331 ibmtr_probe(dev); /* really? */
332 netif_device_attach(dev);
333 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100334
335 return 0;
336}
337
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339/*====================================================================*/
340
341static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
342{
343 int i;
344
345 /* Bizarre IBM behavior, there are 16 bits of information we
346 need to set, but the card only allows us to send 4 bits at a
347 time. For each byte sent to base_addr, bits 7-4 tell the
348 card which part of the 16 bits we are setting, bits 3-0 contain
349 the actual information */
350
351 /* First nibble provides 4 bits of mmio */
352 i = (mmiobase >> 16) & 0x0F;
353 outb(i, dev->base_addr);
354
355 /* Second nibble provides 3 bits of mmio */
356 i = 0x10 | ((mmiobase >> 12) & 0x0E);
357 outb(i, dev->base_addr);
358
359 /* Third nibble, hard-coded values */
360 i = 0x26;
361 outb(i, dev->base_addr);
362
363 /* Fourth nibble sets shared ram page size */
364
365 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
366 i = (sramsize >> 4) & 0x07;
367 i = ((i == 4) ? 3 : i) << 2;
368 i |= 0x30;
369
370 if (ringspeed == 16)
371 i |= 2;
372 if (dev->base_addr == 0xA24)
373 i |= 1;
374 outb(i, dev->base_addr);
375
376 /* 0x40 will release the card for use */
377 outb(0x40, dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700380static struct pcmcia_device_id ibmtr_ids[] = {
381 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
382 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
383 PCMCIA_DEVICE_NULL,
384};
385MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387static struct pcmcia_driver ibmtr_cs_driver = {
388 .owner = THIS_MODULE,
389 .drv = {
390 .name = "ibmtr_cs",
391 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100392 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100393 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700394 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100395 .suspend = ibmtr_suspend,
396 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397};
398
399static int __init init_ibmtr_cs(void)
400{
401 return pcmcia_register_driver(&ibmtr_cs_driver);
402}
403
404static void __exit exit_ibmtr_cs(void)
405{
406 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407}
408
409module_init(init_ibmtr_cs);
410module_exit(exit_ibmtr_cs);