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