blob: 3fd859570db3d16fea84f07b79bdd88260427c95 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 window_handle_t sram_win_handle;
107 struct tok_info *ti;
108} ibmtr_dev_t;
109
110static void netdev_get_drvinfo(struct net_device *dev,
111 struct ethtool_drvinfo *info)
112{
113 strcpy(info->driver, "ibmtr_cs");
114}
115
Jeff Garzik7282d492006-09-13 14:30:00 -0400116static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 .get_drvinfo = netdev_get_drvinfo,
118};
119
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100120static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
121 ibmtr_dev_t *info = dev_id;
122 struct net_device *dev = info->dev;
123 return tok_interrupt(irq, dev);
124};
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126/*======================================================================
127
128 ibmtr_attach() creates an "instance" of the driver, allocating
129 local data structures for one device. The device is registered
130 with Card Services.
131
132======================================================================*/
133
Al Viroabf04372007-03-14 09:04:21 +0000134static int __devinit ibmtr_attach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
136 ibmtr_dev_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct net_device *dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200138
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200139 dev_dbg(&link->dev, "ibmtr_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* Create new token-ring device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700142 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100143 if (!info) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 dev = alloc_trdev(sizeof(struct tok_info));
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100145 if (!dev) {
146 kfree(info);
147 return -ENOMEM;
148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200150 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 link->priv = info;
152 info->ti = netdev_priv(dev);
153
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200154 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
155 link->resource[0]->end = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 link->conf.IntType = INT_MEMORY_AND_IO;
158 link->conf.Present = PRESENT_OPTION;
159
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100160 info->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Dominik Brodowskifd238232006-03-05 10:45:09 +0100162 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200164 return ibmtr_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165} /* ibmtr_attach */
166
167/*======================================================================
168
169 This deletes a driver "instance". The device is de-registered
170 with Card Services. If it has been released, all local data
171 structures are freed. Otherwise, the structures will be freed
172 when the device is released.
173
174======================================================================*/
175
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200176static void ibmtr_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 struct ibmtr_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100179 struct net_device *dev = info->dev;
Paul Walmsley5bebf822007-05-09 10:47:16 -0600180 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200182 dev_dbg(&link->dev, "ibmtr_detach\n");
Paul Walmsley5bebf822007-05-09 10:47:16 -0600183
184 /*
185 * When the card removal interrupt hits tok_interrupt(),
186 * bail out early, so we don't crash the machine
187 */
188 ti->sram_phys |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100190 unregister_netdev(dev);
Paul Walmsley5bebf822007-05-09 10:47:16 -0600191
192 del_timer_sync(&(ti->tr_timer));
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100193
194 ibmtr_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100197 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198} /* ibmtr_detach */
199
200/*======================================================================
201
202 ibmtr_config() is scheduled to run after a CARD_INSERTION event
203 is received, to configure the PCMCIA socket, and to make the
204 token-ring device available to the system.
205
206======================================================================*/
207
Al Viroabf04372007-03-14 09:04:21 +0000208static int __devinit ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 ibmtr_dev_t *info = link->priv;
211 struct net_device *dev = info->dev;
212 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 win_req_t req;
214 memreq_t mem;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200215 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200217 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 link->conf.ConfigIndex = 0x61;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200220 link->io_lines = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222 /* Determine if this is PRIMARY or ALTERNATE. */
223
224 /* Try PRIMARY card at 0xA20-0xA23 */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200225 link->resource[0]->start = 0xA20;
226 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200227 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200229 link->resource[0]->start = 0xA24;
230 ret = pcmcia_request_io(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200231 if (ret)
232 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200234 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Dominik Brodowskieb141202010-03-07 12:21:16 +0100236 ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200237 if (ret)
238 goto failed;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100239 dev->irq = link->irq;
240 ti->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
242
243 /* Allocate the MMIO memory window */
244 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
245 req.Attributes |= WIN_USE_WAIT;
246 req.Base = 0;
247 req.Size = 0x2000;
248 req.AccessSpeed = 250;
Dominik Brodowski6838b032009-11-03 01:31:52 +0100249 ret = pcmcia_request_window(link, &req, &link->win);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200250 if (ret)
251 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253 mem.CardOffset = mmiobase;
254 mem.Page = 0;
Magnus Damm868575d2006-12-13 19:46:43 +0900255 ret = pcmcia_map_mem_page(link, link->win, &mem);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200256 if (ret)
257 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 ti->mmio = ioremap(req.Base, req.Size);
259
260 /* Allocate the SRAM memory window */
261 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
262 req.Attributes |= WIN_USE_WAIT;
263 req.Base = 0;
264 req.Size = sramsize * 1024;
265 req.AccessSpeed = 250;
Dominik Brodowski6838b032009-11-03 01:31:52 +0100266 ret = pcmcia_request_window(link, &req, &info->sram_win_handle);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200267 if (ret)
268 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270 mem.CardOffset = srambase;
271 mem.Page = 0;
Magnus Damm868575d2006-12-13 19:46:43 +0900272 ret = pcmcia_map_mem_page(link, info->sram_win_handle, &mem);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200273 if (ret)
274 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276 ti->sram_base = mem.CardOffset >> 12;
277 ti->sram_virt = ioremap(req.Base, req.Size);
278 ti->sram_phys = req.Base;
279
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200280 ret = pcmcia_request_configuration(link, &link->conf);
281 if (ret)
282 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 /* Set up the Token-Ring Controller Configuration Register and
285 turn on the card. Check the "Local Area Network Credit Card
286 Adapters Technical Reference" SC30-3585 for this info. */
287 ibmtr_hw_setup(dev, mmiobase);
288
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100289 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 i = ibmtr_probe_card(dev);
292 if (i != 0) {
293 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 goto failed;
295 }
296
Joe Perchesad361c92009-07-06 13:05:40 -0700297 printk(KERN_INFO
298 "%s: port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
299 dev->name, dev->base_addr, dev->irq,
300 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
301 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200302 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304failed:
305 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200306 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307} /* ibmtr_config */
308
309/*======================================================================
310
311 After a card is removed, ibmtr_release() will unregister the net
312 device, and release the PCMCIA configuration. If the device is
313 still open, this will be postponed until it is closed.
314
315======================================================================*/
316
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200317static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100319 ibmtr_dev_t *info = link->priv;
320 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200322 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100324 if (link->win) {
325 struct tok_info *ti = netdev_priv(dev);
326 iounmap(ti->mmio);
Magnus Dammf5560da2006-12-13 19:46:38 +0900327 pcmcia_release_window(link, info->sram_win_handle);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100328 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200329 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200332static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100333{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100334 ibmtr_dev_t *info = link->priv;
335 struct net_device *dev = info->dev;
336
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100337 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100338 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100339
340 return 0;
341}
342
Al Viro8814b502008-11-22 17:35:44 +0000343static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100344{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100345 ibmtr_dev_t *info = link->priv;
346 struct net_device *dev = info->dev;
347
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100348 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100349 ibmtr_probe(dev); /* really? */
350 netif_device_attach(dev);
351 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100352
353 return 0;
354}
355
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357/*====================================================================*/
358
359static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
360{
361 int i;
362
363 /* Bizarre IBM behavior, there are 16 bits of information we
364 need to set, but the card only allows us to send 4 bits at a
365 time. For each byte sent to base_addr, bits 7-4 tell the
366 card which part of the 16 bits we are setting, bits 3-0 contain
367 the actual information */
368
369 /* First nibble provides 4 bits of mmio */
370 i = (mmiobase >> 16) & 0x0F;
371 outb(i, dev->base_addr);
372
373 /* Second nibble provides 3 bits of mmio */
374 i = 0x10 | ((mmiobase >> 12) & 0x0E);
375 outb(i, dev->base_addr);
376
377 /* Third nibble, hard-coded values */
378 i = 0x26;
379 outb(i, dev->base_addr);
380
381 /* Fourth nibble sets shared ram page size */
382
383 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
384 i = (sramsize >> 4) & 0x07;
385 i = ((i == 4) ? 3 : i) << 2;
386 i |= 0x30;
387
388 if (ringspeed == 16)
389 i |= 2;
390 if (dev->base_addr == 0xA24)
391 i |= 1;
392 outb(i, dev->base_addr);
393
394 /* 0x40 will release the card for use */
395 outb(0x40, dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396}
397
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700398static struct pcmcia_device_id ibmtr_ids[] = {
399 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
400 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
401 PCMCIA_DEVICE_NULL,
402};
403MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405static struct pcmcia_driver ibmtr_cs_driver = {
406 .owner = THIS_MODULE,
407 .drv = {
408 .name = "ibmtr_cs",
409 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100410 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100411 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700412 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100413 .suspend = ibmtr_suspend,
414 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415};
416
417static int __init init_ibmtr_cs(void)
418{
419 return pcmcia_register_driver(&ibmtr_cs_driver);
420}
421
422static void __exit exit_ibmtr_cs(void)
423{
424 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
427module_init(init_ibmtr_cs);
428module_exit(exit_ibmtr_cs);