blob: 1b8b44dc4c50fc8e5ba55b3077794d1224a4c665 [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
72#ifdef PCMCIA_DEBUG
73static int pc_debug = PCMCIA_DEBUG;
74module_param(pc_debug, int, 0);
75#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
76static char *version =
77"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n"
78" 2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n"
79" 2.4.2 2001/30/28 Midnight (Burt Silverman)\n";
80#else
81#define DEBUG(n, args...)
82#endif
83
84/*====================================================================*/
85
86/* Parameters that can be set with 'insmod' */
87
88/* MMIO base address */
89static u_long mmiobase = 0xce000;
90
91/* SRAM base address */
92static u_long srambase = 0xd0000;
93
94/* SRAM size 8,16,32,64 */
95static u_long sramsize = 64;
96
97/* Ringspeed 4,16 */
98static int ringspeed = 16;
99
100module_param(mmiobase, ulong, 0);
101module_param(srambase, ulong, 0);
102module_param(sramsize, ulong, 0);
103module_param(ringspeed, int, 0);
104MODULE_LICENSE("GPL");
105
106/*====================================================================*/
107
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200108static void ibmtr_config(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200110static void ibmtr_release(struct pcmcia_device *link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100111static void ibmtr_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*====================================================================*/
114
115typedef struct ibmtr_dev_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100116 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 struct net_device *dev;
118 dev_node_t node;
119 window_handle_t sram_win_handle;
120 struct tok_info *ti;
121} ibmtr_dev_t;
122
123static void netdev_get_drvinfo(struct net_device *dev,
124 struct ethtool_drvinfo *info)
125{
126 strcpy(info->driver, "ibmtr_cs");
127}
128
129static struct ethtool_ops netdev_ethtool_ops = {
130 .get_drvinfo = netdev_get_drvinfo,
131};
132
133/*======================================================================
134
135 ibmtr_attach() creates an "instance" of the driver, allocating
136 local data structures for one device. The device is registered
137 with Card Services.
138
139======================================================================*/
140
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200141static int ibmtr_attach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
143 ibmtr_dev_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 struct net_device *dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 DEBUG(0, "ibmtr_attach()\n");
147
148 /* Create new token-ring device */
149 info = kmalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100150 if (!info) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 memset(info,0,sizeof(*info));
152 dev = alloc_trdev(sizeof(struct tok_info));
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100153 if (!dev) {
154 kfree(info);
155 return -ENOMEM;
156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200158 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 link->priv = info;
160 info->ti = netdev_priv(dev);
161
162 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
163 link->io.NumPorts1 = 4;
164 link->io.IOAddrLines = 16;
165 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
166 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
167 link->irq.Handler = &tok_interrupt;
168 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 link->conf.IntType = INT_MEMORY_AND_IO;
170 link->conf.Present = PRESENT_OPTION;
171
172 link->irq.Instance = info->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Dominik Brodowskifd238232006-03-05 10:45:09 +0100174 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100176 link->state |= DEV_PRESENT;
177 ibmtr_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100179 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180} /* ibmtr_attach */
181
182/*======================================================================
183
184 This deletes a driver "instance". The device is de-registered
185 with Card Services. If it has been released, all local data
186 structures are freed. Otherwise, the structures will be freed
187 when the device is released.
188
189======================================================================*/
190
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200191static void ibmtr_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
193 struct ibmtr_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100194 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 DEBUG(0, "ibmtr_detach(0x%p)\n", link);
197
Dominik Brodowskifd238232006-03-05 10:45:09 +0100198 if (link->dev_node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 unregister_netdev(dev);
200
201 {
202 struct tok_info *ti = netdev_priv(dev);
203 del_timer_sync(&(ti->tr_timer));
204 }
205 if (link->state & DEV_CONFIG)
206 ibmtr_release(link);
207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100209 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210} /* ibmtr_detach */
211
212/*======================================================================
213
214 ibmtr_config() is scheduled to run after a CARD_INSERTION event
215 is received, to configure the PCMCIA socket, and to make the
216 token-ring device available to the system.
217
218======================================================================*/
219
220#define CS_CHECK(fn, ret) \
221do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
222
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200223static void ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 ibmtr_dev_t *info = link->priv;
226 struct net_device *dev = info->dev;
227 struct tok_info *ti = netdev_priv(dev);
228 tuple_t tuple;
229 cisparse_t parse;
230 win_req_t req;
231 memreq_t mem;
232 int i, last_ret, last_fn;
233 u_char buf[64];
234
235 DEBUG(0, "ibmtr_config(0x%p)\n", link);
236
237 tuple.Attributes = 0;
238 tuple.TupleData = buf;
239 tuple.TupleDataMax = 64;
240 tuple.TupleOffset = 0;
241 tuple.DesiredTuple = CISTPL_CONFIG;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200242 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
243 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
244 CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 link->conf.ConfigBase = parse.config.base;
246
247 /* Configure card */
248 link->state |= DEV_CONFIG;
249
250 link->conf.ConfigIndex = 0x61;
251
252 /* Determine if this is PRIMARY or ALTERNATE. */
253
254 /* Try PRIMARY card at 0xA20-0xA23 */
255 link->io.BasePort1 = 0xA20;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200256 i = pcmcia_request_io(link, &link->io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (i != CS_SUCCESS) {
258 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
259 link->io.BasePort1 = 0xA24;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200260 CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
262 dev->base_addr = link->io.BasePort1;
263
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200264 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 dev->irq = link->irq.AssignedIRQ;
266 ti->irq = link->irq.AssignedIRQ;
267 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
268
269 /* Allocate the MMIO memory window */
270 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
271 req.Attributes |= WIN_USE_WAIT;
272 req.Base = 0;
273 req.Size = 0x2000;
274 req.AccessSpeed = 250;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200275 CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277 mem.CardOffset = mmiobase;
278 mem.Page = 0;
279 CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem));
280 ti->mmio = ioremap(req.Base, req.Size);
281
282 /* Allocate the SRAM memory window */
283 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
284 req.Attributes |= WIN_USE_WAIT;
285 req.Base = 0;
286 req.Size = sramsize * 1024;
287 req.AccessSpeed = 250;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200288 CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &info->sram_win_handle));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 mem.CardOffset = srambase;
291 mem.Page = 0;
292 CS_CHECK(MapMemPage, pcmcia_map_mem_page(info->sram_win_handle, &mem));
293
294 ti->sram_base = mem.CardOffset >> 12;
295 ti->sram_virt = ioremap(req.Base, req.Size);
296 ti->sram_phys = req.Base;
297
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200298 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 /* Set up the Token-Ring Controller Configuration Register and
301 turn on the card. Check the "Local Area Network Credit Card
302 Adapters Technical Reference" SC30-3585 for this info. */
303 ibmtr_hw_setup(dev, mmiobase);
304
Dominik Brodowskifd238232006-03-05 10:45:09 +0100305 link->dev_node = &info->node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 link->state &= ~DEV_CONFIG_PENDING;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200307 SET_NETDEV_DEV(dev, &handle_to_dev(link));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 i = ibmtr_probe_card(dev);
310 if (i != 0) {
311 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
Dominik Brodowskifd238232006-03-05 10:45:09 +0100312 link->dev_node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 goto failed;
314 }
315
316 strcpy(info->node.dev_name, dev->name);
317
318 printk(KERN_INFO "%s: port %#3lx, irq %d,",
319 dev->name, dev->base_addr, dev->irq);
320 printk (" mmio %#5lx,", (u_long)ti->mmio);
321 printk (" sram %#5lx,", (u_long)ti->sram_base << 12);
322 printk ("\n" KERN_INFO " hwaddr=");
323 for (i = 0; i < TR_ALEN; i++)
324 printk("%02X", dev->dev_addr[i]);
325 printk("\n");
326 return;
327
328cs_failed:
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200329 cs_error(link, last_fn, last_ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330failed:
331 ibmtr_release(link);
332} /* ibmtr_config */
333
334/*======================================================================
335
336 After a card is removed, ibmtr_release() will unregister the net
337 device, and release the PCMCIA configuration. If the device is
338 still open, this will be postponed until it is closed.
339
340======================================================================*/
341
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200342static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100344 ibmtr_dev_t *info = link->priv;
345 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100347 DEBUG(0, "ibmtr_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100349 if (link->win) {
350 struct tok_info *ti = netdev_priv(dev);
351 iounmap(ti->mmio);
352 pcmcia_release_window(info->sram_win_handle);
353 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200354 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200357static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100358{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100359 ibmtr_dev_t *info = link->priv;
360 struct net_device *dev = info->dev;
361
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100362 if ((link->state & DEV_CONFIG) && (link->open))
363 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100364
365 return 0;
366}
367
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200368static int ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100369{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100370 ibmtr_dev_t *info = link->priv;
371 struct net_device *dev = info->dev;
372
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100373 if ((link->state & DEV_CONFIG) && (link->open)) {
374 ibmtr_probe(dev); /* really? */
375 netif_device_attach(dev);
376 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100377
378 return 0;
379}
380
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382/*====================================================================*/
383
384static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
385{
386 int i;
387
388 /* Bizarre IBM behavior, there are 16 bits of information we
389 need to set, but the card only allows us to send 4 bits at a
390 time. For each byte sent to base_addr, bits 7-4 tell the
391 card which part of the 16 bits we are setting, bits 3-0 contain
392 the actual information */
393
394 /* First nibble provides 4 bits of mmio */
395 i = (mmiobase >> 16) & 0x0F;
396 outb(i, dev->base_addr);
397
398 /* Second nibble provides 3 bits of mmio */
399 i = 0x10 | ((mmiobase >> 12) & 0x0E);
400 outb(i, dev->base_addr);
401
402 /* Third nibble, hard-coded values */
403 i = 0x26;
404 outb(i, dev->base_addr);
405
406 /* Fourth nibble sets shared ram page size */
407
408 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
409 i = (sramsize >> 4) & 0x07;
410 i = ((i == 4) ? 3 : i) << 2;
411 i |= 0x30;
412
413 if (ringspeed == 16)
414 i |= 2;
415 if (dev->base_addr == 0xA24)
416 i |= 1;
417 outb(i, dev->base_addr);
418
419 /* 0x40 will release the card for use */
420 outb(0x40, dev->base_addr);
421
422 return;
423}
424
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700425static struct pcmcia_device_id ibmtr_ids[] = {
426 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
427 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
428 PCMCIA_DEVICE_NULL,
429};
430MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432static struct pcmcia_driver ibmtr_cs_driver = {
433 .owner = THIS_MODULE,
434 .drv = {
435 .name = "ibmtr_cs",
436 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100437 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100438 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700439 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100440 .suspend = ibmtr_suspend,
441 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442};
443
444static int __init init_ibmtr_cs(void)
445{
446 return pcmcia_register_driver(&ibmtr_cs_driver);
447}
448
449static void __exit exit_ibmtr_cs(void)
450{
451 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
454module_init(init_ibmtr_cs);
455module_exit(exit_ibmtr_cs);