📄 sonic.c
字号:
/************************************************************* * File: lib/sonic.c * Purpose: A tftp driver for the Sonic Ethernet controller * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 930507 Created * 960909 Made globals be malloc'd * 970221 Added ifdefs for SONIC_DW32 * 970325 Removed typedefs for Ulong etc. Now included by ether.h * 970325 ANDed byte with 0xff in printMem * 970509 Added arp support. * 970617 Added ping support * 970822 Changed RDASIZE to 16 to fix slow dl on large networks * 971115 Removed LE ifdefs around re_sonic code * 971115 Fixed n/4 prob in swap32n * 971118 Fixed bad ether_header messages from swapPkt * 980611 Added casts on free to supress warnings on Tasking cc3 * 980611 Removed cast in call to Qput4 in addRRrec (Tasking). * 980611 Removed assert in retry pack case. * 980615 Renamed re_sonic re_ether * 980615 Added ether_is_sonic. open etc via ptr now. * 980615 Made most stuff static * 981001 Moved all of the chip-independent stuff to ether.c * 981127 Move the GETRXREC swapPkt to ether.c */#include <malloc.h>#include <mips.h>#include <string.h>#include <termio.h>#include <utypes.h>/* * This file contains a very simple driver for the National Sonic * Ethernet controller. It is used to provide PMON with a method to * support download using tftp via Ethernet. It is intended to be * called from ether.c. *//* * This module will not work if the global data that it uses (RRA etc) * crosses a 64KB boundary. i.e. The upper 16 address bits must not change. * That is the reason that these global data areas are malloc'd. *//* All our boards have the Sonic at the same base address */#ifndef ETHERADDR#define ETHERADDR 0xbc000000#endif#ifdef MIPSEB#define SONIC_BASE ((volatile Ushort *)(ETHERADDR+2))#else#define SONIC_BASE ((volatile Ushort *)ETHERADDR)#endif#define getlo(x) (((Ulong)(x))&0xffff)#define gethi(x) (((Ulong)(x))>>16)/*#define PROMISCUOUS /* enable promiscuous mode */#define HDRONLY /* print headers only *//*#define VERBOSE /* be verbose *//*#define CHECKS_ON /* do runtime checks */#ifdef CHECKS_ON#include <assert.h>#else#define assert(x)#endif#ifdef PROMISCUOUS#define VERBOSE#endif#define RRASIZE 8 /* min 4 */#define RBSIZE 2048 /* receive buffer size (min 2048) */#define RDASIZE 16 /* min 2. 970822 */#define TDASIZE 4 /* min 1 */#define TBSIZE 128 /* transmit buffer size */#ifdef ETHERNET /* skip the entire file if ethernet is not enabled *//*************** Ethernet stuff ******************************/#include <ether.h>#include <sonic.h>/* receive resource area */static RRrec *RRA; /* receive resource area */static char *RBA_data;/* receive descriptor area */static RXrec *RDA; /* receive descriptor area *//* transmit descriptor area */static TXrec *TDA; /* transmit resource area */static char *TBA_data;static Ulong CamData[5];/* this scoreboard is used to determine whether an RBA is completely free */typedef struct SBrec { int seq; int cnt; int tot; Ulong addr; } SBrec;static SBrec scorebd[RRASIZE];static SBrec *putScorebd(),*getScorebd();static RXrec *RDA_add; /* start adding new descriptors here */static RXrec *RDA_new; /* start checking for FULL descriptors here */static TXrec *TDA_done; /* start checking transmitted packets here */static TXrec *TDA_next; /* next available packet for transmission *//*************** Queues **************************************/typedef struct Queue4 { volatile int ip; volatile int op; int size; Ulong *ptr; } Queue4;#define Qempty4(q) (((q)->ip == (q)->op)?1:0)static Ulong Qget4();static Qput4();static Queue4 Rxq,*rxq,Rbq,*rbq;static Ulong RxqD[RDASIZE+1],RbqD[RRASIZE+1];/****************** Globals **********************************/extern int vflag;/****************** Forward Declarations *********************/static initHw(),initDA();static pktrx();static pkttx();static rtnRXpkt();static SBrec *putScorebd();static SBrec *getScorebd();static addRXrec();static addRRrec();/************************************************************** pktrx()* Packet received.* Add it to the rxq queue.*/static pktrx(){#if 0if (! IS_K1SEG(RDA_new)) printf("pktrx: %08x: not k1seg\n",RDA_new);#endifwhile (RDA_new->in_use == FULL) { Qput4(rxq,(Ulong)RDA_new); RDA_new = getRXlink(RDA_new); }SONIC_ISR = ISR_PKTRX; /* clear pkt rec'd bit */}/************************************************************** pkttx()* clear up after a pkt was transmitted*/static pkttx(){#if 0if (! IS_K1SEG(TDA_done)) printf("pkttx: %08x: not k1seg\n",TDA_done);#endifwhile (TDA_done->status != 0) { if (vflag) printf("pkttx "); /* aught to check the status here */ TDA_done->status = 0; TDA_done = getTXlink(TDA_done); }SONIC_ISR = ISR_TXDN; /* clear pkt transmitted bit */}/************************************************************** rtnRXpkt(q)*/static rtnRXpkt(q)RXrec *q;{SBrec *p;Ulong rseq;assert(q != 0);rseq = getRXrseq(q);p = getScorebd(rseq);if (p) assert(p->addr != 0);if (!p) p = putScorebd(rseq,Qget4(rbq));assert(p != 0);assert(p->addr != 0);if (q->status&LPKT) { /* last packet in buffer */ p->tot = getRXpseq(q)+1; }p->cnt++;if (p->tot && p->tot == p->cnt) { addRRrec((char *)p->addr,RBSIZE); p->addr = 0; }addRXrec(q);}/************************************************************** SBrec *putScorebd(seq,addr)*/static SBrec *putScorebd(seq,addr)Ulong seq,addr;{int i;assert(addr != 0);for (i=0;i<RRASIZE;i++) { if (scorebd[i].addr == 0) break; assert(scorebd[i].addr != addr); assert(scorebd[i].seq != seq); }assert(i < RRASIZE);scorebd[i].addr = addr;scorebd[i].seq = seq;scorebd[i].cnt = 0;scorebd[i].tot = 0;return(&scorebd[i]);}/************************************************************** SBrec *getScorebd(seq)*/static SBrec *getScorebd(seq)Ulong seq;{int i;for (i=0;i<RRASIZE;i++) { if (scorebd[i].addr && scorebd[i].seq == seq) return(&scorebd[i]); }return(0);}/************************************************************** addRXrec(q)* put RDA back on list for use by SONIC* RDA_new is behind (or equal to) CRDA in the chain. * RDA_add is always ahead of (or equal to) CRDA in the chain.* Thus RDA_new always points the latest packet that has been* received, and RDA_add is where new (empty) packets* are added to the chain.*/static addRXrec(q)RXrec *q;{assert(q != 0);q = k1RXrec(q); /* make sure that it is non cachable *//* prepare descriptor for use */q->link = EOL;q->in_use = EMPTY;if (RDA_add) putRXlink(RDA_add,q);else { putCRDA(q); RDA_new = q; }RDA_add = q;}/************************************************************** addRRrec(p,size)*/static addRRrec(p,size)char *p;int size;{RRrec *q;int is_empty;assert(p != 0);p = (char *)k02k1(p);Qput4(rbq,p);q = getRWP();if (q == getRRP()) is_empty = 1;else is_empty = 0;putRRptr(q,p);putRRwc(q,size);if (q+1 >= getREA()) q = getRSA();else q++;putRWP(q);if (is_empty) SONIC_ISR = ISR_RBE; /* clear RBE bit */}/************************************************************** static Qput4(q,v)* put a word into a queue*/static Qput4(q,v)Queue4 *q;Ulong v;{assert(q != 0);q->ptr[q->ip] = v;if (q->ip+1 > q->size) q->ip = 0;else q->ip++;assert(q->ip != q->op); /* queue full */}/************************************************************** static Ulong Qget4(q)* get a word from a queue*/static Ulong Qget4(q)Queue4 *q;{Ulong v;assert(q != 0);while (q->ip == q->op) ; /* wait while empty */v = q->ptr[q->op];if (q->op+1 > q->size) q->op = 0;else q->op++;assert(v != 0);return(v);}/************************************************************** static int initDA(void)* initialize all the data areas*/static int initDA(void){int i;char *p,*fl[5];Ulong t;rxq = &Rxq;Rxq.size = RDASIZE;Rxq.ip = Rxq.op = 0;Rxq.ptr = RxqD;rbq = &Rbq;Rbq.size = RRASIZE;Rbq.ip = Rbq.op = 0;Rbq.ptr = RbqD;/* * These data structures must not cross a 64KB boundary. Therefore * we request them again if they do. */if (!RRA) { for (i=0;;i++) { RRA = (RRrec *)malloc(RRASIZE*sizeof(RRrec)); RBA_data = (char *)malloc(RBSIZE*(RRASIZE-1)); RDA = (RXrec *)malloc(RDASIZE*sizeof(RXrec)); TDA = (TXrec *)malloc(TDASIZE*sizeof(TXrec)); TBA_data = (char *)malloc(TBSIZE*TDASIZE); if (!RRA || !RBA_data || !RDA || !TDA || !TBA_data) { printf("initDA: malloc failure\n"); return(0); } /* check to see if it is ok */ t = (Ulong)malloc(4); free((void *)t); if ((t>>16) == (((Ulong)RRA)>>16)) break; /* not ok. so dealloc them */ free(RRA);free(RBA_data);free(RDA);free(TDA);free(TBA_data); if (i > 0) { /* too many attempts */ printf("initDA: 2nd malloc failure\n"); return(0); } /* malloc enough to take us to the 64KB boundary */ t = (Ulong)malloc(4); free((void *)t); malloc(0x10000-(t&0xffff)); } }#if 0printf("RRA=%08x RBA_data=%08x RDA=%08x TDA=%08x TBA_data=%08x\n", RRA, RBA_data, RDA, TDA, TBA_data);#endif RDA_add = 0;putCRDA(RDA);for (i=0;i<RDASIZE;i++) addRXrec(&RDA[i]);putRSA(RRA);putREA(RRA+RRASIZE);SONIC_RRP = SONIC_RSA;SONIC_RWP = SONIC_RSA;p = RBA_data;for (i=0;i<RRASIZE-1;i++) { addRRrec(p,RBSIZE); p += RBSIZE; }bzero(scorebd,sizeof(SBrec)+RRASIZE);/* set transmit descriptors up as a circular list */p = (char *)k02k1(TBA_data);for (i=0;i<TDASIZE;i++) { putTXptr(&TDA[i],p); TDA[i].status = 0; TDA[i].config = 0; TDA[i].frag_count = 1; if (i == TDASIZE-1) putTXlink(&TDA[i],&TDA[0],1); else putTXlink(&TDA[i],&TDA[i+1],1); p += TBSIZE; }SONIC_CTDA = (getlo(log2phy(&TDA[0]))|1);SONIC_UTDA = gethi(log2phy(&TDA[0]));TDA_done = k1TXrec(&TDA[0]);TDA_next = k1TXrec(&TDA[0]);return(1);}/************************************************************** static initHw(macAddr)* init the SONIC chip*/static initHw(Uchar *macAddr){int i,n;char tmp[26],*p;#ifdef SONIC_DW32Ulong *ulp;#elseUshort *ulp;#endifSONIC_CR = CR_RST; /* Turn ON RESET *//* Data Control */#ifdef SONIC_DW32SONIC_DCR = (DCR_WAIT0 | DCR_DW32 | DCR_TFT1 | DCR_TFT0 | DCR_STERM | DCR_PO0 | DCR_PO1); #elseSONIC_DCR = (DCR_WAIT0 | DCR_TFT1 | DCR_TFT0 | DCR_STERM | DCR_PO0 | DCR_PO1);#endifSONIC_ISR = 0x7fff; /* Clear ISR */SONIC_IMR = 0; /* All Interrupts Masked */SONIC_CRCT = 0xffff; /* Clear Tally */SONIC_FAET = 0xffff; /* Clear Tally */SONIC_MPT = 0xffff; /* Clear Tally */SONIC_RSC = 0;SONIC_EOBC = 760; /* largest Ethernet packet */SONIC_CR &= ~CR_RST; /* Turn OFF RESET */SONIC_CR = CR_RRRA; /* prime SONIC with RRA read *//* load CAM */i = 0;#ifdef SONIC_DW32ulp = (Ulong *)k02k1(CamData);#elseulp = (Ushort *)k02k1(CamData);#endifulp[i++] = 0;ulp[i++] = (macAddr[1] << 8) | macAddr[0];ulp[i++] = (macAddr[3] << 8) | macAddr[2];ulp[i++] = (macAddr[5] << 8) | macAddr[4];ulp[i] = 0x1; /* Enable entry 0 */SONIC_CDC = 1; /* One entry */SONIC_CDP = getlo(CamData);SONIC_CR = CR_LCAM; /*Load CAM*/for (i=0;(SONIC_ISR & ISR_LCD) == 0 && i < 4000000;i++) ;if (i >= 4000000) { printf("sonic: unable to load CAM\n"); return(0); }SONIC_ISR = ISR_LCD; /* Clear ISR bit */#ifdef PROMISCUOUS /* Enable Promiscuous mode*/SONIC_RCR = RCR_BRD | RCR_PRO;#elseSONIC_RCR = RCR_BRD; /* 970509 */#endifSONIC_MPT = 0xffff;SONIC_CRCT = 0xffff;SONIC_FAET = 0xffff;SONIC_CR = CR_RXEN; /* Turn on Receiver */return(1);}/************************************************************** void *sonic_driver(int op,void *vp1,void *vp2)* Main entry point for this driver. Everything else in this* module should be static.*/void *sonic_driver(int op,void *vp1,void *vp2){RXrec *rr;char *rxptr;Ushort isr;Uchar *macAddr = vp1;isr = SONIC_ISR;if (isr&ISR_PKTRX) pktrx();if (isr&ISR_TXDN) pkttx();switch (op) { case ETHER_INIT : /* int ether_driver(ETHER_INIT,Uchar *macAddr,void) */ if (!initDA()) return(0); if (!initHw(macAddr)) return(0); SONIC_ISR = 0xffff; /* clear all current int requests */ return((void *)1); case ETHER_GETTBA : /* char *ether_driver(ETHER_GETTBA,int *len,void) */ TDA_next->pkt_size = TDA_next->frag_size = *((int *)vp2); return getTXptr(TDA_next); case ETHER_TBARDY : /* int ether_driver(ETHER_TBRDY,void,void) */ SONIC_CR=CR_TXP; TDA_next = getTXlink(TDA_next); assert(TDA_next != 0); return((void *)1); case ETHER_GETRXREC : /* RXrec *ether_driver(ETHER_GETRXREC,void,void) */ rr = (RXrec *)Qget4(rxq); rxptr = (char *)getRXptr(rr); if (re_ether) swap32n(rxptr,rr->byte_count); if (vflag) printMem(rxptr,rr->byte_count);#ifdef VERBOSE printPkt(rxptr,rr->byte_count);#endif return(rr); case ETHER_GETRBA : /* char *ether_driver(ETHER_GETRBA,RXrec *q,int *len) */ rr = (RXrec *)vp1; *((int *)vp2) = rr->byte_count; return(getRXptr(rr)); case ETHER_RXDONE : /* int ether_driver(ETHER_RXDONE,RXrec *q,void) */ rr = (RXrec *)vp1; rtnRXpkt(rr); return((void *)1); case ETHER_RXRDY : /* int ether_driver(ETHER_RXRDY,void,void) */ if (!Qempty4(rxq)) return((void *)1); return(0); default : return(0); }return(0);}#else /* Tasking tools don't like empty files (sigh) */sonic_foobar() {}#endif /* ETHERNET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -