1 /*
2 * SMSC 9221 Ethernet driver
3 * specifically for the ISEE IGEPv2 board,
4 * where it is assigned to Chip Select 5,
5 * its registers are at 0x2c000000 (inherited from u-boot),
6 * and irq is 34 from gpio pin 176, thus gpio module 6.
7 *
8 * it's slow due to the use of fifos instead of buffer rings.
9 * the slow system dma just makes it worse.
10 *
11 * igepv2 u-boot uses pin 64 on gpio 3 as an output pin to reset the 9221.
12 */
13 #include "u.h"
14 #include "../port/lib.h"
15 #include "mem.h"
16 #include "dat.h"
17 #include "fns.h"
18 #include "io.h"
19 #include "../port/error.h"
20 #include "../port/netif.h"
21
22 #include "etherif.h"
23
24 /* currently using kprocs is a lot slower than not (87 s. to boot vs 60) */
25 #undef USE_KPROCS
26
27 enum {
28 Vid9221 = 0x9221,
29 Slop = 4, /* beyond ETHERMAXTU */
30 };
31
32 typedef struct Regs Regs;
33 struct Regs {
34 /* fifo ports */
35 ulong rxdata;
36 uchar _pad0[0x20 - 4];
37 ulong txdata;
38 uchar _pad1[0x40 - 0x24];
39 ulong rxsts;
40 ulong rxstspeek;
41 ulong txsts;
42 ulong txstspeek;
43
44 /* control & status */
45 ushort rev; /* chip revision */
46 ushort id; /* chip id, 0x9221 */
47 ulong irqcfg;
48 ulong intsts;
49 ulong inten;
50 ulong _pad2;
51 ulong bytetest;
52 ulong fifoint; /* fifo level interrupts */
53 ulong rxcfg;
54 ulong txcfg;
55 ulong hwcfg;
56 ulong rxdpctl; /* rx data path control */
57 ulong rxfifoinf;
58 ulong txfifoinf;
59 ulong pmtctl; /* power mgmt. control */
60 ulong gpiocfg;
61 ulong gptcfg; /* timer */
62 ulong gptcnt;
63 ulong _pad3;
64 ulong wordswap;
65 ulong freerun; /* counters */
66 ulong rxdrop;
67
68 /*
69 * mac registers are accessed indirectly via the mac csr registers.
70 * phy registers are doubly indirect, via the mac csr mii_acc &
71 * mii_data mac csr registers.
72 */
73 ulong maccsrcmd; /* mac csr synchronizer */
74 ulong maccsrdata;
75 ulong afccfg; /* automatic flow control cfg. */
76 ulong eepcmd; /* eeprom */
77 ulong eepdata;
78 /* 0xb8 */
79 };
80
81 enum {
82 Nstatistics = 128,
83 };
84
85 enum {
86 /* txcmda bits */
87 Intcompl = 1<<31,
88 Bufendalign = 3<<24, /* mask */
89 Datastoff = 037<<16, /* mask */
90 Firstseg = 1<<13,
91 Lastseg = 1<<12,
92 Bufsize = MASK(11),
93
94 /* txcmdb bits */
95 Pkttag = MASK(16) << 16,
96 Txcksumen = 1<<14,
97 Addcrcdis = 1<<13,
98 Framepaddis = 1<<12,
99 Pktlen = (1<<1) - 1, /* mask */
100
101 /* txcfg bits */
102 Txsdump = 1<<15, /* flush tx status fifo */
103 Txddump = 1<<14, /* flush tx data fifo */
104 Txon = 1<<1,
105 Stoptx = 1<<0,
106
107 /* hwcfg bits */
108 Mbo = 1<<20, /* must be one */
109 Srstto = 1<<1, /* soft reset time-out */
110 Srst = 1<<0,
111
112 /* rxcfg bits */
113 Rxdmacntshift = 16, /* ulong count, 12 bits wide */
114 Rxdmacntmask = MASK(12) << Rxdmacntshift,
115 Rxdump = 1<<15, /* flush rx fifos */
116
117 /* rxsts bits */
118 Rxpktlenshift = 16, /* byte count */
119 Rxpktlenmask = MASK(14) << Rxpktlenshift,
120 Rxerr = 1<<15,
121
122 /* rxfifoinf bits */
123 Rxstsusedshift = 16, /* ulong count */
124 Rxstsusedmask = MASK(8) << Rxstsusedshift,
125 Rxdatausedmask = MASK(16), /* byte count */
126
127 /* txfifoinf bits */
128 Txstsusedshift = 16, /* ulong count */
129 Txstsusedmask = MASK(8) << Txstsusedshift,
130 Txdatafreemask = MASK(16), /* byte count */
131
132 /* pmtctl bits */
133 Dready = 1<<0,
134
135 /* maccsrcmd bits */
136 Csrbusy = 1<<31,
137 Csrread = 1<<30, /* not write */
138 Csraddrshift = 0,
139 Csraddrmask = MASK(8) - 1,
140
141 /* mac registers' indices */
142 Maccr = 1,
143 Macaddrh,
144 Macaddrl,
145 Machashh,
146 Machashl,
147 Macmiiacc, /* for doubly-indirect phy access */
148 Macmiidata,
149 Macflow,
150 Macvlan1,
151 Macvlan2,
152 Macwuff,
153 Macwucsr,
154 Maccoe,
155
156 /* Maccr bits */
157 Rxall = 1<<31,
158 Rcvown = 1<<23, /* don't receive own transmissions */
159 Fdpx = 1<<20, /* full duplex */
160 Mcpas = 1<<19, /* pass all multicast */
161 Prms = 1<<18, /* promiscuous */
162 Ho = 1<<15, /* hash-only filtering */
163 Hpfilt = 1<<13, /* hash/perfect filtering */
164 Padstr = 1<<8, /* strip padding & fcs (crc) */
165 Txen = 1<<3,
166 Rxen = 1<<2,
167
168 /* irqcfg bits */
169 Irqdeasclr = 1<<14, /* deassertion intv'l clear */
170 Irqdeassts = 1<<13, /* deassertion intv'l status */
171 Irqint = 1<<12, /* intr being asserted? (ro) */
172 Irqen = 1<<8,
173 Irqpol = 1<<4, /* irq output is active high */
174 Irqpushpull = 1<<0, /* irq output is push/pull driver */
175
176 /* intsts/inten bits */
177 Swint = 1<<31, /* generate an interrupt */
178 Txstop = 1<<25,
179 Rxstop = 1<<24,
180 Txioc = 1<<21,
181 Rxdma = 1<<20,
182 Gptimer = 1<<19,
183 Phy = 1<<18,
184 Rxe = 1<<14, /* errors */
185 Txe = 1<<13,
186 Tdfo = 1<<10, /* tx data fifo overrun */
187 Tdfa = 1<<9, /* tx data fifo available */
188 Tsff = 1<<8, /* tx status fifo full */
189 Tsfl = 1<<7, /* tx status fifo level */
190 Rsff = 1<<4, /* rx status fifo full */
191 Rsfl = 1<<3, /* rx status fifo level */
192
193 /* eepcmd bits */
194 Epcbusy = 1<<31,
195 Epccmdshift = 28, /* interesting one is Reload (7) */
196 Epctimeout = 1<<9,
197 Epcmacloaded = 1<<8,
198 Epcaddrshift = 0,
199 };
200
201 enum {
202 Rxintrs = Rsff | Rsfl | Rxe,
203 Txintrs = Tsff | Tsfl | Txe | Txioc,
204 };
205
206 /* wake-up frame filter */
207 struct Wakeup {
208 ulong bytemask[4]; /* index is filter # */
209 uchar filt0cmd; /* filter 0 command */
210 uchar _pad0;
211 uchar filt1cmd;
212 uchar _pad1;
213 uchar filt2cmd;
214 uchar _pad2;
215 uchar filt3cmd;
216 uchar _pad3;
217 uchar offset[4]; /* index is filter # */
218 ushort crc16[4]; /* " */
219 };
220
221 typedef struct Ctlr Ctlr;
222 struct Ctlr {
223 int port;
224 Ctlr* next;
225 Ether* edev;
226 Regs* regs;
227 int active;
228 int started;
229 int inited;
230 int id;
231 int cls;
232 ushort eeprom[0x40];
233
234 QLock alock; /* attach */
235 int nrb; /* how many this Ctlr has in the pool */
236
237 int* nic;
238 Lock imlock;
239 int im; /* interrupt mask */
240
241 // Mii* mii;
242 // Rendez lrendez;
243 int lim;
244
245 int link;
246
247 QLock slock;
248 uint statistics[Nstatistics];
249 uint lsleep;
250 uint lintr;
251 uint rsleep;
252 uint rintr;
253 int tsleep;
254 uint tintr;
255
256 uchar ra[Eaddrlen]; /* receive address */
257 ulong mta[128]; /* multicast table array */
258
259 Rendez rrendez;
260 int gotinput;
261 int rdcpydone;
262
263 Rendez trendez;
264 int gotoutput;
265 int wrcpydone;
266
267 Lock tlock;
268 };
269
270 #define csr32r(c, r) (*((c)->nic+((r)/4)))
271 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
272
273 static Ctlr *smcctlrhead, *smcctlrtail;
274
275 static char* statistics[Nstatistics] = { "dummy", };
276
277 static uchar mymac[] = { 0xb0, 0x0f, 0xba, 0xbe, 0x00, 0x00, };
278
279 static void etherclock(void);
280 static void smcreceive(Ether *edev);
281 static void smcinterrupt(Ureg*, void* arg);
282
283 static Ether *thisether;
284 static int attached;
285
286 static void
smconce(Ether * edev)287 smconce(Ether *edev)
288 {
289 static int beenhere;
290 static Lock l;
291
292 ilock(&l);
293 if (!beenhere && edev != nil) {
294 beenhere = 1;
295 /* simulate interrupts if we don't know the irq */
296 if (edev->irq < 0) { /* poll as backup */
297 thisether = edev;
298 addclock0link(etherclock, 1000/HZ);
299 iprint(" polling");
300 }
301 }
302 iunlock(&l);
303 }
304
305 /*
306 * indirect (mac) register access
307 */
308
309 static void
macwait(Regs * regs)310 macwait(Regs *regs)
311 {
312 long bound;
313
314 for (bound = 400*Mhz; regs->maccsrcmd & Csrbusy && bound > 0; bound--)
315 ;
316 if (bound <= 0)
317 iprint("smc: mac registers didn't come ready\n");
318 }
319
320 static ulong
macrd(Regs * regs,uchar index)321 macrd(Regs *regs, uchar index)
322 {
323 macwait(regs);
324 regs->maccsrcmd = Csrbusy | Csrread | index;
325 coherence(); /* back-to-back write/read delay per §6.2.1 */
326 macwait(regs);
327 return regs->maccsrdata;
328 }
329
330 static void
macwr(Regs * regs,uchar index,ulong val)331 macwr(Regs *regs, uchar index, ulong val)
332 {
333 macwait(regs);
334 regs->maccsrdata = val;
335 regs->maccsrcmd = Csrbusy | index; /* fire */
336 macwait(regs);
337 }
338
339
340 static long
smcifstat(Ether * edev,void * a,long n,ulong offset)341 smcifstat(Ether* edev, void* a, long n, ulong offset)
342 {
343 Ctlr *ctlr;
344 char *p, *s;
345 int i, l, r;
346
347 ctlr = edev->ctlr;
348 qlock(&ctlr->slock);
349 p = malloc(READSTR);
350 l = 0;
351 for(i = 0; i < Nstatistics; i++){
352 // read regs->rxdrop TODO
353 r = 0;
354 if((s = statistics[i]) == nil)
355 continue;
356 switch(i){
357 default:
358 ctlr->statistics[i] += r;
359 if(ctlr->statistics[i] == 0)
360 continue;
361 l += snprint(p+l, READSTR-l, "%s: %ud %ud\n",
362 s, ctlr->statistics[i], r);
363 break;
364 }
365 }
366
367 l += snprint(p+l, READSTR-l, "lintr: %ud %ud\n",
368 ctlr->lintr, ctlr->lsleep);
369 l += snprint(p+l, READSTR-l, "rintr: %ud %ud\n",
370 ctlr->rintr, ctlr->rsleep);
371 l += snprint(p+l, READSTR-l, "tintr: %ud %ud\n",
372 ctlr->tintr, ctlr->tsleep);
373
374 l += snprint(p+l, READSTR-l, "eeprom:");
375 for(i = 0; i < 0x40; i++){
376 if(i && ((i & 0x07) == 0))
377 l += snprint(p+l, READSTR-l, "\n ");
378 l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]);
379 }
380 l += snprint(p+l, READSTR-l, "\n");
381 USED(l);
382
383 n = readstr(offset, a, n, p);
384 free(p);
385 qunlock(&ctlr->slock);
386
387 return n;
388 }
389
390 static void
smcpromiscuous(void * arg,int on)391 smcpromiscuous(void* arg, int on)
392 {
393 int rctl;
394 Ctlr *ctlr;
395 Ether *edev;
396 Regs *regs;
397
398 edev = arg;
399 ctlr = edev->ctlr;
400 regs = ctlr->regs;
401 rctl = macrd(regs, Maccr);
402 if(on)
403 rctl |= Prms;
404 else
405 rctl &= ~Prms;
406 macwr(regs, Maccr, rctl);
407 }
408
409 static void
smcmulticast(void *,uchar *,int)410 smcmulticast(void*, uchar*, int)
411 {
412 /* nothing to do, we allow all multicast packets in */
413 }
414
415 static int
iswrcpydone(void * arg)416 iswrcpydone(void *arg)
417 {
418 return ((Ctlr *)arg)->wrcpydone;
419 }
420
421 static int
smctxstart(Ctlr * ctlr,uchar * ubuf,uint len)422 smctxstart(Ctlr *ctlr, uchar *ubuf, uint len)
423 {
424 uint wds, ruplen;
425 ulong *wdp, *txdp;
426 Regs *regs;
427 static ulong buf[ROUNDUP(ETHERMAXTU, sizeof(ulong)) / sizeof(ulong)];
428
429 if (!ctlr->inited) {
430 iprint("smctxstart: too soon to send\n");
431 return -1; /* toss it */
432 }
433 regs = ctlr->regs;
434
435 /* is there room for a packet in the tx data fifo? */
436 if (len < ETHERMINTU)
437 iprint("sending too-short (%d) pkt\n", len);
438 else if (len > ETHERMAXTU)
439 iprint("sending jumbo (%d) pkt\n", len);
440
441 ruplen = ROUNDUP(len, sizeof(ulong));
442 coherence(); /* back-to-back read/read delay per §6.2.2 */
443 if ((regs->txfifoinf & Txdatafreemask) < ruplen + 2*sizeof(ulong))
444 return -1; /* not enough room for data + command words */
445
446 if ((uintptr)ubuf & MASK(2)) { /* ensure word alignment */
447 memmove(buf, ubuf, len);
448 ubuf = (uchar *)buf;
449 }
450
451 /* tx cmd a: length is bytes in this buffer */
452 txdp = ®s->txdata;
453 *txdp = Intcompl | Firstseg | Lastseg | len;
454 /* tx cmd b: length is bytes in this packet (could be multiple buf.s) */
455 *txdp = len;
456
457 /* shovel pkt into tx fifo, which triggers transmission due to Txon */
458 wdp = (ulong *)ubuf;
459 for (wds = ruplen / sizeof(ulong) + 1; --wds > 0; )
460 *txdp = *wdp++;
461
462 regs->intsts = Txintrs; /* dismiss intr */
463 coherence();
464 regs->inten |= Txintrs;
465 coherence(); /* back-to-back write/read delay per §6.2.1 */
466 return 0;
467 }
468
469 static void
smctransmit(Ether * edev)470 smctransmit(Ether* edev)
471 {
472 Block *bp;
473 Ctlr *ctlr;
474
475 ctlr = edev->ctlr;
476 if (ctlr == nil)
477 panic("smctransmit: nil ctlr");
478 ilock(&ctlr->tlock);
479 /*
480 * Try to fill the chip's buffers back up, via the tx fifo.
481 */
482 while ((bp = qget(edev->oq)) != nil)
483 if (smctxstart(ctlr, bp->rp, BLEN(bp)) < 0) {
484 qputback(edev->oq, bp); /* retry the block later */
485 iprint("smctransmit: tx data fifo full\n");
486 break;
487 } else
488 freeb(bp);
489 iunlock(&ctlr->tlock);
490 }
491
492 static void
smctransmitcall(Ether * edev)493 smctransmitcall(Ether *edev) /* called from devether.c */
494 {
495 Ctlr *ctlr;
496
497 ctlr = edev->ctlr;
498 ctlr->gotoutput = 1;
499 #ifdef USE_KPROCS
500 wakeup(&ctlr->trendez);
501 #else
502 smctransmit(edev);
503 #endif
504 }
505
506 static int
smcrim(void * ctlr)507 smcrim(void* ctlr)
508 {
509 return ((Ctlr*)ctlr)->gotinput;
510 }
511
512 static void
smcrproc(void * arg)513 smcrproc(void* arg)
514 {
515 Ctlr *ctlr;
516 Ether *edev;
517
518 edev = arg;
519 ctlr = edev->ctlr;
520 for(;;){
521 ctlr->rsleep++;
522 sleep(&ctlr->rrendez, smcrim, ctlr);
523
524 /* process any newly-arrived packets and pass to etheriq */
525 ctlr->gotinput = 0;
526 smcreceive(edev);
527 }
528 }
529
530 static int
smcgotout(void * ctlr)531 smcgotout(void* ctlr)
532 {
533 return ((Ctlr*)ctlr)->gotoutput;
534 }
535
536 static void
smctproc(void * arg)537 smctproc(void* arg)
538 {
539 Ctlr *ctlr;
540 Ether *edev;
541
542 edev = arg;
543 ctlr = edev->ctlr;
544 for(;;){
545 ctlr->tsleep++;
546 sleep(&ctlr->trendez, smcgotout, ctlr);
547
548 /* process any newly-arrived packets and pass to etheriq */
549 ctlr->gotoutput = 0;
550 smctransmit(edev);
551 }
552 }
553
554 void gpioirqclr(void);
555
556 static void
smcattach(Ether * edev)557 smcattach(Ether* edev)
558 {
559 #ifdef USE_KPROCS
560 char name[KNAMELEN];
561 #endif
562 Ctlr *ctlr;
563
564 ctlr = edev->ctlr;
565 qlock(&ctlr->alock);
566 if(waserror()){
567 qunlock(&ctlr->alock);
568 nexterror();
569 }
570 if (!ctlr->inited) {
571 ctlr->inited = 1;
572 #ifdef USE_KPROCS
573 snprint(name, KNAMELEN, "#l%drproc", edev->ctlrno);
574 kproc(name, smcrproc, edev);
575
576 snprint(name, KNAMELEN, "#l%dtproc", edev->ctlrno);
577 kproc(name, smctproc, edev);
578 #endif
579
580 iprint("smcattach:");
581 #ifdef USE_KPROCS
582 iprint(" with kprocs");
583 #else
584 iprint(" no kprocs");
585 #endif
586 iprint(", no dma");
587 /* can now accept real or simulated interrupts */
588
589 smconce(edev);
590 attached = 1;
591 iprint("\n");
592 }
593 qunlock(&ctlr->alock);
594 poperror();
595 }
596
597 static int
isrdcpydone(void * arg)598 isrdcpydone(void *arg)
599 {
600 return ((Ctlr *)arg)->rdcpydone;
601 }
602
603 static void
smcreceive(Ether * edev)604 smcreceive(Ether *edev)
605 {
606 uint wds, len, sts;
607 ulong *wdp, *rxdp;
608 Block *bp;
609 Ctlr *ctlr;
610 Regs *regs;
611
612 ctlr = edev->ctlr;
613 regs = ctlr->regs;
614 coherence(); /* back-to-back read/read delay per §6.2.2 */
615 /*
616 * is there a full packet in the rx data fifo?
617 */
618 while (((regs->rxfifoinf & Rxstsusedmask) >> Rxstsusedshift) != 0) {
619 coherence();
620 sts = regs->rxsts; /* pop rx status */
621 if(sts & Rxerr)
622 iprint("smcreceive: rx error\n");
623 len = (sts & Rxpktlenmask) >> Rxpktlenshift;
624 if (len > ETHERMAXTU + Slop)
625 iprint("smcreceive: oversized rx pkt (%d)\n", len);
626 else if (len < ETHERMINTU)
627 iprint("smcreceive: too-short (%d) pkt\n", len);
628 wds = ROUNDUP(len, sizeof(ulong)) / sizeof(ulong);
629 if (wds > 0) {
630 /* copy aligned words from rx fifo into a Block */
631 bp = iallocb(len + sizeof(ulong) /* - 1 */);
632 if (bp == nil)
633 panic("smcreceive: nil Block*");
634
635 /* bp->rp should be 32-byte aligned, more than we need */
636 assert(((uintptr)bp->rp & (sizeof(ulong) - 1)) == 0);
637 wdp = (ulong *)bp->rp;
638 rxdp = ®s->rxdata;
639 wds = ROUNDUP(len, sizeof(ulong)) / sizeof(ulong) + 1;
640 while (--wds > 0)
641 *wdp++ = *rxdp;
642 bp->wp = bp->rp + len;
643
644 /* and push the Block upstream */
645 if (ctlr->inited)
646 etheriq(edev, bp, 1);
647 else
648 freeb(bp);
649
650 regs->intsts = Rxintrs; /* dismiss intr */
651 coherence();
652 regs->inten |= Rxintrs;
653 }
654 coherence();
655 }
656 regs->inten |= Rxintrs;
657 coherence();
658 }
659
660 /*
661 * disable the stsclr bits in inten and write them to intsts to ack and dismiss
662 * the interrupt source.
663 */
664 void
ackintr(Regs * regs,ulong stsclr)665 ackintr(Regs *regs, ulong stsclr)
666 {
667 if (stsclr == 0)
668 return;
669
670 regs->inten &= ~stsclr;
671 coherence();
672
673 // regs->intsts = stsclr; /* acknowledge & clear intr(s) */
674 // coherence();
675 }
676
677 static void
smcinterrupt(Ureg *,void * arg)678 smcinterrupt(Ureg*, void* arg)
679 {
680 int junk;
681 unsigned intsts, intr;
682 Ctlr *ctlr;
683 Ether *edev;
684 Regs *regs;
685
686 edev = arg;
687 ctlr = edev->ctlr;
688 ilock(&ctlr->imlock);
689 regs = ctlr->regs;
690
691 gpioirqclr();
692
693 coherence(); /* back-to-back read/read delay per §6.2.2 */
694 intsts = regs->intsts;
695 coherence();
696
697 intsts &= ~MASK(3); /* ignore gpio bits */
698 if (0 && intsts == 0) {
699 coherence();
700 iprint("smc: interrupt without a cause; insts %#ux (vs inten %#lux)\n",
701 intsts, regs->inten);
702 }
703
704 intr = intsts & Rxintrs;
705 if(intr) {
706 /* disable interrupt sources; kproc/smcreceive will reenable */
707 ackintr(regs, intr);
708
709 ctlr->rintr++;
710 ctlr->gotinput = 1;
711 #ifdef USE_KPROCS
712 wakeup(&ctlr->rrendez);
713 #else
714 smcreceive(edev);
715 #endif
716 }
717
718 while(((regs->txfifoinf & Txstsusedmask) >> Txstsusedshift) != 0) {
719 /* probably indicates tx completion, just toss it */
720 junk = regs->txsts; /* pop tx sts */
721 USED(junk);
722 coherence();
723 }
724
725 intr = intsts & Txintrs;
726 if (ctlr->gotoutput || intr) {
727 /* disable interrupt sources; kproc/smctransmit will reenable */
728 ackintr(regs, intr);
729
730 ctlr->tintr++;
731 ctlr->gotoutput = 1;
732 #ifdef USE_KPROCS
733 wakeup(&ctlr->trendez);
734 #else
735 smctransmit(edev);
736 #endif
737 }
738
739 iunlock(&ctlr->imlock);
740 }
741
742 static void
etherclock(void)743 etherclock(void)
744 {
745 smcinterrupt(nil, thisether);
746 }
747
748 static int
smcmii(Ctlr *)749 smcmii(Ctlr *)
750 {
751 return 0;
752 }
753
754 static int
smcdetach(Ctlr * ctlr)755 smcdetach(Ctlr* ctlr)
756 {
757 Regs *regs;
758
759 if (ctlr == nil || ctlr->regs == nil)
760 return -1;
761 regs = ctlr->regs;
762 /* verify that it's real by reading a few registers */
763 switch (regs->id) {
764 case Vid9221:
765 break;
766 default:
767 print("smc: unknown chip id %#ux\n", regs->id);
768 return -1;
769 }
770 regs->inten = 0; /* no interrupts */
771 regs->intsts = ~0; /* clear any pending */
772 regs->gptcfg = 0;
773 coherence();
774 regs->rxcfg = Rxdump;
775 regs->txcfg = Txsdump | Txddump;
776 regs->irqcfg &= ~Irqen;
777 coherence();
778 return 0;
779 }
780
781 static void
smcshutdown(Ether * ether)782 smcshutdown(Ether* ether)
783 {
784 smcdetach(ether->ctlr);
785 }
786
787 static void
powerwait(Regs * regs)788 powerwait(Regs *regs)
789 {
790 long bound;
791
792 regs->bytetest = 0; /* bring power on */
793 for (bound = 400*Mhz; !(regs->pmtctl & Dready) && bound > 0; bound--)
794 ;
795 if (bound <= 0)
796 iprint("smc: pmtctl didn't come ready\n");
797 }
798
799 static int
smcreset(Ctlr * ctlr)800 smcreset(Ctlr* ctlr)
801 {
802 int r;
803 Regs *regs;
804 static char zea[Eaddrlen];
805
806 regs = ctlr->regs;
807 powerwait(regs);
808
809 if(smcdetach(ctlr))
810 return -1;
811
812 /* verify that it's real by reading a few registers */
813 switch (regs->id) {
814 case Vid9221:
815 break;
816 default:
817 print("smc: unknown chip id %#ux\n", regs->id);
818 return -1;
819 }
820 if (regs->bytetest != 0x87654321) {
821 print("smc: bytetest reg %#p (%#lux) != 0x87654321\n",
822 ®s->bytetest, regs->bytetest);
823 return -1;
824 }
825
826 #ifdef TODO /* read MAC from EEPROM */
827 // int ctrl, i, pause, swdpio, txcw;
828 /*
829 * Snarf and set up the receive addresses.
830 * There are 16 addresses. The first should be the MAC address.
831 * The others are cleared and not marked valid (MS bit of Rah).
832 */
833 for(i = Ea; i < Eaddrlen/2; i++){
834 ctlr->ra[2*i] = ctlr->eeprom[i];
835 ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
836 }
837
838 /*
839 * Clear the Multicast Table Array.
840 * It's a 4096 bit vector accessed as 128 32-bit registers.
841 */
842 memset(ctlr->mta, 0, sizeof(ctlr->mta));
843 for(i = 0; i < 128; i++)
844 csr32w(ctlr, Mta+i*4, 0);
845 #endif
846 regs->hwcfg |= Mbo;
847
848 /* don't overwrite existing ea */
849 // if (memcmp(edev->ea, zea, Eaddrlen) == 0)
850 // memmove(edev->ea, ctlr->ra, Eaddrlen);
851
852 r = ctlr->ra[3]<<24 | ctlr->ra[2]<<16 | ctlr->ra[1]<<8 | ctlr->ra[0];
853 macwr(regs, Macaddrl, r);
854 macwr(regs, Macaddrh, ctlr->ra[5]<<8 | ctlr->ra[4]);
855
856 /* turn on the controller */
857 macwr(regs, Maccoe, 0);
858 regs->inten = 0; /* no interrupts yet */
859 regs->intsts = ~0; /* clear any pending */
860 regs->gptcfg = 0;
861 coherence();
862 regs->rxcfg = Rxdump;
863 regs->txcfg = Txsdump | Txddump | Txon;
864 regs->fifoint = 72<<24; /* default values */
865 macwr(regs, Maccr, Rxall | Rcvown | Fdpx | Mcpas | Txen | Rxen);
866 coherence(); /* back-to-back write/read delay per §6.2.1 */
867 regs->irqcfg = 1<<24 | Irqen | Irqpushpull; /* deas for 10µs (linux) */
868 coherence(); /* back-to-back write/read delay per §6.2.1 */
869 regs->inten = Rxintrs | Txintrs;
870 coherence();
871
872 if(smcmii(ctlr) < 0)
873 return -1;
874 return 0;
875 }
876
877 static void
smcpci(void)878 smcpci(void)
879 {
880 Ctlr *ctlr;
881 static int beenhere;
882
883 if (beenhere)
884 return;
885 beenhere = 1;
886
887 if (probeaddr(PHYSETHER) < 0)
888 return;
889 ctlr = malloc(sizeof(Ctlr));
890 ctlr->id = Vid9221<<16 | 0x0424; /* smsc 9221 */
891 ctlr->port = PHYSETHER;
892 ctlr->nic = (int *)PHYSETHER;
893 ctlr->regs = (Regs *)PHYSETHER;
894
895 if(smcreset(ctlr)){
896 free(ctlr);
897 return;
898 }
899 if(smcctlrhead != nil)
900 smcctlrtail->next = ctlr;
901 else
902 smcctlrhead = ctlr;
903 smcctlrtail = ctlr;
904 }
905
906 static int
smcpnp(Ether * edev)907 smcpnp(Ether* edev)
908 {
909 Ctlr *ctlr;
910 static char zea[Eaddrlen];
911
912 if(smcctlrhead == nil)
913 smcpci();
914
915 /*
916 * Any adapter matches if no edev->port is supplied,
917 * otherwise the ports must match.
918 */
919 for(ctlr = smcctlrhead; ctlr != nil; ctlr = ctlr->next){
920 if(ctlr->active)
921 continue;
922 if(edev->port == 0 || edev->port == ctlr->port){
923 ctlr->active = 1;
924 break;
925 }
926 }
927 if(ctlr == nil)
928 return -1;
929
930 edev->ctlr = ctlr;
931 ctlr->edev = edev; /* point back to Ether* */
932 edev->port = ctlr->port;
933 edev->irq = 34;
934 // TODO: verify speed (100Mb/s) and duplicity (full-duplex)
935 edev->mbps = 100;
936
937 /* don't overwrite existing ea */
938 if (memcmp(edev->ea, zea, Eaddrlen) == 0)
939 memmove(edev->ea, ctlr->ra, Eaddrlen);
940
941 /*
942 * Linkage to the generic ethernet driver.
943 */
944 edev->attach = smcattach;
945 edev->transmit = smctransmitcall;
946 edev->interrupt = smcinterrupt;
947 edev->ifstat = smcifstat;
948 /* edev->ctl = smcctl; /* no ctl msgs supported */
949
950 edev->arg = edev;
951 edev->promiscuous = smcpromiscuous;
952 edev->multicast = smcmulticast;
953 edev->shutdown = smcshutdown;
954 return 0;
955 }
956
957 void
ether9221link(void)958 ether9221link(void)
959 {
960 addethercard("9221", smcpnp);
961 }
962