blob: b0d06a3d962fc235fdc22c8f5af840272a5574d3 [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;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200214 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200216 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 link->conf.ConfigIndex = 0x61;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200219 link->io_lines = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221 /* Determine if this is PRIMARY or ALTERNATE. */
222
223 /* Try PRIMARY card at 0xA20-0xA23 */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200224 link->resource[0]->start = 0xA20;
225 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200226 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200228 link->resource[0]->start = 0xA24;
229 ret = pcmcia_request_io(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200230 if (ret)
231 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200233 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Dominik Brodowskieb141202010-03-07 12:21:16 +0100235 ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200236 if (ret)
237 goto failed;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100238 dev->irq = link->irq;
239 ti->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
241
242 /* Allocate the MMIO memory window */
243 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
244 req.Attributes |= WIN_USE_WAIT;
245 req.Base = 0;
246 req.Size = 0x2000;
247 req.AccessSpeed = 250;
Dominik Brodowski6838b032009-11-03 01:31:52 +0100248 ret = pcmcia_request_window(link, &req, &link->win);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200249 if (ret)
250 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200252 ret = pcmcia_map_mem_page(link, link->win, mmiobase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200253 if (ret)
254 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 ti->mmio = ioremap(req.Base, req.Size);
256
257 /* Allocate the SRAM memory window */
258 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
259 req.Attributes |= WIN_USE_WAIT;
260 req.Base = 0;
261 req.Size = sramsize * 1024;
262 req.AccessSpeed = 250;
Dominik Brodowski6838b032009-11-03 01:31:52 +0100263 ret = pcmcia_request_window(link, &req, &info->sram_win_handle);
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 ret = pcmcia_map_mem_page(link, info->sram_win_handle, srambase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200268 if (ret)
269 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200271 ti->sram_base = srambase >> 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 ti->sram_virt = ioremap(req.Base, req.Size);
273 ti->sram_phys = req.Base;
274
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200275 ret = pcmcia_request_configuration(link, &link->conf);
276 if (ret)
277 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 /* Set up the Token-Ring Controller Configuration Register and
280 turn on the card. Check the "Local Area Network Credit Card
281 Adapters Technical Reference" SC30-3585 for this info. */
282 ibmtr_hw_setup(dev, mmiobase);
283
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100284 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 i = ibmtr_probe_card(dev);
287 if (i != 0) {
288 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 goto failed;
290 }
291
Joe Perchesad361c92009-07-06 13:05:40 -0700292 printk(KERN_INFO
293 "%s: port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
294 dev->name, dev->base_addr, dev->irq,
295 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
296 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200297 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299failed:
300 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200301 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302} /* ibmtr_config */
303
304/*======================================================================
305
306 After a card is removed, ibmtr_release() will unregister the net
307 device, and release the PCMCIA configuration. If the device is
308 still open, this will be postponed until it is closed.
309
310======================================================================*/
311
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200312static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100314 ibmtr_dev_t *info = link->priv;
315 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200317 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100319 if (link->win) {
320 struct tok_info *ti = netdev_priv(dev);
321 iounmap(ti->mmio);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100322 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200323 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}
325
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200326static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100327{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100328 ibmtr_dev_t *info = link->priv;
329 struct net_device *dev = info->dev;
330
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100331 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100332 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100333
334 return 0;
335}
336
Al Viro8814b502008-11-22 17:35:44 +0000337static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100338{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100339 ibmtr_dev_t *info = link->priv;
340 struct net_device *dev = info->dev;
341
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100342 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100343 ibmtr_probe(dev); /* really? */
344 netif_device_attach(dev);
345 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100346
347 return 0;
348}
349
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/*====================================================================*/
352
353static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
354{
355 int i;
356
357 /* Bizarre IBM behavior, there are 16 bits of information we
358 need to set, but the card only allows us to send 4 bits at a
359 time. For each byte sent to base_addr, bits 7-4 tell the
360 card which part of the 16 bits we are setting, bits 3-0 contain
361 the actual information */
362
363 /* First nibble provides 4 bits of mmio */
364 i = (mmiobase >> 16) & 0x0F;
365 outb(i, dev->base_addr);
366
367 /* Second nibble provides 3 bits of mmio */
368 i = 0x10 | ((mmiobase >> 12) & 0x0E);
369 outb(i, dev->base_addr);
370
371 /* Third nibble, hard-coded values */
372 i = 0x26;
373 outb(i, dev->base_addr);
374
375 /* Fourth nibble sets shared ram page size */
376
377 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
378 i = (sramsize >> 4) & 0x07;
379 i = ((i == 4) ? 3 : i) << 2;
380 i |= 0x30;
381
382 if (ringspeed == 16)
383 i |= 2;
384 if (dev->base_addr == 0xA24)
385 i |= 1;
386 outb(i, dev->base_addr);
387
388 /* 0x40 will release the card for use */
389 outb(0x40, dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390}
391
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700392static struct pcmcia_device_id ibmtr_ids[] = {
393 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
394 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
395 PCMCIA_DEVICE_NULL,
396};
397MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399static struct pcmcia_driver ibmtr_cs_driver = {
400 .owner = THIS_MODULE,
401 .drv = {
402 .name = "ibmtr_cs",
403 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100404 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100405 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700406 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100407 .suspend = ibmtr_suspend,
408 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409};
410
411static int __init init_ibmtr_cs(void)
412{
413 return pcmcia_register_driver(&ibmtr_cs_driver);
414}
415
416static void __exit exit_ibmtr_cs(void)
417{
418 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419}
420
421module_init(init_ibmtr_cs);
422module_exit(exit_ibmtr_cs);