|
|
1.1 root 1: /* netboot
2: *
3: * ne2100.c,v
4: * Revision 1.1 1993/07/08 16:04:05 brezak
5: * Diskless boot prom code from Jim McKim ([email protected])
6: *
7: * Revision 1.1.1.1 1993/05/28 11:41:07 mckim
8: * Initial version.
9: *
10: *
11: * source in this file came from
12: * the Mach ethernet boot written by Leendert van Doorn.
13: *
14: * A very simple network driver for NE2100 boards that polls.
15: *
16: * Copyright (c) 1992 by Leendert van Doorn
17: */
18:
19: #include "assert.h"
20: #include "nbtypes.h"
21: #include "packet.h"
22: #include "ether.h"
23: #include "lance.h"
24: #include "proto.h"
25:
26: /* configurable parameters */
27: #define NE_BASEREG 0x300 /* base register */
28: #define NE_DMACHANNEL 5 /* DMA channel */
29:
30: /* Lance register offsets */
31: #define LA_CSR (NE_BASEREG+0x10)
32: #define LA_CSR1 (NE_BASEREG+0x10)
33: #define LA_CSR2 (NE_BASEREG+0x10)
34: #define LA_CSR3 (NE_BASEREG+0x10)
35: #define LA_RAP (NE_BASEREG+0x12)
36:
37: /*
38: * Some driver specific constants.
39: * Take care when tuning, this program only has 32 Kb
40: */
41: #define LANCEBUFSIZE 1518 /* plus 4 CRC bytes */
42: #define MAXLOOP 1000000L /* arbitrary retry limit */
43: #define LOG2NRCVRING 2 /* log2(NRCVRING) */
44: #define NRCVRING (1 << LOG2NRCVRING)
45:
46: u_char eth_myaddr[ETH_ADDRSIZE];
47:
48: static int next_rmd; /* next receive element */
49: static initblock_t *initblock; /* initialization block */
50: static tmde_t *tmd; /* transmit ring */
51: static rmde_t *rmd; /* receive ring */
52: static char rbuffer[NRCVRING][LANCEBUFSIZE]; /* receive buffers */
53:
54: static char *top = (char *)RAMSIZE;
55: static char last;
56:
57: static char *
58: aalloc(size, align)
59: int size, align;
60: {
61: register char *p;
62: register int mask;
63:
64: if (align == 0)
65: align = sizeof(int);
66: mask = align - 1;
67: assert((align & mask) == 0);
68: top = top - (size + align);
69: p = (char *)((int)top & ~mask);
70: assert(p > &last);
71: assert(p <= (char *) RAMSIZE);
72: return top = p;
73: }
74:
75: /*
76: * Program DMA channel 'chan' for cascade mode
77: */
78: static void
79: dma_cascade(chan)
80: int chan;
81: {
82: assert(chan >= 0);
83: assert(chan <= 7);
84: if (chan >= 0 && chan <= 3) {
85: outb(0x0B, 0xC0 | (chan & 03));
86: outb(0x0A, chan & 03);
87: } else {
88: outb(0xD6, 0xC0 | ((chan - 4) & 03));
89: outb(0xD4, (chan - 4) & 03);
90: }
91: }
92:
93: /*
94: * Reset ethernet board (i.e. after a timeout)
95: */
96: void
97: EtherReset(void) {
98: long l;
99: u_long addr;
100: int i;
101:
102: /* program DMA chip */
103: dma_cascade(NE_DMACHANNEL);
104:
105: /* stop the chip, and make sure it did */
106: outw(LA_RAP, RDP_CSR0);
107: outw(LA_CSR, CSR_STOP);
108: for (l = 0; (inw(LA_CSR) & CSR_STOP) == 0; l++) {
109: if (l >= MAXLOOP) {
110: printf("Lance failed to stop\n");
111: return;
112: }
113: }
114:
115: /* fill lance initialization block */
116: bzero(initblock, sizeof(initblock_t));
117:
118: /* set my ethernet address */
119: initblock->ib_padr[0] = eth_myaddr[0];
120: initblock->ib_padr[1] = eth_myaddr[1];
121: initblock->ib_padr[2] = eth_myaddr[2];
122: initblock->ib_padr[3] = eth_myaddr[3];
123: initblock->ib_padr[4] = eth_myaddr[4];
124: initblock->ib_padr[5] = eth_myaddr[5];
125:
126: /* receive ring pointer */
127: addr = LA(rmd);
128: initblock->ib_rdralow = (u_short)addr;
129: initblock->ib_rdrahigh = (u_char)(addr >> 16);
130: initblock->ib_rlen = LOG2NRCVRING << 5;
131:
132: /* transmit ring with one element */
133: addr = LA(tmd);
134: initblock->ib_tdralow = (u_short)addr;
135: initblock->ib_tdrahigh = (u_char)(addr >> 16);
136: initblock->ib_tlen = 0 << 5;
137:
138: /* setup the receive ring entries */
139: for (next_rmd = 0, i = 0; i < NRCVRING; i++) {
140: addr = LA(&rbuffer[i]);
141: rmd[i].rmd_ladr = (u_short)addr;
142: rmd[i].rmd_hadr = (u_char)(addr >> 16);
143: rmd[i].rmd_mcnt = 0;
144: rmd[i].rmd_bcnt = -LANCEBUFSIZE;
145: rmd[i].rmd_flags = RMD_OWN;
146: }
147:
148: /* zero transmit ring */
149: bzero(tmd, sizeof(tmde_t));
150:
151: /* give lance the init block */
152: addr = LA(initblock);
153: outw(LA_RAP, RDP_CSR1);
154: outw(LA_CSR1, (u_short)addr);
155: outw(LA_RAP, RDP_CSR2);
156: outw(LA_CSR2, (char)(addr >> 16));
157: outw(LA_RAP, RDP_CSR3);
158: outw(LA_CSR3, 0);
159:
160: /* and initialize it */
161: outw(LA_RAP, RDP_CSR0);
162: outw(LA_CSR, CSR_INIT|CSR_STRT);
163:
164: /* wait for the lance to complete initialization and fire it up */
165: for (l = 0; (inw(LA_CSR) & CSR_IDON) == 0; l++) {
166: if (l >= MAXLOOP) {
167: printf("Lance failed to initialize\n");
168: break;
169: }
170: }
171: for (l=0; (inw(LA_CSR)&(CSR_TXON|CSR_RXON))!=(CSR_TXON|CSR_RXON); l++) {
172: if (l >= MAXLOOP) {
173: printf("Lance not started\n");
174: break;
175: }
176: }
177: }
178:
179: /*
180: * Get ethernet address and compute checksum to be sure
181: * that there is a board at this address.
182: */
183: int
184: EtherInit()
185: {
186: u_short checksum, sum;
187: int i;
188:
189: for (i = 0; i < 6; i++)
190: eth_myaddr[i] = inb(NE_BASEREG + i);
191:
192: sum = 0;
193: for (i = 0x00; i <= 0x0B; i++)
194: sum += inb(NE_BASEREG + i);
195: for (i = 0x0E; i <= 0xF; i++)
196: sum += inb(NE_BASEREG + i);
197: checksum = inb(NE_BASEREG + 0x0C) | (inb(NE_BASEREG + 0x0D) << 8);
198: if (sum != checksum)
199: return 0;
200:
201: /* initblock, tmd, and rmd should be 8 byte aligned ! */
202: initblock = (initblock_t *) aalloc(sizeof(initblock_t), 8);
203: tmd = (tmde_t *) aalloc(sizeof(tmde_t), 8);
204: rmd = (rmde_t *) aalloc(NRCVRING * sizeof(rmde_t), 8);
205: EtherReset();
206: return 1;
207: }
208:
209: /*
210: * Disable DMA for channel 'chan'
211: */
212: static void
213: dma_done(chan)
214: int chan;
215: {
216: assert(chan >= 0);
217: assert(chan <= 7);
218: if (chan >= 0 && chan <= 3)
219: outb(0x0A, 0x04 | (chan & 03));
220: else
221: outb(0xD4, 0x04 | ((chan - 4 ) & 03));
222: }
223:
224: /*
225: * Stop ethernet board
226: */
227: void
228: EtherStop()
229: {
230: long l;
231:
232: /* stop chip and disable DMA access */
233: outw(LA_RAP, RDP_CSR0);
234: outw(LA_CSR, CSR_STOP);
235: for (l = 0; (inw(LA_CSR) & CSR_STOP) == 0; l++) {
236: if (l >= MAXLOOP) {
237: printf("Lance failed to stop\n");
238: break;
239: }
240: }
241: dma_done(NE_DMACHANNEL);
242: }
243:
244: /*
245: * Send an ethernet packet to destination 'dest'
246: */
247: void
248: EtherSend(pkt, proto, dest)
249: packet_t *pkt;
250: u_short proto;
251: u_char *dest;
252: {
253: ethhdr_t *ep;
254: long l;
255: u_long addr;
256: u_short csr;
257:
258: /* add ethernet header and fill in source & destination */
259: pkt->pkt_len += sizeof(ethhdr_t);
260: pkt->pkt_offset -= sizeof(ethhdr_t);
261: ep = (ethhdr_t *) pkt->pkt_offset;
262: ep->eth_proto = htons(proto);
263: bcopy(dest, ep->eth_dst, ETH_ADDRSIZE);
264: bcopy(eth_myaddr, ep->eth_src, ETH_ADDRSIZE);
265: if (pkt->pkt_len < 60)
266: pkt->pkt_len = 60;
267: assert(pkt->pkt_len <= 1514);
268:
269: /* set up transmit ring element */
270: assert((tmd->tmd_flags & TMD_OWN) == 0);
271: addr = LA(pkt->pkt_offset);
272: assert((addr & 1) == 0);
273: tmd->tmd_ladr = (u_short)addr;
274: tmd->tmd_hadr = (u_char)(addr >> 16);
275: tmd->tmd_bcnt = -pkt->pkt_len;
276: tmd->tmd_err = 0;
277: tmd->tmd_flags = TMD_OWN|TMD_STP|TMD_ENP;
278:
279: /* start transmission */
280: outw(LA_CSR, CSR_TDMD);
281:
282: /* wait for interrupt and acknowledge it */
283: for (l = 0; l < MAXLOOP; l++) {
284: if ((csr = inw(LA_CSR)) & CSR_TINT) {
285: outw(LA_CSR, CSR_TINT);
286: break;
287: }
288: }
289: }
290:
291: /*
292: * Poll the LANCE just see if there's an Ethernet packet
293: * available. If there is, its contents is returned in a
294: * pkt structure, otherwise a nil pointer is returned.
295: */
296: packet_t *
297: EtherReceive(void) {
298: packet_t *pkt;
299: rmde_t *rp;
300: u_long addr;
301: u_short csr;
302:
303: pkt = (packet_t *)0;
304: if ((csr = inw(LA_CSR)) & CSR_RINT) {
305: outw(LA_CSR, CSR_RINT);
306: assert(next_rmd >= 0);
307: assert(next_rmd <= NRCVRING);
308: rp = &rmd[next_rmd];
309: if ((rp->rmd_flags & ~RMD_OFLO) == (RMD_STP|RMD_ENP)) {
310: pkt = PktAlloc(0);
311: pkt->pkt_len = rp->rmd_mcnt - 4;
312: assert(pkt->pkt_len >= 0);
313: assert(pkt->pkt_len < PKT_DATASIZE);
314: bcopy(rbuffer[next_rmd], pkt->pkt_offset, pkt->pkt_len);
315: /* give packet back to the lance */
316: rp->rmd_bcnt = -LANCEBUFSIZE;
317: rp->rmd_mcnt = 0;
318: rp->rmd_flags = RMD_OWN;
319: }
320: next_rmd = (next_rmd + 1) & (NRCVRING - 1);
321: }
322: return pkt;
323: }
324:
325: /*
326: * Print an ethernet address in human readable form
327: */
328: void
329: EtherPrintAddr(addr)
330: u_char *addr;
331: {
332: printf("%x:%x:%x:%x:%x:%x",
333: addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF,
334: addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF);
335: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.