blob: feedeeb17a52ce4e0a988efb11e4827f765c155f [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
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/ptrace.h>
51#include <linux/slab.h>
52#include <linux/string.h>
53#include <linux/timer.h>
54#include <linux/module.h>
55#include <linux/ethtool.h>
56#include <linux/netdevice.h>
57#include <linux/trdevice.h>
58#include <linux/ibmtr.h>
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <pcmcia/cs.h>
61#include <pcmcia/cistpl.h>
62#include <pcmcia/ds.h>
63
64#include <asm/uaccess.h>
65#include <asm/io.h>
66#include <asm/system.h>
67
68#define PCMCIA
69#include "../tokenring/ibmtr.c"
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72/*====================================================================*/
73
74/* Parameters that can be set with 'insmod' */
75
76/* MMIO base address */
77static u_long mmiobase = 0xce000;
78
79/* SRAM base address */
80static u_long srambase = 0xd0000;
81
82/* SRAM size 8,16,32,64 */
83static u_long sramsize = 64;
84
85/* Ringspeed 4,16 */
86static int ringspeed = 16;
87
88module_param(mmiobase, ulong, 0);
89module_param(srambase, ulong, 0);
90module_param(sramsize, ulong, 0);
91module_param(ringspeed, int, 0);
92MODULE_LICENSE("GPL");
93
94/*====================================================================*/
95
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020096static int ibmtr_config(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020098static void ibmtr_release(struct pcmcia_device *link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010099static void ibmtr_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/*====================================================================*/
102
103typedef struct ibmtr_dev_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100104 struct pcmcia_device *p_dev;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200105 struct net_device *dev;
106 struct tok_info *ti;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107} ibmtr_dev_t;
108
109static void netdev_get_drvinfo(struct net_device *dev,
110 struct ethtool_drvinfo *info)
111{
112 strcpy(info->driver, "ibmtr_cs");
113}
114
Jeff Garzik7282d492006-09-13 14:30:00 -0400115static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 .get_drvinfo = netdev_get_drvinfo,
117};
118
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100119static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
120 ibmtr_dev_t *info = dev_id;
121 struct net_device *dev = info->dev;
122 return tok_interrupt(irq, dev);
123};
124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125/*======================================================================
126
127 ibmtr_attach() creates an "instance" of the driver, allocating
128 local data structures for one device. The device is registered
129 with Card Services.
130
131======================================================================*/
132
Al Viroabf04372007-03-14 09:04:21 +0000133static int __devinit ibmtr_attach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
135 ibmtr_dev_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 struct net_device *dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200137
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200138 dev_dbg(&link->dev, "ibmtr_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 /* Create new token-ring device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700141 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100142 if (!info) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 dev = alloc_trdev(sizeof(struct tok_info));
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100144 if (!dev) {
145 kfree(info);
146 return -ENOMEM;
147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200149 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 link->priv = info;
151 info->ti = netdev_priv(dev);
152
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200153 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
154 link->resource[0]->end = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 link->conf.Attributes = CONF_ENABLE_IRQ;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200156 link->config_regs = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100158 info->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Dominik Brodowskifd238232006-03-05 10:45:09 +0100160 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200162 return ibmtr_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163} /* ibmtr_attach */
164
165/*======================================================================
166
167 This deletes a driver "instance". The device is de-registered
168 with Card Services. If it has been released, all local data
169 structures are freed. Otherwise, the structures will be freed
170 when the device is released.
171
172======================================================================*/
173
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200174static void ibmtr_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 struct ibmtr_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100177 struct net_device *dev = info->dev;
Paul Walmsley5bebf822007-05-09 10:47:16 -0600178 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200180 dev_dbg(&link->dev, "ibmtr_detach\n");
Paul Walmsley5bebf822007-05-09 10:47:16 -0600181
182 /*
183 * When the card removal interrupt hits tok_interrupt(),
184 * bail out early, so we don't crash the machine
185 */
186 ti->sram_phys |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100188 unregister_netdev(dev);
Paul Walmsley5bebf822007-05-09 10:47:16 -0600189
190 del_timer_sync(&(ti->tr_timer));
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100191
192 ibmtr_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100195 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196} /* ibmtr_detach */
197
198/*======================================================================
199
200 ibmtr_config() is scheduled to run after a CARD_INSERTION event
201 is received, to configure the PCMCIA socket, and to make the
202 token-ring device available to the system.
203
204======================================================================*/
205
Al Viroabf04372007-03-14 09:04:21 +0000206static int __devinit ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 ibmtr_dev_t *info = link->priv;
209 struct net_device *dev = info->dev;
210 struct tok_info *ti = netdev_priv(dev);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200211 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200213 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200215 link->io_lines = 16;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200216 link->config_index = 0x61;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 /* Determine if this is PRIMARY or ALTERNATE. */
219
220 /* Try PRIMARY card at 0xA20-0xA23 */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200221 link->resource[0]->start = 0xA20;
222 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200223 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200225 link->resource[0]->start = 0xA24;
226 ret = pcmcia_request_io(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200227 if (ret)
228 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200230 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Dominik Brodowskieb141202010-03-07 12:21:16 +0100232 ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200233 if (ret)
234 goto failed;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100235 dev->irq = link->irq;
236 ti->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
238
239 /* Allocate the MMIO memory window */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200240 link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
241 link->resource[2]->flags |= WIN_USE_WAIT;
242 link->resource[2]->start = 0;
243 link->resource[2]->end = 0x2000;
244 ret = pcmcia_request_window(link, link->resource[2], 250);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200245 if (ret)
246 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200248 ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200249 if (ret)
250 goto failed;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200251 ti->mmio = ioremap(link->resource[2]->start,
252 resource_size(link->resource[2]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 /* Allocate the SRAM memory window */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200255 link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
256 link->resource[3]->flags |= WIN_USE_WAIT;
257 link->resource[3]->start = 0;
258 link->resource[3]->end = sramsize * 1024;
259 ret = pcmcia_request_window(link, link->resource[3], 250);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200260 if (ret)
261 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200263 ret = pcmcia_map_mem_page(link, link->resource[3], srambase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200264 if (ret)
265 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200267 ti->sram_base = srambase >> 12;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200268 ti->sram_virt = ioremap(link->resource[3]->start,
269 resource_size(link->resource[3]));
270 ti->sram_phys = link->resource[3]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200272 ret = pcmcia_request_configuration(link, &link->conf);
273 if (ret)
274 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276 /* Set up the Token-Ring Controller Configuration Register and
277 turn on the card. Check the "Local Area Network Credit Card
278 Adapters Technical Reference" SC30-3585 for this info. */
279 ibmtr_hw_setup(dev, mmiobase);
280
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100281 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 i = ibmtr_probe_card(dev);
284 if (i != 0) {
285 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 goto failed;
287 }
288
Joe Perchesad361c92009-07-06 13:05:40 -0700289 printk(KERN_INFO
290 "%s: port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
291 dev->name, dev->base_addr, dev->irq,
292 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
293 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200294 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296failed:
297 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200298 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299} /* ibmtr_config */
300
301/*======================================================================
302
303 After a card is removed, ibmtr_release() will unregister the net
304 device, and release the PCMCIA configuration. If the device is
305 still open, this will be postponed until it is closed.
306
307======================================================================*/
308
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200309static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100311 ibmtr_dev_t *info = link->priv;
312 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200314 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200316 if (link->resource[2]->end) {
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100317 struct tok_info *ti = netdev_priv(dev);
318 iounmap(ti->mmio);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100319 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200320 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321}
322
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200323static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100324{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100325 ibmtr_dev_t *info = link->priv;
326 struct net_device *dev = info->dev;
327
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100328 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100329 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100330
331 return 0;
332}
333
Al Viro8814b502008-11-22 17:35:44 +0000334static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100335{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100336 ibmtr_dev_t *info = link->priv;
337 struct net_device *dev = info->dev;
338
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100339 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100340 ibmtr_probe(dev); /* really? */
341 netif_device_attach(dev);
342 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100343
344 return 0;
345}
346
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348/*====================================================================*/
349
350static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
351{
352 int i;
353
354 /* Bizarre IBM behavior, there are 16 bits of information we
355 need to set, but the card only allows us to send 4 bits at a
356 time. For each byte sent to base_addr, bits 7-4 tell the
357 card which part of the 16 bits we are setting, bits 3-0 contain
358 the actual information */
359
360 /* First nibble provides 4 bits of mmio */
361 i = (mmiobase >> 16) & 0x0F;
362 outb(i, dev->base_addr);
363
364 /* Second nibble provides 3 bits of mmio */
365 i = 0x10 | ((mmiobase >> 12) & 0x0E);
366 outb(i, dev->base_addr);
367
368 /* Third nibble, hard-coded values */
369 i = 0x26;
370 outb(i, dev->base_addr);
371
372 /* Fourth nibble sets shared ram page size */
373
374 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
375 i = (sramsize >> 4) & 0x07;
376 i = ((i == 4) ? 3 : i) << 2;
377 i |= 0x30;
378
379 if (ringspeed == 16)
380 i |= 2;
381 if (dev->base_addr == 0xA24)
382 i |= 1;
383 outb(i, dev->base_addr);
384
385 /* 0x40 will release the card for use */
386 outb(0x40, dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700389static struct pcmcia_device_id ibmtr_ids[] = {
390 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
391 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
392 PCMCIA_DEVICE_NULL,
393};
394MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396static struct pcmcia_driver ibmtr_cs_driver = {
397 .owner = THIS_MODULE,
398 .drv = {
399 .name = "ibmtr_cs",
400 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100401 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100402 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700403 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100404 .suspend = ibmtr_suspend,
405 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406};
407
408static int __init init_ibmtr_cs(void)
409{
410 return pcmcia_register_driver(&ibmtr_cs_driver);
411}
412
413static void __exit exit_ibmtr_cs(void)
414{
415 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
418module_init(init_ibmtr_cs);
419module_exit(exit_ibmtr_cs);