blob: dbdea7f5e423204126377dac3b585ed4857adf5c [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 link->conf.IntType = INT_MEMORY_AND_IO;
157 link->conf.Present = PRESENT_OPTION;
158
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100159 info->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Dominik Brodowskifd238232006-03-05 10:45:09 +0100161 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200163 return ibmtr_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164} /* ibmtr_attach */
165
166/*======================================================================
167
168 This deletes a driver "instance". The device is de-registered
169 with Card Services. If it has been released, all local data
170 structures are freed. Otherwise, the structures will be freed
171 when the device is released.
172
173======================================================================*/
174
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200175static void ibmtr_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
177 struct ibmtr_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100178 struct net_device *dev = info->dev;
Paul Walmsley5bebf822007-05-09 10:47:16 -0600179 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200181 dev_dbg(&link->dev, "ibmtr_detach\n");
Paul Walmsley5bebf822007-05-09 10:47:16 -0600182
183 /*
184 * When the card removal interrupt hits tok_interrupt(),
185 * bail out early, so we don't crash the machine
186 */
187 ti->sram_phys |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100189 unregister_netdev(dev);
Paul Walmsley5bebf822007-05-09 10:47:16 -0600190
191 del_timer_sync(&(ti->tr_timer));
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100192
193 ibmtr_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100196 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197} /* ibmtr_detach */
198
199/*======================================================================
200
201 ibmtr_config() is scheduled to run after a CARD_INSERTION event
202 is received, to configure the PCMCIA socket, and to make the
203 token-ring device available to the system.
204
205======================================================================*/
206
Al Viroabf04372007-03-14 09:04:21 +0000207static int __devinit ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 ibmtr_dev_t *info = link->priv;
210 struct net_device *dev = info->dev;
211 struct tok_info *ti = netdev_priv(dev);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200212 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200214 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 link->conf.ConfigIndex = 0x61;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200217 link->io_lines = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 /* Determine if this is PRIMARY or ALTERNATE. */
220
221 /* Try PRIMARY card at 0xA20-0xA23 */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200222 link->resource[0]->start = 0xA20;
223 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200224 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200226 link->resource[0]->start = 0xA24;
227 ret = pcmcia_request_io(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200228 if (ret)
229 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200231 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Dominik Brodowskieb141202010-03-07 12:21:16 +0100233 ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200234 if (ret)
235 goto failed;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100236 dev->irq = link->irq;
237 ti->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
239
240 /* Allocate the MMIO memory window */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200241 link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
242 link->resource[2]->flags |= WIN_USE_WAIT;
243 link->resource[2]->start = 0;
244 link->resource[2]->end = 0x2000;
245 ret = pcmcia_request_window(link, link->resource[2], 250);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200246 if (ret)
247 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200249 ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200250 if (ret)
251 goto failed;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200252 ti->mmio = ioremap(link->resource[2]->start,
253 resource_size(link->resource[2]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 /* Allocate the SRAM memory window */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200256 link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
257 link->resource[3]->flags |= WIN_USE_WAIT;
258 link->resource[3]->start = 0;
259 link->resource[3]->end = sramsize * 1024;
260 ret = pcmcia_request_window(link, link->resource[3], 250);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200261 if (ret)
262 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200264 ret = pcmcia_map_mem_page(link, link->resource[3], srambase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200265 if (ret)
266 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200268 ti->sram_base = srambase >> 12;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200269 ti->sram_virt = ioremap(link->resource[3]->start,
270 resource_size(link->resource[3]));
271 ti->sram_phys = link->resource[3]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200273 ret = pcmcia_request_configuration(link, &link->conf);
274 if (ret)
275 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277 /* Set up the Token-Ring Controller Configuration Register and
278 turn on the card. Check the "Local Area Network Credit Card
279 Adapters Technical Reference" SC30-3585 for this info. */
280 ibmtr_hw_setup(dev, mmiobase);
281
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100282 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 i = ibmtr_probe_card(dev);
285 if (i != 0) {
286 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 goto failed;
288 }
289
Joe Perchesad361c92009-07-06 13:05:40 -0700290 printk(KERN_INFO
291 "%s: port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
292 dev->name, dev->base_addr, dev->irq,
293 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
294 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200295 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297failed:
298 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200299 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300} /* ibmtr_config */
301
302/*======================================================================
303
304 After a card is removed, ibmtr_release() will unregister the net
305 device, and release the PCMCIA configuration. If the device is
306 still open, this will be postponed until it is closed.
307
308======================================================================*/
309
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200310static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100312 ibmtr_dev_t *info = link->priv;
313 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200315 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200317 if (link->resource[2]->end) {
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100318 struct tok_info *ti = netdev_priv(dev);
319 iounmap(ti->mmio);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100320 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200321 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200324static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100325{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100326 ibmtr_dev_t *info = link->priv;
327 struct net_device *dev = info->dev;
328
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100329 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100330 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100331
332 return 0;
333}
334
Al Viro8814b502008-11-22 17:35:44 +0000335static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100336{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100337 ibmtr_dev_t *info = link->priv;
338 struct net_device *dev = info->dev;
339
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100340 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100341 ibmtr_probe(dev); /* really? */
342 netif_device_attach(dev);
343 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100344
345 return 0;
346}
347
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/*====================================================================*/
350
351static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
352{
353 int i;
354
355 /* Bizarre IBM behavior, there are 16 bits of information we
356 need to set, but the card only allows us to send 4 bits at a
357 time. For each byte sent to base_addr, bits 7-4 tell the
358 card which part of the 16 bits we are setting, bits 3-0 contain
359 the actual information */
360
361 /* First nibble provides 4 bits of mmio */
362 i = (mmiobase >> 16) & 0x0F;
363 outb(i, dev->base_addr);
364
365 /* Second nibble provides 3 bits of mmio */
366 i = 0x10 | ((mmiobase >> 12) & 0x0E);
367 outb(i, dev->base_addr);
368
369 /* Third nibble, hard-coded values */
370 i = 0x26;
371 outb(i, dev->base_addr);
372
373 /* Fourth nibble sets shared ram page size */
374
375 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
376 i = (sramsize >> 4) & 0x07;
377 i = ((i == 4) ? 3 : i) << 2;
378 i |= 0x30;
379
380 if (ringspeed == 16)
381 i |= 2;
382 if (dev->base_addr == 0xA24)
383 i |= 1;
384 outb(i, dev->base_addr);
385
386 /* 0x40 will release the card for use */
387 outb(0x40, dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700390static struct pcmcia_device_id ibmtr_ids[] = {
391 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
392 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
393 PCMCIA_DEVICE_NULL,
394};
395MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397static struct pcmcia_driver ibmtr_cs_driver = {
398 .owner = THIS_MODULE,
399 .drv = {
400 .name = "ibmtr_cs",
401 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100402 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100403 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700404 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100405 .suspend = ibmtr_suspend,
406 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407};
408
409static int __init init_ibmtr_cs(void)
410{
411 return pcmcia_register_driver(&ibmtr_cs_driver);
412}
413
414static void __exit exit_ibmtr_cs(void)
415{
416 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
419module_init(init_ibmtr_cs);
420module_exit(exit_ibmtr_cs);