blob: 6fc89eba9c8fe9c473daddf444f4073bea50d47b [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_types.h>
61#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;
107 dev_node_t node;
108 window_handle_t sram_win_handle;
109 struct tok_info *ti;
110} ibmtr_dev_t;
111
112static void netdev_get_drvinfo(struct net_device *dev,
113 struct ethtool_drvinfo *info)
114{
115 strcpy(info->driver, "ibmtr_cs");
116}
117
Jeff Garzik7282d492006-09-13 14:30:00 -0400118static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .get_drvinfo = netdev_get_drvinfo,
120};
121
122/*======================================================================
123
124 ibmtr_attach() creates an "instance" of the driver, allocating
125 local data structures for one device. The device is registered
126 with Card Services.
127
128======================================================================*/
129
Al Viroabf04372007-03-14 09:04:21 +0000130static int __devinit ibmtr_attach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
132 ibmtr_dev_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 struct net_device *dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200134
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200135 dev_dbg(&link->dev, "ibmtr_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 /* Create new token-ring device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700138 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100139 if (!info) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 dev = alloc_trdev(sizeof(struct tok_info));
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100141 if (!dev) {
142 kfree(info);
143 return -ENOMEM;
144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200146 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 link->priv = info;
148 info->ti = netdev_priv(dev);
149
150 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
151 link->io.NumPorts1 = 4;
152 link->io.IOAddrLines = 16;
153 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
154 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
155 link->irq.Handler = &tok_interrupt;
156 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
160 link->irq.Instance = 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 Brodowskifd238232006-03-05 10:45:09 +0100190 if (link->dev_node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 unregister_netdev(dev);
Paul Walmsley5bebf822007-05-09 10:47:16 -0600192
193 del_timer_sync(&(ti->tr_timer));
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100194
195 ibmtr_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100198 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199} /* ibmtr_detach */
200
201/*======================================================================
202
203 ibmtr_config() is scheduled to run after a CARD_INSERTION event
204 is received, to configure the PCMCIA socket, and to make the
205 token-ring device available to the system.
206
207======================================================================*/
208
Al Viroabf04372007-03-14 09:04:21 +0000209static int __devinit ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 ibmtr_dev_t *info = link->priv;
212 struct net_device *dev = info->dev;
213 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 win_req_t req;
215 memreq_t mem;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200216 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200218 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 link->conf.ConfigIndex = 0x61;
221
222 /* Determine if this is PRIMARY or ALTERNATE. */
223
224 /* Try PRIMARY card at 0xA20-0xA23 */
225 link->io.BasePort1 = 0xA20;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200226 i = pcmcia_request_io(link, &link->io);
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. */
229 link->io.BasePort1 = 0xA24;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200230 ret = pcmcia_request_io(link, &link->io);
231 if (ret)
232 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 }
234 dev->base_addr = link->io.BasePort1;
235
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200236 ret = pcmcia_request_irq(link, &link->irq);
237 if (ret)
238 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 dev->irq = link->irq.AssignedIRQ;
240 ti->irq = link->irq.AssignedIRQ;
241 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 Brodowskidd0fab52009-10-24 15:51:05 +0200249 ret = pcmcia_request_window(&link, &req, &link->win);
250 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 Brodowskidd0fab52009-10-24 15:51:05 +0200266 ret = pcmcia_request_window(&link, &req, &info->sram_win_handle);
267 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 Brodowskifd238232006-03-05 10:45:09 +0100289 link->dev_node = &info->node;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200290 SET_NETDEV_DEV(dev, &handle_to_dev(link));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 i = ibmtr_probe_card(dev);
293 if (i != 0) {
294 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
Dominik Brodowskifd238232006-03-05 10:45:09 +0100295 link->dev_node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 goto failed;
297 }
298
299 strcpy(info->node.dev_name, dev->name);
300
Joe Perchesad361c92009-07-06 13:05:40 -0700301 printk(KERN_INFO
302 "%s: port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
303 dev->name, dev->base_addr, dev->irq,
304 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
305 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200306 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308failed:
309 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200310 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311} /* ibmtr_config */
312
313/*======================================================================
314
315 After a card is removed, ibmtr_release() will unregister the net
316 device, and release the PCMCIA configuration. If the device is
317 still open, this will be postponed until it is closed.
318
319======================================================================*/
320
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200321static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100323 ibmtr_dev_t *info = link->priv;
324 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200326 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100328 if (link->win) {
329 struct tok_info *ti = netdev_priv(dev);
330 iounmap(ti->mmio);
Magnus Dammf5560da2006-12-13 19:46:38 +0900331 pcmcia_release_window(link, info->sram_win_handle);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100332 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200333 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200336static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100337{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100338 ibmtr_dev_t *info = link->priv;
339 struct net_device *dev = info->dev;
340
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100341 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100342 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100343
344 return 0;
345}
346
Al Viro8814b502008-11-22 17:35:44 +0000347static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100348{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100349 ibmtr_dev_t *info = link->priv;
350 struct net_device *dev = info->dev;
351
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100352 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100353 ibmtr_probe(dev); /* really? */
354 netif_device_attach(dev);
355 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100356
357 return 0;
358}
359
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361/*====================================================================*/
362
363static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
364{
365 int i;
366
367 /* Bizarre IBM behavior, there are 16 bits of information we
368 need to set, but the card only allows us to send 4 bits at a
369 time. For each byte sent to base_addr, bits 7-4 tell the
370 card which part of the 16 bits we are setting, bits 3-0 contain
371 the actual information */
372
373 /* First nibble provides 4 bits of mmio */
374 i = (mmiobase >> 16) & 0x0F;
375 outb(i, dev->base_addr);
376
377 /* Second nibble provides 3 bits of mmio */
378 i = 0x10 | ((mmiobase >> 12) & 0x0E);
379 outb(i, dev->base_addr);
380
381 /* Third nibble, hard-coded values */
382 i = 0x26;
383 outb(i, dev->base_addr);
384
385 /* Fourth nibble sets shared ram page size */
386
387 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
388 i = (sramsize >> 4) & 0x07;
389 i = ((i == 4) ? 3 : i) << 2;
390 i |= 0x30;
391
392 if (ringspeed == 16)
393 i |= 2;
394 if (dev->base_addr == 0xA24)
395 i |= 1;
396 outb(i, dev->base_addr);
397
398 /* 0x40 will release the card for use */
399 outb(0x40, dev->base_addr);
400
401 return;
402}
403
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700404static struct pcmcia_device_id ibmtr_ids[] = {
405 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
406 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
407 PCMCIA_DEVICE_NULL,
408};
409MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411static struct pcmcia_driver ibmtr_cs_driver = {
412 .owner = THIS_MODULE,
413 .drv = {
414 .name = "ibmtr_cs",
415 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100416 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100417 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700418 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100419 .suspend = ibmtr_suspend,
420 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421};
422
423static int __init init_ibmtr_cs(void)
424{
425 return pcmcia_register_driver(&ibmtr_cs_driver);
426}
427
428static void __exit exit_ibmtr_cs(void)
429{
430 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431}
432
433module_init(init_ibmtr_cs);
434module_exit(exit_ibmtr_cs);