2 * SMC EtherEZ (SMC91cXX chip) PCMCIA card support.
6 #include "../port/lib.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 #include "../port/etherif.h"
16 IoSize = 0x10, /* port pool size */
20 enum { /* PCMCIA related */
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 */
34 enum { /* bank 1 registers */
37 Addr0 = 0x0004, /* ethernet address */
44 enum { /* bank 2 registers */
55 enum { /* bank 3 registers */
64 BankSelect = 0x000E /* bank select register */
68 BsrMask = 0xFF00, /* mask for chip identification */
73 enum { /* Tcr values */
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 */
84 TcrNormal = TcrEnable,
87 enum { /* Eph values */
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 */
102 EphTxUnrn = 0x8000, /* tx underrun */
105 enum { /* Rcr values */
108 RcrAllMcast = 0x0004,
110 RcrStripCrc = 0x0200,
111 RcrSoftReset = 0x8000,
112 RcrNormal = RcrStripCrc | RcrEnable,
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 */
126 enum { /* MemInfo value masks */
127 MirTotalMask = 0x00FF,
128 MirFreeMask = 0xFF00,
131 enum { /* Config values */
134 CfgDisLink = 0x0040, /* disable 10BaseT link test */
136 CfgAuiSelect = 0x0100,
137 CfgSetSqlch = 0x0200,
138 CfgFullStep = 0x0400,
140 CfgMiiSelect = 0x8000,
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 */
154 enum { /* MmuCmd values */
156 McAlloc = 0x0020, /* | with number of 256 byte packets - 1 */
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 */
164 enum { /* AllocRes values */
168 enum { /* FifoPorts values */
175 enum { /* Pointer values */
181 enum { /* Interrupt values */
190 enum { /* transmit status bits */
197 enum { /* receive status bits */
204 RsError = RsAlgnErr | RsBadCrc | RsTooLong | RsTooShort,
208 RxLenMask = 0x07FF, /* significant rx len bits */
209 HdrSize = 6, /* packet header length */
210 PageSize = 256, /* page length */
213 typedef struct Smc91xx Smc91xx;
230 #define SELECT_BANK(x) outs(port + BankSelect, x)
233 readnodeid(int slot, Ether* ether)
235 uchar data[Eaddrlen + 1];
239 if (pcmcistuple(slot, TupleFunce, TfNodeId, data, len) != len)
242 if (data[0] != Eaddrlen)
245 memmove(ether->ea, &data[1], Eaddrlen);
250 chipreset(Ether* ether)
259 outs(port + Rcr, RcrSoftReset);
261 outs(port + Rcr, RcrClear);
262 outs(port + Tcr, TcrClear);
264 outs(port + Control, CtlAutoRls | CtlTeEnable |
267 for(i = 0; i < 6; i++) {
268 outb(port + Addr0 + i, ether->ea[i]);
272 outs(port + MmuCmd, McReset);
276 chipenable(Ether* ether)
282 outs(port + Tcr, TcrNormal);
283 outs(port + Rcr, RcrNormal);
285 outb(port + IntrMask, IntEph | IntRxOvrn | IntRcv);
296 if (ctlr->attached) {
307 txstart(Ether* ether)
315 /* assumes ctlr is locked and bank 2 is selected */
316 /* leaves bank 2 selected on return */
324 bp = qget(ether->oq);
329 npages = (len + HdrSize) / PageSize;
330 outs(port + MmuCmd, McAlloc | npages);
333 pno = inb(port + AllocRes);
334 if (pno & ArFailed) {
335 outb(port + IntrMask, inb(port + IntrMask) | IntAlloc);
337 ctlr->txtime = MACHP(0)->ticks;
341 outb(port + PktNo, pno);
342 outs(port + Pointer, PtrAutoInc);
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);
352 outb(port + Data1, bp->rp[len - 1]);
353 outb(port + Data1, 0x20); /* no info what 0x20 means */
356 outb(port + IntrMask, inb(port + IntrMask) |
357 IntTxError | IntTxEmpty);
359 outs(port + MmuCmd, McEnqueue);
364 receive(Ether* ether)
368 int pktno, status, len;
370 /* assumes ctlr is locked and bank 2 is selected */
371 /* leaves bank 2 selected on return */
374 pktno = ins(port + FifoPorts);
375 if (pktno & FpRxEmpty) {
379 outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc);
380 status = ins(port + Data1);
381 len = ins(port + Data1) & RxLenMask - HdrSize;
383 if (status & RsOddFrame)
386 if ((status & RsError) || (bp = iallocb(len)) == 0) {
388 if (status & RsAlgnErr)
390 if (status & (RsTooShort | RsTooLong))
392 if (status & RsBadCrc)
395 outs(port + MmuCmd, McRelease);
399 /* packet length is padded to word */
400 inss(port + Data1, bp->rp, len / 2);
401 bp->wp = bp->rp + (len & ~1);
404 *bp->wp = inb(port + Data1);
410 outs(port + MmuCmd, McRelease);
414 txerror(Ether* ether)
421 /* assumes ctlr is locked and bank 2 is selected */
422 /* leaves bank 2 selected on return */
426 save_pkt = inb(port + PktNo);
428 pktno = ins(port + FifoPorts) & FpTxMask;
429 outb(port + PktNo, pktno);
430 outs(port + Pointer, PtrAutoInc | PtrRead);
431 status = ins(port + Data1);
433 if (status & TsLostCar)
436 if (status & TsLatCol)
439 if (status & Ts16Col)
445 outs(port + Tcr, ins(port + Tcr) | TcrEnable);
448 outs(port + MmuCmd, McFreePkt);
450 outb(port + PktNo, save_pkt);
454 eph_irq(Ether* ether)
461 /* assumes ctlr is locked and bank 2 is selected */
462 /* leaves bank 2 selected on return */
467 status = ins(port + Eph);
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;
478 /* if there was a transmit error, Tcr is disabled */
479 outs(port + Tcr, ins(port + Tcr) | TcrEnable);
481 /* clear a link error interrupt */
483 outs(port + Control, CtlAutoRls);
484 outs(port + Control, CtlAutoRls | CtlTeEnable | CtlCrEnable);
490 transmit(Ether* ether)
500 n = TK2MS(MACHP(0)->ticks - ctlr->txtime);
517 interrupt(Ureg*, void *arg)
531 save_bank = ins(port + BankSelect);
533 save_pointer = ins(port + Pointer);
535 mask = inb(port + IntrMask);
536 outb(port + IntrMask, 0);
538 while ((status = inb(port + Interrupt) & mask) != 0) {
539 if (status & IntRcv) {
543 if (status & IntTxError) {
547 if (status & IntTxEmpty) {
548 outb(port + Interrupt, IntTxEmpty);
549 outb(port + IntrMask, mask & ~IntTxEmpty);
551 mask = inb(port + IntrMask);
554 if (status & IntAlloc) {
555 outb(port + IntrMask, mask & ~IntAlloc);
557 mask = inb(port + IntrMask);
560 if (status & IntRxOvrn) {
563 outb(port + Interrupt,IntRxOvrn);
570 outb(port + IntrMask, mask);
571 outs(port + Pointer, save_pointer);
572 outs(port + BankSelect, save_bank);
577 promiscuous(void* arg, int on)
601 multicast(void* arg, uchar *addr, int on)
628 ifstat(Ether* ether, void* a, long n, ulong offset)
630 static char *chiprev[] = {
651 if (r < nelem(chiprev))
655 if ((ctlr->rev & 0x0F) >= 6)
662 p = smalloc(READSTR);
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);
673 n = readstr(offset, a, n, p);
692 if (ether->port == 0)
696 for(i = 0; i < ether->nopt; i++) {
697 if (cistrncmp(ether->opt[i], "id=", 3))
699 type = ðer->opt[i][3];
703 if ((slot = pcmspecial(type, ether)) < 0)
706 if (ioalloc(ether->port, IoSize, 0, "smc91cXX") < 0) {
707 pcmspecialclose(slot);
711 ctlr = malloc(sizeof(Smc91xx));
713 print("smc: can't allocate memory\n");
715 pcmspecialclose(slot);
735 if ((ins(port + BankSelect) & BsrMask) != BsrId) {
736 outs(port + Control, 0); /* try powering up the chip */
740 outs(port + Config, ins(port + Config) | Cfg16Bit);
741 x = ins(port + BaseAddr);
743 if (((ins(port + BankSelect) & BsrMask) != BsrId) ||
744 ((x >> 8) == (x & 0xFF))) {
747 pcmspecialclose(slot);
752 ctlr->rev = ins(port + Revision) & 0xFF;
754 memset(ea, 0, Eaddrlen);
755 if (memcmp(ea, ether->ea, Eaddrlen) == 0) {
756 if (readnodeid(slot, ether) < 0) {
757 print("Smc91cXX: cannot find ethernet address\n");
760 pcmspecialclose(slot);
767 ether->attach = attach;
768 ether->transmit = transmit;
769 ether->ifstat = ifstat;
770 ether->promiscuous = promiscuous;
771 ether->multicast = multicast;
776 intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
784 addethercard("smc91cXX", reset);