1 /*
2 * Crystal CS8900 ethernet controller
3 * Specifically for the Teralogic Puma architecture
4 */
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 #include "puma.h"
15
16 /*
17 * On the Puma board the CS8900 can be addressed from either
18 * ISA I/O space or ISA memory space at the following locations.
19 * The cs8900 address pins are shifted by 1 relative to the CPU.
20 */
21 enum {
22 IsaIOBase = 0xf0000000,
23 IsaMemBase = 0xe0000000,
24
25 IOBase = 0x300,
26 MemBase = 0xc0000,
27 };
28
29 /* I/O accesses */
30 #define out16(port, val) (*((ushort *)IsaIOBase + IOBase + (port)) = (val))
31 #define in16(port) *((ushort *)IsaIOBase + IOBase + (port))
32 #define in8(port) *((uchar *)IsaIOBase + ((IOBase+(port))<<1))
33 #define regIOw(reg, val) do {out16(PpPtr, (reg)|0x3000); out16(PpData, val);} while(0)
34 #define regIOr(reg) (out16(PpPtr, (reg)|0x3000), in16(PpData))
35 #define regIOr1(reg) (out16(PpPtr, (reg)|0x3000), in16(PpData1))
36
37 /* Memory accesses */
38 #define regw(reg, val) *((ushort *)IsaMemBase + MemBase + (reg)) = (val)
39 #define regr(reg) *((ushort *)IsaMemBase + MemBase + (reg))
40
41 /* Puma frame copying */
42 #define copyout(src, len) { \
43 int _len = (len); \
44 ushort *_src = (ushort *)(src); \
45 ushort *_dst = (ushort *)IsaMemBase + MemBase + TxFrame; \
46 while(_len > 0) { \
47 *_dst++ = *_src++; \
48 _dst++; \
49 _len -= 2; \
50 } \
51 }
52 #define copyoutIO(src, len) { \
53 int _len = (len); \
54 ushort *_src = (ushort *)(src); \
55 while(_len > 0) { \
56 out16(RxTxData, *_src); \
57 _src++; \
58 _len -= 2; \
59 } \
60 }
61 #define copyin(dst, len) { \
62 int _len = (len), _len2 = (len)&~1; \
63 ushort *_src = (ushort *)IsaMemBase + MemBase + RxFrame; \
64 ushort *_dst = (ushort *)(dst); \
65 while(_len2 > 0) { \
66 *_dst++ = *_src++; \
67 _src++; \
68 _len2 -= 2; \
69 } \
70 if(_len&1) \
71 *(uchar*)_dst = (*_src)&0xff; \
72 }
73 #define copyinIO(dst, len) { \
74 int _i, _len = (len), _len2 = (len)&~1; \
75 ushort *_dst = (ushort *)(dst); \
76 _i = in16(RxTxData); USED(_i); /* RxStatus */ \
77 _i = in16(RxTxData); USED(_i); /* RxLen */ \
78 while(_len2 > 0) { \
79 *_dst++ = in16(RxTxData); \
80 _len2 -= 2; \
81 } \
82 if(_len&1) \
83 *(uchar*)_dst = (in16(RxTxData))&0xff; \
84 }
85
86
87
88 enum { /* I/O Mode Register Offsets */
89 RxTxData = 0x00, /* receive/transmit data - port 0 */
90 TxCmdIO = 0x04, /* transmit command */
91 TxLenIO = 0x06, /* transmit length */
92 IsqIO = 0x08, /* Interrupt status queue */
93 PpPtr = 0x0a, /* packet page pointer */
94 PpData = 0x0c, /* packet page data */
95 PpData1 = 0x0e, /* packet page data - port 1*/
96 };
97
98 enum { /* Memory Mode Register Offsets */
99 /* Bus Interface Registers */
100 Ern = 0x0000, /* EISA registration numberion */
101 Pic = 0x0002, /* Product identification code */
102 Iob = 0x0020, /* I/O base address */
103 Intr = 0x0022, /* interrupt number */
104 Mba = 0x002c, /* memory base address */
105
106 Ecr = 0x0040, /* EEPROM command register */
107 Edw = 0x0042, /* EEPROM data word */
108 Rbc = 0x0050, /* receive frame byte counter */
109
110 /* Status and Control Registers */
111 RxCfg = 0x0102,
112 RxCtl = 0x0104,
113 TxCfg = 0x0106,
114 BufCfg = 0x010a,
115 LineCtl = 0x0112,
116 SelfCtl = 0x0114,
117 BusCtl = 0x0116,
118 TestCtl = 0x0118,
119 Isq = 0x0120,
120 RxEvent = 0x0124,
121 TxEvent = 0x0128,
122 BufEvent = 0x012c,
123 RxMISS = 0x0130,
124 TxCol = 0x0132,
125 LineSt = 0x0134,
126 SelfSt = 0x0136,
127 BusSt = 0x0138,
128 Tdr = 0x013c,
129
130 /* Initiate Transmit Registers */
131 TxCmd = 0x0144, /* transmit command */
132 TxLen = 0x0146, /* transmit length */
133
134 /* Address Filter Registers */
135 IndAddr = 0x0158, /* individual address registers */
136
137 /* Frame Location */
138 RxStatus = 0x0400, /* receive status */
139 RxLen = 0x0402, /* receive length */
140 RxFrame = 0x0404, /* receive frame location */
141 TxFrame = 0x0a00, /* transmit frame location */
142 };
143
144 enum { /* Ecr */
145 Addr = 0x00ff, /* EEPROM word address (field) */
146 Opcode = 0x0300, /* command opcode (field) */
147 };
148
149 enum { /* Isq */
150 Regnum = 0x003f, /* register number held by Isq (field) */
151 IsqRxEvent = 0x04,
152 IsqTxEvent = 0x08,
153 IsqBufEvent = 0x0c,
154 IsqRxMiss = 0x10,
155 IsqTxCol = 0x12,
156 RegContent = 0xffc0, /* register data contents (field) */
157 };
158
159 enum { /* RxCfg */
160 Skip_1 = 0x0040,
161 StreamE = 0x0080,
162 RxOKiE = 0x0100,
163 RxDMAonly = 0x0200,
164 AutoRxDMAE = 0x0400,
165 BufferCRC = 0x0800,
166 CRCerroriE = 0x1000,
167 RuntiE = 0x2000,
168 ExtradataiE = 0x4000,
169 };
170
171 enum { /* RxEvent */
172 IAHash = 0x0040,
173 Dribblebits = 0x0080,
174 RxOK = 0x0100,
175 Hashed = 0x0200,
176 IndividualAdr = 0x0400,
177 Broadcast = 0x0800,
178 CRCerror = 0x1000,
179 Runt = 0x2000,
180 Extradata = 0x4000,
181 };
182
183 enum { /* RxCtl */
184 IAHashA = 0x0040,
185 PromiscuousA = 0x0080,
186 RxOKA = 0x0100,
187 MulticastA = 0x0200,
188 IndividualA = 0x0400,
189 BroadcastA = 0x0800,
190 CRCerrorA = 0x1000,
191 RuntA = 0x2000,
192 ExtradataA = 0x4000,
193 };
194
195 enum { /* TxCfg */
196 LossofCRSiE = 0x0040,
197 SQEerroriE = 0x0080,
198 TxOKiE = 0x0100,
199 OutofWindowiE = 0x0200,
200 JabberiE = 0x0400,
201 AnycolliE = 0x0800,
202 Coll16iE = 0x8000,
203 };
204
205 enum { /* TxEvent */
206 LossofCRS = 0x0040,
207 SQEerror = 0x0080,
208 TxOK = 0x0100,
209 OutofWindow = 0x0200,
210 Jabber = 0x0400,
211 NTxCols = 0x7800, /* number of Tx collisions (field) */
212 coll16 = 0x8000,
213 };
214
215 enum { /* BufCfg */
216 SWintX = 0x0040,
217 RxDMAiE = 0x0080,
218 Rdy4TxiE = 0x0100,
219 TxUnderruniE = 0x0200,
220 RxMissiE = 0x0400,
221 Rx128iE = 0x0800,
222 TxColOvfiE = 0x1000,
223 MissOvfloiE = 0x2000,
224 RxDestiE = 0x8000,
225 };
226
227 enum { /* BufEvent */
228 SWint = 0x0040,
229 RxDMAFrame = 0x0080,
230 Rdy4Tx = 0x0100,
231 TxUnderrun = 0x0200,
232 RxMiss = 0x0400,
233 Rx128 = 0x0800,
234 RxDest = 0x8000,
235 };
236
237 enum { /* RxMiss */
238 MissCount = 0xffc0,
239 };
240
241 enum { /* TxCol */
242 ColCount = 0xffc0,
243 };
244
245 enum { /* LineCtl */
246 SerRxOn = 0x0040,
247 SerTxOn = 0x0080,
248 Iface = 0x0300, /* (field) 01 - AUI, 00 - 10BASE-T, 10 - Auto select */
249 ModBackoffE = 0x0800,
250 PolarityDis = 0x1000,
251 DefDis = 0x2000,
252 LoRxSquelch = 0x4000,
253 };
254
255 enum { /* LineSt */
256 LinkOK = 0x0080,
257 AUI = 0x0100,
258 TenBT = 0x0200,
259 PolarityOK = 0x1000,
260 CRS = 0x4000,
261 };
262
263 enum { /* SelfCtl */
264 RESET = 0x0040,
265 SWSuspend = 0x0100,
266 HWSleepE = 0x0200,
267 HWStandbyE = 0x0400,
268 };
269
270 enum { /* SelfSt */
271 INITD = 0x0080,
272 SIBUSY = 0x0100,
273 EepromPresent = 0x0200,
274 EepromOK = 0x0400,
275 ElPresent = 0x0800,
276 EeSize = 0x1000,
277 };
278
279 enum { /* BusCtl */
280 ResetRxDMA = 0x0040,
281 UseSA = 0x0200,
282 MemoryE = 0x0400,
283 DMABurst = 0x0800,
284 EnableIRQ = 0x8000,
285 };
286
287 enum { /* BusST */
288 TxBidErr = 0x0080,
289 Rdy4TxNOW = 0x0100,
290 };
291
292 enum { /* TestCtl */
293 FDX = 0x4000, /* full duplex */
294 };
295
296 enum { /* TxCmd */
297 TxStart = 0x00c0, /* bytes before transmit starts (field) */
298 TxSt5 = 0x0000, /* start after 5 bytes */
299 TxSt381 = 0x0040, /* start after 381 bytes */
300 TxSt1021 = 0x0080, /* start after 1021 bytes */
301 TxStAll = 0x00c0, /* start after the entire frame is in the cs8900 */
302 Force = 0x0100,
303 Onecoll = 0x0200,
304 InhibitCRC = 0x1000,
305 TxPadDis = 0x2000,
306 };
307
308 static Queue *pendingTx[MaxEther];
309
310 static void
attach(Ctlr * ctlr)311 attach(Ctlr *ctlr)
312 {
313 int reg;
314
315 USED(ctlr);
316 /* enable transmit and receive */
317 reg = regr(BusCtl);
318 regw(BusCtl, reg|EnableIRQ);
319 reg = regr(LineCtl);
320 regw(LineCtl, reg|SerRxOn|SerTxOn);
321 }
322
323 static char pbuf[200];
324 int
sprintx(void * f,char * to,int count)325 sprintx(void *f, char *to, int count)
326 {
327 int i, printable;
328 char *start = to;
329 uchar *from = f;
330
331 if(count < 0) {
332 print("BAD DATA COUNT %d\n", count);
333 return 0;
334 }
335 printable = 1;
336 if(count > 40)
337 count = 40;
338 for(i=0; i<count && printable; i++)
339 if((from[i]<32 && from[i] !='\n' && from[i] !='\r' && from[i] !='\b' && from[i] !='\t') || from[i]>127)
340 printable = 0;
341 *to++ = '\'';
342 if(printable){
343 memmove(to, from, count);
344 to += count;
345 }else{
346 for(i=0; i<count; i++){
347 if(i>0 && i%4==0)
348 *to++ = ' ';
349 sprint(to, "%2.2ux", from[i]);
350 to += 2;
351 }
352 }
353 *to++ = '\'';
354 *to = 0;
355 return to - start;
356 }
357
358 static void
transmit(Ctlr * ctlr)359 transmit(Ctlr *ctlr)
360 {
361 int len, status;
362 Block *b;
363
364 for(;;){
365 /* is TxCmd pending ? - check */
366 if(qlen(pendingTx[ctlr->ctlrno]) > 0)
367 break;
368 b = qget(ctlr->oq);
369 if(b == 0)
370 break;
371 len = BLEN(b);
372 regw(TxCmd, TxSt381);
373 regw(TxLen, len);
374 status = regr(BusSt);
375 if((status & Rdy4TxNOW) == 0) {
376 qbwrite(pendingTx[ctlr->ctlrno], b);
377 break;
378 }
379 /*
380 * Copy the packet to the transmit buffer.
381 */
382 copyout(b->rp, len);
383 freeb(b);
384 }
385 }
386
387 static void
interrupt(Ureg *,Ctlr * ctlr)388 interrupt(Ureg*, Ctlr *ctlr)
389 {
390 int len, events, status;
391 Block *b;
392 Queue *q;
393
394 while((events = regr(Isq)) != 0) {
395 status = events&RegContent;
396
397 switch(events&Regnum) {
398
399 case IsqBufEvent:
400 if(status&Rdy4Tx) {
401 if(qlen(pendingTx[ctlr->ctlrno]) > 0)
402 q = pendingTx[ctlr->ctlrno];
403 else
404 q = ctlr->oq;
405 b = qget(q);
406 if(b == 0)
407 break;
408 len = BLEN(b);
409 copyout(b->rp, len);
410 freeb(b);
411 } else
412 if(status&TxUnderrun) {
413 print("TxUnderrun\n");
414 } else
415 if(status&RxMiss) {
416 print("RxMiss\n");
417 } else {
418 print("IsqBufEvent status = %ux\n", status);
419 }
420 break;
421
422 case IsqRxEvent:
423 if(status&RxOK) {
424 len = regr(RxLen);
425 if((b = iallocb(len)) != 0) {
426 copyin(b->wp, len);
427 b->wp += len;
428 etheriq(ctlr, b, 1);
429 }
430 } else {
431 print("IsqRxEvent status = %ux\n", status);
432 }
433 break;
434
435 case IsqTxEvent:
436 if(status&TxOK) {
437 if(qlen(pendingTx[ctlr->ctlrno]) > 0)
438 q = pendingTx[ctlr->ctlrno];
439 else
440 q = ctlr->oq;
441 b = qget(q);
442 if(b == 0)
443 break;
444 len = BLEN(b);
445 regw(TxCmd, TxSt381);
446 regw(TxLen, len);
447 if((regr(BusSt) & Rdy4TxNOW) == 0) {
448 print("IsqTxEvent and Rdy4TxNow == 0\n");
449 }
450 copyout(b->rp, len);
451 freeb(b);
452 } else {
453 print("IsqTxEvent status = %ux\n", status);
454 }
455 break;
456 case IsqRxMiss:
457 break;
458 case IsqTxCol:
459 break;
460 }
461 }
462 }
463
464 int
cs8900reset(Ctlr * ctlr)465 cs8900reset(Ctlr* ctlr)
466 {
467 int i, reg;
468 uchar ea[Eaddrlen];
469
470 ctlr->card.irq = V_ETHERNET;
471 pendingTx[ctlr->ctlrno] = qopen(16*1024, 1, 0, 0);
472
473 /*
474 * If the Ethernet address is not set in the plan9.ini file
475 * a) try reading from the Puma board ROM. The ether address is found in
476 * bytes 4-9 of the ROM. The Teralogic Organizational Unique Id (OUI)
477 * is in bytes 4-6 and should be 00 10 8a.
478 */
479 memset(ea, 0, Eaddrlen);
480 if(memcmp(ea, ctlr->card.ea, Eaddrlen) == 0) {
481 uchar *rom = (uchar *)EPROM_BASE;
482 if(rom[4] != 0x00 || rom[5] != 0x10 || rom[6] != 0x8a)
483 panic("no ether address");
484 memmove(ea, &rom[4], Eaddrlen);
485 }
486 memmove(ctlr->card.ea, ea, Eaddrlen);
487
488 /*
489 * Identify the chip by reading the Pic register.
490 * The EISA registration number is in the low word
491 * and the product identification code in the high code.
492 * The ERN for Crystal Semiconductor is 0x630e.
493 * Bits 0-7 and 13-15 of the Pic should be zero for a CS8900.
494 */
495 if(regIOr(Ern) != 0x630e || (regIOr(Pic) & 0xe0ff) != 0)
496 panic("no cs8900 found");
497
498 /*
499 * Reset the chip and ensure 16-bit mode operation
500 */
501 regIOw(SelfCtl, RESET);
502 delay(10);
503 i=in8(PpPtr); USED(i);
504 i=in8(PpPtr+1); USED(i);
505 i=in8(PpPtr); USED(i);
506 i=in8(PpPtr+1); USED(i);
507
508 /*
509 * Wait for initialisation and EEPROM reads to complete
510 */
511 i=0;
512 for(;;) {
513 short st = regIOr(SelfSt);
514 if((st&SIBUSY) == 0 && st&INITD)
515 break;
516 if(i++ > 1000000)
517 panic("cs8900: initialisation failed");
518 }
519
520 /*
521 * Enable memory mode operation.
522 */
523 regIOw(Mba, MemBase & 0xffff);
524 regIOw(Mba+2, MemBase >> 16);
525 regIOw(BusCtl, MemoryE|UseSA);
526
527 /*
528 * Enable 10BASE-T half duplex, transmit in interrupt mode
529 */
530 reg = regr(LineCtl);
531 regw(LineCtl, reg&~Iface);
532 reg = regr(TestCtl);
533 regw(TestCtl, reg&~FDX);
534 regw(BufCfg, Rdy4TxiE|TxUnderruniE|RxMissiE);
535 regw(TxCfg, TxOKiE|JabberiE|Coll16iE);
536 regw(RxCfg, RxOKiE);
537 regw(RxCtl, RxOKA|IndividualA|BroadcastA);
538
539 for(i=0; i<Eaddrlen; i+=2)
540 regw(IndAddr+i, ea[i] | (ea[i+1] << 8));
541
542 /* Puma IRQ tied to INTRQ0 */
543 regw(Intr, 0);
544
545 ctlr->card.reset = cs8900reset;
546 ctlr->card.port = 0x300;
547 ctlr->card.attach = attach;
548 ctlr->card.transmit = transmit;
549 ctlr->card.intr = interrupt;
550
551 print("Ether reset...\n");uartwait();
552
553 return 0;
554 }
555
556