|
|
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.