Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/9/pc/ethersmc.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * SMC EtherEZ (SMC91cXX chip) PCMCIA card support.
3
 */
4
 
5
#include "u.h"
6
#include "../port/lib.h"
7
#include "mem.h"
8
#include "dat.h"
9
#include "fns.h"
10
#include "io.h"
11
#include "../port/error.h"
12
#include "../port/netif.h"
13
#include "etherif.h"
14
 
15
enum {
16
	IoSize		= 0x10,		/* port pool size */
17
	TxTimeout	= 150,
18
};
19
 
20
enum {	/* PCMCIA related */
21
	TupleFunce	= 0x22,
22
	TfNodeId	= 0x04,
23
};
24
 
25
enum {	/* bank 0 registers */
26
	Tcr		= 0x0000,	/* transmit control */
27
	Eph		= 0x0002,	/* ethernet protocol handler */
28
	Rcr		= 0x0004,	/* receiver control */
29
	Counter		= 0x0006,	/* statistics counter */
30
	MemInfo		= 0x0008,
31
	MemCfg		= 0x000A,
32
};
33
 
34
enum {	/* bank 1 registers */
35
	Config		= 0x0000,
36
	BaseAddr	= 0x0002,
37
	Addr0		= 0x0004,	/* ethernet address */
38
	Addr1		= 0x0006,
39
	Addr2		= 0x0008,
40
	General		= 0x000A,
41
	Control		= 0x000C,
42
};
43
 
44
enum {	/* bank 2 registers */
45
	MmuCmd		= 0x0000,
46
	PktNo		= 0x0002,
47
	AllocRes	= 0x0003,
48
	FifoPorts	= 0x0004,
49
	Pointer		= 0x0006,
50
	Data1		= 0x0008,
51
	Interrupt	= 0x000C,
52
	IntrMask	= 0x000D,
53
};
54
 
55
enum {	/* bank 3 registers */
56
	Mcast0		= 0x0000,
57
	Mcast2		= 0x0002,
58
	Mcast4		= 0x0004,
59
	Mcast6		= 0x0006,
60
	Revision	= 0x000A,
61
};
62
 
63
enum {
64
	BankSelect	= 0x000E	/* bank select register */
65
};
66
 
67
enum {
68
	BsrMask		= 0xFF00,	/* mask for chip identification */
69
	BsrId		= 0x3300,
70
};
71
 
72
 
73
enum {	/* Tcr values */
74
	TcrClear	= 0x0000,
75
	TcrEnable	= 0x0001,	/* enable transmit */
76
	TcrLoop		= 0x0002,	/* enable internal analogue loopback */
77
	TcrForceCol	= 0x0004,	/* force collision on next tx */
78
	TcrPadEn	= 0x0080,	/* pad short packets to 64 bytes */
79
	TcrNoCrc	= 0x0100,	/* do not append CRC */
80
	TcrMonCns	= 0x0400,	/* monitor carrier status */
81
	TcrFduplx	= 0x0800,
82
	TcrStpSqet	= 0x1000,
83
	TcrEphLoop	= 0x2000,
84
	TcrNormal	= TcrEnable,
85
};
86
 
87
enum {	/* Eph values */
88
	EphTxOk		= 0x0001,
89
	Eph1Col		= 0x0002,	/* single collision */
90
	EphMCol		= 0x0004,	/* multiple collisions */  
91
	EphTxMcast	= 0x0008,	/* multicast transmit */
92
	Eph16Col	= 0x0010,	/* 16 collisions, tx disabled */
93
	EphSqet		= 0x0020,	/* SQE test failed, tx disabled */
94
	EphTxBcast	= 0x0040,	/* broadcast tx */
95
	EphDefr		= 0x0080,	/* deffered tx */
96
	EphLatCol	= 0x0200,	/* late collision, tx disabled */
97
	EphLostCarr	= 0x0400,	/* lost carrier, tx disabled */
98
	EphExcDefr	= 0x0800,	/* excessive defferals */
99
	EphCntRol	= 0x1000,	/* ECR counter(s) rolled over */
100
	EphRxOvrn	= 0x2000,	/* receiver overrun, packets dropped */
101
	EphLinkOk	= 0x4000,
102
	EphTxUnrn	= 0x8000,	/* tx underrun */
103
};
104
 
105
enum {	/* Rcr values */
106
	RcrClear	= 0x0000,
107
	RcrPromisc	= 0x0002,
108
	RcrAllMcast	= 0x0004,
109
	RcrEnable	= 0x0100,
110
	RcrStripCrc	= 0x0200,
111
	RcrSoftReset	= 0x8000,
112
	RcrNormal	= RcrStripCrc | RcrEnable,
113
};
114
 
115
enum { /* Counter value masks */
116
	CntColMask	= 0x000F,	/* collisions */
117
	CntMColMask	= 0x00F0,	/* multiple collisions */
118
	CntDtxMask	= 0x0F00,	/* deferred transmits */
119
	CntExDtxMask	= 0xF000,	/* excessively deferred transmits */
120
 
121
	CntColShr	= 1,
122
	CntMColShr	= 4,
123
	CntDtxShr	= 8,
124
};
125
 
126
enum { /* MemInfo value masks */
127
	MirTotalMask	= 0x00FF,
128
	MirFreeMask	= 0xFF00,
129
};
130
 
131
enum {	/* Config values */
132
	CfgIrqSel0	= 0x0002,
133
	CfgIrqSel1	= 0x0004,
134
	CfgDisLink	= 0x0040,	/* disable 10BaseT link test */
135
	Cfg16Bit	= 0x0080,
136
	CfgAuiSelect	= 0x0100,
137
	CfgSetSqlch	= 0x0200,
138
	CfgFullStep	= 0x0400,
139
	CfgNoWait	= 0x1000,
140
	CfgMiiSelect	= 0x8000,
141
};
142
 
143
enum {	/* Control values */
144
	CtlStore	= 0x0001,	/* store to EEPROM */
145
	CtlReload	= 0x0002,	/* reload EEPROM into registers */
146
	CtlEeSelect	= 0x0004,	/* select registers for reload/store */
147
	CtlTeEnable	= 0x0020,	/* tx error detection via eph irq */
148
	CtlCrEnable	= 0x0040,	/* counter rollover via eph irq */
149
	CtlLeEnable	= 0x0080,	/* link error detection via eph irq*/
150
	CtlAutoRls	= 0x0800,	/* auto release mode */
151
	CtlPowerDn	= 0x2000,
152
};
153
 
154
enum {	/* MmuCmd values */
155
	McBusy		= 0x0001,
156
	McAlloc		= 0x0020,	/* | with number of 256 byte packets - 1 */
157
	McReset		= 0x0040,
158
	McRelease	= 0x0080,	/* dequeue (but not free) current rx packet */
159
	McFreePkt	= 0x00A0,	/* dequeue and free current rx packet */
160
	McEnqueue	= 0x00C0,	/* enqueue the packet for tx */
161
	McTxReset	= 0x00E0,	/* reset transmit queues */
162
};
163
 
164
enum { /* AllocRes values */
165
	ArFailed	= 0x80,
166
};
167
 
168
enum {	/* FifoPorts values */
169
	FpTxEmpty	= 0x0080,
170
	FpRxEmpty	= 0x8000,
171
	FpTxMask	= 0x007F,
172
	FpRxMask	= 0x7F00,
173
};
174
 
175
enum {	/* Pointer values */
176
	PtrRead		= 0x2000,
177
	PtrAutoInc	= 0x4000,
178
	PtrRcv		= 0x8000,
179
};
180
 
181
enum {	/* Interrupt values */
182
	IntRcv		= 0x0001,
183
	IntTxError	= 0x0002,
184
	IntTxEmpty	= 0x0004,
185
	IntAlloc	= 0x0008,
186
	IntRxOvrn	= 0x0010,
187
	IntEph		= 0x0020,
188
};
189
 
190
enum { /* transmit status bits */
191
	TsSuccess	= 0x0001,
192
	Ts16Col		= 0x00A0,
193
	TsLatCol	= 0x0200,
194
	TsLostCar	= 0x0400,
195
};
196
 
197
enum { /* receive status bits */
198
	RsMcast		= 0x0001,
199
	RsTooShort	= 0x0400,
200
	RsTooLong	= 0x0800,
201
	RsOddFrame	= 0x1000,
202
	RsBadCrc	= 0x2000,
203
	RsAlgnErr	= 0x8000,
204
	RsError		= RsAlgnErr | RsBadCrc | RsTooLong | RsTooShort,
205
};
206
 
207
enum {
208
	RxLenMask	= 0x07FF,	/* significant rx len bits */
209
	HdrSize		= 6,		/* packet header length */
210
	PageSize	= 256,		/* page length */
211
};
212
 
213
typedef struct Smc91xx Smc91xx;
214
struct Smc91xx {
215
	Lock;
216
	ushort rev;
217
	int attached;
218
	Block *txbp;
219
	ulong txtime;
220
 
221
	ulong rovrn;
222
	ulong lcar;
223
	ulong col;
224
	ulong scol;
225
	ulong mcol;
226
	ulong lcol;
227
	ulong dfr;
228
};
229
 
230
#define SELECT_BANK(x) outs(port + BankSelect, x)
231
 
232
static int
233
readnodeid(int slot, Ether* ether)
234
{
235
	uchar data[Eaddrlen + 1];
236
	int len;
237
 
238
	len = sizeof(data);
239
	if (pcmcistuple(slot, TupleFunce, TfNodeId, data, len) != len)
240
		return -1;
241
 
242
	if (data[0] != Eaddrlen)
243
		return -1;
244
 
245
	memmove(ether->ea, &data[1], Eaddrlen);
246
	return 0;
247
}
248
 
249
static void
250
chipreset(Ether* ether)
251
{
252
	int port;
253
	int i;
254
 
255
	port = ether->port;
256
 
257
	/* reset the chip */
258
	SELECT_BANK(0);
259
	outs(port + Rcr, RcrSoftReset);
260
	delay(1);
261
	outs(port + Rcr, RcrClear);
262
	outs(port + Tcr, TcrClear);
263
	SELECT_BANK(1);
264
	outs(port + Control, CtlAutoRls | CtlTeEnable |
265
		CtlCrEnable);
266
 
267
	for(i = 0; i < 6; i++) {
268
		outb(port + Addr0 +  i, ether->ea[i]);
269
	}
270
 
271
	SELECT_BANK(2);
272
	outs(port + MmuCmd, McReset);
273
}
274
 
275
static void
276
chipenable(Ether* ether)
277
{
278
	int port;
279
 
280
	port = ether->port;
281
	SELECT_BANK(0);
282
	outs(port + Tcr, TcrNormal);
283
	outs(port + Rcr, RcrNormal);
284
	SELECT_BANK(2);
285
	outb(port + IntrMask, IntEph | IntRxOvrn | IntRcv);
286
}
287
 
288
static void
289
attach(Ether *ether)
290
{
291
	Smc91xx* ctlr;
292
 
293
	ctlr = ether->ctlr;
294
	ilock(ctlr);
295
 
296
	if (ctlr->attached) {
297
		iunlock(ctlr);
298
		return;
299
	}
300
 
301
	chipenable(ether);
302
	ctlr->attached = 1;
303
	iunlock(ctlr);
304
}
305
 
306
static void
307
txstart(Ether* ether)
308
{
309
	int port;
310
	Smc91xx* ctlr;
311
	Block* bp;
312
	int len, npages;
313
	int pno;
314
 
315
	/* assumes ctlr is locked and bank 2 is selected */
316
	/* leaves bank 2 selected on return */
317
	port = ether->port;
318
	ctlr = ether->ctlr;
319
 
320
	if (ctlr->txbp) {
321
		bp = ctlr->txbp;
322
		ctlr->txbp = 0;
323
	} else {
324
		bp = qget(ether->oq);
325
		if (bp == 0)
326
			return;
327
 
328
		len = BLEN(bp);
329
		npages = (len + HdrSize) / PageSize;
330
		outs(port + MmuCmd, McAlloc | npages);
331
	}
332
 
333
	pno = inb(port + AllocRes);
334
	if (pno & ArFailed) {
335
		outb(port + IntrMask, inb(port + IntrMask) | IntAlloc);
336
		ctlr->txbp = bp;
337
		ctlr->txtime = MACHP(0)->ticks;
338
		return;
339
	}
340
 
341
	outb(port + PktNo, pno);
342
	outs(port + Pointer, PtrAutoInc);
343
 
344
	len = BLEN(bp);
345
	outs(port + Data1, 0);
346
	outb(port + Data1, (len + HdrSize) & 0xFF);
347
	outb(port + Data1, (len + HdrSize) >> 8);
348
	outss(port + Data1, bp->rp, len / 2);
349
	if ((len & 1) == 0) {
350
		outs(port + Data1, 0);
351
	} else {
352
		outb(port + Data1, bp->rp[len - 1]);
353
		outb(port + Data1, 0x20);	/* no info what 0x20 means */
354
	}
355
 
356
	outb(port + IntrMask, inb(port + IntrMask) |
357
			IntTxError | IntTxEmpty);
358
 
359
	outs(port + MmuCmd, McEnqueue);
360
	freeb(bp);
361
}
362
 
363
static void
364
receive(Ether* ether)
365
{
366
	int port;
367
	Block* bp;
368
	int pktno, status, len;
369
 
370
	/* assumes ctlr is locked and bank 2 is selected */
371
	/* leaves bank 2 selected on return */
372
	port = ether->port;
373
 
374
	pktno = ins(port + FifoPorts);
375
	if (pktno & FpRxEmpty) {
376
		return;
377
	}
378
 
379
	outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc);
380
	status = ins(port + Data1);
381
	len = ins(port + Data1) & RxLenMask - HdrSize;
382
 
383
	if (status & RsOddFrame)
384
		len++;
385
 
386
	if ((status & RsError) || (bp = iallocb(len)) == 0) {
387
 
388
		if (status & RsAlgnErr)
389
			ether->frames++;
390
		if (status & (RsTooShort | RsTooLong))
391
			ether->buffs++;
392
		if (status & RsBadCrc)
393
			ether->crcs++;
394
 
395
		outs(port + MmuCmd, McRelease);
396
		return;
397
	}
398
 
399
	/* packet length is padded to word */
400
	inss(port + Data1, bp->rp, len / 2);
401
	bp->wp = bp->rp + (len & ~1);
402
 
403
	if (len & 1) {
404
		*bp->wp = inb(port + Data1);
405
		bp->wp++;
406
	}
407
 
408
	etheriq(ether, bp, 1);
409
	ether->inpackets++;
410
	outs(port + MmuCmd, McRelease);
411
}
412
 
413
static void
414
txerror(Ether* ether)
415
{
416
	int port;
417
	Smc91xx* ctlr;
418
	int save_pkt;
419
	int pktno, status;
420
 
421
	/* assumes ctlr is locked and bank 2 is selected */
422
	/* leaves bank 2 selected on return */
423
	port = ether->port;
424
	ctlr = ether->ctlr;
425
 
426
	save_pkt = inb(port + PktNo);
427
 
428
	pktno = ins(port + FifoPorts) & FpTxMask;
429
	outb(port + PktNo, pktno);
430
	outs(port + Pointer, PtrAutoInc | PtrRead);
431
	status = ins(port + Data1);
432
 
433
	if (status & TsLostCar)
434
		ctlr->lcar++;
435
 
436
	if (status & TsLatCol)
437
		ctlr->lcol++;
438
 
439
	if (status & Ts16Col)
440
		ctlr->scol++;
441
 
442
	ether->oerrs++;
443
 
444
	SELECT_BANK(0);
445
	outs(port + Tcr, ins(port + Tcr) | TcrEnable);
446
 
447
	SELECT_BANK(2);
448
	outs(port + MmuCmd, McFreePkt);
449
 
450
	outb(port + PktNo, save_pkt);
451
}
452
 
453
static void
454
eph_irq(Ether* ether)
455
{
456
	int port;
457
	Smc91xx* ctlr;
458
	ushort status;
459
	int n;
460
 
461
	/* assumes ctlr is locked and bank 2 is selected */
462
	/* leaves bank 2 selected on return */
463
	port = ether->port;
464
	ctlr = ether->ctlr;
465
 
466
	SELECT_BANK(0);
467
	status = ins(port + Eph);
468
 
469
	if (status & EphCntRol) {
470
		/* read the counter register even if we don't need it */
471
		/* otherwise we will keep getting this interrupt */
472
		n = ins(port + Counter);
473
		ctlr->col += (n & CntColMask) >> CntColShr;
474
		ctlr->mcol += (n & CntMColMask) >> CntMColShr;
475
		ctlr->dfr += (n & CntDtxMask) >> CntDtxShr;
476
	}
477
 
478
	/* if there was a transmit error, Tcr is disabled */
479
	outs(port + Tcr, ins(port + Tcr) | TcrEnable);
480
 
481
	/* clear a link error interrupt */
482
	SELECT_BANK(1);
483
	outs(port + Control, CtlAutoRls);
484
	outs(port + Control, CtlAutoRls | CtlTeEnable | CtlCrEnable);
485
 
486
	SELECT_BANK(2);
487
}
488
 
489
static void
490
transmit(Ether* ether)
491
{
492
	Smc91xx* ctlr;
493
	int port, n;
494
 
495
	ctlr = ether->ctlr;
496
	port = ether->port;
497
	ilock(ctlr);
498
 
499
	if (ctlr->txbp) {
500
		n = TK2MS(MACHP(0)->ticks - ctlr->txtime);
501
		if (n > TxTimeout) {
502
			chipreset(ether);
503
			chipenable(ether);
504
			freeb(ctlr->txbp);
505
			ctlr->txbp = 0;
506
		}
507
		iunlock(ctlr);
508
		return;
509
	}
510
 
511
	SELECT_BANK(2);
512
	txstart(ether);
513
	iunlock(ctlr);
514
}
515
 
516
static void
517
interrupt(Ureg*, void *arg)
518
{
519
	int port;
520
	Smc91xx* ctlr;
521
	Ether* ether;
522
	int save_bank;
523
	int save_pointer;
524
	int mask, status;
525
 
526
	ether = arg;
527
	port = ether->port;
528
	ctlr = ether->ctlr;
529
 
530
	ilock(ctlr);
531
	save_bank = ins(port + BankSelect);
532
	SELECT_BANK(2);
533
	save_pointer = ins(port + Pointer);
534
 
535
	mask = inb(port + IntrMask);
536
	outb(port + IntrMask, 0);
537
 
538
	while ((status = inb(port + Interrupt) & mask) != 0) {
539
		if (status & IntRcv) {
540
			receive(ether);
541
		}
542
 
543
		if (status & IntTxError) {
544
			txerror(ether);
545
		}
546
 
547
		if (status & IntTxEmpty) {
548
			outb(port + Interrupt, IntTxEmpty);
549
			outb(port + IntrMask, mask & ~IntTxEmpty);
550
			txstart(ether);
551
			mask = inb(port + IntrMask);
552
		}
553
 
554
		if (status & IntAlloc) {
555
			outb(port + IntrMask, mask & ~IntAlloc);
556
			txstart(ether);
557
			mask = inb(port + IntrMask);
558
		}
559
 
560
		if (status & IntRxOvrn) {
561
			ctlr->rovrn++;
562
			ether->misses++;
563
			outb(port + Interrupt,IntRxOvrn);
564
		}
565
 
566
		if (status & IntEph)
567
			eph_irq(ether);
568
	}
569
 
570
	outb(port + IntrMask, mask);
571
	outs(port + Pointer, save_pointer);
572
	outs(port + BankSelect, save_bank);
573
	iunlock(ctlr);
574
}
575
 
576
static void
577
promiscuous(void* arg, int on)
578
{
579
	int port;
580
	Smc91xx *ctlr;
581
	Ether* ether;
582
	ushort x;
583
 
584
	ether = arg;
585
	port = ether->port;
586
	ctlr = ether->ctlr;
587
 
588
	ilock(ctlr);
589
	SELECT_BANK(0);
590
	x = ins(port + Rcr);
591
	if (on)
592
		x |= RcrPromisc;
593
	else
594
		x &= ~RcrPromisc;
595
 
596
	outs(port + Rcr, x);
597
	iunlock(ctlr);
598
}
599
 
600
static void
601
multicast(void* arg, uchar *addr, int on)
602
{
603
	int port;
604
	Smc91xx*ctlr;
605
	Ether *ether;
606
	ushort x;
607
 
608
	USED(addr, on);
609
 
610
	ether = arg;
611
	port = ether->port;
612
	ctlr = ether->ctlr;
613
	ilock(ctlr);
614
 
615
	SELECT_BANK(0);
616
	x = ins(port + Rcr);
617
 
618
	if (ether->nmaddr)
619
		x |= RcrAllMcast;
620
	else
621
		x &= ~RcrAllMcast;
622
 
623
	outs(port + Rcr, x);
624
	iunlock(ctlr);
625
}
626
 
627
static long
628
ifstat(Ether* ether, void* a, long n, ulong offset)
629
{
630
	static char *chiprev[] = {
631
		[3] 	"92",
632
		[5]	"95",
633
		[7]	"100",
634
		[8]	"100-FD",
635
		[9]	"110",
636
	};
637
	Smc91xx* ctlr;
638
	char *p, *s;
639
	int r, len;
640
 
641
	if (n == 0)
642
		return 0;
643
 
644
	ctlr = ether->ctlr;
645
	p = malloc(READSTR);
646
	if(p == nil)
647
		error(Enomem);
648
 
649
	s = 0;
650
	if (ctlr->rev > 0) {
651
		r = ctlr->rev >> 4;
652
		if (r < nelem(chiprev))
653
			s = chiprev[r];
654
 
655
		if (r == 4) {
656
			if ((ctlr->rev & 0x0F) >= 6)
657
				s = "96";
658
			else
659
				s = "94";
660
		}
661
	}
662
 
663
	len = snprint(p, READSTR, "rev: 91c%s\n", (s) ? s : "???");
664
	len += snprint(p + len, READSTR - len, "rxovrn: %uld\n", ctlr->rovrn);
665
	len += snprint(p + len, READSTR - len, "lcar: %uld\n", ctlr->lcar);
666
	len += snprint(p + len, READSTR - len, "col: %uld\n", ctlr->col);
667
	len += snprint(p + len, READSTR - len, "16col: %uld\n", ctlr->scol);
668
	len += snprint(p + len, READSTR - len, "mcol: %uld\n", ctlr->mcol);
669
	len += snprint(p + len, READSTR - len, "lcol: %uld\n", ctlr->lcol);
670
	len += snprint(p + len, READSTR - len, "dfr: %uld\n", ctlr->dfr);
671
	USED(len);
672
 
673
	n = readstr(offset, a, n, p);
674
	free(p);
675
 
676
	return n;
677
}
678
 
679
static int
680
reset(Ether* ether)
681
{
682
	int port;
683
	int i, x;
684
	char* type;
685
	Smc91xx* ctlr;
686
	int slot;
687
	uchar ea[Eaddrlen];
688
 
689
	if (ether->irq == 0)
690
		ether->irq = 9;
691
 
692
	if (ether->port == 0)
693
		ether->port = 0x100;
694
 
695
	type = "8020";
696
	for(i = 0; i < ether->nopt; i++) {
697
		if (cistrncmp(ether->opt[i], "id=", 3))
698
			continue;
699
		type = &ether->opt[i][3];
700
		break;
701
	}
702
 
703
	if ((slot = pcmspecial(type, ether)) < 0)
704
		return -1;
705
 
706
	if (ioalloc(ether->port, IoSize, 0, "smc91cXX") < 0) {
707
		pcmspecialclose(slot);
708
		return -1;
709
	}
710
 
711
	ether->ctlr = malloc(sizeof(Smc91xx));
712
	ctlr = ether->ctlr;
713
	if (ctlr == 0) {
714
		iofree(ether->port);
715
		pcmspecialclose(slot);
716
		return -1;
717
	}
718
 
719
	ilock(ctlr);
720
	ctlr->rev = 0;
721
	ctlr->txbp = nil;
722
	ctlr->attached = 0;
723
	ctlr->rovrn = 0;
724
	ctlr->lcar = 0;
725
	ctlr->col = 0;
726
	ctlr->scol = 0;
727
	ctlr->mcol = 0;
728
	ctlr->lcol = 0;
729
	ctlr->dfr = 0;
730
 
731
	port = ether->port;
732
 
733
	SELECT_BANK(1);
734
	if ((ins(port + BankSelect) & BsrMask) != BsrId) {
735
		outs(port + Control, 0);	/* try powering up the chip */
736
		delay(55);
737
	}
738
 
739
	outs(port + Config, ins(port + Config) | Cfg16Bit);
740
	x = ins(port + BaseAddr);
741
 
742
	if (((ins(port + BankSelect) & BsrMask) != BsrId) ||
743
		((x >> 8) == (x & 0xFF))) {
744
		iunlock(ctlr);
745
		iofree(port);
746
		pcmspecialclose(slot);
747
		return -1;
748
	}
749
 
750
	SELECT_BANK(3);
751
	ctlr->rev = ins(port + Revision) & 0xFF;
752
 
753
	memset(ea, 0, Eaddrlen);
754
	if (memcmp(ea, ether->ea, Eaddrlen) == 0) {
755
		if (readnodeid(slot, ether) < 0) {
756
			print("Smc91cXX: cannot find ethernet address\n");
757
			iunlock(ctlr);
758
			iofree(port);
759
			pcmspecialclose(slot);
760
			return -1;
761
		}
762
	}
763
 
764
	chipreset(ether);
765
 
766
	ether->attach = attach;
767
	ether->transmit = transmit;
768
	ether->interrupt = interrupt;
769
	ether->ifstat = ifstat;
770
	ether->promiscuous = promiscuous;
771
	ether->multicast = multicast;
772
	ether->shutdown = chipreset;
773
	ether->arg = ether;
774
	iunlock(ctlr);
775
	return 0;
776
}
777
 
778
void
779
ethersmclink(void)
780
{
781
	addethercard("smc91cXX", reset);
782
}