ibmtr.c 63.1 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>

Linus Torvalds's avatar
Linus Torvalds committed
112 113 114 115 116
#ifdef PCMCIA
#undef ENABLE_PAGING
#else
#define ENABLE_PAGING 1		
#endif
Linus Torvalds's avatar
Linus Torvalds committed
117 118 119 120

#define FALSE 0
#define TRUE (!FALSE)

Linus Torvalds's avatar
Linus Torvalds committed
121
/* changes the output format of driver initialization */
Linus Torvalds's avatar
Linus Torvalds committed
122 123 124 125 126 127 128 129 130
#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>
131

Linus Torvalds's avatar
Linus Torvalds committed
132 133 134 135 136 137 138 139 140
#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
141 142 143 144 145 146 147 148 149 150 151
/* 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
152 153
/* this allows displaying full adapter information */

Linus Torvalds's avatar
Linus Torvalds committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
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
172 173
};

Linus Torvalds's avatar
Linus Torvalds committed
174
char __devinit *adapter_def(char type)
Linus Torvalds's avatar
Linus Torvalds committed
175
{
Linus Torvalds's avatar
Linus Torvalds committed
176 177 178 179 180 181
	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
182 183 184
	};
};

Linus Torvalds's avatar
Linus Torvalds committed
185 186 187
#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
188

Linus Torvalds's avatar
Linus Torvalds committed
189
int 		ibmtr_probe(struct net_device *dev);
Linus Torvalds's avatar
Linus Torvalds committed
190
static int	ibmtr_probe1(struct net_device *dev, int ioaddr);
Linus Torvalds's avatar
Linus Torvalds committed
191 192 193 194 195 196 197 198 199
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
200
irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
Linus Torvalds's avatar
Linus Torvalds committed
201
static void 	initial_tok_int(struct net_device *dev);
Linus Torvalds's avatar
Linus Torvalds committed
202 203 204 205 206 207 208 209 210 211 212
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
213
};
Linus Torvalds's avatar
Linus Torvalds committed
214 215 216
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
217

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

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

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
252 253 254 255 256 257 258
	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;
259 260 261 262
		ram_mapped = ioremap((u32)ram_addr,0x1fff) ; 
		if (ram_mapped==NULL) 
 			continue ; 
		chanid=(CHANNEL_ID + ram_mapped);
Linus Torvalds's avatar
Linus Torvalds committed
263
		tchanid=pcchannelid;
264
		ctemp=readb(chanid) & 0x0f;
Linus Torvalds's avatar
Linus Torvalds committed
265 266
		if (ctemp != *tchanid) continue;
		for (i=2,j=1; i<=46; i=i+2,j++) {
267
			if ((readb(chanid+i) & 0x0f) != tchanid[j]){
Linus Torvalds's avatar
Linus Torvalds committed
268 269 270 271 272 273
				found_turbo=0;
				break;
			}
		}
		if (!found_turbo) continue;

274
		writeb(0x90, ram_mapped+0x1E01);
Linus Torvalds's avatar
Linus Torvalds committed
275
		for(i=2; i<0x0f; i++) {
276
			writeb(0x00, ram_mapped+0x1E01+i);
Linus Torvalds's avatar
Linus Torvalds committed
277
		}
278
		writeb(0x00, ram_mapped+0x1E01);
279
		for(jif=jiffies+TR_BUSY_INTERVAL; time_before_eq(jiffies,jif););
280
		intf_tbl=ntohs(readw(ram_mapped+ACA_OFFSET+ACA_RW+WRBR_EVEN));
Linus Torvalds's avatar
Linus Torvalds committed
281 282 283 284 285 286
		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++) {
287
				printk("%x:",readb(ram_addr+intf_tbl+i));
Linus Torvalds's avatar
Linus Torvalds committed
288 289 290
			}
			printk("\n");
#endif
291 292
			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
293
			outb(0, turbo_io[index] + ADAPTRESET);
294
			for(jif=jiffies+TR_RST_TIME;time_before_eq(jiffies,jif););
Linus Torvalds's avatar
Linus Torvalds committed
295 296 297 298 299 300 301 302
			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
303
	iounmap(ram_mapped) ; 	
304
	} /* for */
Linus Torvalds's avatar
Linus Torvalds committed
305 306 307 308 309 310 311 312 313 314 315
	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
316 317 318 319 320 321 322 323 324
 *	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
325 326 327
 ****************************************************************************/

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

Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336 337 338 339 340
	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
341

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

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
363 364 365
	/*    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
366
	 */
Linus Torvalds's avatar
Linus Torvalds committed
367 368 369 370 371 372 373 374 375 376 377
	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
378
	/*
Linus Torvalds's avatar
Linus Torvalds committed
379 380
	 *    Compute the linear base address of the MMIO area
	 *    as LINUX doesn't care about segments
Linus Torvalds's avatar
Linus Torvalds committed
381
	 */
Linus Torvalds's avatar
Linus Torvalds committed
382
	t_mmio = ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
Linus Torvalds's avatar
Linus Torvalds committed
383 384 385 386 387
	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
388
	if (ibmtr_debug_trace & TRC_INIT)
Linus Torvalds's avatar
Linus Torvalds committed
389
		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %p intr: %d\n"
Linus Torvalds's avatar
Linus Torvalds committed
390
				, PIOaddr, (int) segment, t_mmio, (int) intr);
Linus Torvalds's avatar
Linus Torvalds committed
391 392

	/*
Linus Torvalds's avatar
Linus Torvalds committed
393 394
	 *    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
395
	 */
Linus Torvalds's avatar
Linus Torvalds committed
396
#ifdef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
397 398
	iounmap(t_mmio);
	t_mmio = (void *)ti->mmio;	/*BMS to get virtual address */
Linus Torvalds's avatar
Linus Torvalds committed
399 400 401 402 403 404 405 406 407 408 409 410 411
	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
412
	}
Linus Torvalds's avatar
Linus Torvalds committed
413 414 415 416 417 418 419
	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
420 421 422
		}
	}
	/* 
Linus Torvalds's avatar
Linus Torvalds committed
423 424
	 *    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
425
	 */
Linus Torvalds's avatar
Linus Torvalds committed
426 427 428
	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
429 430 431 432 433 434
		if (!(ibmtr_debug_trace & TRC_INIT)) {
#ifndef PCMCIA
			iounmap(t_mmio);
#endif
			return -ENODEV;
		}
Linus Torvalds's avatar
Linus Torvalds committed
435 436 437 438 439 440 441 442 443 444 445
		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
446
	}
447
	/* Now, setup some of the pl0 buffers for this driver.. */
Linus Torvalds's avatar
Linus Torvalds committed
448
	/* If called from PCMCIA, it is already set up, so no need to 
Linus Torvalds's avatar
Linus Torvalds committed
449 450
	   waste the memory, just use the existing structure */
#ifndef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
451
	ti->mmio = t_mmio;
452 453 454
        for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) {
                if (turbo_io[i] != PIOaddr)
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
455
#if IBMTR_DEBUG_MESSAGES 
456 457
		printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n",
		       PIOaddr);
Linus Torvalds's avatar
Linus Torvalds committed
458
#endif
459 460
		ti->turbo = 1;
		t_irq = turbo_irq[i];
Linus Torvalds's avatar
Linus Torvalds committed
461
        }
Linus Torvalds's avatar
Linus Torvalds committed
462
#endif /* !PCMCIA */
Linus Torvalds's avatar
Linus Torvalds committed
463 464 465
	ti->readlog_pending = 0;
	init_waitqueue_head(&ti->wait_for_reset);

Linus Torvalds's avatar
Linus Torvalds committed
466 467 468
	/* 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
469
#ifndef PCMCIA
Linus Torvalds's avatar
Linus Torvalds committed
470 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
	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
499
			iounmap(t_mmio);
Linus Torvalds's avatar
Linus Torvalds committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513
			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
514
			DPRINTK(", ti->mmio=%p", ti->mmio);
Linus Torvalds's avatar
Linus Torvalds committed
515
			printk(", segment=%02X", segment);
Linus Torvalds's avatar
Linus Torvalds committed
516 517 518 519 520
		}
		printk(".\n");
	}

	/* Get hw address of token ring card */
Linus Torvalds's avatar
Linus Torvalds committed
521 522
	j = 0;
	for (i = 0; i < 0x18; i = i + 2) {
Linus Torvalds's avatar
Linus Torvalds committed
523
		/* technical reference states to do this */
Linus Torvalds's avatar
Linus Torvalds committed
524 525 526 527 528
		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
529 530
		++j;
	}
Linus Torvalds's avatar
Linus Torvalds committed
531 532
	/* 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
533 534

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

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

	/* How much shared RAM is on adapter ? */
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543 544 545 546
	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
547
	/* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
Linus Torvalds's avatar
Linus Torvalds committed
548 549 550 551 552 553 554
	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
555 556 557
	}

	/* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
Linus Torvalds's avatar
Linus Torvalds committed
558 559 560 561 562 563
	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
564 565
	}

Linus Torvalds's avatar
Linus Torvalds committed
566 567 568 569 570 571
	/*    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
572 573 574
	 */

	/*
Linus Torvalds's avatar
Linus Torvalds committed
575
	 *    determine how much of total RAM is mapped into PC space 
Linus Torvalds's avatar
Linus Torvalds committed
576
	 */
Linus Torvalds's avatar
Linus Torvalds committed
577 578 579 580 581 582
	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
583
#ifdef ENABLE_PAGING
Linus Torvalds's avatar
Linus Torvalds committed
584 585 586 587
		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
588 589 590
		case 0xf:
			break;
		case 0xe:
Linus Torvalds's avatar
Linus Torvalds committed
591 592
			ti->page_mask = (ti->mapped_ram_size == 32) ? 0xc0 : 0;
			pg_size = 32;	/* 16KB page size */
Linus Torvalds's avatar
Linus Torvalds committed
593 594
			break;
		case 0xd:
Linus Torvalds's avatar
Linus Torvalds committed
595 596
			ti->page_mask = (ti->mapped_ram_size == 64) ? 0x80 : 0;
			pg_size = 64;	/* 32KB page size */
Linus Torvalds's avatar
Linus Torvalds committed
597 598
			break;
		case 0xc:
Linus Torvalds's avatar
Linus Torvalds committed
599 600 601 602 603 604 605 606 607 608
			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
609 610
			break;
		default:
Linus Torvalds's avatar
Linus Torvalds committed
611 612
			DPRINTK("Unknown shared ram paging info %01X\n",
							ti->shared_ram_paging);
Linus Torvalds's avatar
Linus Torvalds committed
613
			iounmap(t_mmio); 
Linus Torvalds's avatar
Linus Torvalds committed
614 615 616
			kfree(ti);
			return -ENODEV;
			break;
Linus Torvalds's avatar
Linus Torvalds committed
617 618 619 620 621 622 623 624 625
		} /*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
626 627
	}

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

Linus Torvalds's avatar
Linus Torvalds committed
635
		rrr_32=readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03;
Linus Torvalds's avatar
Linus Torvalds committed
636
		rbm = ram_bndry_mask[rrr_32];
Linus Torvalds's avatar
Linus Torvalds committed
637 638
		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
639
		if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) {
Linus Torvalds's avatar
Linus Torvalds committed
640 641 642
			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
643
			iounmap(t_mmio);
Linus Torvalds's avatar
Linus Torvalds committed
644
			kfree(ti);
Linus Torvalds's avatar
Linus Torvalds committed
645 646
			return -ENODEV;
		} else { /* seems cool, record what we have figured out */
Linus Torvalds's avatar
Linus Torvalds committed
647 648 649 650
			ti->sram_base = new_base >> 12;
			ibmtr_mem_base = chk_base;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
651
	else  ti->sram_base = ti->sram_virt >> 12;
Linus Torvalds's avatar
Linus Torvalds committed
652 653 654

	/* 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
655 656 657
	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
658
		iounmap(t_mmio);
Linus Torvalds's avatar
Linus Torvalds committed
659 660 661 662
		kfree(ti);
		return -ENODEV;
	}
	/*?? Now, allocate some of the PIO PORTs for this driver.. */
Linus Torvalds's avatar
Linus Torvalds committed
663
	/* record PIOaddr range as busy */
Linus Torvalds's avatar
Linus Torvalds committed
664 665 666 667 668 669 670 671
	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
672 673 674
	if (!version_printed++) {
		printk(version);
	}
Linus Torvalds's avatar
Linus Torvalds committed
675
#endif /* !PCMCIA */
Linus Torvalds's avatar
Linus Torvalds committed
676
	DPRINTK("%s %s found\n",
Linus Torvalds's avatar
Linus Torvalds committed
677
		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
Linus Torvalds's avatar
Linus Torvalds committed
678
	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
Linus Torvalds's avatar
Linus Torvalds committed
679
			irq, PIOaddr, ti->mapped_ram_size / 2);
Linus Torvalds's avatar
Linus Torvalds committed
680 681 682
	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
683 684 685 686 687 688 689 690
	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
691
	/* Calculate the maximum DHB we can use */
Linus Torvalds's avatar
Linus Torvalds committed
692 693 694 695 696
	/* 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
697
	if (!ti->page_mask) {
Linus Torvalds's avatar
Linus Torvalds committed
698 699
		ti->avail_shared_ram=
				MIN(ti->mapped_ram_size,ti->avail_shared_ram);
Linus Torvalds's avatar
Linus Torvalds committed
700
	}
Linus Torvalds's avatar
Linus Torvalds committed
701

Linus Torvalds's avatar
Linus Torvalds committed
702
	switch (ti->avail_shared_ram) {
Linus Torvalds's avatar
Linus Torvalds committed
703 704
	case 16:		/* 8KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048);
Linus Torvalds's avatar
Linus Torvalds committed
705
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
706
		ti->rbuf_cnt4=2;
Linus Torvalds's avatar
Linus Torvalds committed
707 708
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
709
		ti->rbuf_cnt16=2;
Linus Torvalds's avatar
Linus Torvalds committed
710
		break;
Linus Torvalds's avatar
Linus Torvalds committed
711 712 713 714 715 716 717
	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
718
		break;
Linus Torvalds's avatar
Linus Torvalds committed
719 720
	case 64:		/* 32KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
Linus Torvalds's avatar
Linus Torvalds committed
721
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
722 723
		ti->rbuf_cnt4=6;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240);
Linus Torvalds's avatar
Linus Torvalds committed
724
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
725
		ti->rbuf_cnt16=6;
Linus Torvalds's avatar
Linus Torvalds committed
726
		break;
Linus Torvalds's avatar
Linus Torvalds committed
727 728
	case 127:		/* 63.5KB shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
Linus Torvalds's avatar
Linus Torvalds committed
729
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
730 731
		ti->rbuf_cnt4=6;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384);
Linus Torvalds's avatar
Linus Torvalds committed
732
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
733
		ti->rbuf_cnt16=16;
Linus Torvalds's avatar
Linus Torvalds committed
734
		break;
Linus Torvalds's avatar
Linus Torvalds committed
735 736
	case 128:		/* 64KB   shared RAM */
		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
Linus Torvalds's avatar
Linus Torvalds committed
737
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
738 739
		ti->rbuf_cnt4=6;
		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960);
Linus Torvalds's avatar
Linus Torvalds committed
740
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
741
		ti->rbuf_cnt16=16;
Linus Torvalds's avatar
Linus Torvalds committed
742
		break;
Linus Torvalds's avatar
Linus Torvalds committed
743 744
	default:
		ti->dhb_size4mb = 2048;
Linus Torvalds's avatar
Linus Torvalds committed
745
		ti->rbuf_len4 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
746
		ti->rbuf_cnt4=2;
Linus Torvalds's avatar
Linus Torvalds committed
747 748
		ti->dhb_size16mb = 2048;
		ti->rbuf_len16 = 1032;
Linus Torvalds's avatar
Linus Torvalds committed
749
		ti->rbuf_cnt16=2;
Linus Torvalds's avatar
Linus Torvalds committed
750 751
		break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
	/* 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
767
	trdev_init(dev);
Linus Torvalds's avatar
Linus Torvalds committed
768 769
	return 0;   /* Return 0 to indicate we have found a Token Ring card. */
}				/*ibmtr_probe1() */
Linus Torvalds's avatar
Linus Torvalds committed
770

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

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

Linus Torvalds's avatar
Linus Torvalds committed
776
static unsigned char __devinit get_sram_size(struct tok_info *adapt_info)
Linus Torvalds's avatar
Linus Torvalds committed
777 778
{
	unsigned char avail_sram_code;
Linus Torvalds's avatar
Linus Torvalds committed
779
	static unsigned char size_code[] = { 0, 16, 32, 64, 127, 128 };
Linus Torvalds's avatar
Linus Torvalds committed
780 781 782 783 784 785 786
	/* 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
787 788 789 790 791
	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
792 793
}

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

Linus Torvalds's avatar
Linus Torvalds committed
796 797 798
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
799 800

	SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
801 802 803 804 805
        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
806
	dev->set_multicast_list = tok_set_multicast_list;
Linus Torvalds's avatar
Linus Torvalds committed
807
	dev->change_mtu = ibmtr_change_mtu;
Linus Torvalds's avatar
Linus Torvalds committed
808 809 810 811

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
812 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);
			MOD_INC_USE_COUNT;
			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 1045
	netif_stop_queue(dev);
	DPRINTK("Adapter is closed.\n");
	MOD_DEC_USE_COUNT;
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
1046

Linus Torvalds's avatar
Linus Torvalds committed
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 1099
/*****************************************************************************/

#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
1100
	}
Linus Torvalds's avatar
Linus Torvalds committed
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 1139
	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
1140 1141
}

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

Andrew Morton's avatar
Andrew Morton committed
1144
irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
1145 1146
{
	unsigned char status;
Linus Torvalds's avatar
Linus Torvalds committed
1147
	/*  unsigned char status_even ; */
Linus Torvalds's avatar
Linus Torvalds committed
1148 1149 1150 1151 1152 1153 1154 1155
	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
1156
	DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs);
Linus Torvalds's avatar
Linus Torvalds committed
1157
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1158 1159
	ti = (struct tok_info *) dev->priv;
	if (ti->sram_virt & 1)
Andrew Morton's avatar
Andrew Morton committed
1160
		return IRQ_NONE;         /* PCMCIA card extraction flag */
Linus Torvalds's avatar
Linus Torvalds committed
1161 1162
	spin_lock(&(ti->lock));
#ifdef ENABLE_PAGING
Linus Torvalds's avatar
Linus Torvalds committed
1163
	save_srpr = readb(ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1164 1165
#endif

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

	/* Reset interrupt for ISA boards */
Linus Torvalds's avatar
Linus Torvalds committed
1170 1171 1172 1173 1174 1175 1176 1177
	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
1178
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1179
                spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1180
                return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
        }
	/*  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
1201

Linus Torvalds's avatar
Linus Torvalds committed
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
		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
1218
		spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1219
		return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
	}
	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
1234
                return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1235 1236 1237
        }
	if (status & SRB_RESP_INT) {	/* SRB response */
		SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1238
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1239 1240
		DPRINTK("SRB resp: cmd=%02X rsp=%02X\n",
				readb(ti->srb), readb(ti->srb + RETCODE_OFST));
Linus Torvalds's avatar
Linus Torvalds committed
1241
#endif
Linus Torvalds's avatar
Linus Torvalds committed
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 1341
		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
1342
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
			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
1353
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1354
		DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb));
Linus Torvalds's avatar
Linus Torvalds committed
1355 1356
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376
		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
1377
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1378
		DPRINTK("ARB resp: cmd=%02X\n", readb(ti->arb));
Linus Torvalds's avatar
Linus Torvalds committed
1379 1380
#endif

Linus Torvalds's avatar
Linus Torvalds committed
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 1436
		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
1437
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459

		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
1460
#ifdef ENABLE_PAGING
Linus Torvalds's avatar
Linus Torvalds committed
1461
	writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1462
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1463
	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
Linus Torvalds's avatar
Linus Torvalds committed
1464
	spin_unlock(&(ti->lock));
Andrew Morton's avatar
Andrew Morton committed
1465
	return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
1466 1467 1468 1469 1470 1471 1472
}				/*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
1473 1474 1475 1476

static void initial_tok_int(struct net_device *dev)
{

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

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

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

	/* we assign the shared-ram address for ISA devices */
Linus Torvalds's avatar
Linus Torvalds committed
1486 1487 1488 1489 1490
	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
1491
	if (ti->page_mask) {
Linus Torvalds's avatar
Linus Torvalds committed
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
		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
1505 1506 1507 1508 1509
	}
	SET_PAGE(ti->init_srb_page);

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

Linus Torvalds's avatar
Linus Torvalds committed
1512 1513 1514 1515
	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
1516
	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
1517
	}
Linus Torvalds's avatar
Linus Torvalds committed
1518 1519
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1520 1521 1522 1523 1524 1525 1526 1527 1528
	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
1529

Linus Torvalds's avatar
Linus Torvalds committed
1530 1531 1532 1533
        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
1534

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
1544
static void tr_tx(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
1545
{
Linus Torvalds's avatar
Linus Torvalds committed
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
	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
1556

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

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

Linus Torvalds's avatar
Linus Torvalds committed
1561 1562 1563 1564 1565 1566 1567 1568 1569
	/* 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
1570
	}
Linus Torvalds's avatar
Linus Torvalds committed
1571
	dhb += ti->sram_virt;
Linus Torvalds's avatar
Linus Torvalds committed
1572

Linus Torvalds's avatar
Linus Torvalds committed
1573 1574 1575 1576 1577 1578
	/* 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
1579

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

Linus Torvalds's avatar
Linus Torvalds committed
1582 1583 1584
	llc_ssap = llc->ssap;
	SET_PAGE(ti->srb_page);
	memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb));
Linus Torvalds's avatar
Linus Torvalds committed
1585
	SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
	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
1596
		SET_PAGE(dhb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1597 1598 1599 1600 1601 1602 1603
		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
1604 1605 1606
		return;
	}
	/*
Linus Torvalds's avatar
Linus Torvalds committed
1607 1608
	 *    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
1609
	 */
Linus Torvalds's avatar
Linus Torvalds committed
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 1636
	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
1637
	dev_kfree_skb_irq(ti->current_skb);
Linus Torvalds's avatar
Linus Torvalds committed
1638
	ti->current_skb = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1639
	netif_wake_queue(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
	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
1656 1657 1658

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
1684 1685 1686 1687 1688
	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
1689

Linus Torvalds's avatar
Linus Torvalds committed
1690 1691 1692 1693 1694 1695
	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
1696 1697 1698
	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);

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

#if TR_VERBOSE
	DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
Linus Torvalds's avatar
Linus Torvalds committed
1703 1704 1705
	(__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
1706 1707
	DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, "
		"ethertype: %04X\n",
Linus Torvalds's avatar
Linus Torvalds committed
1708 1709 1710 1711
		(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
1712
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1713 1714 1715
	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
1716
		ti->tr_stats.rx_dropped++;
Linus Torvalds's avatar
Linus Torvalds committed
1717
		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
Linus Torvalds's avatar
Linus Torvalds committed
1718 1719 1720
		return;
	}
	length = ntohs(rarb.frame_len);
Linus Torvalds's avatar
Linus Torvalds committed
1721 1722 1723
	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
1724
#if TR_VERBOSE
Linus Torvalds's avatar
Linus Torvalds committed
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
#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
1746 1747
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1748 1749 1750 1751 1752 1753
	/*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
1754
		SET_PAGE(ti->asb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
		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
1766 1767

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

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

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

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

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

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

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

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
1861 1862 1863
{
	struct tok_info *ti;

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

Linus Torvalds's avatar
Linus Torvalds committed
1866
	ti->readlog_pending = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1867
	SET_PAGE(ti->srb_page);
Linus Torvalds's avatar
Linus Torvalds committed
1868 1869 1870
	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
1871

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

}

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

Linus Torvalds's avatar
Linus Torvalds committed
1878 1879 1880 1881 1882
/* 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
1883 1884
static struct net_device_stats *tok_get_stats(struct net_device *dev)
{
Linus Torvalds's avatar
Linus Torvalds committed
1885 1886

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
1897 1898 1899 1900 1901 1902 1903 1904
	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
1905
/*****************************************************************************/
Linus Torvalds's avatar
Linus Torvalds committed
1906 1907 1908
#ifdef MODULE

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

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

Linus Torvalds's avatar
Linus Torvalds committed
1916 1917 1918 1919 1920 1921
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");

int init_module(void)
{
Linus Torvalds's avatar
Linus Torvalds committed
1922 1923 1924 1925
	int i;
	int count=0;

	find_turbo_adapters(io);
1926

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

void cleanup_module(void)
{
Linus Torvalds's avatar
Linus Torvalds committed
1954 1955 1956
	int i,j;

	for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){
1957 1958
		if (!dev_ibmtr[i])
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
1959 1960 1961 1962 1963
		if (dev_ibmtr[i]->base_addr) {
			outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET);
			for(j=jiffies+TR_RST_TIME;
				time_before_eq(jiffies,j);) ;
                        outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL);
Linus Torvalds's avatar
Linus Torvalds committed
1964
                }
1965
		unregister_netdev(dev_ibmtr[i]);
Linus Torvalds's avatar
Linus Torvalds committed
1966 1967 1968 1969
		free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
		release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
#ifndef PCMCIA
		{ 
1970 1971 1972 1973
			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
1974 1975 1976 1977 1978
		}
#endif		
		kfree(dev_ibmtr[i]);
		dev_ibmtr[i] = NULL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1979
}
Linus Torvalds's avatar
Linus Torvalds committed
1980
#endif				/* MODULE */