|
|
1.1 root 1: /*
2: * National Semiconductor DP8390
3: * and SMC 83C90
4: * Network Interface Controller.
5: */
6: #include "u.h"
7: #include "lib.h"
8: #include "mem.h"
9: #include "dat.h"
10: #include "fns.h"
11: #include "io.h"
12:
13: #include "ether.h"
14:
15: enum {
16: Cr = 0x00, /* command register, all pages */
17:
18: Stp = 0x01, /* stop */
19: Sta = 0x02, /* start */
20: Txp = 0x04, /* transmit packet */
21: RDMAread = (1<<3), /* remote DMA read */
22: RDMAwrite = (2<<3), /* remote DMA write */
23: RDMAsend = (3<<3), /* remote DMA send packet */
24: RDMAabort = (4<<3), /* abort/complete remote DMA */
25: Ps0 = 0x40, /* page select */
26: Ps1 = 0x80, /* page select */
27: Page0 = 0x00,
28: Page1 = Ps0,
29: Page2 = Ps1,
30: };
31:
32: enum { /* Page 0, read */
33: Clda0 = 0x01, /* current local DMA address 0 */
34: Clda1 = 0x02, /* current local DMA address 1 */
35: Bnry = 0x03, /* boundary pointer (R/W) */
36: Tsr = 0x04, /* transmit status register */
37: Ncr = 0x05, /* number of collisions register */
38: Fifo = 0x06, /* FIFO */
39: Isr = 0x07, /* interrupt status register (R/W) */
40: Crda0 = 0x08, /* current remote DMA address 0 */
41: Crda1 = 0x09, /* current remote DMA address 1 */
42: Rsr = 0x0C, /* receive status register */
43: Cntr0 = 0x0D, /* frame alignment errors */
44: Cntr1 = 0x0E, /* CRC errors */
45: Cntr2 = 0x0F, /* missed packet errors */
46: };
47:
48: enum { /* Page 0, write */
49: Pstart = 0x01, /* page start register */
50: Pstop = 0x02, /* page stop register */
51: Tpsr = 0x04, /* transmit page start address */
52: Tbcr0 = 0x05, /* transmit byte count register 0 */
53: Tbcr1 = 0x06, /* transmit byte count register 1 */
54: Rsar0 = 0x08, /* remote start address register 0 */
55: Rsar1 = 0x09, /* remote start address register 1 */
56: Rbcr0 = 0x0A, /* remote byte count register 0 */
57: Rbcr1 = 0x0B, /* remote byte count register 1 */
58: Rcr = 0x0C, /* receive configuration register */
59: Tcr = 0x0D, /* transmit configuration register */
60: Dcr = 0x0E, /* data configuration register */
61: Imr = 0x0F, /* interrupt mask */
62: };
63:
64: enum { /* Page 1, read/write */
65: Par0 = 0x01, /* physical address register 0 */
66: Curr = 0x07, /* current page register */
67: Mar0 = 0x08, /* multicast address register 0 */
68: };
69:
70: enum { /* Interrupt Status Register */
71: Prx = 0x01, /* packet received */
72: Ptx = 0x02, /* packet transmitted */
73: Rxe = 0x04, /* receive error */
74: Txe = 0x08, /* transmit error */
75: Ovw = 0x10, /* overwrite warning */
76: Cnt = 0x20, /* counter overflow */
77: Rdc = 0x40, /* remote DMA complete */
78: Rst = 0x80, /* reset status */
79: };
80:
81: enum { /* Interrupt Mask Register */
82: Prxe = 0x01, /* packet received interrupt enable */
83: Ptxe = 0x02, /* packet transmitted interrupt enable */
84: Rxee = 0x04, /* receive error interrupt enable */
85: Txee = 0x08, /* transmit error interrupt enable */
86: Ovwe = 0x10, /* overwrite warning interrupt enable */
87: Cnte = 0x20, /* counter overflow interrupt enable */
88: Rdce = 0x40, /* DMA complete interrupt enable */
89: };
90:
91: enum { /* Data Configuration register */
92: Wts = 0x01, /* word transfer select */
93: Bos = 0x02, /* byte order select */
94: Las = 0x04, /* long address select */
95: Ls = 0x08, /* loopback select */
96: Arm = 0x10, /* auto-initialise remote */
97: Ft1 = (0x00<<5), /* FIFO threshhold select 1 byte/word */
98: Ft2 = (0x01<<5), /* FIFO threshhold select 2 bytes/words */
99: Ft4 = (0x02<<5), /* FIFO threshhold select 4 bytes/words */
100: Ft6 = (0x03<<5), /* FIFO threshhold select 6 bytes/words */
101: };
102:
103: enum { /* Transmit Configuration Register */
104: Crc = 0x01, /* inhibit CRC */
105: Lb = 0x02, /* internal loopback */
106: Atd = 0x08, /* auto transmit disable */
107: Ofst = 0x10, /* collision offset enable */
108: };
109:
110: enum { /* Transmit Status Register */
111: Ptxok = 0x01, /* packet transmitted */
112: Col = 0x04, /* transmit collided */
113: Abt = 0x08, /* tranmit aborted */
114: Crs = 0x10, /* carrier sense lost */
115: Fu = 0x20, /* FIFO underrun */
116: Cdh = 0x40, /* CD heartbeat */
117: Owc = 0x80, /* out of window collision */
118: };
119:
120: enum { /* Receive Configuration Register */
121: Sep = 0x01, /* save errored packets */
122: Ar = 0x02, /* accept runt packets */
123: Ab = 0x04, /* accept broadcast */
124: Am = 0x08, /* accept multicast */
125: Pro = 0x10, /* promiscuous physical */
126: Mon = 0x20, /* monitor mode */
127: };
128:
129: enum { /* Receive Status Register */
130: Prxok = 0x01, /* packet received intact */
131: Crce = 0x02, /* CRC error */
132: Fae = 0x04, /* frame alignment error */
133: Fo = 0x08, /* FIFO overrun */
134: Mpa = 0x10, /* missed packet */
135: Phy = 0x20, /* physical/multicast address */
136: Dis = 0x40, /* receiver disabled */
137: Dfr = 0x80, /* deferring */
138: };
139:
140: typedef struct {
141: uchar status;
142: uchar next;
143: uchar len0;
144: uchar len1;
145: } Hdr;
146:
147: static void
148: dp8390disable(Ctlr *ctlr)
149: {
150: ulong dp8390;
151: int timo;
152:
153: dp8390 = ctlr->card.dp8390;
154: /*
155: * Stop the chip. Set the Stp bit and wait for the chip
156: * to finish whatever was on its tiny mind before it sets
157: * the Rst bit.
158: * We need the timeout because there may not be a real
159: * chip there if this is called when probing for a device
160: * at boot.
161: */
162: dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
163: dp8390outb(dp8390+Rbcr0, 0);
164: dp8390outb(dp8390+Rbcr1, 0);
165: for(timo = 10000; (dp8390inb(dp8390+Isr) & Rst) == 0 && timo; timo--)
166: ;
167: }
168:
169: static void
170: dp8390ring(Ctlr *ctlr)
171: {
172: ulong dp8390;
173:
174: dp8390 = ctlr->card.dp8390;
175: dp8390outb(dp8390+Pstart, ctlr->card.pstart);
176: dp8390outb(dp8390+Pstop, ctlr->card.pstop);
177: dp8390outb(dp8390+Bnry, ctlr->card.pstop-1);
178:
179: dp8390outb(dp8390+Cr, Page1|RDMAabort|Stp);
180: dp8390outb(dp8390+Curr, ctlr->card.pstart);
181: dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
182:
183: ctlr->card.nxtpkt = ctlr->card.pstart;
184: }
185:
186: void
187: dp8390reset(Ctlr *ctlr)
188: {
189: ulong dp8390;
190:
191: dp8390 = ctlr->card.dp8390;
192: /*
193: * This is the initialisation procedure described
194: * as 'mandatory' in the datasheet, with references
195: * to the 3Com503 technical reference manual.
196: */
197: dp8390disable(ctlr);
198: if(ctlr->card.bit16)
199: dp8390outb(dp8390+Dcr, Ft4|Ls|Wts);
200: else
201: dp8390outb(dp8390+Dcr, Ft4|Ls);
202:
203: dp8390outb(dp8390+Rbcr0, 0);
204: dp8390outb(dp8390+Rbcr1, 0);
205:
206: dp8390outb(dp8390+Tcr, 0);
207: dp8390outb(dp8390+Rcr, Mon);
208:
209: /*
210: * Init the ring hardware and software ring pointers.
211: * Can't initialise ethernet address as we may not know
212: * it yet.
213: */
214: dp8390ring(ctlr);
215: dp8390outb(dp8390+Tpsr, ctlr->card.tstart);
216:
217: dp8390outb(dp8390+Isr, 0xFF);
218: dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
219:
220: /*
221: * Leave the chip initialised,
222: * but in monitor mode.
223: */
224: dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
225: }
226:
227: void
228: dp8390attach(Ctlr *ctlr)
229: {
230: /*
231: * Enable the chip for transmit/receive.
232: * The init routine leaves the chip in monitor
233: * mode. Clear the missed-packet counter, it
234: * increments while in monitor mode.
235: */
236: dp8390outb(ctlr->card.dp8390+Rcr, Ab);
237: dp8390inb(ctlr->card.dp8390+Cntr2);
238: }
239:
240: void
241: dp8390mode(Ctlr *ctlr, int on)
242: {
243: /*
244: * Set/reset promiscuous mode.
245: */
246: if(on)
247: dp8390outb(ctlr->card.dp8390+Rcr, Pro|Ab);
248: else
249: dp8390outb(ctlr->card.dp8390+Rcr, Ab);
250: }
251:
252: void
253: dp8390setea(Ctlr *ctlr)
254: {
255: ulong dp8390;
256: uchar cr;
257: int i;
258:
259: dp8390 = ctlr->card.dp8390;
260: /*
261: * Set the ethernet address into the chip.
262: * Take care to restore the command register
263: * afterwards. We don't care about multicast
264: * addresses as we never set the multicast
265: * enable.
266: */
267: cr = dp8390inb(dp8390+Cr) & ~Txp;
268: dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
269: for(i = 0; i < sizeof(ctlr->card.ea); i++)
270: dp8390outb(dp8390+Par0+i, ctlr->card.ea[i]);
271: dp8390outb(dp8390+Cr, cr);
272: }
273:
274: void
275: dp8390getea(Ctlr *ctlr)
276: {
277: ulong dp8390;
278: uchar cr;
279: int i;
280:
281: dp8390 = ctlr->card.dp8390;
282: /*
283: * Set the ethernet address into the chip.
284: * Take care to restore the command register
285: * afterwards. We don't care about multicast
286: * addresses as we never set the multicast
287: * enable.
288: */
289: cr = dp8390inb(dp8390+Cr) & ~Txp;
290: dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
291: for(i = 0; i < sizeof(ctlr->card.ea); i++)
292: ctlr->card.ea[i] = dp8390inb(dp8390+Par0+i);
293: dp8390outb(dp8390+Cr, cr);
294: }
295:
296: void*
297: dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
298: {
299: ulong dp8390;
300: uchar cr;
301: int timo;
302:
303: dp8390 = ctlr->card.dp8390;
304: /*
305: * Read some data at offset 'from' in the card's memory
306: * using the DP8390 remote DMA facility, and place it at
307: * 'to' in main memory, via the I/O data port.
308: */
309: cr = dp8390inb(dp8390+Cr) & ~Txp;
310: dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
311: dp8390outb(dp8390+Isr, Rdc);
312:
313: /*
314: * Set up the remote DMA address and count.
315: */
316: if(ctlr->card.bit16)
317: len = ROUNDUP(len, 2);
318: dp8390outb(dp8390+Rbcr0, len & 0xFF);
319: dp8390outb(dp8390+Rbcr1, (len>>8) & 0xFF);
320: dp8390outb(dp8390+Rsar0, from & 0xFF);
321: dp8390outb(dp8390+Rsar1, (from>>8) & 0xFF);
322:
323: /*
324: * Start the remote DMA read and suck the data
325: * out of the I/O port.
326: */
327: dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
328: if(ctlr->card.bit16)
329: inss(ctlr->card.data, to, len/2);
330: else
331: insb(ctlr->card.data, to, len);
332:
333: /*
334: * Wait for the remote DMA to complete. The timeout
335: * is necessary because we may call this routine on
336: * a non-existent chip during initialisation and, due
337: * to the miracles of the bus, we could get this far
338: * and still be talking to a slot full of nothing.
339: */
340: for(timo = 10000; (dp8390inb(dp8390+Isr) & Rdc) == 0 && timo; timo--)
341: ;
342:
343: dp8390outb(dp8390+Isr, Rdc);
344: dp8390outb(dp8390+Cr, cr);
345: return to;
346: }
347:
348: void*
349: dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
350: {
351: ulong dp8390, crda;
352: uchar cr;
353:
354: dp8390 = ctlr->card.dp8390;
355: /*
356: * Write some data to offset 'to' in the card's memory
357: * using the DP8390 remote DMA facility, reading it at
358: * 'from' in main memory, via the I/O data port.
359: */
360: cr = dp8390inb(dp8390+Cr) & ~Txp;
361: dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
362: dp8390outb(dp8390+Isr, Rdc);
363:
364: if(ctlr->card.bit16)
365: len = ROUNDUP(len, 2);
366:
367: /*
368: * Set up the remote DMA address and count.
369: * This is straight from the DP8390[12D] datasheet, hence
370: * the initial set up for read.
371: */
372: crda = to-1-ctlr->card.bit16;
373: dp8390outb(dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
374: dp8390outb(dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
375: dp8390outb(dp8390+Rsar0, crda & 0xFF);
376: dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF);
377: dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
378:
379: for(;;){
380: crda = dp8390inb(dp8390+Crda0);
381: crda |= dp8390inb(dp8390+Crda1)<<8;
382: if(crda == to){
383: /*
384: * Start the remote DMA write and make sure
385: * the registers are correct.
386: */
387: dp8390outb(dp8390+Cr, Page0|RDMAwrite|Sta);
388:
389: crda = dp8390inb(dp8390+Crda0);
390: crda |= dp8390inb(dp8390+Crda1)<<8;
391: if(crda != to)
392: panic("crda write %d to %d\n", crda, to);
393:
394: break;
395: }
396: }
397:
398: /*
399: * Pump the data into the I/O port.
400: */
401: if(ctlr->card.bit16)
402: outss(ctlr->card.data, from, len/2);
403: else
404: outsb(ctlr->card.data, from, len);
405:
406: /*
407: * Wait for the remote DMA to finish. We'll need
408: * a timeout here if this ever gets called before
409: * we know there really is a chip there.
410: */
411: while((dp8390inb(dp8390+Isr) & Rdc) == 0)
412: ;
413:
414: dp8390outb(dp8390+Isr, Rdc);
415: dp8390outb(dp8390+Cr, cr);
416: return (void*)to;
417: }
418:
419: static uchar
420: getcurr(ulong dp8390)
421: {
422: uchar cr, curr;
423:
424: cr = dp8390inb(dp8390+Cr) & ~Txp;
425: dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
426: curr = dp8390inb(dp8390+Curr);
427: dp8390outb(dp8390+Cr, cr);
428: return curr;
429: }
430:
431: void
432: dp8390receive(Ctlr *ctlr)
433: {
434: RingBuf *ring;
435: uchar curr, len1, *pkt;
436: Hdr hdr;
437: ulong dp8390, data, len;
438:
439: dp8390 = ctlr->card.dp8390;
440: for(curr = getcurr(dp8390); ctlr->card.nxtpkt != curr; curr = getcurr(dp8390)){
441: ctlr->inpackets++;
442:
443: data = ctlr->card.nxtpkt*Dp8390BufSz;
444: (*ctlr->card.read)(ctlr, &hdr, data, sizeof(Hdr));
445:
446: /*
447: * Don't believe the upper byte count, work it
448: * out from the software next-page pointer and
449: * the current next-page pointer.
450: */
451: if(hdr.next > ctlr->card.nxtpkt)
452: len1 = hdr.next - ctlr->card.nxtpkt - 1;
453: else
454: len1 = (ctlr->card.pstop-ctlr->card.nxtpkt) + (hdr.next-ctlr->card.pstart) - 1;
455: if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
456: len1--;
457:
458: len = ((len1<<8)|hdr.len0)-4;
459:
460: /*
461: * Chip is badly scrogged, reinitialise the ring.
462: */
463: if(hdr.next < ctlr->card.pstart || hdr.next >= ctlr->card.pstop
464: || len < 60 || len > sizeof(Etherpkt)){
465: print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|",
466: hdr.status, hdr.next, hdr.len0, hdr.len1, len);
467: dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
468: dp8390ring(ctlr);
469: dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
470: return;
471: }
472:
473: /*
474: * If it's a good packet and we have a place to put it,
475: * read it in to the software ring.
476: * If the packet wraps round the hardware ring, read it
477: * in two pieces.
478: */
479: ring = &ctlr->rb[ctlr->ri];
480: if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && ring->owner == Interface){
481: pkt = ring->pkt;
482: data += sizeof(Hdr);
483: ring->len = len;
484:
485: if((data+len) >= ctlr->card.pstop*Dp8390BufSz){
486: ulong count = ctlr->card.pstop*Dp8390BufSz - data;
487:
488: (*ctlr->card.read)(ctlr, pkt, data, count);
489: pkt += count;
490: data = ctlr->card.pstart*Dp8390BufSz;
491: len -= count;
492: }
493: if(len)
494: (*ctlr->card.read)(ctlr, pkt, data, len);
495:
496: ring->owner = Host;
497: ctlr->ri = NEXT(ctlr->ri, ctlr->nrb);
498: }
499:
500: /*
501: * Finished woth this packet, update the
502: * hardware and software ring pointers.
503: */
504: ctlr->card.nxtpkt = hdr.next;
505:
506: hdr.next--;
507: if(hdr.next < ctlr->card.pstart)
508: hdr.next = ctlr->card.pstop-1;
509: dp8390outb(dp8390+Bnry, hdr.next);
510: }
511: }
512:
513: /*
514: * Initiate a transmission. Must be called splhi().
515: */
516: void
517: dp8390transmit(Ctlr *ctlr)
518: {
519: ulong dp8390;
520: RingBuf *ring;
521:
522: dp8390 = ctlr->card.dp8390;
523: ring = &ctlr->tb[ctlr->ti];
524: if(ctlr->tbusy == 0 && ring->owner == Interface){
525:
526: ctlr->tbusy = 1;
527:
528: (*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len);
529:
530: dp8390outb(dp8390+Tbcr0, ring->len & 0xFF);
531: dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF);
532: dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
533: }
534: }
535:
536: void
537: dp8390overflow(Ctlr *ctlr)
538: {
539: ulong dp8390;
540: uchar txp;
541: int resend;
542:
543: dp8390 = ctlr->card.dp8390;
544: /*
545: * The following procedure is taken from the DP8390[12D] datasheet,
546: * it seems pretty adamant that this is what has to be done.
547: */
548: txp = dp8390inb(dp8390+Cr) & Txp;
549: dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
550: delay(2);
551: dp8390outb(dp8390+Rbcr0, 0);
552: dp8390outb(dp8390+Rbcr1, 0);
553:
554: resend = 0;
555: if(txp && (dp8390inb(dp8390+Isr) & (Txe|Ptx)) == 0)
556: resend = 1;
557:
558: dp8390outb(dp8390+Tcr, Lb);
559: dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
560: (*ctlr->card.receive)(ctlr);
561: dp8390outb(dp8390+Isr, Ovw);
562: dp8390outb(dp8390+Tcr, 0);
563:
564: if(resend)
565: dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
566: }
567:
568: void
569: dp8390intr(Ureg*, Ctlr *ctlr)
570: {
571: ulong dp8390;
572: RingBuf *ring;
573: uchar isr, r;
574:
575: dp8390 = ctlr->card.dp8390;
576: /*
577: * While there is something of interest,
578: * clear all the interrupts and process.
579: */
580: dp8390outb(dp8390+Imr, 0x00);
581: while(isr = dp8390inb(dp8390+Isr)){
582:
583: if(isr & Ovw){
584: if(ctlr->card.overflow)
585: (*ctlr->card.overflow)(ctlr);
586: dp8390outb(dp8390+Isr, Ovw);
587: ctlr->overflows++;
588: }
589:
590: /*
591: * We have received packets.
592: * Take a spin round the ring and
593: * wakeup the kproc.
594: */
595: if(isr & (Rxe|Prx)){
596: (*ctlr->card.receive)(ctlr);
597: dp8390outb(dp8390+Isr, Rxe|Prx);
598: }
599:
600: /*
601: * A packet completed transmission, successfully or
602: * not. Start transmission on the next buffered packet,
603: * and wake the output routine.
604: */
605: if(isr & (Txe|Ptx)){
606: r = dp8390inb(dp8390+Tsr);
607: if(isr & Txe){
608: if((r & (Cdh|Fu|Crs|Abt)))
609: print("Tsr#%2.2ux|", r);
610: ctlr->oerrs++;
611: }
612:
613: if(isr & Ptx)
614: ctlr->outpackets++;
615:
616: dp8390outb(dp8390+Isr, Txe|Ptx);
617:
618: ring = &ctlr->tb[ctlr->ti];
619: ring->owner = Host;
620: ctlr->tbusy = 0;
621: ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
622: (*ctlr->card.transmit)(ctlr);
623: }
624:
625: if(isr & Cnt){
626: ctlr->frames += dp8390inb(dp8390+Cntr0);
627: ctlr->crcs += dp8390inb(dp8390+Cntr1);
628: ctlr->buffs += dp8390inb(dp8390+Cntr2);
629: dp8390outb(dp8390+Isr, Cnt);
630: }
631: }
632: dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
633: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.