|
|
1.1 root 1: /* netboot
2: *
3: * wd80x3.c,v
4: * Revision 1.2 1993/07/09 15:24:14 brezak
5: * Cleanup warnings and add netbsd kernel name suffix.
6: *
7: * Revision 1.1 1993/07/08 16:04:14 brezak
8: * Diskless boot prom code from Jim McKim ([email protected])
9: *
10: * Revision 1.2 1993/06/08 14:35:17 mckim
11: * *** empty log message ***
12: *
13: * Revision 1.1.1.1 1993/05/28 11:41:07 mckim
14: * Initial version.
15: *
16: *
17: * source in this file came from
18: * the Mach ethernet boot written by Leendert van Doorn.
19: *
20: * A very simple network driver for WD80x3 boards that polls.
21: *
22: * Copyright (c) 1992 by Leendert van Doorn
23: */
24:
25: #include "proto.h"
26: #include "assert.h"
27: #include "packet.h"
28: #include "ether.h"
29: #include "dp8390.h"
30:
31: /* configurable parameters */
32: #define WD_BASEREG 0x280 /* base register */
33: /* the base address doesn't have to be particularly accurate - the
34: board seems to pick up on addresses in the range a0000..effff.
35: */
36: #define WD_BASEMEM 0xd0000 /* base ram */
37:
38: /* bit definitions for board features */
39: #define INTERFACE_CHIP 01 /* has an WD83C583 interface chip */
40: #define BOARD_16BIT 02 /* 16 bit board */
41: #define SLOT_16BIT 04 /* 16 bit slot */
42:
43: /* register offset definitions */
44: #define WD_MSR 0x00 /* control (w) and status (r) */
45: #define WD_REG0 0x00 /* generic register definitions */
46: #define WD_REG1 0x01
47: #define WD_REG2 0x02
48: #define WD_REG3 0x03
49: #define WD_REG4 0x04
50: #define WD_REG5 0x05
51: #define WD_REG6 0x06
52: #define WD_REG7 0x07
53: #define WD_EA0 0x08 /* most significant addr byte */
54: #define WD_EA1 0x09
55: #define WD_EA2 0x0A
56: #define WD_EA3 0x0B
57: #define WD_EA4 0x0C
58: #define WD_EA5 0x0D /* least significant addr byte */
59: #define WD_LTB 0x0E /* LAN type byte */
60: #define WD_CHKSUM 0x0F /* sum from WD_EA0 upto here is 0xFF */
61: #define WD_DP8390 0x10 /* natsemi chip */
62:
63: /* bits in control register */
64: #define WD_MSR_MEMMASK 0x3F /* memory enable bits mask */
65: #define WD_MSR_MENABLE 0x40 /* memory enable */
66: #define WD_MSR_RESET 0x80 /* software reset */
67:
68: /* bits in bus size register */
69: #define WD_BSR_16BIT 0x01 /* 16 bit bus */
70:
71: /* bits in LA address register */
72: #define WD_LAAR_A19 0x01 /* address lines for above 1Mb ram */
73: #define WD_LAAR_LAN16E 0x40 /* enables 16bit shrd RAM for LAN */
74: #define WD_LAAR_MEM16E 0x80 /* enables 16bit shrd RAM for host */
75:
76: u_char eth_myaddr[ETH_ADDRSIZE];
77:
78: static int boardid;
79: static dpconf_t dpc;
80:
81: /*
82: * Determine whether wd8003 hardware performs register aliasing
83: * (i.e. whether it is an old WD8003E board).
84: */
85: static int
86: Aliasing(void) {
87: if (inb(WD_BASEREG + WD_REG1) != inb(WD_BASEREG + WD_EA1))
88: return 0;
89: if (inb(WD_BASEREG + WD_REG2) != inb(WD_BASEREG + WD_EA2))
90: return 0;
91: if (inb(WD_BASEREG + WD_REG3) != inb(WD_BASEREG + WD_EA3))
92: return 0;
93: if (inb(WD_BASEREG + WD_REG4) != inb(WD_BASEREG + WD_EA4))
94: return 0;
95: if (inb(WD_BASEREG + WD_REG7) != inb(WD_BASEREG + WD_CHKSUM))
96: return 0;
97: return 1;
98: }
99:
100: /*
101: * This trick is stolen from the clarkson packet driver
102: TBD - this is _ugly_ bogus! should use system timer
103: */
104: static void
105: LongPause(void) {
106: short i;
107: for (i = 1600; i > 0; i++)
108: (void) inb(0x61);
109: }
110:
111: /*
112: * Determine whether this board has 16-bit capabilities
113: */
114: static int
115: BoardIs16Bit(void) {
116: u_char bsreg = inb(WD_BASEREG + WD_REG1);
117:
118: outb(WD_BASEREG + WD_REG1, bsreg ^ WD_BSR_16BIT);
119: LongPause();
120: if (inb(WD_BASEREG + WD_REG1) == bsreg) {
121: /*
122: * Pure magic: LTB is 0x05 indicates that this is a WD8013EB board,
123: * 0x27 indicates that this is an WD8013 Elite board, and 0x29
124: * indicates an SMC Elite 16 board.
125: */
126: u_char tlb = inb(WD_BASEREG + WD_LTB);
127: return tlb == 0x05 || tlb == 0x27 || tlb == 0x29;
128: }
129: outb(WD_BASEREG + WD_REG1, bsreg);
130: return 1;
131: }
132:
133: /*
134: * Determine whether the 16 bit capable board is plugged
135: * into a 16 bit slot.
136: */
137: static int
138: SlotIs16Bit(void) {
139: return inb(WD_BASEREG + WD_REG1) & WD_BSR_16BIT;
140: }
141:
142: /*
143: * Reset ethernet board after a timeout
144: */
145: void
146: EtherReset(void) {
147: int dpreg = dpc.dc_reg;
148: /* initialize the board */
149: outb(WD_BASEREG + WD_MSR,
150: WD_MSR_MENABLE | (((u_long)WD_BASEMEM >> 13) & WD_MSR_MEMMASK));
151:
152: /* reset dp8390 ethernet chip */
153: outb(dpreg + DP_CR, CR_STP|CR_DM_ABORT);
154:
155: /* initialize first register set */
156: outb(dpreg + DP_IMR, 0);
157: outb(dpreg + DP_CR, CR_PS_P0|CR_STP|CR_DM_ABORT);
158: outb(dpreg + DP_TPSR, dpc.dc_tpsr);
159: outb(dpreg + DP_PSTART, dpc.dc_pstart);
160: outb(dpreg + DP_PSTOP, dpc.dc_pstop);
161: outb(dpreg + DP_BNRY, dpc.dc_pstart);
162: outb(dpreg + DP_RCR, RCR_MON);
163: outb(dpreg + DP_TCR, TCR_NORMAL|TCR_OFST);
164: if (boardid & SLOT_16BIT)
165: outb(dpreg + DP_DCR, DCR_WORDWIDE|DCR_8BYTES);
166: else
167: outb(dpreg + DP_DCR, DCR_BYTEWIDE|DCR_8BYTES);
168: outb(dpreg + DP_RBCR0, 0);
169: outb(dpreg + DP_RBCR1, 0);
170: outb(dpreg + DP_ISR, 0xFF);
171:
172: /* initialize second register set */
173: outb(dpreg + DP_CR, CR_PS_P1|CR_DM_ABORT);
174: outb(dpreg + DP_PAR0, eth_myaddr[0]);
175: outb(dpreg + DP_PAR1, eth_myaddr[1]);
176: outb(dpreg + DP_PAR2, eth_myaddr[2]);
177: outb(dpreg + DP_PAR3, eth_myaddr[3]);
178: outb(dpreg + DP_PAR4, eth_myaddr[4]);
179: outb(dpreg + DP_PAR5, eth_myaddr[5]);
180: outb(dpreg + DP_CURR, dpc.dc_pstart+1);
181:
182: /* and back to first register set */
183: outb(dpreg + DP_CR, CR_PS_P0|CR_DM_ABORT);
184: outb(dpreg + DP_RCR, RCR_AB);
185:
186: /* flush counters */
187: (void) inb(dpreg + DP_CNTR0);
188: (void) inb(dpreg + DP_CNTR1);
189: (void) inb(dpreg + DP_CNTR2);
190:
191: /* and go ... */
192: outb(dpreg + DP_CR, CR_STA|CR_DM_ABORT);
193: }
194:
195: /*
196: * Initialize the WD80X3 board
197: */
198: int
199: EtherInit(void) {
200: unsigned sum;
201: int memsize;
202: /* reset the ethernet card */
203: outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
204: LongPause();
205: outb(WD_BASEREG + WD_MSR, 0);
206:
207: /* determine whether the controller is there */
208: sum = inb(WD_BASEREG + WD_EA0) + inb(WD_BASEREG + WD_EA1) +
209: inb(WD_BASEREG + WD_EA2) + inb(WD_BASEREG + WD_EA3) +
210: inb(WD_BASEREG + WD_EA4) + inb(WD_BASEREG + WD_EA5) +
211: inb(WD_BASEREG + WD_LTB) + inb(WD_BASEREG + WD_CHKSUM);
212: if ((sum & 0xFF) != 0xFF)
213: return 0;
214:
215: /*
216: * Determine the type of board
217: */
218: boardid = 0;
219: if (!Aliasing()) {
220: if (BoardIs16Bit()) {
221: boardid |= BOARD_16BIT;
222: if (SlotIs16Bit())
223: boardid |= SLOT_16BIT;
224: }
225: }
226: memsize = (boardid & BOARD_16BIT) ? 0x4000 : 0x2000; /* 16 or 8 Kb */
227:
228: /* special setup needed for WD8013 boards */
229: if (boardid & SLOT_16BIT)
230: outb(WD_BASEREG + WD_REG5, WD_LAAR_A19|WD_LAAR_LAN16E);
231:
232: /* get ethernet address */
233: eth_myaddr[0] = inb(WD_BASEREG + WD_EA0);
234: eth_myaddr[1] = inb(WD_BASEREG + WD_EA1);
235: eth_myaddr[2] = inb(WD_BASEREG + WD_EA2);
236: eth_myaddr[3] = inb(WD_BASEREG + WD_EA3);
237: eth_myaddr[4] = inb(WD_BASEREG + WD_EA4);
238: eth_myaddr[5] = inb(WD_BASEREG + WD_EA5);
239:
240: /* save settings for future use */
241: dpc.dc_reg = WD_BASEREG + WD_DP8390;
242: dpc.dc_mem = WD_BASEMEM;
243: dpc.dc_tpsr = 0;
244: dpc.dc_pstart = 6;
245: dpc.dc_pstop = (memsize >> 8) & 0xFF;
246:
247: printf("Using wd80x3 board, port 0x%x, iomem 0x%x, iosiz %d\n", WD_BASEREG, WD_BASEMEM, memsize);
248:
249: EtherReset();
250: return 1;
251: }
252:
253: /*
254: * Stop ethernet board
255: */
256: void
257: EtherStop(void) {
258: /* stop dp8390, followed by a board reset */
259: outb(dpc.dc_reg + DP_CR, CR_STP|CR_DM_ABORT);
260: outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
261: outb(WD_BASEREG + WD_MSR, 0);
262: }
263:
264: /* TBD - all users must take care to use the current "data seg" value
265: when moving data from/to the controller */
266: static void
267: WdCopy(u_long src, u_long dst, u_long count) {
268: #if TRACE > 0
269: printf("WdCopy from %x to %x for %d\n", src, dst, count);
270: #endif
271: assert(count <= 1514);
272: if (boardid & SLOT_16BIT)
273: outb(WD_BASEREG + WD_REG5,
274: WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
275: PhysBcopy(src, dst, count);
276: if (boardid & SLOT_16BIT)
277: outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
278: }
279:
280: /*
281: * Send an ethernet packet to destination 'dest'
282: */
283: void
284: EtherSend(packet_t *pkt, u_short proto, u_char *dest) {
285: ethhdr_t *ep;
286:
287: pkt->pkt_len += sizeof(ethhdr_t);
288: pkt->pkt_offset -= sizeof(ethhdr_t);
289: ep = (ethhdr_t *) pkt->pkt_offset;
290: ep->eth_proto = htons(proto);
291: bcopy((char *)dest, (char *)ep->eth_dst, ETH_ADDRSIZE);
292: bcopy((char *)eth_myaddr, (char *)ep->eth_src, ETH_ADDRSIZE);
293: #if 0
294: DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t));
295: #endif
296: if (pkt->pkt_len < 60)
297: pkt->pkt_len = 60;
298:
299: #if TRACE > 0
300: {
301: int i;
302: DUMP_STRUCT("EtherSend: pkt", pkt->pkt_offset, pkt->pkt_len);
303: #if 0
304: for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)(pkt->pkt_offset)+i));
305: printe("\n");
306: #endif
307: }
308: #endif
309:
310: #if 0
311: printe("EtherSend: WdCopy from %x to %x for %d\n", LA(pkt->pkt_offset), dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len);
312: #endif
313: WdCopy(LA(pkt->pkt_offset),
314: dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len);
315: outb(dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
316: outb(dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF));
317: outb(dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF);
318: outb(dpc.dc_reg + DP_CR, CR_TXP);
319:
320: #if 0
321: printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
322: printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF));
323: printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF);
324: printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_CR, CR_TXP);
325: #endif
326: }
327:
328: /*
329: * Copy dp8390 packet header for observation
330: */
331: static void
332: GetHeader(u_long haddr, dphdr_t *dph) {
333: #if TRACE > 0
334: printe("GetHeader: WdCopy from %x to %x for %d\n", haddr, LA(dph), sizeof(dphdr_t));
335: #endif
336: WdCopy(haddr, LA(dph), sizeof(dphdr_t));
337: #if 0
338: DUMP_STRUCT("GetHeader: dphdr_t", dph, sizeof(dphdr_t));
339: #endif
340: }
341:
342: /*
343: * Poll the dp8390 just see if there's an Ethernet packet
344: * available. If there is, its contents is returned in a
345: * pkt structure, otherwise a nil pointer is returned.
346: */
347: packet_t *
348: EtherReceive(void) {
349: u_char pageno, curpage, nextpage;
350: int dpreg = dpc.dc_reg;
351: packet_t *pkt;
352: dphdr_t dph;
353: u_long addr;
354:
355: pkt = (packet_t *)0;
356: if (inb(dpreg + DP_RSR) & RSR_PRX) {
357: /* get current page numbers */
358: pageno = inb(dpreg + DP_BNRY) + 1;
359: if (pageno == dpc.dc_pstop)
360: pageno = dpc.dc_pstart;
361: outb(dpreg + DP_CR, CR_PS_P1);
362: curpage = inb(dpreg + DP_CURR);
363: outb(dpreg + DP_CR, CR_PS_P0);
364: if (pageno == curpage)
365: return (packet_t *) 0;
366:
367: /* get packet header */
368: addr = dpc.dc_mem + (pageno << 8);
369: GetHeader(addr, &dph);
370: nextpage = dph.dh_next;
371:
372: /* allocate packet */
373: pkt = PktAlloc(0);
374: #if 0
375: printe("EtherReceive: allocated pkt %x\n", pkt);
376: #endif
377: pkt->pkt_len = ((dph.dh_rbch & 0xFF) << 8) | (dph.dh_rbcl & 0xFF);
378: pkt->pkt_len -= sizeof(dphdr_t);
379: if (pkt->pkt_len > 1514) /* bug in dp8390 */
380: pkt->pkt_len = 1514;
381:
382: #if TRACE > 0
383: {
384: int i;
385: printe("EtherReceive %d bytes: ", pkt->pkt_len);
386: #if 0
387: for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)pkt+i));
388: #else
389: DUMP_STRUCT("", pkt, pkt->pkt_len);
390: #endif
391: printe("\n");
392: }
393: #endif
394:
395: /*
396: * The dp8390 maintains a circular buffer of pages (256 bytes)
397: * in which incomming ethernet packets are stored. The following
398: * if detects wrap arounds, and copies the ethernet packet to
399: * our local buffer in two chunks if necesarry.
400: */
401: assert(pkt->pkt_offset);
402: assert(pkt->pkt_len <= (6 << 8));
403: if (nextpage < pageno && nextpage > dpc.dc_pstart) {
404: u_long nbytes = ((dpc.dc_pstop - pageno) << 8) - sizeof(dphdr_t);
405:
406: assert(nbytes <= (6 << 8));
407: #if TRACE > 0
408: printe("EtherReceive1: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), nbytes);
409: #endif
410: WdCopy(addr + sizeof(dphdr_t),
411: LA(pkt->pkt_offset), nbytes);
412: if ((pkt->pkt_len - nbytes) > 0)
413: /* TBD - this OK? */
414: #if TRACE > 0
415: printe("EtherReceive2: WdCopy from %x to %x for %x\n",dpc.dc_mem + (dpc.dc_pstart << 8), LA(pkt->pkt_offset) + nbytes, pkt->pkt_len - nbytes);
416: #endif
417: WdCopy(dpc.dc_mem + (dpc.dc_pstart << 8),
418: LA(pkt->pkt_offset) + nbytes,
419: pkt->pkt_len - nbytes);
420: } else {
421: #if TRACE > 0
422: printe("EtherReceive3: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), (u_long)pkt->pkt_len);
423: #endif
424: WdCopy(addr + sizeof(dphdr_t),
425: LA(pkt->pkt_offset), (u_long)pkt->pkt_len);
426: }
427:
428: /* release occupied pages */
429: if (nextpage == dpc.dc_pstart)
430: nextpage = dpc.dc_pstop;
431: outb(dpreg + DP_BNRY, nextpage - 1);
432: }
433:
434: return pkt;
435: }
436:
437: /*
438: * Print an ethernet address in human readable form
439: */
440: void
441: EtherPrintAddr(u_char *addr) {
442: printf("%x:%x:%x:%x:%x:%x",
443: addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF,
444: addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF);
445: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.