blob: 15d57f5b6f2967b0eadb3335b1ec835230ec7f1b [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
Joe Perches636b8112010-08-12 12:22:51 +000048#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/init.h>
52#include <linux/ptrace.h>
53#include <linux/slab.h>
54#include <linux/string.h>
55#include <linux/timer.h>
56#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/netdevice.h>
58#include <linux/trdevice.h>
59#include <linux/ibmtr.h>
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#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
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100109static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
110 ibmtr_dev_t *info = dev_id;
111 struct net_device *dev = info->dev;
112 return tok_interrupt(irq, dev);
113};
114
Al Viroabf04372007-03-14 09:04:21 +0000115static int __devinit ibmtr_attach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 ibmtr_dev_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 struct net_device *dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200119
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200120 dev_dbg(&link->dev, "ibmtr_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 /* Create new token-ring device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700123 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100124 if (!info) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 dev = alloc_trdev(sizeof(struct tok_info));
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100126 if (!dev) {
127 kfree(info);
128 return -ENOMEM;
129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200131 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 link->priv = info;
133 info->ti = netdev_priv(dev);
134
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200135 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
136 link->resource[0]->end = 4;
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200137 link->config_flags |= CONF_ENABLE_IRQ;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200138 link->config_regs = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100140 info->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200142 return ibmtr_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143} /* ibmtr_attach */
144
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200145static void ibmtr_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 struct ibmtr_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100148 struct net_device *dev = info->dev;
Paul Walmsley5bebf822007-05-09 10:47:16 -0600149 struct tok_info *ti = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200151 dev_dbg(&link->dev, "ibmtr_detach\n");
Paul Walmsley5bebf822007-05-09 10:47:16 -0600152
153 /*
154 * When the card removal interrupt hits tok_interrupt(),
155 * bail out early, so we don't crash the machine
156 */
157 ti->sram_phys |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100159 unregister_netdev(dev);
Paul Walmsley5bebf822007-05-09 10:47:16 -0600160
161 del_timer_sync(&(ti->tr_timer));
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100162
163 ibmtr_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 free_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100166 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167} /* ibmtr_detach */
168
Al Viroabf04372007-03-14 09:04:21 +0000169static int __devinit ibmtr_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 ibmtr_dev_t *info = link->priv;
172 struct net_device *dev = info->dev;
173 struct tok_info *ti = netdev_priv(dev);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200174 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200176 dev_dbg(&link->dev, "ibmtr_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200178 link->io_lines = 16;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200179 link->config_index = 0x61;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 /* Determine if this is PRIMARY or ALTERNATE. */
182
183 /* Try PRIMARY card at 0xA20-0xA23 */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200184 link->resource[0]->start = 0xA20;
185 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200186 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200188 link->resource[0]->start = 0xA24;
189 ret = pcmcia_request_io(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200190 if (ret)
191 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200193 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Dominik Brodowskieb141202010-03-07 12:21:16 +0100195 ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200196 if (ret)
197 goto failed;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100198 dev->irq = link->irq;
199 ti->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
201
202 /* Allocate the MMIO memory window */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200203 link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
204 link->resource[2]->flags |= WIN_USE_WAIT;
205 link->resource[2]->start = 0;
206 link->resource[2]->end = 0x2000;
207 ret = pcmcia_request_window(link, link->resource[2], 250);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200208 if (ret)
209 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200211 ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200212 if (ret)
213 goto failed;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200214 ti->mmio = ioremap(link->resource[2]->start,
215 resource_size(link->resource[2]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 /* Allocate the SRAM memory window */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200218 link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
219 link->resource[3]->flags |= WIN_USE_WAIT;
220 link->resource[3]->start = 0;
221 link->resource[3]->end = sramsize * 1024;
222 ret = pcmcia_request_window(link, link->resource[3], 250);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200223 if (ret)
224 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200226 ret = pcmcia_map_mem_page(link, link->resource[3], srambase);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200227 if (ret)
228 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200230 ti->sram_base = srambase >> 12;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200231 ti->sram_virt = ioremap(link->resource[3]->start,
232 resource_size(link->resource[3]));
233 ti->sram_phys = link->resource[3]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200235 ret = pcmcia_enable_device(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200236 if (ret)
237 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 /* Set up the Token-Ring Controller Configuration Register and
240 turn on the card. Check the "Local Area Network Credit Card
241 Adapters Technical Reference" SC30-3585 for this info. */
242 ibmtr_hw_setup(dev, mmiobase);
243
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100244 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 i = ibmtr_probe_card(dev);
247 if (i != 0) {
Joe Perches636b8112010-08-12 12:22:51 +0000248 pr_notice("register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 goto failed;
250 }
251
Joe Perches636b8112010-08-12 12:22:51 +0000252 netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
253 dev->base_addr, dev->irq,
254 (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
255 dev->dev_addr);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200256 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258failed:
259 ibmtr_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200260 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261} /* ibmtr_config */
262
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200263static void ibmtr_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100265 ibmtr_dev_t *info = link->priv;
266 struct net_device *dev = info->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200268 dev_dbg(&link->dev, "ibmtr_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200270 if (link->resource[2]->end) {
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100271 struct tok_info *ti = netdev_priv(dev);
272 iounmap(ti->mmio);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100273 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200274 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275}
276
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200277static int ibmtr_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100278{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100279 ibmtr_dev_t *info = link->priv;
280 struct net_device *dev = info->dev;
281
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100282 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100283 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100284
285 return 0;
286}
287
Al Viro8814b502008-11-22 17:35:44 +0000288static int __devinit ibmtr_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100289{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100290 ibmtr_dev_t *info = link->priv;
291 struct net_device *dev = info->dev;
292
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100293 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100294 ibmtr_probe(dev); /* really? */
295 netif_device_attach(dev);
296 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100297
298 return 0;
299}
300
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302/*====================================================================*/
303
304static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
305{
306 int i;
307
308 /* Bizarre IBM behavior, there are 16 bits of information we
309 need to set, but the card only allows us to send 4 bits at a
310 time. For each byte sent to base_addr, bits 7-4 tell the
311 card which part of the 16 bits we are setting, bits 3-0 contain
312 the actual information */
313
314 /* First nibble provides 4 bits of mmio */
315 i = (mmiobase >> 16) & 0x0F;
316 outb(i, dev->base_addr);
317
318 /* Second nibble provides 3 bits of mmio */
319 i = 0x10 | ((mmiobase >> 12) & 0x0E);
320 outb(i, dev->base_addr);
321
322 /* Third nibble, hard-coded values */
323 i = 0x26;
324 outb(i, dev->base_addr);
325
326 /* Fourth nibble sets shared ram page size */
327
328 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
329 i = (sramsize >> 4) & 0x07;
330 i = ((i == 4) ? 3 : i) << 2;
331 i |= 0x30;
332
333 if (ringspeed == 16)
334 i |= 2;
335 if (dev->base_addr == 0xA24)
336 i |= 1;
337 outb(i, dev->base_addr);
338
339 /* 0x40 will release the card for use */
340 outb(0x40, dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341}
342
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700343static struct pcmcia_device_id ibmtr_ids[] = {
344 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
345 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
346 PCMCIA_DEVICE_NULL,
347};
348MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350static struct pcmcia_driver ibmtr_cs_driver = {
351 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200352 .name = "ibmtr_cs",
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100353 .probe = ibmtr_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100354 .remove = ibmtr_detach,
Dominik Brodowski469bf2b92005-06-27 16:28:22 -0700355 .id_table = ibmtr_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100356 .suspend = ibmtr_suspend,
357 .resume = ibmtr_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358};
359
360static int __init init_ibmtr_cs(void)
361{
362 return pcmcia_register_driver(&ibmtr_cs_driver);
363}
364
365static void __exit exit_ibmtr_cs(void)
366{
367 pcmcia_unregister_driver(&ibmtr_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
369
370module_init(init_ibmtr_cs);
371module_exit(exit_ibmtr_cs);