ibmtr.c 63.2 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4
/* ibmtr.c:  A shared-memory IBM Token Ring 16/4 driver for linux
 *
 *	Written 1993 by Mark Swanson and Peter De Schrijver.
 *	This software may be used and distributed according to the terms
Linus Torvalds's avatar
Linus Torvalds committed
5
 *	of the GNU General Public License, incorporated herein by reference.
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8 9
 *
 *	This device driver should work with Any IBM Token Ring Card that does
 *	not use DMA.
 *
Linus Torvalds's avatar
Linus Torvalds committed
10
 *	I used Donald Becker's (becker@scyld.com) device driver work
Linus Torvalds's avatar
Linus Torvalds committed
11 12
 *	as a base for most of my initial work.
 *
Linus Torvalds's avatar
Linus Torvalds committed
13 14
 *	Changes by Peter De Schrijver
 *		(Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
Linus Torvalds's avatar
Linus Torvalds committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
 *
 *	+ changed name to ibmtr.c in anticipation of other tr boards.
 *	+ changed reset code and adapter open code.
 *	+ added SAP open code.
 *	+ a first attempt to write interrupt, transmit and receive routines.
 *
 *	Changes by David W. Morris (dwm@shell.portal.com) :
 *	941003 dwm: - Restructure tok_probe for multiple adapters, devices.
 *	+ Add comments, misc reorg for clarity.
 *	+ Flatten interrupt handler levels.
 *
 *	Changes by Farzad Farid (farzy@zen.via.ecp.fr)
 *	and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) :
 *	+ multi ring support clean up.
 *	+ RFC1042 compliance enhanced.
 *
 *	Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) :
 *	+ bug correction in tr_tx
 *	+ removed redundant information display
 *	+ some code reworking
 *
 *	Changes by Michel Lespinasse (walken@via.ecp.fr),
 *	Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr)
 *	(February 18, 1996) :
 *	+ modified shared memory and mmio access port the driver to
 *	  alpha platform (structure access -> readb/writeb)
 *
 *	Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com)
 *	(January 18 1996):
 *	+ swapped WWOR and WWCR in ibmtr.h
 *	+ moved some init code from tok_probe into trdev_init.  The
 *	  PCMCIA code can call trdev_init to complete initializing
 *	  the driver.
 *	+ added -DPCMCIA to support PCMCIA
 *	+ detecting PCMCIA Card Removal in interrupt handler.  If
 *	  ISRP is FF, then a PCMCIA card has been removed
Linus Torvalds's avatar
Linus Torvalds committed
51
 *        10/2000 Burt needed a new method to avoid crashing the OS
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
 *
 *	Changes by Paul Norton (pnorton@cts.com) :
 *	+ restructured the READ.LOG logic to prevent the transmit SRB
 *	  from being rudely overwritten before the transmit cycle is
 *	  complete. (August 15 1996)
 *	+ completed multiple adapter support. (November 20 1996)
 *	+ implemented csum_partial_copy in tr_rx and increased receive 
 *        buffer size and count. Minor fixes. (March 15, 1997)
 *
 *	Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
 *	+ Now compiles ok as a module again.
 *
 *	Changes by Paul Norton (pnorton@ieee.org) :
 *      + moved the header manipulation code in tr_tx and tr_rx to
 *        net/802/tr.c. (July 12 1997)
 *      + add retry and timeout on open if cable disconnected. (May 5 1998)
 *      + lifted 2000 byte mtu limit. now depends on shared-RAM size.
 *        May 25 1998)
 *      + can't allocate 2k recv buff at 8k shared-RAM. (20 October 1998)
 *
 *      Changes by Joel Sloan (jjs@c-me.com) :
 *      + disable verbose debug messages by default - to enable verbose
 *	  debugging, edit the IBMTR_DEBUG_MESSAGES define below 
 *	
 *	Changes by Mike Phillips <phillim@amtrak.com> :
 *	+ Added extra #ifdef's to work with new PCMCIA Token Ring Code.
 *	  The PCMCIA code now just sets up the card so it can be recognized
 *        by ibmtr_probe. Also checks allocated memory vs. on-board memory
 *	  for correct figure to use.
 *
 *	Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) :
 *	+ added spinlocks for SMP sanity (10 March 1999)
 *
 *      Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting
 *      i.e. using functional address C0 00 00 04 00 00 to transmit and 
 *      receive multicast packets.
Linus Torvalds's avatar
Linus Torvalds committed
88
 *
Linus Torvalds's avatar
Linus Torvalds committed
89 90 91 92 93 94 95
 *      Changes by Mike Sullivan (based on original sram patch by Dave Grothe
 *      to support windowing into on adapter shared ram.
 *      i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging
 *      will shift this 16K window over the entire available shared RAM.
 *
 *      Changes by Peter De Schrijver (p2@mind.be) :
 *      + fixed a problem with PCMCIA card removal
Linus Torvalds's avatar
Linus Torvalds committed
96 97 98 99 100 101 102
 *
 *      Change by Mike Sullivan et al.:
 *      + added turbo card support. No need to use lanaid to configure
 *      the adapter into isa compatiblity mode.
 *
 *      Changes by Burt Silverman to allow the computer to behave nicely when
 *	a cable is pulled or not in place, or a PCMCIA card is removed hot.
Linus Torvalds's avatar
Linus Torvalds committed
103 104 105 106 107 108 109 110 111
 */

/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value 
in the event that chatty debug messages are desired - jjs 12/30/98 */

#define IBMTR_DEBUG_MESSAGES 0

#include <linux/module.h>

112 113
#ifdef PCMCIA		/* required for ibmtr_cs.c to build */
#undef MODULE		/* yes, really */
Linus Torvalds's avatar
Linus Torvalds committed
114 115 116 117
#undef ENABLE_PAGING
#else
#define ENABLE_PAGING 1		
#endif
Linus Torvalds's avatar
Linus Torvalds committed
118 119 120 121

#define FALSE 0
#define TRUE (!FALSE)

Linus Torvalds's avatar
Linus Torvalds committed
122
/* changes the output format of driver initialization */
Linus Torvalds's avatar
Linus Torvalds committed
123 124 125 126 127 128 129 130 131
#define TR_VERBOSE	0

/* some 95 OS send many non UI frame; this allow removing the warning */
#define TR_FILTERNONUI	1

#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/trdevice.h>
#include <linux/ibmtr.h>
132

Linus Torvalds's avatar
Linus Torvalds committed
133 134 135 136 137 138 139 140 141
#include <net/checksum.h>

#include <asm/io.h>

#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))

Linus Torvalds's avatar
Linus Torvalds committed
142 143 144 145 146 147 148 149 150 151 152
/* version and credits */
#ifndef PCMCIA
static char version[] __initdata =
    "\nibmtr.c: v1.3.57   8/ 7/94 Peter De Schrijver and Mark Swanson\n"
    "         v2.1.125 10/20/98 Paul Norton    <pnorton@ieee.org>\n"
    "         v2.2.0   12/30/98 Joel Sloan     <jjs@c-me.com>\n"
    "         v2.2.1   02/08/00 Mike Sullivan  <sullivam@us.ibm.com>\n" 
    "         v2.2.2   07/27/00 Burt Silverman <burts@us.ibm.com>\n" 
    "         v2.4.0   03/01/01 Mike Sullivan <sullivan@us.ibm.com>\n";
#endif

Linus Torvalds's avatar
Linus Torvalds committed
153 154
/* this allows displaying full adapter information */

Linus Torvalds's avatar
Linus Torvalds committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
char *channel_def[] __initdata = { "ISA", "MCA", "ISA P&P" };

static char pcchannelid[] __devinitdata = {
	0x05, 0x00, 0x04, 0x09,
	0x04, 0x03, 0x04, 0x0f,
	0x03, 0x06, 0x03, 0x01,
	0x03, 0x01, 0x03, 0x00,
	0x03, 0x09, 0x03, 0x09,
	0x03, 0x00, 0x02, 0x00
};

static char mcchannelid[] __devinitdata =  {
	0x04, 0x0d, 0x04, 0x01,
	0x05, 0x02, 0x05, 0x03,
	0x03, 0x06, 0x03, 0x03,
	0x05, 0x08, 0x03, 0x04,
	0x03, 0x05, 0x03, 0x01,
	0x03, 0x08, 0x02, 0x00
Linus Torvalds's avatar
Linus Torvalds committed
173 174
};

Linus Torvalds's avatar
Linus Torvalds committed
175
char __devinit *adapter_def(char type)
Linus Torvalds's avatar
Linus Torvalds committed
176
{
Linus Torvalds's avatar
Linus Torvalds committed
177 178 179 180 181 182
	switch (type) {
	case 0xF: return "PC Adapter | PC Adapter II | Adapter/A";
	case 0xE: return "16/4 Adapter | 16/4 Adapter/A (long)";
	case 0xD: return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
	case 0xC: return "Auto 16/4 Adapter";
	default: return "adapter (unknown type)";
Linus Torvalds's avatar
Linus Torvalds committed
183 184 185
	};
};

Linus Torvalds's avatar
Linus Torvalds committed
186 187 188
#define TRC_INIT 0x01		/*  Trace initialization & PROBEs */
#define TRC_INITV 0x02		/*  verbose init trace points     */
unsigned char ibmtr_debug_trace = 0;
Linus Torvalds's avatar
Linus Torvalds committed
189

Linus Torvalds's avatar
Linus Torvalds committed
190
int 		ibmtr_probe(struct net_device *dev);
Linus Torvalds's avatar
Linus Torvalds committed
191
static int	ibmtr_probe1(struct net_device *dev, int ioaddr);
Linus Torvalds's avatar
Linus Torvalds committed
192 193 194 195 196 197 198 199 200
static unsigned char get_sram_size(struct tok_info *adapt_info);
static int 	trdev_init(struct net_device *dev);
static int 	tok_open(struct net_device *dev);
static int 	tok_init_card(struct net_device *dev);
void 		tok_open_adapter(unsigned long dev_addr);
static void 	open_sap(unsigned char type, struct net_device *dev);
static void 	tok_set_multicast_list(struct net_device *dev);
static int 	tok_send_packet(struct sk_buff *skb, struct net_device *dev);
static int 	tok_close(struct net_device *dev);
Andrew Morton's avatar
Andrew Morton committed
201
irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
Linus Torvalds's avatar
Linus Torvalds committed
202
static void 	initial_tok_int(struct net_device *dev);
Linus Torvalds's avatar
Linus Torvalds committed
203 204 205 206 207 208 209 210 211 212 213
static void 	tr_tx(struct net_device *dev);
static void 	tr_rx(struct net_device *dev);
void 		ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev);
static void	tok_rerun(unsigned long dev_addr);
void 		ibmtr_readlog(struct net_device *dev);
static struct 	net_device_stats *tok_get_stats(struct net_device *dev);
int 		ibmtr_change_mtu(struct net_device *dev, int mtu);
static void	find_turbo_adapters(int *iolist);

static int ibmtr_portlist[IBMTR_MAX_ADAPTERS+1] __devinitdata = {
	0xa20, 0xa24, 0, 0, 0
Linus Torvalds's avatar
Linus Torvalds committed
214
};
Linus Torvalds's avatar
Linus Torvalds committed
215 216 217
static int __devinitdata turbo_io[IBMTR_MAX_ADAPTERS] = {0};
static int __devinitdata turbo_irq[IBMTR_MAX_ADAPTERS] = {0};
static int __devinitdata turbo_searched = 0;
Linus Torvalds's avatar
Linus Torvalds committed
218

Linus Torvalds's avatar
Linus Torvalds committed
219 220 221
#ifndef PCMCIA
static __u32 ibmtr_mem_base __initdata = 0xd0000;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
222

Linus Torvalds's avatar
Linus Torvalds committed
223
static void __devinit PrtChanID(char *pcid, short stride)
Linus Torvalds's avatar
Linus Torvalds committed
224 225
{
	short i, j;
Linus Torvalds's avatar
Linus Torvalds committed
226
	for (i = 0, j = 0; i < 24; i++, j += stride)
Linus Torvalds's avatar
Linus Torvalds committed
227 228 229 230
		printk("%1x", ((int) pcid[j]) & 0x0f);
	printk("\n");
}

Linus Torvalds's avatar
Linus Torvalds committed
231
static void __devinit HWPrtChanID(void * pcid, short stride)
Linus Torvalds's avatar
Linus Torvalds committed
232 233
{
	short i, j;
Linus Torvalds's avatar
Linus Torvalds committed
234 235
	for (i = 0, j = 0; i < 24; i++, j += stride)
		printk("%1x", ((int) readb(pcid + j)) & 0x0f);
Linus Torvalds's avatar
Linus Torvalds committed
236 237 238
	printk("\n");
}

239 240 241 242
/* We have to ioremap every checked address, because isa_readb is 
 * going away. 
 */

Linus Torvalds's avatar
Linus Torvalds committed
243 244 245
static void __devinit find_turbo_adapters(int *iolist) {
	int ram_addr;
	int index=0;
Alan Cox's avatar
Alan Cox committed
246
	void *chanid;
Linus Torvalds's avatar
Linus Torvalds committed
247 248
	int found_turbo=0;
	unsigned char *tchanid, ctemp;
249 250
	int i, j;
	unsigned long jif;
251 252
	void *ram_mapped ;   

Linus Torvalds's avatar
Linus Torvalds committed
253 254 255 256 257 258 259
	if (turbo_searched == 1) return;
	turbo_searched=1;
	for (ram_addr=0xC0000; ram_addr < 0xE0000; ram_addr+=0x2000) {

		__u32 intf_tbl=0;

		found_turbo=1;
260 261 262 263
		ram_mapped = ioremap((u32)ram_addr,0x1fff) ; 
		if (ram_mapped==NULL) 
 			continue ; 
		chanid=(CHANNEL_ID + ram_mapped);
Linus Torvalds's avatar
Linus Torvalds committed
264
		tchanid=pcchannelid;
265
		ctemp=readb(chanid) & 0x0f;
Linus Torvalds's avatar
Linus Torvalds committed
266 267
		if (ctemp != *tchanid) continue;
		for (i=2,j=1; i<=46; i=i+2,j++) {
268
			if ((readb(chanid+i) & 0x0f) != tchanid[j]){
Linus Torvalds's avatar
Linus Torvalds committed
269 270 271 272 273 274
				found_turbo=0;
				break;
			}
		}
		if (!found_turbo) continue;

275
		writeb(0x90, ram_mapped+0x1E01);
Linus Torvalds's avatar
Linus Torvalds committed
276
		for(i=2; i<0x0f; i++) {
277
			writeb(0x00, ram_mapped+0x1E01+i);
Linus Torvalds's avatar
Linus Torvalds committed
278
		}
279
		writeb(0x00, ram_mapped+0x1E01);
280
		for(jif=jiffies+TR_BUSY_INTERVAL; time_before_eq(jiffies,jif););
281
		intf_tbl=ntohs(readw(ram_mapped+ACA_OFFSET+ACA_RW+WRBR_EVEN));
Linus Torvalds's avatar
Linus Torvalds committed
282 283 284 285 286 287
		if (intf_tbl) {
#if IBMTR_DEBUG_MESSAGES
			printk("ibmtr::find_turbo_adapters, Turbo found at "
				"ram_addr %x\n",ram_addr);
			printk("ibmtr::find_turbo_adapters, interface_table ");
			for(i=0; i<6; i++) {
288
				printk("%x:",readb(ram_addr+intf_tbl+i));
Linus Torvalds's avatar
Linus Torvalds committed
289 290 291
			}
			printk("\n");
#endif
292 293
			turbo_io[index]=ntohs(readw(ram_mapped+intf_tbl+4));
			turbo_irq[index]=readb(ram_mapped+intf_tbl+3);
Linus Torvalds's avatar
Linus Torvalds committed
294
			outb(0, turbo_io[index] + ADAPTRESET);
295
			for(jif=jiffies+TR_RST_TIME;time_before_eq(jiffies,jif););
Linus Torvalds's avatar
Linus Torvalds committed
296 297 298 299 300 301 302 303
			outb(0, turbo_io[index] + ADAPTRESETREL);
			index++;
			continue;
		}
#if IBMTR_DEBUG_MESSAGES 
		printk("ibmtr::find_turbo_adapters, ibmtr card found at"
			" %x but not a Turbo model\n",ram_addr);
#endif
Alan Cox's avatar
Alan Cox committed
304
	iounmap(ram_mapped) ; 	
305
	} /* for */
Linus Torvalds's avatar
Linus Torvalds committed
306 307 308 309 310 311 312 313 314 315 316
	for(i=0; i<IBMTR_MAX_ADAPTERS; i++) {
		if(!turbo_io[i]) break;
		for (j=0; j<IBMTR_MAX_ADAPTERS; j++) {
			if ( iolist[j] && iolist[j] != turbo_io[i]) continue;
			iolist[j]=turbo_io[i];
			break;
		}
	}
}

/****************************************************************************
Linus Torvalds's avatar
Linus Torvalds committed
317 318 319 320 321 322 323 324 325
 *	ibmtr_probe():  Routine specified in the network device structure
 *	to probe for an IBM Token Ring Adapter.  Routine outline:
 *	I.    Interrogate hardware to determine if an adapter exists
 *	      and what the speeds and feeds are
 *	II.   Setup data structures to control execution based upon
 *	      adapter characteristics.
 *
 *	We expect ibmtr_probe to be called once for each device entry
 *	which references it.
Linus Torvalds's avatar
Linus Torvalds committed
326 327 328
 ****************************************************************************/

int __devinit ibmtr_probe(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
329
{
Linus Torvalds's avatar
Linus Torvalds committed
330 331
	int i;
	int base_addr = dev->base_addr;
Linus Torvalds's avatar
Linus Torvalds committed
332

Linus Torvalds's avatar
Linus Torvalds committed
333 334 335 336 337 338 339 340 341
	if (base_addr && base_addr <= 0x1ff) /* Don't probe at all. */
		return -ENXIO;
	if (base_addr > 0x1ff) { /* Check a single specified location.  */
		if (!ibmtr_probe1(dev, base_addr)) return 0;
		return -ENODEV;
	}
	find_turbo_adapters(ibmtr_portlist);
	for (i = 0; ibmtr_portlist[i]; i++) {
		int ioaddr = ibmtr_portlist[i];
Linus Torvalds's avatar
Linus Torvalds committed
342

Linus Torvalds's avatar
Linus Torvalds committed
343 344 345
		if (!ibmtr_probe1(dev, ioaddr)) return 0;
	}
	return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
346 347
}

Linus Torvalds's avatar
Linus Torvalds committed
348 349 350
/*****************************************************************************/

static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
Linus Torvalds's avatar
Linus Torvalds committed
351
{
Linus Torvalds's avatar
Linus Torvalds committed
352 353

	unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
Linus Torvalds's avatar
Linus Torvalds committed
354
	void * t_mmio = 0;
355
	struct tok_info *ti = dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
356
	void *cd_chanid;
Linus Torvalds's avatar
Linus Torvalds committed
357 358
	unsigned char *tchanid, ctemp;
#ifndef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
359 360 361
	unsigned char t_irq=0;
        unsigned long timeout;
	static int version_printed;
Linus Torvalds's avatar
Linus Torvalds committed
362 363
#endif

Linus Torvalds's avatar
Linus Torvalds committed
364 365 366
	/*    Query the adapter PIO base port which will return
	 *    indication of where MMIO was placed. We also have a
	 *    coded interrupt number.
Linus Torvalds's avatar
Linus Torvalds committed
367
	 */
Linus Torvalds's avatar
Linus Torvalds committed
368 369 370 371 372 373 374 375 376 377 378
	segment = inb(PIOaddr);
	if (segment < 0x40 || segment > 0xe0) {
		/* Out of range values so we'll assume non-existent IO device
		 * but this is not necessarily a problem, esp if a turbo
		 * adapter is being used.  */
#if IBMTR_DEBUG_MESSAGES
		DPRINTK("ibmtr_probe1(): unhappy that inb(0x%X) == 0x%X, "
			"Hardware Problem?\n",PIOaddr,segment);
#endif
		return -ENODEV;
	}
Linus Torvalds's avatar
Linus Torvalds committed
379
	/*
Linus Torvalds's avatar
Linus Torvalds committed
380 381
	 *    Compute the linear base address of the MMIO area
	 *    as LINUX doesn't care about segments
Linus Torvalds's avatar
Linus Torvalds committed
382
	 */
Linus Torvalds's avatar
Linus Torvalds committed
383
	t_mmio = ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
Linus Torvalds's avatar
Linus Torvalds committed
384 385 386 387 388
	if (!t_mmio) { 
		DPRINTK("Cannot remap mmiobase memory area") ; 
		return -ENODEV ; 
	} 
	intr = segment & 0x03;	/* low bits is coded interrupt # */
Linus Torvalds's avatar
Linus Torvalds committed
389
	if (ibmtr_debug_trace & TRC_INIT)
Linus Torvalds's avatar
Linus Torvalds committed
390
		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %p intr: %d\n"
Linus Torvalds's avatar
Linus Torvalds committed
391
				, PIOaddr, (int) segment, t_mmio, (int) intr);
Linus Torvalds's avatar
Linus Torvalds committed
392 393

	/*
Linus Torvalds's avatar
Linus Torvalds committed
394 395
	 *    Now we will compare expected 'channelid' strings with
	 *    what we is there to learn of ISA/MCA or not TR card
Linus Torvalds's avatar
Linus Torvalds committed
396
	 */
Linus Torvalds's avatar
Linus Torvalds committed
397
#ifdef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
398 399
	iounmap(t_mmio);
	t_mmio = (void *)ti->mmio;	/*BMS to get virtual address */
Linus Torvalds's avatar
Linus Torvalds committed
400 401 402 403 404 405 406 407 408 409 410 411 412
	irq = ti->irq;		/*BMS to display the irq!   */
#endif
	cd_chanid = (CHANNEL_ID + t_mmio);	/* for efficiency */
	tchanid = pcchannelid;
	cardpresent = TR_ISA;	/* try ISA */

	/*    Suboptimize knowing first byte different */
	ctemp = readb(cd_chanid) & 0x0f;
	if (ctemp != *tchanid) {	/* NOT ISA card, try MCA */
		tchanid = mcchannelid;
		cardpresent = TR_MCA;
		if (ctemp != *tchanid)	/* Neither ISA nor MCA */
			cardpresent = NOTOK;
Linus Torvalds's avatar
Linus Torvalds committed
413
	}
Linus Torvalds's avatar
Linus Torvalds committed
414 415 416 417 418 419 420
	if (cardpresent != NOTOK) {
		/*       Know presumed type, try rest of ID */
		for (i = 2, j = 1; i <= 46; i = i + 2, j++) {
			if( (readb(cd_chanid+i)&0x0f) == tchanid[j]) continue;
			/* match failed, not TR card */
			cardpresent = NOTOK;
			break;
Linus Torvalds's avatar
Linus Torvalds committed
421 422 423
		}
	}
	/* 
Linus Torvalds's avatar
Linus Torvalds committed
424 425
	 *    If we have an ISA board check for the ISA P&P version,
	 *    as it has different IRQ settings 
Linus Torvalds's avatar
Linus Torvalds committed
426
	 */
Linus Torvalds's avatar
Linus Torvalds committed
427 428 429
	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e))
		cardpresent = TR_ISAPNP;
	if (cardpresent == NOTOK) {	/* "channel_id" did not match, report */
Linus Torvalds's avatar
Linus Torvalds committed
430 431 432 433 434 435
		if (!(ibmtr_debug_trace & TRC_INIT)) {
#ifndef PCMCIA
			iounmap(t_mmio);
#endif
			return -ENODEV;
		}
Linus Torvalds's avatar
Linus Torvalds committed
436 437 438 439 440 441 442 443 444 445 446
		DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n",
								PIOaddr);
		DPRINTK("Expected for ISA: ");
		PrtChanID(pcchannelid, 1);
		DPRINTK("           found: ");
/* BMS Note that this can be misleading, when hardware is flaky, because you
   are reading it a second time here. So with my flaky hardware, I'll see my-
   self in this block, with the HW ID matching the ISA ID exactly! */
		HWPrtChanID(cd_chanid, 2);
		DPRINTK("Expected for MCA: ");
		PrtChanID(mcchannelid, 1);
Linus Torvalds's avatar
Linus Torvalds committed
447
	}
448
	/* Now, setup some of the pl0 buffers for this driver.. */
Linus Torvalds's avatar
Linus Torvalds committed
449
	/* If called from PCMCIA, it is already set up, so no need to 
Linus Torvalds's avatar
Linus Torvalds committed
450 451
	   waste the memory, just use the existing structure */
#ifndef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
452
	ti->mmio = t_mmio;
453 454 455
        for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) {
                if (turbo_io[i] != PIOaddr)
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
456
#if IBMTR_DEBUG_MESSAGES 
457 458
		printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n",
		       PIOaddr);
Linus Torvalds's avatar
Linus Torvalds committed
459
#endif
460 461
		ti->turbo = 1;
		t_irq = turbo_irq[i];
Linus Torvalds's avatar
Linus Torvalds committed
462
        }
Linus Torvalds's avatar
Linus Torvalds committed
463
#endif /* !PCMCIA */
Linus Torvalds's avatar
Linus Torvalds committed
464 465 466
	ti->readlog_pending = 0;
	init_waitqueue_head(&ti->wait_for_reset);

Linus Torvalds's avatar
Linus Torvalds committed
467 468 469
	/* if PCMCIA, the card can be recognized as either TR_ISA or TR_ISAPNP
	 * depending which card is inserted.	*/
	
Linus Torvalds's avatar
Linus Torvalds committed
470
#ifndef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
	switch (cardpresent) {
	case TR_ISA:
		if (intr == 0) irq = 9;	/* irq2 really is irq9 */
		if (intr == 1) irq = 3;
		if (intr == 2) irq = 6;
		if (intr == 3) irq = 7;
		ti->adapter_int_enable = PIOaddr + ADAPTINTREL;
		break;
	case TR_MCA:
		if (intr == 0) irq = 9;
		if (intr == 1) irq = 3;
		if (intr == 2) irq = 10;
		if (intr == 3) irq = 11;
		ti->global_int_enable = 0;
		ti->adapter_int_enable = 0;
		ti->sram_virt=(__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12;
		break;
	case TR_ISAPNP:
		if (!t_irq) {
			if (intr == 0) irq = 9;
			if (intr == 1) irq = 3;
			if (intr == 2) irq = 10;
			if (intr == 3) irq = 11;
		} else
			irq=t_irq;
		timeout = jiffies + TR_SPIN_INTERVAL;
		while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){
			if (!time_after(jiffies, timeout)) continue;
			DPRINTK( "Hardware timeout during initialization.\n");
Linus Torvalds's avatar
Linus Torvalds committed
500
			iounmap(t_mmio);
Linus Torvalds's avatar
Linus Torvalds committed
501 502 503 504 505 506 507 508 509 510 511 512 513 514
			kfree(ti);
			return -ENODEV;
		}
		ti->sram_virt =
		     ((__u32)readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_EVEN)<<12);
		ti->adapter_int_enable = PIOaddr + ADAPTINTREL;
		break;
	} /*end switch (cardpresent) */
#endif	/*not PCMCIA */

	if (ibmtr_debug_trace & TRC_INIT) {	/* just report int */
		DPRINTK("irq=%d", irq);
		printk(", sram_virt=0x%x", ti->sram_virt);
		if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */
Linus Torvalds's avatar
Linus Torvalds committed
515
			DPRINTK(", ti->mmio=%p", ti->mmio);
Linus Torvalds's avatar
Linus Torvalds committed
516
			printk(", segment=%02X", segment);
Linus Torvalds's avatar
Linus Torvalds committed
517 518 519 520 521
		}
		printk(".\n");
	}

	/* Get hw address of token ring card */
Linus Torvalds's avatar
Linus Torvalds committed
522 523
	j = 0;
	for (i = 0; i < 0x18; i = i + 2) {
Linus Torvalds's avatar
Linus Torvalds committed
524
		/* technical reference states to do this */
Linus Torvalds's avatar
Linus Torvalds committed
525 526 527 528 529
		temp = readb(ti->mmio + AIP + i) & 0x0f;
		ti->hw_address[j] = temp;
		if (j & 1)
			dev->dev_addr[(j / 2)] =
				ti->hw_address[j]+ (ti->hw_address[j - 1] << 4);
Linus Torvalds's avatar
Linus Torvalds committed
530 531
		++j;
	}
Linus Torvalds's avatar
Linus Torvalds committed
532 533
	/* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,... */
	ti->adapter_type = readb(ti->mmio + AIPADAPTYPE);
Linus Torvalds's avatar
Linus Torvalds committed
534 535

	/* get Data Rate:  F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */
Linus Torvalds's avatar
Linus Torvalds committed
536
	ti->data_rate = readb(ti->mmio + AIPDATARATE);
Linus Torvalds's avatar
Linus Torvalds committed
537 538

	/* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */
Linus Torvalds's avatar
Linus Torvalds committed
539
	ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
Linus Torvalds's avatar
Linus Torvalds committed
540 541

	/* How much shared RAM is on adapter ? */
Linus Torvalds's avatar
Linus Torvalds committed
542 543 544 545 546 547
	if (ti->turbo) {
		ti->avail_shared_ram=127;
	} else {
		ti->avail_shared_ram = get_sram_size(ti);/*in 512 byte units */
	}
	/* We need to set or do a bunch of work here based on previous results*/
Linus Torvalds's avatar
Linus Torvalds committed
548
	/* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
Linus Torvalds's avatar
Linus Torvalds committed
549 550 551 552 553 554 555
	ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);

	/* Available DHB  4Mb size:   F=2048, E=4096, D=4464 */
	switch (readb(ti->mmio + AIP4MBDHB)) {
	case 0xe: ti->dhb_size4mb = 4096; break;
	case 0xd: ti->dhb_size4mb = 4464; break;
	default:  ti->dhb_size4mb = 2048; break;
Linus Torvalds's avatar
Linus Torvalds committed
556 557 558
	}

	/* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
Linus Torvalds's avatar
Linus Torvalds committed
559 560 561 562 563 564
	switch (readb(ti->mmio + AIP16MBDHB)) {
	case 0xe: ti->dhb_size16mb = 4096; break;
	case 0xd: ti->dhb_size16mb = 8192; break;
	case 0xc: ti->dhb_size16mb = 16384; break;
	case 0xb: ti->dhb_size16mb = 17960; break;
	default:  ti->dhb_size16mb = 2048; break;
Linus Torvalds's avatar
Linus Torvalds committed
565 566
	}

Linus Torvalds's avatar
Linus Torvalds committed
567 568 569 570 571 572
	/*    We must figure out how much shared memory space this adapter
	 *    will occupy so that if there are two adapters we can fit both
	 *    in.  Given a choice, we will limit this adapter to 32K.  The
	 *    maximum space will will use for two adapters is 64K so if the
	 *    adapter we are working on demands 64K (it also doesn't support
	 *    paging), then only one adapter can be supported.  
Linus Torvalds's avatar
Linus Torvalds committed
573 574 575
	 */

	/*
Linus Torvalds's avatar
Linus Torvalds committed
576
	 *    determine how much of total RAM is mapped into PC space 
Linus Torvalds's avatar
Linus Torvalds committed
577
	 */
Linus Torvalds's avatar
Linus Torvalds committed
578 579 580 581 582 583
	ti->mapped_ram_size= /*sixteen to onehundredtwentyeight 512byte blocks*/
	    1<< ((readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03) + 4);
	ti->page_mask = 0;
	if (ti->turbo)  ti->page_mask=0xf0;
	else if (ti->shared_ram_paging == 0xf);  /* No paging in adapter */
	else {
Linus Torvalds's avatar
Linus Torvalds committed
584
#ifdef ENABLE_PAGING
Linus Torvalds's avatar
Linus Torvalds committed
585 586 587 588
		unsigned char pg_size = 0;
		/* BMS:   page size: PCMCIA, use configuration register;
		   ISAPNP, use LANAIDC config tool from www.ibm.com  */
		switch (ti->shared_ram_paging) {
Linus Torvalds's avatar
Linus Torvalds committed
589 590 591
		case 0xf:
			break;
		case 0xe:
Linus Torvalds's avatar
Linus Torvalds committed
592 593
			ti->page_mask = (ti->mapped_ram_size == 32) ? 0xc0 : 0;
			pg_size = 32;	/* 16KB page size */
Linus Torvalds's avatar
Linus Torvalds committed
594 595
			break;
		case 0xd:
Linus Torvalds's avatar
Linus Torvalds committed
596 597
			ti->page_mask = (ti->mapped_ram_size == 64) ? 0x80 : 0;
			pg_size = 64;	/* 32KB page size */
Linus Torvalds's avatar
Linus Torvalds committed
598 599
			break;
		case 0xc:
Linus Torvalds's avatar
Linus Torvalds committed
600 601 602 603 604 605 606 607 608 609
			switch (ti->mapped_ram_size) {
			case 32:
				ti->page_mask = 0xc0;
				pg_size = 32;
				break;
			case 64:
				ti->page_mask = 0x80;
				pg_size = 64;
				break;
			}
Linus Torvalds's avatar
Linus Torvalds committed
610 611
			break;
		default:
Linus Torvalds's avatar
Linus Torvalds committed
612 613
			DPRINTK("Unknown shared ram paging info %01X\n",
							ti->shared_ram_paging);
Linus Torvalds's avatar
Linus Torvalds committed
614
			iounmap(t_mmio); 
Linus Torvalds's avatar
Linus Torvalds committed
615 616 617
			kfree(ti);
			return -ENODEV;
			break;
Linus Torvalds's avatar
Linus Torvalds committed
618 619 620 621 622 623 624 625 626
		} /*end switch shared_ram_paging */

		if (ibmtr_debug_trace & TRC_INIT)
			DPRINTK("Shared RAM paging code: %02X, "
				"mapped RAM size: %dK, shared RAM size: %dK, "
				"page mask: %02X\n:",
				ti->shared_ram_paging, ti->mapped_ram_size / 2,
				ti->avail_shared_ram / 2, ti->page_mask);
#endif	/*ENABLE_PAGING */
Linus Torvalds's avatar
Linus Torvalds committed
627 628
	}

Linus Torvalds's avatar
Linus Torvalds committed
629
#ifndef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
630
	/* finish figuring the shared RAM address */
Linus Torvalds's avatar
Linus Torvalds committed
631 632 633
	if (cardpresent == TR_ISA) {
		static __u32 ram_bndry_mask[] =
			{ 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000 };
Linus Torvalds's avatar
Linus Torvalds committed
634 635
		__u32 new_base, rrr_32, chk_base, rbm;

Linus Torvalds's avatar
Linus Torvalds committed
636
		rrr_32=readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03;
Linus Torvalds's avatar
Linus Torvalds committed
637
		rbm = ram_bndry_mask[rrr_32];
Linus Torvalds's avatar
Linus Torvalds committed
638 639
		new_base = (ibmtr_mem_base + (~rbm)) & rbm;/* up to boundary */
		chk_base = new_base + (ti->mapped_ram_size << 9);
Linus Torvalds's avatar
Linus Torvalds committed
640
		if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) {
Linus Torvalds's avatar
Linus Torvalds committed
641 642 643
			DPRINTK("Shared RAM for this adapter (%05x) exceeds "
			"driver limit (%05x), adapter not started.\n",
			chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed
644
			iounmap(t_mmio);
Linus Torvalds's avatar
Linus Torvalds committed
645
			kfree(ti);
Linus Torvalds's avatar
Linus Torvalds committed
646 647
			return -ENODEV;
		} else { /* seems cool, record what we have figured out */
Linus Torvalds's avatar
Linus Torvalds committed
648 649 650 651
			ti->sram_base = new_base >> 12;
			ibmtr_mem_base = chk_base;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
652
	else  ti->sram_base = ti->sram_virt >> 12;
Linus Torvalds's avatar
Linus Torvalds committed
653 654 655

	/* The PCMCIA has already got the interrupt line and the io port, 
	   so no chance of anybody else getting it - MLP */
Linus Torvalds's avatar
Linus Torvalds committed
656 657 658
	if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) {
		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",
					irq);
Linus Torvalds's avatar
Linus Torvalds committed
659
		iounmap(t_mmio);
Linus Torvalds's avatar
Linus Torvalds committed
660 661 662 663
		kfree(ti);
		return -ENODEV;
	}
	/*?? Now, allocate some of the PIO PORTs for this driver.. */
Linus Torvalds's avatar
Linus Torvalds committed
664
	/* record PIOaddr range as busy */
Linus Torvalds's avatar
Linus Torvalds committed
665 666 667 668 669 670 671 672
	if (!request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr")) {
		DPRINTK("Could not grab PIO range. Halting driver.\n");
		free_irq(dev->irq, dev);
		iounmap(t_mmio);
		kfree(ti);
		return -EBUSY;
	}

Linus Torvalds's avatar
Linus Torvalds committed
673 674 675
	if (!version_printed++) {
		printk(version);
	}
Linus Torvalds's avatar
Linus Torvalds committed
676
#endif /* !PCMCIA */
Linus Torvalds's avatar
Linus Torvalds committed
677
	DPRINTK("%s %s found\n",
Linus Torvalds's avatar
Linus Torvalds committed
678
		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
Linus Torvalds's avatar
Linus Torvalds committed
679
	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
Linus Torvalds's avatar
Linus Torvalds committed
680
			irq, PIOaddr, ti->mapped_ram_size / 2);
Linus Torvalds's avatar
Linus Torvalds committed
681 682 683
	DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
Linus Torvalds's avatar
Linus Torvalds committed
684 685 686 687 688 689 690 691
	if (ti->page_mask)
		DPRINTK("Shared RAM paging enabled. "
			"Page size: %uK Shared Ram size %dK\n",
			((ti->page_mask^0xff)+1) >>2, ti->avail_shared_ram / 2);
	else
		DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n",
								ti->page_mask);

Linus Torvalds's avatar
Linus Torvalds committed
692
	/* Calculate the maximum DHB we can use */
Linus Torvalds's avatar
Linus Torvalds committed
693 694 695 696 697
	/* two cases where avail_shared_ram doesn't equal mapped_ram_size:
	    1. avail_shared_ram is 127 but mapped_ram_size is 128 (typical)
	    2. user has configured adapter for less than avail_shared_ram
	       but is not using paging (she should use paging, I believe)
	*/
Linus Torvalds's avatar
Linus Torvalds committed
698
	if (!ti->page_mask) {
Linus Torvalds's avatar
Linus Torvalds committed
699 700
		ti->avail_shared_ram=
				MIN(ti->mapped_ram_size,ti->avail_shared_ram);
Linus Torvalds's avatar
Linus Torvalds committed
701
	}
Linus Torvalds's avatar
Linus Torvalds committed
702

Linus Torvalds's avatar
Linus Torvalds committed
703
	switch (ti->avail_shared_ram) {
Linus Torvalds's avatar
Linus Torvalds committed
704 705
	case 16:		/* 8KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048);
Linus Torvalds's avatar
Linus Torvalds committed
706
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
707
		ti->rbuf_cnt4=2;
Linus Torvalds's avatar
Linus Torvalds committed
708 709
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
710
		ti->rbuf_cnt16=2;
Linus Torvalds's avatar
Linus Torvalds committed
711
		break;
Linus Torvalds's avatar
Linus Torvalds committed
712 713 714 715 716 717 718
	case 32:		/* 16KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
		ti->rbuf_len4 = 1032;
		ti->rbuf_cnt4=4;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096);
		ti->rbuf_len16 = 1032;	/*1024 usable */
		ti->rbuf_cnt16=4;
Linus Torvalds's avatar
Linus Torvalds committed
719
		break;
Linus Torvalds's avatar
Linus Torvalds committed
720 721
	case 64:		/* 32KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
Linus Torvalds's avatar
Linus Torvalds committed
722
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
723 724
		ti->rbuf_cnt4=6;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240);
Linus Torvalds's avatar
Linus Torvalds committed
725
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
726
		ti->rbuf_cnt16=6;
Linus Torvalds's avatar
Linus Torvalds committed
727
		break;
Linus Torvalds's avatar
Linus Torvalds committed
728 729
	case 127:		/* 63.5KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
Linus Torvalds's avatar
Linus Torvalds committed
730
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
731 732
		ti->rbuf_cnt4=6;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384);
Linus Torvalds's avatar
Linus Torvalds committed
733
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
734
		ti->rbuf_cnt16=16;
Linus Torvalds's avatar
Linus Torvalds committed
735
		break;
Linus Torvalds's avatar
Linus Torvalds committed
736 737
	case 128:		/* 64KB   shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
Linus Torvalds's avatar
Linus Torvalds committed
738
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
739 740
		ti->rbuf_cnt4=6;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960);
Linus Torvalds's avatar
Linus Torvalds committed
741
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
742
		ti->rbuf_cnt16=16;
Linus Torvalds's avatar
Linus Torvalds committed
743
		break;
Linus Torvalds's avatar
Linus Torvalds committed
744 745
	default:
		ti->dhb_size4mb = 2048;
Linus Torvalds's avatar
Linus Torvalds committed
746
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
747
		ti->rbuf_cnt4=2;
Linus Torvalds's avatar
Linus Torvalds committed
748 749
		ti->dhb_size16mb = 2048;
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
750
		ti->rbuf_cnt16=2;
Linus Torvalds's avatar
Linus Torvalds committed
751 752
		break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
	/* this formula is not smart enough for the paging case
	ti->rbuf_cnt<x> = (ti->avail_shared_ram * BLOCKSZ - ADAPT_PRIVATE -
			ARBLENGTH - SSBLENGTH - DLC_MAX_SAP * SAPLENGTH -
			DLC_MAX_STA * STALENGTH - ti->dhb_size<x>mb * NUM_DHB -
			SRBLENGTH - ASBLENGTH) / ti->rbuf_len<x>;
	*/
	ti->maxmtu16 = (ti->rbuf_len16 - 8) * ti->rbuf_cnt16  - TR_HLEN;
	ti->maxmtu4 = (ti->rbuf_len4 - 8) * ti->rbuf_cnt4 - TR_HLEN;
	/*BMS assuming 18 bytes of Routing Information (usually works) */
	DPRINTK("Maximum Receive Internet Protocol MTU 16Mbps: %d, 4Mbps: %d\n",
						     ti->maxmtu16, ti->maxmtu4);

	dev->base_addr = PIOaddr;	/* set the value for device */
	dev->mem_start = ti->sram_base << 12;
	dev->mem_end = dev->mem_start + (ti->mapped_ram_size << 9) - 1;
Linus Torvalds's avatar
Linus Torvalds committed
768
	trdev_init(dev);
Linus Torvalds's avatar
Linus Torvalds committed
769 770
	return 0;   /* Return 0 to indicate we have found a Token Ring card. */
}				/*ibmtr_probe1() */
Linus Torvalds's avatar
Linus Torvalds committed
771

Linus Torvalds's avatar
Linus Torvalds committed
772
/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
773 774

/* query the adapter for the size of shared RAM  */
Linus Torvalds's avatar
Linus Torvalds committed
775
/* the function returns the RAM size in units of 512 bytes */
Linus Torvalds's avatar
Linus Torvalds committed
776

Linus Torvalds's avatar
Linus Torvalds committed
777
static unsigned char __devinit get_sram_size(struct tok_info *adapt_info)
Linus Torvalds's avatar
Linus Torvalds committed
778 779
{
	unsigned char avail_sram_code;
Linus Torvalds's avatar
Linus Torvalds committed
780
	static unsigned char size_code[] = { 0, 16, 32, 64, 127, 128 };
Linus Torvalds's avatar
Linus Torvalds committed
781 782 783 784 785 786 787
	/* Adapter gives
	   'F' -- use RRR bits 3,2
	   'E' -- 8kb   'D' -- 16kb
	   'C' -- 32kb  'A' -- 64KB
	   'B' - 64KB less 512 bytes at top
	   (WARNING ... must zero top bytes in INIT */

Linus Torvalds's avatar
Linus Torvalds committed
788 789 790 791 792
	avail_sram_code = 0xf - readb(adapt_info->mmio + AIPAVAILSHRAM);
	if (avail_sram_code) return size_code[avail_sram_code];
	else		/* for code 'F', must compute size from RRR(3,2) bits */
		return 1 <<
		 ((readb(adapt_info->mmio+ACA_OFFSET+ACA_RW+RRR_ODD)>>2&3)+4);
Linus Torvalds's avatar
Linus Torvalds committed
793 794
}

Linus Torvalds's avatar
Linus Torvalds committed
795
/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
796

Linus Torvalds's avatar
Linus Torvalds committed
797 798 799
static int __devinit trdev_init(struct net_device *dev)
{
	struct tok_info *ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
800 801

	SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
802 803 804 805 806
        ti->open_failure = NO    ;
	dev->open = tok_open;
	dev->stop = tok_close;
	dev->hard_start_xmit = tok_send_packet;
	dev->get_stats = tok_get_stats;
Linus Torvalds's avatar
Linus Torvalds committed
807
	dev->set_multicast_list = tok_set_multicast_list;
Linus Torvalds's avatar
Linus Torvalds committed
808
	dev->change_mtu = ibmtr_change_mtu;
Linus Torvalds's avatar
Linus Torvalds committed
809 810 811 812

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
/*****************************************************************************/

static int tok_init_card(struct net_device *dev)
{
	struct tok_info *ti;
	short PIOaddr;
	unsigned long i;

	PIOaddr = dev->base_addr;
	ti = (struct tok_info *) dev->priv;
	/* Special processing for first interrupt after reset */
	ti->do_tok_int = FIRST_INT;
	/* Reset adapter */
	writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
	outb(0, PIOaddr + ADAPTRESET);

	current->state=TASK_UNINTERRUPTIBLE;
	schedule_timeout(TR_RST_TIME); /* wait 50ms */

	outb(0, PIOaddr + ADAPTRESETREL);
#ifdef ENABLE_PAGING
	if (ti->page_mask)
		writeb(SRPR_ENABLE_PAGING,ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN);
#endif
	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
	i = sleep_on_timeout(&ti->wait_for_reset, 4 * HZ);
	return i? 0 : -EAGAIN;
}

/*****************************************************************************/
static int tok_open(struct net_device *dev)
{
	struct tok_info *ti = (struct tok_info *) dev->priv;
	int i;

	/*the case we were left in a failure state during a previous open */
	if (ti->open_failure == YES) {
		DPRINTK("Last time you were disconnected, how about now?\n");
		printk("You can't insert with an ICS connector half-cocked.\n");
	}

	ti->open_status  = CLOSED; /* CLOSED or OPEN      */
	ti->sap_status   = CLOSED; /* CLOSED or OPEN      */
	ti->open_failure =     NO; /* NO     or YES       */
	ti->open_mode    = MANUAL; /* MANUAL or AUTOMATIC */
	/* 12/2000 not typical Linux, but we can use RUNNING to let us know when
	the network has crapped out or cables are disconnected. Useful because
	the IFF_UP flag stays up the whole time, until ifconfig tr0 down.
	*/
	dev->flags &= ~IFF_RUNNING;

	ti->sram_virt &= ~1; /* to reverse what we do in tok_close */
	/* init the spinlock */
	ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;

	i = tok_init_card(dev);
	if (i) return i;

	while (1){
		tok_open_adapter((unsigned long) dev);
		i= interruptible_sleep_on_timeout(&ti->wait_for_reset, 25 * HZ);
		/* sig catch: estimate opening adapter takes more than .5 sec*/
		if (i>(245*HZ)/10) break; /* fancier than if (i==25*HZ) */
		if (i==0) break;
		if (ti->open_status == OPEN && ti->sap_status==OPEN) {
			netif_start_queue(dev);
			DPRINTK("Adapter is up and running\n");
			return 0;
		}
		current->state=TASK_INTERRUPTIBLE;
		i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */
		if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */
	}
	outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/
	DPRINTK("TERMINATED via signal\n");	/*BMS useful */
	return -EAGAIN;
}

/*****************************************************************************/

#define COMMAND_OFST             0
#define OPEN_OPTIONS_OFST        8
#define NUM_RCV_BUF_OFST        24
#define RCV_BUF_LEN_OFST        26
#define DHB_LENGTH_OFST         28
#define NUM_DHB_OFST            30
#define DLC_MAX_SAP_OFST        32
#define DLC_MAX_STA_OFST        33

void tok_open_adapter(unsigned long dev_addr)
{
	struct net_device *dev = (struct net_device *) dev_addr;
	struct tok_info *ti;
	int i;

	ti = (struct tok_info *) dev->priv;
	SET_PAGE(ti->init_srb_page); 
	writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
	for (i = 0; i < sizeof(struct dir_open_adapter); i++)
		writeb(0, ti->init_srb + i);
	writeb(DIR_OPEN_ADAPTER, ti->init_srb + COMMAND_OFST);
	writew(htons(OPEN_PASS_BCON_MAC), ti->init_srb + OPEN_OPTIONS_OFST);
	if (ti->ring_speed == 16) {
		writew(htons(ti->dhb_size16mb), ti->init_srb + DHB_LENGTH_OFST);
		writew(htons(ti->rbuf_cnt16), ti->init_srb + NUM_RCV_BUF_OFST);
		writew(htons(ti->rbuf_len16), ti->init_srb + RCV_BUF_LEN_OFST);
	} else {
		writew(htons(ti->dhb_size4mb), ti->init_srb + DHB_LENGTH_OFST);
		writew(htons(ti->rbuf_cnt4), ti->init_srb + NUM_RCV_BUF_OFST);
		writew(htons(ti->rbuf_len4), ti->init_srb + RCV_BUF_LEN_OFST);
	}
	writeb(NUM_DHB,		/* always 2 */ ti->init_srb + NUM_DHB_OFST);
	writeb(DLC_MAX_SAP, ti->init_srb + DLC_MAX_SAP_OFST);
	writeb(DLC_MAX_STA, ti->init_srb + DLC_MAX_STA_OFST);
	ti->srb = ti->init_srb;	/* We use this one in the interrupt handler */
	ti->srb_page = ti->init_srb_page;
	DPRINTK("Opening adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n",
		readb(ti->init_srb + NUM_DHB_OFST),
		ntohs(readw(ti->init_srb + DHB_LENGTH_OFST)),
		ntohs(readw(ti->init_srb + NUM_RCV_BUF_OFST)),
		ntohs(readw(ti->init_srb + RCV_BUF_LEN_OFST)));
	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
}

/*****************************************************************************/

static void open_sap(unsigned char type, struct net_device *dev)
{
	int i;
	struct tok_info *ti = (struct tok_info *) dev->priv;

	SET_PAGE(ti->srb_page);
	for (i = 0; i < sizeof(struct dlc_open_sap); i++)
		writeb(0, ti->srb + i);

#define MAX_I_FIELD_OFST        14
#define SAP_VALUE_OFST          16
#define SAP_OPTIONS_OFST        17
#define STATION_COUNT_OFST      18

	writeb(DLC_OPEN_SAP, ti->srb + COMMAND_OFST);
	writew(htons(MAX_I_FIELD), ti->srb + MAX_I_FIELD_OFST);
	writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, ti->srb+ SAP_OPTIONS_OFST);
	writeb(SAP_OPEN_STATION_CNT, ti->srb + STATION_COUNT_OFST);
	writeb(type, ti->srb + SAP_VALUE_OFST);
	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
}


/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
964 965 966

static void tok_set_multicast_list(struct net_device *dev)
{
Linus Torvalds's avatar
Linus Torvalds committed
967
	struct tok_info *ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
968 969 970 971 972
	struct dev_mc_list *mclist;
	unsigned char address[4];

	int i;

Linus Torvalds's avatar
Linus Torvalds committed
973 974 975
	/*BMS the next line is CRUCIAL or you may be sad when you */
	/*BMS ifconfig tr down or hot unplug a PCMCIA card ??hownowbrowncow*/
	if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return;
Linus Torvalds's avatar
Linus Torvalds committed
976 977
	address[0] = address[1] = address[2] = address[3] = 0;
	mclist = dev->mc_list;
Linus Torvalds's avatar
Linus Torvalds committed
978
	for (i = 0; i < dev->mc_count; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
979 980 981 982 983 984 985
		address[0] |= mclist->dmi_addr[2];
		address[1] |= mclist->dmi_addr[3];
		address[2] |= mclist->dmi_addr[4];
		address[3] |= mclist->dmi_addr[5];
		mclist = mclist->next;
	}
	SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
986 987
	for (i = 0; i < sizeof(struct srb_set_funct_addr); i++)
		writeb(0, ti->srb + i);
Linus Torvalds's avatar
Linus Torvalds committed
988

Linus Torvalds's avatar
Linus Torvalds committed
989
#define FUNCT_ADDRESS_OFST 6
Linus Torvalds's avatar
Linus Torvalds committed
990

Linus Torvalds's avatar
Linus Torvalds committed
991 992 993 994 995
	writeb(DIR_SET_FUNC_ADDR, ti->srb + COMMAND_OFST);
	for (i = 0; i < 4; i++) 
		writeb(address[i], ti->srb + FUNCT_ADDRESS_OFST + i);
	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
996
	DPRINTK("Setting functional address: ");
Linus Torvalds's avatar
Linus Torvalds committed
997
	for (i=0;i<4;i++)  printk("%02X ", address[i]);
Linus Torvalds's avatar
Linus Torvalds committed
998
	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
999
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1000 1001
}

Linus Torvalds's avatar
Linus Torvalds committed
1002
/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
1003

Linus Torvalds's avatar
Linus Torvalds committed
1004
#define STATION_ID_OFST 4
Linus Torvalds's avatar
Linus Torvalds committed
1005

Linus Torvalds's avatar
Linus Torvalds committed
1006 1007 1008 1009 1010
static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
{
	struct tok_info *ti;
	unsigned long flags;
	ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1011

Linus Torvalds's avatar
Linus Torvalds committed
1012
        netif_stop_queue(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1013

Linus Torvalds's avatar
Linus Torvalds committed
1014 1015
	/* lock against other CPUs */
	spin_lock_irqsave(&(ti->lock), flags);
Linus Torvalds's avatar
Linus Torvalds committed
1016

Linus Torvalds's avatar
Linus Torvalds committed
1017 1018 1019 1020 1021 1022 1023 1024 1025
	/* Save skb; we'll need it when the adapter asks for the data */
	ti->current_skb = skb;
	SET_PAGE(ti->srb_page);
	writeb(XMIT_UI_FRAME, ti->srb + COMMAND_OFST);
	writew(ti->exsap_station_id, ti->srb + STATION_ID_OFST);
	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
	spin_unlock_irqrestore(&(ti->lock), flags);
	dev->trans_start = jiffies;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1026 1027
}

Linus Torvalds's avatar
Linus Torvalds committed
1028 1029
/*****************************************************************************/

Linus Torvalds's avatar
Linus Torvalds committed
1030 1031
static int tok_close(struct net_device *dev)
{
Linus Torvalds's avatar
Linus Torvalds committed
1032
	struct tok_info *ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1033

Linus Torvalds's avatar
Linus Torvalds committed
1034 1035 1036 1037 1038 1039
	/* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */
	/* unloading the module from memory, and then if a timer pops, ouch */
	del_timer(&ti->tr_timer);
	outb(0, dev->base_addr + ADAPTRESET);
	ti->sram_virt |= 1;
	ti->open_status = CLOSED;
Linus Torvalds's avatar
Linus Torvalds committed
1040

Linus Torvalds's avatar
Linus Torvalds committed
1041 1042 1043 1044
	netif_stop_queue(dev);
	DPRINTK("Adapter is closed.\n");
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
1045

Linus Torvalds's avatar
Linus Torvalds committed
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
/*****************************************************************************/

#define RETCODE_OFST		2
#define OPEN_ERROR_CODE_OFST	6
#define ASB_ADDRESS_OFST        8
#define SRB_ADDRESS_OFST        10
#define ARB_ADDRESS_OFST        12
#define SSB_ADDRESS_OFST        14

static char *printphase[]= {"Lobe media test","Physical insertion",
	      "Address verification","Roll call poll","Request Parameters"};
static char *printerror[]={"Function failure","Signal loss","Reserved",
		"Frequency error","Timeout","Ring failure","Ring beaconing",
		"Duplicate node address",
		"Parameter request-retry count exceeded","Remove received",
		"IMPL force received","Duplicate modifier",
		"No monitor detected","Monitor contention failed for RPL"};

void dir_open_adapter (struct net_device *dev) {

        struct tok_info *ti = (struct tok_info *) dev->priv;
        unsigned char ret_code;
        __u16 err;

        ti->srb = ntohs(readw(ti->init_srb + SRB_ADDRESS_OFST));
        ti->ssb = ntohs(readw(ti->init_srb + SSB_ADDRESS_OFST));
        ti->arb = ntohs(readw(ti->init_srb + ARB_ADDRESS_OFST));
        ti->asb = ntohs(readw(ti->init_srb + ASB_ADDRESS_OFST));
        if (ti->page_mask) {
                ti->srb_page = (ti->srb >> 8) & ti->page_mask;
                ti->srb &= ~(ti->page_mask << 8);
                ti->ssb_page = (ti->ssb >> 8) & ti->page_mask;
                ti->ssb &= ~(ti->page_mask << 8);
                ti->arb_page = (ti->arb >> 8) & ti->page_mask;
                ti->arb &= ~(ti->page_mask << 8);
                ti->asb_page = (ti->asb >> 8) & ti->page_mask;
                ti->asb &= ~(ti->page_mask << 8);
        }
        ti->srb += ti->sram_virt;
        ti->ssb += ti->sram_virt;
        ti->arb += ti->sram_virt;
        ti->asb += ti->sram_virt;
        ti->current_skb = NULL;
        ret_code = readb(ti->init_srb + RETCODE_OFST);
        err = ntohs(readw(ti->init_srb + OPEN_ERROR_CODE_OFST));
        if (!ret_code) {
		ti->open_status = OPEN; /* TR adapter is now available */
                if (ti->open_mode == AUTOMATIC) {
			DPRINTK("Adapter reopened.\n");
                }
                writeb(~SRB_RESP_INT, ti->mmio+ACA_OFFSET+ACA_RESET+ISRP_ODD);
                open_sap(EXTENDED_SAP, dev);
		return;
Linus Torvalds's avatar
Linus Torvalds committed
1099
	}
Linus Torvalds's avatar
Linus Torvalds committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
	ti->open_failure = YES;
	if (ret_code == 7){
               if (err == 0x24) {
			if (!ti->auto_speedsave) {
				DPRINTK("Open failed: Adapter speed must match "
                                 "ring speed if Automatic Ring Speed Save is "
				 "disabled.\n");
				ti->open_action = FAIL;
			}else
				DPRINTK("Retrying open to adjust to "
					"ring speed, ");
                } else if (err == 0x2d) {
			DPRINTK("Physical Insertion: No Monitor Detected, ");
			printk("retrying after %ds delay...\n",
					TR_RETRY_INTERVAL/HZ);
                } else if (err == 0x11) {
			DPRINTK("Lobe Media Function Failure (0x11), ");
			printk(" retrying after %ds delay...\n",
					TR_RETRY_INTERVAL/HZ);
                } else {
			char **prphase = printphase;
			char **prerror = printerror;
			DPRINTK("TR Adapter misc open failure, error code = ");
			printk("0x%x, Phase: %s, Error: %s\n",
				err, prphase[err/16 -1], prerror[err%16 -1]);
			printk(" retrying after %ds delay...\n",
					TR_RETRY_INTERVAL/HZ);
                }
        } else DPRINTK("open failed: ret_code = %02X..., ", ret_code);
	if (ti->open_action != FAIL) {
		if (ti->open_mode==AUTOMATIC){
			ti->open_action = REOPEN;
			ibmtr_reset_timer(&(ti->tr_timer), dev);
			return;
		}
		wake_up(&ti->wait_for_reset);
		return;
	}
	DPRINTK("FAILURE, CAPUT\n");
Linus Torvalds's avatar
Linus Torvalds committed
1139 1140
}

Linus Torvalds's avatar
Linus Torvalds committed
1141 1142
/******************************************************************************/

Andrew Morton's avatar
Andrew Morton committed
1143
irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
1144 1145
{
	unsigned char status;
Linus Torvalds's avatar
Linus Torvalds committed
1146
	/*  unsigned char status_even ; */
Linus Torvalds's avatar
Linus Torvalds committed
1147 1148 1149 1150 1151 1152 1153 1154
	struct tok_info *ti;
	struct net_device *dev;
#ifdef ENABLE_PAGING
	unsigned char save_srpr;
#endif

	dev = dev_id;
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1155
	DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs);
Linus Torvalds's avatar
Linus Torvalds committed
1156
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1157 1158
	ti = (struct tok_info *) dev->priv;
	if (ti->sram_virt & 1)
Andrew Morton's avatar
Andrew Morton committed
1159
		return IRQ_NONE;         /* PCMCIA card extraction flag */
Linus Torvalds's avatar
Linus Torvalds committed
1160 1161
	spin_lock(&(ti->lock));
#ifdef ENABLE_PAGING
Linus Torvalds's avatar
Linus Torvalds committed
1162
	save_srpr = readb(ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1163 1164
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1165 1166
	/* Disable interrupts till processing is finished */
	writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1167 1168

	/* Reset interrupt for ISA boards */
Linus Torvalds's avatar
Linus Torvalds committed
1169 1170 1171 1172 1173 1174 1175 1176
	if (ti->adapter_int_enable)
		outb(0, ti->adapter_int_enable);
	else /* used for PCMCIA cards */
		outb(0, ti->global_int_enable);
        if (ti->do_tok_int == FIRST_INT){
                initial_tok_int(dev);
#ifdef ENABLE_PAGING
                writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1177
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1178
                spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1179
                return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
        }
	/*  Begin interrupt handler HERE inline to avoid the extra
	    levels of logic and call depth for the original solution. */
	status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
	/*BMSstatus_even = readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) */
	/*BMSdebugprintk("tok_interrupt: ISRP_ODD = 0x%x ISRP_EVEN = 0x%x\n", */
	/*BMS                                       status,status_even);      */

	if (status & ADAP_CHK_INT) {
		int i;
		__u32 check_reason;
		__u8 check_reason_page = 0;
		check_reason =
			ntohs(readw(ti->mmio+ ACA_OFFSET+ACA_RW + WWCR_EVEN));
		if (ti->page_mask) {
			check_reason_page = (check_reason >> 8) & ti->page_mask;
			check_reason &= ~(ti->page_mask << 8);
		}
		check_reason += ti->sram_virt;
		SET_PAGE(check_reason_page);
Linus Torvalds's avatar
Linus Torvalds committed
1200

Linus Torvalds's avatar
Linus Torvalds committed
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
		DPRINTK("Adapter check interrupt\n");
		DPRINTK("8 reason bytes follow: ");
		for (i = 0; i < 8; i++, check_reason++)
			printk("%02X ", (int) readb(check_reason));
		printk("\n");
		writeb(~ADAP_CHK_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
		status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRA_EVEN);
		DPRINTK("ISRA_EVEN == 0x02%x\n",status);
		ti->open_status = CLOSED;
		ti->sap_status  = CLOSED;
		ti->open_mode   = AUTOMATIC;
		dev->flags &= ~IFF_RUNNING;
		netif_stop_queue(dev);
		ti->open_action = RESTART;
		outb(0, dev->base_addr + ADAPTRESET);
		ibmtr_reset_timer(&(ti->tr_timer), dev);/*BMS try to reopen*/
Linus Torvalds's avatar
Linus Torvalds committed
1217
		spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1218
		return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
	}
	if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
		& (TCR_INT | ERR_INT | ACCESS_INT)) {
		DPRINTK("adapter error: ISRP_EVEN : %02x\n",
			(int)readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRP_EVEN));
		writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
			ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
		status= readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRA_EVEN);/*BMS*/
		DPRINTK("ISRA_EVEN == 0x02%x\n",status);/*BMS*/
                writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
#ifdef ENABLE_PAGING
                writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
#endif
                spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1233
                return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1234 1235 1236
        }
	if (status & SRB_RESP_INT) {	/* SRB response */
		SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1237
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1238 1239
		DPRINTK("SRB resp: cmd=%02X rsp=%02X\n",
				readb(ti->srb), readb(ti->srb + RETCODE_OFST));
Linus Torvalds's avatar
Linus Torvalds committed
1240
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
		switch (readb(ti->srb)) {	/* SRB command check */
		case XMIT_DIR_FRAME:{
			unsigned char xmit_ret_code;
			xmit_ret_code = readb(ti->srb + RETCODE_OFST);
			if (xmit_ret_code == 0xff) break;
			DPRINTK("error on xmit_dir_frame request: %02X\n",
								xmit_ret_code);
			if (ti->current_skb) {
				dev_kfree_skb_irq(ti->current_skb);
				ti->current_skb = NULL;
			}
			/*dev->tbusy = 0;*/
			netif_wake_queue(dev);
			if (ti->readlog_pending)
				ibmtr_readlog(dev);
			break;
		}
		case XMIT_UI_FRAME:{
			unsigned char xmit_ret_code;

			xmit_ret_code = readb(ti->srb + RETCODE_OFST);
			if (xmit_ret_code == 0xff) break;
			DPRINTK("error on xmit_ui_frame request: %02X\n",
								xmit_ret_code);
			if (ti->current_skb) {
				dev_kfree_skb_irq(ti->current_skb);
				ti->current_skb = NULL;
			}
			netif_wake_queue(dev);
			if (ti->readlog_pending)
				ibmtr_readlog(dev);
			break;
		}
		case DIR_OPEN_ADAPTER:
			dir_open_adapter(dev);
			break;
		case DLC_OPEN_SAP:
			if (readb(ti->srb + RETCODE_OFST)) {
				DPRINTK("open_sap failed: ret_code = %02X, "
					"retrying\n",
					(int) readb(ti->srb + RETCODE_OFST));
				ti->open_action = REOPEN;
				ibmtr_reset_timer(&(ti->tr_timer), dev);
				break;
			}
			ti->exsap_station_id = readw(ti->srb + STATION_ID_OFST);
			ti->sap_status = OPEN;/* TR adapter is now available */
			if (ti->open_mode==MANUAL){
				wake_up(&ti->wait_for_reset);
				break;
			}
			netif_wake_queue(dev);
			dev->flags |= IFF_RUNNING;/*BMS 12/2000*/
			break;
		case DIR_INTERRUPT:
		case DIR_MOD_OPEN_PARAMS:
		case DIR_SET_GRP_ADDR:
		case DIR_SET_FUNC_ADDR:
		case DLC_CLOSE_SAP:
			if (readb(ti->srb + RETCODE_OFST))
				DPRINTK("error on %02X: %02X\n",
					(int) readb(ti->srb + COMMAND_OFST),
					(int) readb(ti->srb + RETCODE_OFST));
			break;
		case DIR_READ_LOG:
			if (readb(ti->srb + RETCODE_OFST)){
				DPRINTK("error on dir_read_log: %02X\n",
					(int) readb(ti->srb + RETCODE_OFST));
				netif_wake_queue(dev);
				break;
			}
#if IBMTR_DEBUG_MESSAGES

#define LINE_ERRORS_OFST                 0
#define INTERNAL_ERRORS_OFST             1
#define BURST_ERRORS_OFST                2
#define AC_ERRORS_OFST                   3
#define ABORT_DELIMITERS_OFST            4
#define LOST_FRAMES_OFST                 6
#define RECV_CONGEST_COUNT_OFST          7
#define FRAME_COPIED_ERRORS_OFST         8
#define FREQUENCY_ERRORS_OFST            9
#define TOKEN_ERRORS_OFST               10

			DPRINTK("Line errors %02X, Internal errors %02X, "
			"Burst errors %02X\n" "A/C errors %02X, "
			"Abort delimiters %02X, Lost frames %02X\n"
			"Receive congestion count %02X, "
			"Frame copied errors %02X\nFrequency errors %02X, "
			"Token errors %02X\n",
			(int) readb(ti->srb + LINE_ERRORS_OFST),
			(int) readb(ti->srb + INTERNAL_ERRORS_OFST),
			(int) readb(ti->srb + BURST_ERRORS_OFST),
			(int) readb(ti->srb + AC_ERRORS_OFST),
			(int) readb(ti->srb + ABORT_DELIMITERS_OFST),
			(int) readb(ti->srb + LOST_FRAMES_OFST),
			(int) readb(ti->srb + RECV_CONGEST_COUNT_OFST),
			(int) readb(ti->srb + FRAME_COPIED_ERRORS_OFST),
			(int) readb(ti->srb + FREQUENCY_ERRORS_OFST),
			(int) readb(ti->srb + TOKEN_ERRORS_OFST));
Linus Torvalds's avatar
Linus Torvalds committed
1341
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
			netif_wake_queue(dev);
			break;
		default:
			DPRINTK("Unknown command %02X encountered\n",
						(int) readb(ti->srb));
        	}	/* end switch SRB command check */
		writeb(~SRB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
	}	/* if SRB response */
	if (status & ASB_FREE_INT) {	/* ASB response */
		SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1352
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1353
		DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb));
Linus Torvalds's avatar
Linus Torvalds committed
1354 1355
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
		switch (readb(ti->asb)) {	/* ASB command check */
		case REC_DATA:
		case XMIT_UI_FRAME:
		case XMIT_DIR_FRAME:
			break;
		default:
			DPRINTK("unknown command in asb %02X\n",
						(int) readb(ti->asb));
		}	/* switch ASB command check */
		if (readb(ti->asb + 2) != 0xff)	/* checks ret_code */
			DPRINTK("ASB error %02X in cmd %02X\n",
				(int) readb(ti->asb + 2), (int) readb(ti->asb));
		writeb(~ASB_FREE_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
	}	/* if ASB response */

#define STATUS_OFST             6
#define NETW_STATUS_OFST        6

	if (status & ARB_CMD_INT) {	/* ARB response */
		SET_PAGE(ti->arb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1376
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1377
		DPRINTK("ARB resp: cmd=%02X\n", readb(ti->arb));
Linus Torvalds's avatar
Linus Torvalds committed
1378 1379
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
		switch (readb(ti->arb)) {	/* ARB command check */
		case DLC_STATUS:
			DPRINTK("DLC_STATUS new status: %02X on station %02X\n",
				ntohs(readw(ti->arb + STATUS_OFST)),
				ntohs(readw(ti->arb+ STATION_ID_OFST)));
			break;
		case REC_DATA:
			tr_rx(dev);
			break;
		case RING_STAT_CHANGE:{
			unsigned short ring_status;
			ring_status= ntohs(readw(ti->arb + NETW_STATUS_OFST));
			if (ibmtr_debug_trace & TRC_INIT)
				DPRINTK("Ring Status Change...(0x%x)\n",
								ring_status);
			if(ring_status& (REMOVE_RECV|AUTO_REMOVAL|LOBE_FAULT)){
				netif_stop_queue(dev);
				dev->flags &= ~IFF_RUNNING;/*not typical Linux*/
				DPRINTK("Remove received, or Auto-removal error"
					", or Lobe fault\n");
				DPRINTK("We'll try to reopen the closed adapter"
					" after a %d second delay.\n",
						TR_RETRY_INTERVAL/HZ);
				/*I was confused: I saw the TR reopening but */
				/*forgot:with an RJ45 in an RJ45/ICS adapter */
				/*but adapter not in the ring, the TR will   */
				/* open, and then soon close and come here.  */
				ti->open_mode = AUTOMATIC;
				ti->open_status = CLOSED; /*12/2000 BMS*/
				ti->open_action = REOPEN;
				ibmtr_reset_timer(&(ti->tr_timer), dev);
			} else if (ring_status & LOG_OVERFLOW) {
				if(netif_queue_stopped(dev))
					ti->readlog_pending = 1;
				else
					ibmtr_readlog(dev);
			}
			break;
          	}
		case XMIT_DATA_REQ:
			tr_tx(dev);
			break;
		default:
			DPRINTK("Unknown command %02X in arb\n",
						(int) readb(ti->arb));
			break;
		}	/* switch ARB command check */
		writeb(~ARB_CMD_INT, ti->mmio+ ACA_OFFSET+ACA_RESET + ISRP_ODD);
		writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
	}	/* if ARB response */
	if (status & SSB_RESP_INT) {	/* SSB response */
		unsigned char retcode;
		SET_PAGE(ti->ssb_page);
#if TR_VERBOSE
		DPRINTK("SSB resp: cmd=%02X rsp=%02X\n",
				readb(ti->ssb), readb(ti->ssb + 2));
Linus Torvalds's avatar
Linus Torvalds committed
1436
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458

		switch (readb(ti->ssb)) {	/* SSB command check */
		case XMIT_DIR_FRAME:
		case XMIT_UI_FRAME:
			retcode = readb(ti->ssb + 2);
			if (retcode && (retcode != 0x22))/* checks ret_code */
				DPRINTK("xmit ret_code: %02X xmit error code: "
					"%02X\n",
					(int)retcode, (int)readb(ti->ssb + 6));
			else
				ti->tr_stats.tx_packets++;
			break;
		case XMIT_XID_CMD:
			DPRINTK("xmit xid ret_code: %02X\n",
						(int) readb(ti->ssb + 2));
		default:
			DPRINTK("Unknown command %02X in ssb\n",
						(int) readb(ti->ssb));
		}	/* SSB command check */
		writeb(~SSB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
		writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
	}	/* if SSB response */
Linus Torvalds's avatar
Linus Torvalds committed
1459
#ifdef ENABLE_PAGING
Linus Torvalds's avatar
Linus Torvalds committed
1460
	writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1461
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1462
	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1463
	spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1464
	return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1465 1466 1467 1468 1469 1470 1471
}				/*tok_interrupt */

/*****************************************************************************/

#define INIT_STATUS_OFST        1
#define INIT_STATUS_2_OFST      2
#define ENCODED_ADDRESS_OFST    8
Linus Torvalds's avatar
Linus Torvalds committed
1472 1473 1474 1475

static void initial_tok_int(struct net_device *dev)
{

Linus Torvalds's avatar
Linus Torvalds committed
1476
	__u32 encoded_addr, hw_encoded_addr;
Linus Torvalds's avatar
Linus Torvalds committed
1477
	struct tok_info *ti;
Linus Torvalds's avatar
Linus Torvalds committed
1478
        unsigned char init_status; /*BMS 12/2000*/
Linus Torvalds's avatar
Linus Torvalds committed
1479

Linus Torvalds's avatar
Linus Torvalds committed
1480
	ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1481

Linus Torvalds's avatar
Linus Torvalds committed
1482
	ti->do_tok_int = NOT_FIRST;
Linus Torvalds's avatar
Linus Torvalds committed
1483 1484

	/* we assign the shared-ram address for ISA devices */
Linus Torvalds's avatar
Linus Torvalds committed
1485 1486 1487 1488 1489
	writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
#ifndef PCMCIA
        ti->sram_virt = (u32)ioremap(((__u32)ti->sram_base << 12), ti->avail_shared_ram);
#endif
	ti->init_srb = ntohs(readw(ti->mmio + ACA_OFFSET + WRBR_EVEN));
Linus Torvalds's avatar
Linus Torvalds committed
1490
	if (ti->page_mask) {
Linus Torvalds's avatar
Linus Torvalds committed
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
		ti->init_srb_page = (ti->init_srb >> 8) & ti->page_mask;
		ti->init_srb &= ~(ti->page_mask << 8);
	}
	ti->init_srb += ti->sram_virt;
	if (ti->page_mask && ti->avail_shared_ram == 127) {
		int last_512 = 0xfe00, i;
		int last_512_page=0;
		last_512_page=(last_512>>8)&ti->page_mask;
		last_512 &= ~(ti->page_mask << 8);
		/* initialize high section of ram (if necessary) */
		SET_PAGE(last_512_page);
		for (i = 0; i < 512; i++)
			writeb(0, ti->sram_virt + last_512 + i);
Linus Torvalds's avatar
Linus Torvalds committed
1504 1505 1506 1507 1508
	}
	SET_PAGE(ti->init_srb_page);

#if TR_VERBOSE
	{
Linus Torvalds's avatar
Linus Torvalds committed
1509
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
1510

Linus Torvalds's avatar
Linus Torvalds committed
1511 1512 1513 1514
	DPRINTK("ti->init_srb_page=0x%x\n", ti->init_srb_page);
	DPRINTK("init_srb(%x):", (ti->init_srb) );
	for (i = 0; i < 20; i++)
		printk("%02X ", (int) readb(ti->init_srb + i));
Linus Torvalds's avatar
Linus Torvalds committed
1515
	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
1516
	}
Linus Torvalds's avatar
Linus Torvalds committed
1517 1518
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1519 1520 1521 1522 1523 1524 1525 1526 1527
	hw_encoded_addr = readw(ti->init_srb + ENCODED_ADDRESS_OFST);
	encoded_addr = ntohs(hw_encoded_addr);
        init_status= /*BMS 12/2000 check for shallow mode possibility (Turbo)*/
	readb(ti->init_srb+offsetof(struct srb_init_response,init_status));
	/*printk("Initial interrupt: init_status= 0x%02x\n",init_status);*/
	ti->ring_speed = init_status & 0x01 ? 16 : 4;
	DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
				ti->ring_speed, (unsigned int)dev->mem_start);
	ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE;
Linus Torvalds's avatar
Linus Torvalds committed
1528

Linus Torvalds's avatar
Linus Torvalds committed
1529 1530 1531 1532
        if (ti->open_mode == MANUAL)	wake_up(&ti->wait_for_reset);
	else				tok_open_adapter((unsigned long)dev);
        
} /*initial_tok_int() */
Linus Torvalds's avatar
Linus Torvalds committed
1533

Linus Torvalds's avatar
Linus Torvalds committed
1534
/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
1535

Linus Torvalds's avatar
Linus Torvalds committed
1536 1537
#define CMD_CORRELATE_OFST      1
#define DHB_ADDRESS_OFST        6
Linus Torvalds's avatar
Linus Torvalds committed
1538

Linus Torvalds's avatar
Linus Torvalds committed
1539 1540 1541
#define FRAME_LENGTH_OFST       6
#define HEADER_LENGTH_OFST      8
#define RSAP_VALUE_OFST         9
Linus Torvalds's avatar
Linus Torvalds committed
1542

Linus Torvalds's avatar
Linus Torvalds committed
1543
static void tr_tx(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
1544
{
Linus Torvalds's avatar
Linus Torvalds committed
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
	struct tok_info *ti = (struct tok_info *) dev->priv;
	struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data;
	unsigned int hdr_len;
	__u32 dhb=0,dhb_base;
	unsigned char xmit_command;
	int i,dhb_len=0x4000,src_len,src_offset;
	struct trllc *llc;
	struct srb_xmit xsrb;
	__u8 dhb_page = 0;
	__u8 llc_ssap;
Linus Torvalds's avatar
Linus Torvalds committed
1555

Linus Torvalds's avatar
Linus Torvalds committed
1556
	SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1557

Linus Torvalds's avatar
Linus Torvalds committed
1558
	if (readb(ti->asb+RETCODE_OFST) != 0xFF) DPRINTK("ASB not free !!!\n");
Linus Torvalds's avatar
Linus Torvalds committed
1559

Linus Torvalds's avatar
Linus Torvalds committed
1560 1561 1562 1563 1564 1565 1566 1567 1568
	/* in providing the transmit interrupts, is telling us it is ready for
	   data and providing a shared memory address for us to stuff with data.
	   Here we compute the effective address where we will place data.
	*/
	SET_PAGE(ti->arb_page);
	dhb=dhb_base=ntohs(readw(ti->arb + DHB_ADDRESS_OFST));
	if (ti->page_mask) {
		dhb_page = (dhb_base >> 8) & ti->page_mask;
		dhb=dhb_base & ~(ti->page_mask << 8);
Linus Torvalds's avatar
Linus Torvalds committed
1569
	}
Linus Torvalds's avatar
Linus Torvalds committed
1570
	dhb += ti->sram_virt;
Linus Torvalds's avatar
Linus Torvalds committed
1571

Linus Torvalds's avatar
Linus Torvalds committed
1572 1573 1574 1575 1576 1577
	/* Figure out the size of the 802.5 header */
	if (!(trhdr->saddr[0] & 0x80))	/* RIF present? */
		hdr_len = sizeof(struct trh_hdr) - TR_MAXRIFLEN;
	else
		hdr_len = ((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK) >> 8)
		    + sizeof(struct trh_hdr) - TR_MAXRIFLEN;
Linus Torvalds's avatar
Linus Torvalds committed
1578

Linus Torvalds's avatar
Linus Torvalds committed
1579
	llc = (struct trllc *) (ti->current_skb->data + hdr_len);
Linus Torvalds's avatar
Linus Torvalds committed
1580

Linus Torvalds's avatar
Linus Torvalds committed
1581 1582 1583
	llc_ssap = llc->ssap;
	SET_PAGE(ti->srb_page);
	memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb));
Linus Torvalds's avatar
Linus Torvalds committed
1584
	SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
	xmit_command = xsrb.command;

	writeb(xmit_command, ti->asb + COMMAND_OFST);
	writew(xsrb.station_id, ti->asb + STATION_ID_OFST);
	writeb(llc_ssap, ti->asb + RSAP_VALUE_OFST);
	writeb(xsrb.cmd_corr, ti->asb + CMD_CORRELATE_OFST);
	writeb(0, ti->asb + RETCODE_OFST);
	if ((xmit_command == XMIT_XID_CMD) || (xmit_command == XMIT_TEST_CMD)) {
		writew(htons(0x11), ti->asb + FRAME_LENGTH_OFST);
		writeb(0x0e, ti->asb + HEADER_LENGTH_OFST);
Linus Torvalds's avatar
Linus Torvalds committed
1595
		SET_PAGE(dhb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1596 1597 1598 1599 1600 1601 1602
		writeb(AC, dhb);
		writeb(LLC_FRAME, dhb + 1);
		for (i = 0; i < TR_ALEN; i++)
			writeb((int) 0x0FF, dhb + i + 2);
		for (i = 0; i < TR_ALEN; i++)
			writeb(0, dhb + i + TR_ALEN + 2);
		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
Linus Torvalds's avatar
Linus Torvalds committed
1603 1604 1605
		return;
	}
	/*
Linus Torvalds's avatar
Linus Torvalds committed
1606 1607
	 *    the token ring packet is copied from sk_buff to the adapter
	 *    buffer identified in the command data received with the interrupt.
Linus Torvalds's avatar
Linus Torvalds committed
1608
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
	writeb(hdr_len, ti->asb + HEADER_LENGTH_OFST);
	writew(htons(ti->current_skb->len), ti->asb + FRAME_LENGTH_OFST);
	src_len=ti->current_skb->len;
	src_offset=0;
	dhb=dhb_base;
	while(1) {
		if (ti->page_mask) {
			dhb_page=(dhb >> 8) & ti->page_mask;
			dhb=dhb & ~(ti->page_mask << 8);
			dhb_len=0x4000-dhb; /* remaining size of this page */
		}
		dhb+=ti->sram_virt;
		SET_PAGE(dhb_page);
		if (src_len > dhb_len) {
			memcpy_toio(dhb,&ti->current_skb->data[src_offset],
					dhb_len);
			src_len -= dhb_len;
			src_offset += dhb_len;
			dhb_base+=dhb_len;
			dhb=dhb_base;
			continue;
		}
		memcpy_toio(dhb, &ti->current_skb->data[src_offset], src_len);
		break;
	}
	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
	ti->tr_stats.tx_bytes += ti->current_skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
1636
	dev_kfree_skb_irq(ti->current_skb);
Linus Torvalds's avatar
Linus Torvalds committed
1637
	ti->current_skb = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1638
	netif_wake_queue(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
	if (ti->readlog_pending)
		ibmtr_readlog(dev);
}				/*tr_tx */

/*****************************************************************************/


#define RECEIVE_BUFFER_OFST     6
#define LAN_HDR_LENGTH_OFST     8
#define DLC_HDR_LENGTH_OFST     9

#define DSAP_OFST               0
#define SSAP_OFST               1
#define LLC_OFST                2
#define PROTID_OFST             3
#define ETHERTYPE_OFST          6
Linus Torvalds's avatar
Linus Torvalds committed
1655 1656 1657

static void tr_rx(struct net_device *dev)
{
Linus Torvalds's avatar
Linus Torvalds committed
1658
	struct tok_info *ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1659
	__u32 rbuffer, rbufdata;
Linus Torvalds's avatar
Linus Torvalds committed
1660
	__u8 rbuffer_page = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1661 1662 1663
	__u32 llc;
	unsigned char *data;
	unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
Linus Torvalds's avatar
Linus Torvalds committed
1664
	unsigned char dlc_hdr_len;
Linus Torvalds's avatar
Linus Torvalds committed
1665 1666
	struct sk_buff *skb;
	unsigned int skb_size = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1667
	int IPv4_p = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1668 1669 1670 1671 1672
	unsigned int chksum = 0;
	struct iphdr *iph;
	struct arb_rec_req rarb;

	SET_PAGE(ti->arb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1673 1674
	memcpy_fromio(&rarb, ti->arb, sizeof(rarb));
	rbuffer = ntohs(rarb.rec_buf_addr) ;
Linus Torvalds's avatar
Linus Torvalds committed
1675
	if (ti->page_mask) {
Linus Torvalds's avatar
Linus Torvalds committed
1676 1677
		rbuffer_page = (rbuffer >> 8) & ti->page_mask;
		rbuffer &= ~(ti->page_mask << 8);
Linus Torvalds's avatar
Linus Torvalds committed
1678
	}
Linus Torvalds's avatar
Linus Torvalds committed
1679 1680
	rbuffer += ti->sram_virt;

Linus Torvalds's avatar
Linus Torvalds committed
1681 1682
	SET_PAGE(ti->asb_page);

Linus Torvalds's avatar
Linus Torvalds committed
1683 1684 1685 1686 1687
	if (readb(ti->asb + RETCODE_OFST) !=0xFF) DPRINTK("ASB not free !!!\n");

	writeb(REC_DATA, ti->asb + COMMAND_OFST);
	writew(rarb.station_id, ti->asb + STATION_ID_OFST);
	writew(rarb.rec_buf_addr, ti->asb + RECEIVE_BUFFER_OFST);
Linus Torvalds's avatar
Linus Torvalds committed
1688

Linus Torvalds's avatar
Linus Torvalds committed
1689 1690 1691 1692 1693 1694
	lan_hdr_len = rarb.lan_hdr_len;
	if (lan_hdr_len > sizeof(struct trh_hdr)) {
		DPRINTK("Linux cannot handle greater than 18 bytes RIF\n");
		return;
	}			/*BMS I added this above just to be very safe */
	dlc_hdr_len = readb(ti->arb + DLC_HDR_LENGTH_OFST);
Linus Torvalds's avatar
Linus Torvalds committed
1695 1696 1697
	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);

	SET_PAGE(rbuffer_page);
Linus Torvalds's avatar
Linus Torvalds committed
1698
	llc = (rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
Linus Torvalds's avatar
Linus Torvalds committed
1699 1700 1701

#if TR_VERBOSE
	DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
Linus Torvalds's avatar
Linus Torvalds committed
1702 1703 1704
	(__u32) offsetof(struct rec_buf, data), (unsigned int) lan_hdr_len);
	DPRINTK("llc: %08X rec_buf_addr: %04X dev->mem_start: %lX\n",
		llc, ntohs(rarb.rec_buf_addr), dev->mem_start);
Linus Torvalds's avatar
Linus Torvalds committed
1705 1706
	DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, "
		"ethertype: %04X\n",
Linus Torvalds's avatar
Linus Torvalds committed
1707 1708 1709 1710
		(int) readb(llc + DSAP_OFST), (int) readb(llc + SSAP_OFST),
		(int) readb(llc + LLC_OFST), (int) readb(llc + PROTID_OFST),
		(int) readb(llc+PROTID_OFST+1),(int)readb(llc+PROTID_OFST + 2),
		(int) ntohs(readw(llc + ETHERTYPE_OFST)));
Linus Torvalds's avatar
Linus Torvalds committed
1711
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1712 1713 1714
	if (readb(llc + offsetof(struct trllc, llc)) != UI_CMD) {
		SET_PAGE(ti->asb_page);
		writeb(DATA_LOST, ti->asb + RETCODE_OFST);
Linus Torvalds's avatar
Linus Torvalds committed
1715
		ti->tr_stats.rx_dropped++;
Linus Torvalds's avatar
Linus Torvalds committed
1716
		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
Linus Torvalds's avatar
Linus Torvalds committed
1717 1718 1719
		return;
	}
	length = ntohs(rarb.frame_len);
Linus Torvalds's avatar
Linus Torvalds committed
1720 1721 1722
	if (readb(llc + DSAP_OFST) == EXTENDED_SAP &&
	   readb(llc + SSAP_OFST) == EXTENDED_SAP &&
		length >= hdr_len)	IPv4_p = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1723
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
#define SADDR_OFST	8
#define DADDR_OFST	2

	if (!IPv4_p) {

		__u32 trhhdr;

		trhhdr = (rbuffer + offsetof(struct rec_buf, data));

		DPRINTK("Probably non-IP frame received.\n");
		DPRINTK("ssap: %02X dsap: %02X "
			"saddr: %02X:%02X:%02X:%02X:%02X:%02X "
			"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
			readb(llc + SSAP_OFST), readb(llc + DSAP_OFST),
			readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1),
			readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3),
			readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5),
			readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1),
			readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3),
			readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5));
	}
Linus Torvalds's avatar
Linus Torvalds committed
1745 1746
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1747 1748 1749 1750 1751 1752
	/*BMS handle the case she comes in with few hops but leaves with many */
        skb_size=length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc);

	if (!(skb = dev_alloc_skb(skb_size))) {
		DPRINTK("out of memory. frame dropped.\n");
		ti->tr_stats.rx_dropped++;
Linus Torvalds's avatar
Linus Torvalds committed
1753
		SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
		writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
		return;
	}
	/*BMS again, if she comes in with few but leaves with many */
	skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len);
	skb_put(skb, length);
	skb->dev = dev;
	data = skb->data;
	rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
	rbufdata = rbuffer + offsetof(struct rec_buf, data);
Linus Torvalds's avatar
Linus Torvalds committed
1765 1766

	if (IPv4_p) {
Linus Torvalds's avatar
Linus Torvalds committed
1767 1768
		/* Copy the headers without checksumming */
		memcpy_fromio(data, rbufdata, hdr_len);
Linus Torvalds's avatar
Linus Torvalds committed
1769 1770

		/* Watch for padded packets and bogons */
Linus Torvalds's avatar
Linus Torvalds committed
1771
		iph= (struct iphdr *)(data+ lan_hdr_len + sizeof(struct trllc));
Linus Torvalds's avatar
Linus Torvalds committed
1772 1773 1774 1775 1776 1777 1778
		ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
		length -= hdr_len;
		if ((ip_len <= length) && (ip_len > 7))
			length = ip_len;
		data += hdr_len;
		rbuffer_len -= hdr_len;
		rbufdata += hdr_len;
Linus Torvalds's avatar
Linus Torvalds committed
1779
	}
Linus Torvalds's avatar
Linus Torvalds committed
1780
	/* Copy the payload... */
Linus Torvalds's avatar
Linus Torvalds committed
1781 1782
#define BUFFER_POINTER_OFST	2
#define BUFFER_LENGTH_OFST      6
Linus Torvalds's avatar
Linus Torvalds committed
1783
	for (;;) {
Linus Torvalds's avatar
Linus Torvalds committed
1784 1785 1786
		if (ibmtr_debug_trace&TRC_INITV && length < rbuffer_len)
			DPRINTK("CURIOUS, length=%d < rbuffer_len=%d\n",
						length,rbuffer_len);
Linus Torvalds's avatar
Linus Torvalds committed
1787
		if (IPv4_p)
Linus Torvalds's avatar
Linus Torvalds committed
1788 1789
			chksum=csum_partial_copy_nocheck((void*)rbufdata,
			    data,length<rbuffer_len?length:rbuffer_len,chksum);
Linus Torvalds's avatar
Linus Torvalds committed
1790
		else
Linus Torvalds's avatar
Linus Torvalds committed
1791 1792
			memcpy_fromio(data, rbufdata, rbuffer_len);
		rbuffer = ntohs(readw(rbuffer+BUFFER_POINTER_OFST)) ;
Linus Torvalds's avatar
Linus Torvalds committed
1793 1794
		if (!rbuffer)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1795
		rbuffer -= 2;
Linus Torvalds's avatar
Linus Torvalds committed
1796 1797 1798
		length -= rbuffer_len;
		data += rbuffer_len;
		if (ti->page_mask) {
Linus Torvalds's avatar
Linus Torvalds committed
1799 1800
			rbuffer_page = (rbuffer >> 8) & ti->page_mask;
			rbuffer &= ~(ti->page_mask << 8);
Linus Torvalds's avatar
Linus Torvalds committed
1801
		}
Linus Torvalds's avatar
Linus Torvalds committed
1802
		rbuffer += ti->sram_virt;
Linus Torvalds's avatar
Linus Torvalds committed
1803
		SET_PAGE(rbuffer_page);
Linus Torvalds's avatar
Linus Torvalds committed
1804
		rbuffer_len = ntohs(readw(rbuffer + BUFFER_LENGTH_OFST));
Linus Torvalds's avatar
Linus Torvalds committed
1805 1806 1807 1808
		rbufdata = rbuffer + offsetof(struct rec_buf, data);
	}

	SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1809
	writeb(0, ti->asb + offsetof(struct asb_rec, ret_code));
Linus Torvalds's avatar
Linus Torvalds committed
1810

Linus Torvalds's avatar
Linus Torvalds committed
1811
	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
Linus Torvalds's avatar
Linus Torvalds committed
1812 1813

	ti->tr_stats.rx_bytes += skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
1814
	ti->tr_stats.rx_packets++;
Linus Torvalds's avatar
Linus Torvalds committed
1815

Linus Torvalds's avatar
Linus Torvalds committed
1816 1817 1818
	skb->protocol = tr_type_trans(skb, dev);
	if (IPv4_p) {
		skb->csum = chksum;
Linus Torvalds's avatar
Linus Torvalds committed
1819 1820 1821
		skb->ip_summed = 1;
	}
	netif_rx(skb);
Linus Torvalds's avatar
Linus Torvalds committed
1822
	dev->last_rx = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
}				/*tr_rx */

/*****************************************************************************/

void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
{
	tmr->expires = jiffies + TR_RETRY_INTERVAL;
	tmr->data = (unsigned long) dev;
	tmr->function = tok_rerun;
	init_timer(tmr);
	add_timer(tmr);
Linus Torvalds's avatar
Linus Torvalds committed
1834 1835
}

Linus Torvalds's avatar
Linus Torvalds committed
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
/*****************************************************************************/

void tok_rerun(unsigned long dev_addr){

	struct net_device *dev = (struct net_device *)dev_addr;
	struct tok_info *ti = (struct tok_info *) dev->priv;

	if ( ti->open_action == RESTART){
		ti->do_tok_int = FIRST_INT;
		outb(0, dev->base_addr + ADAPTRESETREL);
#ifdef ENABLE_PAGING
		if (ti->page_mask)
			writeb(SRPR_ENABLE_PAGING,
				ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
#endif

		writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
	} else
		tok_open_adapter(dev_addr);
}

/*****************************************************************************/

void ibmtr_readlog(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
1860 1861 1862
{
	struct tok_info *ti;

Linus Torvalds's avatar
Linus Torvalds committed
1863
	ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1864

Linus Torvalds's avatar
Linus Torvalds committed
1865
	ti->readlog_pending = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1866
	SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1867 1868 1869
	writeb(DIR_READ_LOG, ti->srb);
	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
Linus Torvalds's avatar
Linus Torvalds committed
1870

Linus Torvalds's avatar
Linus Torvalds committed
1871
	netif_stop_queue(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1872 1873 1874

}

Linus Torvalds's avatar
Linus Torvalds committed
1875 1876
/*****************************************************************************/

Linus Torvalds's avatar
Linus Torvalds committed
1877 1878 1879 1880 1881
/* tok_get_stats():  Basically a scaffold routine which will return
   the address of the tr_statistics structure associated with
   this device -- the tr.... structure is an ethnet look-alike
   so at least for this iteration may suffice.   */

Linus Torvalds's avatar
Linus Torvalds committed
1882 1883
static struct net_device_stats *tok_get_stats(struct net_device *dev)
{
Linus Torvalds's avatar
Linus Torvalds committed
1884 1885

	struct tok_info *toki;
Linus Torvalds's avatar
Linus Torvalds committed
1886
	toki = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1887 1888 1889
	return (struct net_device_stats *) &toki->tr_stats;
}

Linus Torvalds's avatar
Linus Torvalds committed
1890 1891 1892 1893
/*****************************************************************************/

int ibmtr_change_mtu(struct net_device *dev, int mtu)
{
Linus Torvalds's avatar
Linus Torvalds committed
1894
	struct tok_info *ti = (struct tok_info *) dev->priv;
Linus Torvalds's avatar
Linus Torvalds committed
1895

Linus Torvalds's avatar
Linus Torvalds committed
1896 1897 1898 1899 1900 1901 1902 1903
	if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
		return -EINVAL;
	if (ti->ring_speed == 4 && mtu > ti->maxmtu4)
		return -EINVAL;
	dev->mtu = mtu;
	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
1904
/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
1905 1906 1907
#ifdef MODULE

/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
Linus Torvalds's avatar
Linus Torvalds committed
1908 1909
static struct net_device *dev_ibmtr[IBMTR_MAX_ADAPTERS];
static int io[IBMTR_MAX_ADAPTERS] = { 0xa20, 0xa24 };
Linus Torvalds's avatar
Linus Torvalds committed
1910 1911 1912
static int irq[IBMTR_MAX_ADAPTERS];
static int mem[IBMTR_MAX_ADAPTERS];

Linus Torvalds's avatar
Linus Torvalds committed
1913 1914
MODULE_LICENSE("GPL");

Linus Torvalds's avatar
Linus Torvalds committed
1915 1916 1917 1918
MODULE_PARM(io, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
MODULE_PARM(mem, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");

1919
static int __init ibmtr_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
1920
{
Linus Torvalds's avatar
Linus Torvalds committed
1921 1922 1923 1924
	int i;
	int count=0;

	find_turbo_adapters(io);
1925

Linus Torvalds's avatar
Linus Torvalds committed
1926 1927
	for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) {
		irq[i] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1928
		mem[i] = 0;
1929
		dev_ibmtr[i] = alloc_trdev(sizeof(struct tok_info));
Linus Torvalds's avatar
Linus Torvalds committed
1930
		if (dev_ibmtr[i] == NULL) { 
1931
			if (i == 0)
Linus Torvalds's avatar
Linus Torvalds committed
1932
				return -ENOMEM;
1933
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1934
		}
Linus Torvalds's avatar
Linus Torvalds committed
1935 1936
		dev_ibmtr[i]->base_addr = io[i];
		dev_ibmtr[i]->irq = irq[i];
Linus Torvalds's avatar
Linus Torvalds committed
1937
		dev_ibmtr[i]->mem_start = mem[i];
Linus Torvalds's avatar
Linus Torvalds committed
1938
		dev_ibmtr[i]->init = &ibmtr_probe;
1939
		if (register_netdev(dev_ibmtr[i]) != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
1940 1941
			kfree(dev_ibmtr[i]);
			dev_ibmtr[i] = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1942 1943 1944
			continue;
		}
		count++;
Linus Torvalds's avatar
Linus Torvalds committed
1945
	}
Linus Torvalds's avatar
Linus Torvalds committed
1946
	if (count) return 0;
1947
	printk("ibmtr: register_netdev() returned non-zero.\n");
Linus Torvalds's avatar
Linus Torvalds committed
1948
	return -EIO;
1949 1950
}
module_init(ibmtr_init);
Linus Torvalds's avatar
Linus Torvalds committed
1951

1952
static void __exit ibmtr_cleanup(void)
Linus Torvalds's avatar
Linus Torvalds committed
1953
{
1954
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
1955 1956

	for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){
1957 1958
		if (!dev_ibmtr[i])
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
1959 1960
		if (dev_ibmtr[i]->base_addr) {
			outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET);
1961 1962 1963
			
			schedule_timeout(TR_RST_TIME); /* wait 50ms */

Linus Torvalds's avatar
Linus Torvalds committed
1964
                        outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL);
Linus Torvalds's avatar
Linus Torvalds committed
1965
                }
1966

1967
		unregister_netdev(dev_ibmtr[i]);
Linus Torvalds's avatar
Linus Torvalds committed
1968 1969 1970 1971
		free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
		release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
#ifndef PCMCIA
		{ 
1972 1973 1974 1975
			struct tok_info *ti = (struct tok_info *)
				dev_ibmtr[i]->priv;
			iounmap((u32 *)ti->mmio);
			iounmap((u32 *)ti->sram_virt);
Linus Torvalds's avatar
Linus Torvalds committed
1976 1977 1978 1979 1980
		}
#endif		
		kfree(dev_ibmtr[i]);
		dev_ibmtr[i] = NULL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1981
}
1982 1983
module_exit(ibmtr_cleanup);
#endif