xref: /plan9/sys/src/9/ppc/ethersaturn.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 #include "../port/netif.h"
9 #include "msaturn.h"
10 
11 #include "etherif.h"
12 
13 enum{
14 	Etcr = Saturn + 0x0c00,
15 	Etsr = Saturn + 0x0c02,
16 	Ercr = Saturn + 0x0c04,
17 	Ersr = Saturn + 0x0c06,
18 	Eisr = Saturn + 0x0d04,
19 	Eimr = Saturn + 0x0d06,
20 	Emacaddr0 = Saturn + 0x0e02,
21 	Miicr = Saturn + 0x0f02,
22 	Miiwdr = Saturn + 0x0f04,
23 	Miirdr = Saturn + 0x0f06,
24 
25 	Ethermem = 0xf2c00000,
26 	Etherfsize = 0x2000,
27 	Nrx = 14,
28 	Ntx = 2,		// Nrx + Ntx must be 16
29 
30 	Ersr_rxfpmask = 0xf,
31 	Ersr_rxevent = RBIT(0, ushort),
32 	Etcr_txfpmask = 0xf,
33 	Ercr_rxenab = RBIT(0, ushort),
34 	Ercr_auienab = RBIT(2, ushort),
35 	Etcr_txstart = RBIT(1, ushort),
36 	Etcr_retries = 0xf<<8,
37 	Ei_txecall = RBIT(0, ushort),
38 	Ei_txretry = RBIT(2, ushort),
39 	Ei_txdefer = RBIT(3, ushort),
40 	Ei_txcrs = RBIT(4, ushort),
41 	Ei_txdone = RBIT(5, ushort),
42 	Ei_rxcrcerr = RBIT(8, ushort),
43 	Ei_rxdrib = RBIT(9, ushort),
44 	Ei_rxdone = RBIT(10, ushort),
45 	Ei_rxshort = RBIT(11, ushort),
46 	Ei_rxlong = RBIT(12, ushort),
47 
48 	Miicr_regshift = 6,
49 	Miicr_read = RBIT(10, ushort),
50 	Miicr_preambledis = RBIT(12, ushort),
51 	Miicr_accack = RBIT(14, ushort),
52 	Miicr_accbsy = RBIT(15, ushort),
53 };
54 
55 typedef struct {
56 	Lock;
57 	int		txbusy;
58 	int		txempty;
59 	int		txfull;
60 	int		ntx;			/* number of entries in transmit ring */
61 	int		rxlast;
62 
63 	int		active;
64 	ulong	interrupts;	/* statistics */
65 	ulong	overflows;
66 } Ctlr;
67 
68 uchar etheraddr[6] = { 0x90, 0x85, 0x82, 0x32, 0x83, 0x00};
69 static ushort*etcr=(ushort*)Etcr;
70 static ushort*etsr=(ushort*)Etsr;
71 static ushort*ercr=(ushort*)Ercr;
72 static ushort*ersr=(ushort*)Ersr;
73 static ushort*eimr=(ushort*)Eimr;
74 static ushort*eisr=(ushort*)Eisr;
75 static ushort*miicr=(ushort*)Miicr;
76 static ushort*miirdr=(ushort*)Miirdr;
77 
78 static void
txfill(Ether * ether,Ctlr * ctlr)79 txfill(Ether*ether, Ctlr*ctlr)
80 {
81 	int len;
82 	Block *b;
83 	ushort*dst;
84 
85 	while(ctlr->ntx<Ntx){
86 		if((b=qget(ether->oq)) == nil)
87 			break;
88 
89 		len = BLEN(b);
90 		dst = (ushort*)(Ethermem+(ctlr->txempty+Nrx)*Etherfsize);
91 		*dst = len;
92 		memmove(&dst[1], b->rp, len);
93 		ctlr->ntx++;
94 		ctlr->txempty++;
95 		if(ctlr->txempty==Ntx)
96 			ctlr->txempty = 0;
97 		freeb(b);
98 	}
99 }
100 
101 static void
txrestart(Ctlr * ctlr)102 txrestart(Ctlr*ctlr)
103 {
104 	if(ctlr->ntx==0 || ctlr->txbusy)
105 		return;
106 	ctlr->txbusy = 1;
107 	*etcr = Etcr_txstart|Etcr_retries|(ctlr->txfull+Nrx);
108 }
109 
110 static void interrupt(Ureg*, void*);
111 
112 static void
transmit(Ether * ether)113 transmit(Ether*ether)
114 {
115 	Ctlr *ctlr;
116 
117 	ctlr = ether->ctlr;
118 	ilock(ctlr);
119 	txfill(ether, ctlr);
120 	txrestart(ctlr);
121 	iunlock(ctlr);
122 
123 }
124 
125 static void
interrupt(Ureg *,void * arg)126 interrupt(Ureg*, void*arg)
127 {
128 	Ctlr*ctlr;
129 	Ether*ether = arg;
130 	Etherpkt*pkt;
131 	ushort ie;
132 	int rx, len;
133 	Block *b;
134 
135 	ctlr = ether->ctlr;
136 	if(!ctlr->active)
137 		return;	/* not ours */
138 	ctlr->interrupts++;
139 
140 	ilock(ctlr);
141 	ie = *eisr;
142 	*eisr = ie;
143 	intack();
144 
145 	if(ie==0)
146 		iprint("interrupt: no interrupt source?\n");
147 
148 	if(ie&Ei_txdone){
149 		if((*etcr&Etcr_txstart)==0){
150 			if(ctlr->txbusy){
151 				ctlr->txbusy = 0;
152 				ctlr->ntx--;
153 				ctlr->txfull++;
154 				if(ctlr->txfull==Ntx)
155 					ctlr->txfull = 0;
156 			}
157 			txrestart(ctlr);
158 			txfill(ether, ctlr);
159 			txrestart(ctlr);
160 		}
161 		else
162 			iprint("interrupt: bogus tx interrupt\n");
163 		ie &= ~Ei_txdone;
164 	}
165 
166 	if(ie&Ei_rxdone){
167 		rx=*ersr&Ersr_rxfpmask;
168 		while(ctlr->rxlast!=rx){
169 
170 			ctlr->rxlast++;
171 			if(ctlr->rxlast >= Nrx)
172 				ctlr->rxlast = 0;
173 
174 			pkt = (Etherpkt*)(Ethermem+ctlr->rxlast*Etherfsize);
175 			len = *(ushort*)pkt;
176 			if((b = iallocb(len+sizeof(ushort))) != nil){
177 				memmove(b->wp, pkt, len+sizeof(ushort));
178 				b->rp += sizeof(ushort);
179 				b->wp = b->rp + len;
180 				etheriq(ether, b, 1);
181 			}else
182 				ether->soverflows++;
183 			rx=*ersr&Ersr_rxfpmask;
184 		}
185 		ie &= ~Ei_rxdone;
186 	}
187 
188 	if(ie&Ei_txretry){
189 		iprint("ethersaturn: txretry!\n");
190 		ie &= ~Ei_txretry;
191 		ctlr->txbusy = 0;
192 		txrestart(ctlr);
193 	}
194 
195 	ie &= ~Ei_txcrs;
196 	if(ie)
197 		iprint("interrupt: unhandled interrupts %.4uX\n", ie);
198 	iunlock(ctlr);
199 }
200 
201 static int
reset(Ether * ether)202 reset(Ether* ether)
203 {
204 	Ctlr*ctlr;
205 
206 	*ercr = 0;
207 	ctlr = malloc(sizeof(*ctlr));
208 	memset(ctlr, 0, sizeof(*ctlr));
209 	ctlr->active = 1;
210 
211 	ether->ctlr = ctlr;
212 	ether->transmit = transmit;
213 	ether->interrupt = interrupt;
214 	ether->irq = Vecether;
215 	ether->arg = ether;
216 	memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
217 
218 	*ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
219 	*eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
220 
221 	iprint("reset: ercr %.4uX\n", *ercr);
222 	return 0;
223 }
224 
225 void
ethersaturnlink(void)226 ethersaturnlink(void)
227 {
228 	addethercard("saturn", reset);
229 }
230 
231