|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1997 Apple Computer, Inc. ! 27: * ! 28: * ethernet driver for mace on-board ethernet ! 29: * ! 30: * HISTORY ! 31: * ! 32: * Dieter Siegmund ([email protected]) Thu Feb 27 18:25:33 PST 1997 ! 33: * - ripped off code from MK/LINUX, turned it into a polled-mode ! 34: * driver for the PCI (8500) class machines ! 35: * ! 36: * Dieter Siegmund ([email protected]) Fri Mar 21 12:41:29 PST 1997 ! 37: * - reworked to support a BSD-style interface, and to support kdb polled ! 38: * interface and interrupt-driven interface concurrently ! 39: * ! 40: * Justin Walker ([email protected]) Tue May 20 10:29:29 PDT 1997 ! 41: * - Added multicast support ! 42: * ! 43: * Dieter Siegmund ([email protected]) Thu May 29 15:02:29 PDT 1997 ! 44: * - fixed problem with sending arp packets for ip address 0.0.0.0 ! 45: * - use kdp_register_send_receive() instead of defining ! 46: * en_send_pkt/en_recv_pkt routines to avoid name space ! 47: * collisions with IOEthernetDebugger and allow these routines to be ! 48: * overridden by a driverkit-style driver ! 49: * ! 50: * Dieter Siegmund ([email protected]) Tue Jun 24 18:29:15 PDT 1997 ! 51: * - don't let the adapter auto-strip 802.3 receive frames, it messes ! 52: * up the frame size logic ! 53: * ! 54: * Dieter Siegmund ([email protected]) Tue Aug 5 16:24:52 PDT 1997 ! 55: * - handle multicast address deletion correctly ! 56: */ ! 57: #ifdef MACE_DEBUG ! 58: /* ! 59: * Caveat: MACE_DEBUG delimits some code that is getting kind of ! 60: * stale. Before blindly turning on MACE_DEBUG for your ! 61: * testing, take a look at the code enabled by it to check ! 62: * that it is reasonably sane. ! 63: */ ! 64: #endif ! 65: ! 66: #import <machdep/ppc/dbdma.h> ! 67: #import <kern/kdp_en_debugger.h> ! 68: ! 69: #define RECEIVE_INT DBDMA_INT_ALWAYS ! 70: ! 71: #import <sys/types.h> ! 72: #import <sys/systm.h> ! 73: #import <sys/param.h> ! 74: #import <sys/errno.h> ! 75: #import <sys/socket.h> ! 76: #import <net/if.h> ! 77: #import <net/etherdefs.h> ! 78: #import <netinet/if_ether.h> ! 79: #import <sys/sockio.h> ! 80: #import <netinet/in_var.h> ! 81: #import <netinet/in.h> ! 82: #import <sys/mbuf.h> ! 83: #import <mach/mach_types.h> ! 84: #import <ppc/powermac.h> ! 85: #import <ppc/interrupts.h> ! 86: #import <ppc/proc_reg.h> ! 87: #import <libkern/libkern.h> ! 88: #import <kern/thread_call.h> ! 89: #import "if_en.h" ! 90: #import "mace.h" ! 91: ! 92: extern int kdp_flag; ! 93: ! 94: #if NBPFILTER > 0 ! 95: #import <net/bpf.h> ! 96: #endif ! 97: ! 98: static void polled_send_pkt(char * data, int len); ! 99: static void polled_receive_pkt(char *data, int *len, int timeout_ms); ! 100: void mace_dbdma_rx_intr(int unit, void *, void *); ! 101: void mace_dbdma_tx_intr(int, void *, void *); ! 102: void mace_pci_intr(int, void *); ! 103: void mace_service_queue(struct ifnet * ifp); ! 104: ! 105: #ifdef MACE_DEBUG ! 106: static int mace_watchdog(); ! 107: #endif ! 108: ! 109: static __inline__ vm_offset_t ! 110: KVTOPHYS(vm_offset_t v) ! 111: { ! 112: return (v); ! 113: } ! 114: ! 115: typedef int (*funcptr)(char *, int, void *); ! 116: ! 117: #ifdef MACE_DEBUG ! 118: static int ! 119: macAddrsEqual(unsigned char * one, unsigned char * two) ! 120: { ! 121: int i; ! 122: ! 123: for (i = 0; i < NUM_EN_ADDR_BYTES; i++) ! 124: if (*one++ != *two++) ! 125: return 0; ! 126: return 1; ! 127: } ! 128: #endif ! 129: ! 130: static __inline__ int ! 131: isprint(unsigned char c) ! 132: { ! 133: return (c >= 0x20 && c <= 0x7e); ! 134: } ! 135: ! 136: static void ! 137: printEtherHeader(enet_addr_t * dh, enet_addr_t * sh, u_short etype) ! 138: { ! 139: u_char * dhost = dh->ether_addr_octet; ! 140: u_char * shost = sh->ether_addr_octet; ! 141: ! 142: printf("Dst: %x:%x:%x:%x:%x:%x Src: %x:%x:%x:%x:%x:%x Type: 0x%x\n", ! 143: dhost[0], dhost[1], dhost[2], dhost[3], dhost[4], dhost[5], ! 144: shost[0], shost[1], shost[2], shost[3], shost[4], shost[5], ! 145: etype); ! 146: } ! 147: ! 148: static void ! 149: printData(u_char * data_p, int n_bytes) ! 150: { ! 151: #define CHARS_PER_LINE 16 ! 152: char line_buf[CHARS_PER_LINE + 1]; ! 153: int line_pos; ! 154: int offset; ! 155: ! 156: for (line_pos = 0, offset = 0; offset < n_bytes; offset++, data_p++) { ! 157: if (line_pos == 0) { ! 158: printf("%04d ", offset); ! 159: } ! 160: ! 161: line_buf[line_pos] = isprint(*data_p) ? *data_p : '.'; ! 162: printf(" %02x", *data_p); ! 163: line_pos++; ! 164: if (line_pos == CHARS_PER_LINE) { ! 165: line_buf[CHARS_PER_LINE] = '\0'; ! 166: printf(" %s\n", line_buf); ! 167: line_pos = 0; ! 168: } ! 169: } ! 170: if (line_pos) { /* need to finish up the line */ ! 171: for (; line_pos < CHARS_PER_LINE; line_pos++) { ! 172: printf(" "); ! 173: line_buf[line_pos] = ' '; ! 174: } ! 175: line_buf[CHARS_PER_LINE] = '\0'; ! 176: printf(" %s\n", line_buf); ! 177: } ! 178: } ! 179: ! 180: static void ! 181: printEtherPacket(enet_addr_t * dhost, enet_addr_t * shost, u_short type, ! 182: u_char * data_p, int n_bytes) ! 183: { ! 184: printEtherHeader(dhost, shost, type); ! 185: printData(data_p, n_bytes); ! 186: } ! 187: ! 188: void ! 189: printContiguousEtherPacket(u_char * data_p, int n_bytes) ! 190: { ! 191: printEtherPacket((enet_addr_t *)data_p, ! 192: (enet_addr_t *)(data_p + NUM_EN_ADDR_BYTES), ! 193: *((u_short *)(data_p + (NUM_EN_ADDR_BYTES * 2))), ! 194: data_p, n_bytes); ! 195: } ! 196: ! 197: mace_t mace; ! 198: ! 199: #define MACE_DMA_AREA_SIZE (ETHER_RX_NUM_DBDMA_BUFS * ETHERNET_BUF_SIZE + PG_SIZE) ! 200: static unsigned long mace_rx_dma_area[(MACE_DMA_AREA_SIZE + sizeof(long))/sizeof(long)]; ! 201: ! 202: static unsigned long mace_tx_dma_area[(ETHERNET_BUF_SIZE + PG_SIZE + sizeof(long))/sizeof(long)]; ! 203: ! 204: /* ! 205: * mace_get_hwid ! 206: * ! 207: * This function computes the Ethernet Hardware address ! 208: * from PROM. (Its best not to ask how this is done.) ! 209: */ ! 210: ! 211: unsigned char ! 212: mace_swapbits(unsigned char bits) ! 213: { ! 214: unsigned char mask = 0x1, i, newbits = 0; ! 215: ! 216: for (i = 0x80; i; mask <<= 1, i >>=1) { ! 217: if (bits & mask) ! 218: newbits |= i; ! 219: } ! 220: ! 221: return newbits; ! 222: } ! 223: ! 224: void ! 225: mace_get_hwid(unsigned char *hwid_addr, mace_t * m) ! 226: { ! 227: int i; ! 228: ! 229: for (i = 0; i < NUM_EN_ADDR_BYTES; i++, hwid_addr += 16) { ! 230: m->macaddr[i] = mace_swapbits(*hwid_addr); ! 231: } ! 232: } ! 233: ! 234: /* ! 235: * mace_reset ! 236: * ! 237: * Reset the board.. ! 238: */ ! 239: ! 240: void ! 241: mace_reset() ! 242: { ! 243: dbdma_reset(DBDMA_ETHERNET_RV); ! 244: dbdma_reset(DBDMA_ETHERNET_TX); ! 245: } ! 246: ! 247: ! 248: /* ! 249: * mace_geteh: ! 250: * ! 251: * This function gets the ethernet address (array of 6 unsigned ! 252: * bytes) from the MACE board registers. ! 253: * ! 254: */ ! 255: ! 256: void ! 257: mace_geteh(char *ep) ! 258: { ! 259: int i; ! 260: unsigned char ep_temp; ! 261: ! 262: mace.ereg->iac = IAC_PHYADDR; eieio(); ! 263: ! 264: for (i = 0; i < ETHER_ADD_SIZE; i++) { ! 265: ep_temp = mace.ereg->padr; eieio(); ! 266: *ep++ = ep_temp; ! 267: } ! 268: } ! 269: ! 270: /* ! 271: * mace_seteh: ! 272: * ! 273: * This function sets the ethernet address (array of 6 unsigned ! 274: * bytes) on the MACE board. ! 275: */ ! 276: ! 277: static void ! 278: mace_seteh(char *ep) ! 279: { ! 280: int i; ! 281: unsigned char status; ! 282: ! 283: if (mace.chip_id != MACE_REVISION_A2) { ! 284: mace.ereg->iac = IAC_ADDRCHG|IAC_PHYADDR; eieio(); ! 285: ! 286: while ((status = mace.ereg->iac)) { ! 287: if ((status & IAC_ADDRCHG) == 0) { ! 288: eieio(); ! 289: break; ! 290: } ! 291: eieio(); ! 292: } ! 293: } ! 294: else { ! 295: /* start to load the address.. */ ! 296: mace.ereg->iac = IAC_PHYADDR; eieio(); ! 297: } ! 298: ! 299: for (i = 0; i < NUM_EN_ADDR_BYTES; i++) { ! 300: mace.ereg->padr = *(ep+i); eieio(); ! 301: } ! 302: return; ! 303: } ! 304: ! 305: /* ! 306: * mace_setup_dbdma ! 307: * ! 308: * Setup various dbdma pointers. ! 309: */ ! 310: ! 311: void ! 312: mace_setup_dbdma() ! 313: { ! 314: mace_t * m = &mace; ! 315: int i; ! 316: dbdma_command_t * d; ! 317: vm_offset_t address; ! 318: dbdma_regmap_t * regmap; ! 319: ! 320: #define ALIGN_MASK 0xfffffffcUL ! 321: if (m->rv_dma_area == 0) { ! 322: m->rv_dma_area = (unsigned char *) ! 323: ((((unsigned long)mace_rx_dma_area) + 3) & ALIGN_MASK); ! 324: m->rv_dma = dbdma_alloc(ETHER_RX_NUM_DBDMA_BUFS + 2); ! 325: m->tx_dma = dbdma_alloc(TX_NUM_DBDMA); ! 326: m->tx_dma_area = (unsigned char *) ! 327: ((((unsigned long)mace_tx_dma_area) + 3) & ALIGN_MASK); ! 328: } ! 329: ! 330: /* set up a ring of buffers */ ! 331: d = m->rv_dma; ! 332: for (i = 0; i < ETHER_RX_NUM_DBDMA_BUFS; i++, d++) { ! 333: address = (vm_offset_t) KVTOPHYS((vm_offset_t)&m->rv_dma_area[i*ETHERNET_BUF_SIZE]); ! 334: DBDMA_BUILD(d, DBDMA_CMD_IN_LAST, 0, ETHERNET_BUF_SIZE, ! 335: address, RECEIVE_INT, ! 336: DBDMA_WAIT_NEVER, ! 337: DBDMA_BRANCH_NEVER); ! 338: } ! 339: ! 340: /* stop when we hit the end of the list */ ! 341: DBDMA_BUILD(d, DBDMA_CMD_STOP, 0, 0, 0, RECEIVE_INT, ! 342: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); ! 343: d++; ! 344: ! 345: /* branch to command at "address" ie. element 0 of the "array" */ ! 346: DBDMA_BUILD(d, DBDMA_CMD_NOP, 0, 0, 0, DBDMA_INT_NEVER, ! 347: DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); ! 348: address = (vm_offset_t) KVTOPHYS((vm_offset_t)m->rv_dma); ! 349: dbdma_st4_endian(&d->d_cmddep, address); ! 350: ! 351: m->rv_head = 0; ! 352: m->rv_tail = ETHER_RX_NUM_DBDMA_BUFS; /* always contains DBDMA_CMD_STOP */ ! 353: ! 354: /* stop/init/restart dma channel */ ! 355: dbdma_reset(DBDMA_ETHERNET_RV); ! 356: dbdma_reset(DBDMA_ETHERNET_TX); ! 357: ! 358: /* Set the wait value.. */ ! 359: regmap = DBDMA_REGMAP(DBDMA_ETHERNET_RV); ! 360: dbdma_st4_endian(®map->d_wait, DBDMA_SET_CNTRL(0x00)); ! 361: ! 362: /* Set the tx wait value */ ! 363: regmap = DBDMA_REGMAP(DBDMA_ETHERNET_TX); ! 364: dbdma_st4_endian(®map->d_wait, DBDMA_SET_CNTRL(0x20)); ! 365: ! 366: flush_cache_v((vm_offset_t)m->rv_dma, ! 367: sizeof(dbdma_command_t) * (ETHER_RX_NUM_DBDMA_BUFS + 2)); ! 368: /* start receiving */ ! 369: dbdma_start(DBDMA_ETHERNET_RV, m->rv_dma); ! 370: } ! 371: ! 372: #ifdef MACE_DEBUG ! 373: static unsigned char testBuffer[PG_SIZE * 4]; ! 374: static unsigned char testMsg[] = "mace ethernet interface test"; ! 375: ! 376: static void ! 377: send_test_packet() ! 378: { ! 379: unsigned char * tp; ! 380: ! 381: bzero(testBuffer, sizeof(testBuffer)); ! 382: ! 383: tp = testBuffer; ! 384: ! 385: /* send self-addressed packet */ ! 386: bcopy(&mace.macaddr[0], tp, NUM_EN_ADDR_BYTES); ! 387: tp += NUM_EN_ADDR_BYTES; ! 388: bcopy(&mace.macaddr[0], tp, NUM_EN_ADDR_BYTES); ! 389: tp += NUM_EN_ADDR_BYTES; ! 390: *tp++ = 0; ! 391: *tp++ = 0; ! 392: bcopy(testMsg, tp, sizeof(testMsg)); ! 393: polled_send_pkt(testBuffer, 80); ! 394: return; ! 395: } ! 396: #endif ! 397: ! 398: /* ! 399: * Function: init_mace ! 400: * ! 401: * Purpose: ! 402: * Called early on, initializes the adapter and readies it for ! 403: * kdb kernel debugging. ! 404: */ ! 405: void ! 406: init_mace() ! 407: { ! 408: unsigned char status; ! 409: mace_t * m = &mace; ! 410: struct mace_board * ereg; ! 411: int mpc = 0; ! 412: ! 413: /* ! 414: * Only use in-kernel driver for early debugging (bootargs: kdp=1 or kdp=3) ! 415: */ ! 416: if ( (kdp_flag & 1) == 0 ) ! 417: { ! 418: return; ! 419: } ! 420: ! 421: bzero(&mace, sizeof(mace)); ! 422: ! 423: /* get the ethernet registers' mapped address */ ! 424: ereg = m->ereg ! 425: = (struct mace_board *) POWERMAC_IO(PCI_ETHERNET_BASE_PHYS); ! 426: mace_get_hwid((unsigned char *)POWERMAC_IO(PCI_ETHERNET_ADDR_PHYS), m); ! 427: ! 428: /* Reset the board & AMIC.. */ ! 429: mace_reset(); ! 430: ! 431: /* grab the MACE chip rev */ ! 432: m->chip_id = (ereg->chipid2 << 8 | ereg->chipid1); ! 433: ! 434: /* don't auto-strip for 802.3 */ ! 435: m->ereg->rcvfc &= ~(RCVFC_ASTRPRCV); ! 436: ! 437: /* set the ethernet address */ ! 438: mace_seteh(mace.macaddr); ! 439: { ! 440: unsigned char macaddr[NUM_EN_ADDR_BYTES]; ! 441: mace_geteh(macaddr); ! 442: printf("mace ethernet [%02x:%02x:%02x:%02x:%02x:%02x]\n", ! 443: macaddr[0], macaddr[1], macaddr[2], ! 444: macaddr[3], macaddr[4], macaddr[5]); ! 445: } ! 446: ! 447: /* Now clear the Multicast filter */ ! 448: if (m->chip_id != MACE_REVISION_A2) { ! 449: ereg->iac = IAC_ADDRCHG|IAC_LOGADDR; eieio(); ! 450: ! 451: while ((status = ereg->iac)) { ! 452: if ((status & IAC_ADDRCHG) == 0) ! 453: break; ! 454: eieio(); ! 455: } ! 456: eieio(); ! 457: } ! 458: else { ! 459: ereg->iac = IAC_LOGADDR; eieio(); ! 460: } ! 461: { ! 462: int i; ! 463: ! 464: for (i=0; i < 8; i++) ! 465: { ereg->ladrf = 0; ! 466: eieio(); ! 467: } ! 468: } ! 469: ! 470: /* register interrupt routines */ ! 471: mace_setup_dbdma(); ! 472: ! 473: /* Start the chip... */ ! 474: m->ereg->maccc = MACCC_ENXMT|MACCC_ENRCV; eieio(); ! 475: { ! 476: volatile char ch = mace.ereg->ir; eieio(); ! 477: } ! 478: ! 479: delay(500); /* paranoia */ ! 480: mace.ereg->imr = 0xfe; eieio(); ! 481: ! 482: /* register our debugger routines */ ! 483: kdp_register_send_receive((kdp_send_t)polled_send_pkt, ! 484: (kdp_receive_t)polled_receive_pkt); ! 485: ! 486: #if 0 ! 487: printf("Testing 1 2 3\n"); ! 488: send_test_packet(); ! 489: printf("Testing 1 2 3\n"); ! 490: send_test_packet(); ! 491: printf("Testing 1 2 3\n"); ! 492: send_test_packet(); ! 493: do { ! 494: static unsigned char buf[ETHERNET_BUF_SIZE]; ! 495: int len; ! 496: int nmpc = mace.ereg->mpc; eieio(); ! 497: ! 498: if (nmpc > mpc) { ! 499: mpc = nmpc; ! 500: printf("mpc %d\n", mpc); ! 501: } ! 502: polled_receive_pkt(buf, &len, 100); ! 503: if (len > 0) { ! 504: printf("rx %d\n", len); ! 505: printContiguousEtherPacket(buf, len); ! 506: } ! 507: } while(1); ! 508: #endif ! 509: ! 510: return; ! 511: } ! 512: ! 513: #ifdef MACE_DEBUG ! 514: static void ! 515: txstatus(char * msg) ! 516: { ! 517: volatile dbdma_regmap_t * dmap = DBDMA_REGMAP(DBDMA_ETHERNET_TX); ! 518: volatile unsigned long status; ! 519: volatile unsigned long intr; ! 520: volatile unsigned long branch; ! 521: volatile unsigned long wait; ! 522: ! 523: status = dbdma_ld4_endian(&dmap->d_status); eieio(); ! 524: intr = dbdma_ld4_endian(&dmap->d_intselect); eieio(); ! 525: branch = dbdma_ld4_endian(&dmap->d_branch); eieio(); ! 526: wait = dbdma_ld4_endian(&dmap->d_wait); eieio(); ! 527: printf("(%s s=0x%x i=0x%x b=0x%x w=0x%x)", msg, status, intr, branch, ! 528: wait); ! 529: return; ! 530: } ! 531: #endif ! 532: ! 533: static void ! 534: tx_dbdma(char * data, int len) ! 535: { ! 536: unsigned long count; ! 537: dbdma_command_t * d; ! 538: unsigned long page; ! 539: ! 540: d = mace.tx_dma; ! 541: page = ((unsigned long) data) & PG_MASK; ! 542: if ((page + len) <= PG_SIZE) { /* one piece dma */ ! 543: DBDMA_BUILD(d, DBDMA_CMD_OUT_LAST, DBDMA_KEY_STREAM0, ! 544: len, ! 545: (vm_offset_t) KVTOPHYS((vm_offset_t) data), ! 546: DBDMA_INT_NEVER, ! 547: DBDMA_WAIT_IF_FALSE, DBDMA_BRANCH_NEVER); ! 548: } ! 549: else { /* two piece dma */ ! 550: count = PG_SIZE - page; ! 551: DBDMA_BUILD(d, DBDMA_CMD_OUT_MORE, DBDMA_KEY_STREAM0, ! 552: count, ! 553: (vm_offset_t)KVTOPHYS((vm_offset_t) data), ! 554: DBDMA_INT_NEVER, ! 555: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); ! 556: d++; ! 557: DBDMA_BUILD(d, DBDMA_CMD_OUT_LAST, DBDMA_KEY_STREAM0, ! 558: len - count, (vm_offset_t) ! 559: KVTOPHYS((vm_offset_t)((unsigned char *)data + count)), ! 560: DBDMA_INT_NEVER, ! 561: DBDMA_WAIT_IF_FALSE, DBDMA_BRANCH_NEVER); ! 562: } ! 563: d++; ! 564: DBDMA_BUILD(d, DBDMA_CMD_LOAD_QUAD, DBDMA_KEY_SYSTEM, ! 565: 1, KVTOPHYS((vm_offset_t) &mace.ereg->xmtfs),DBDMA_INT_NEVER, ! 566: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); ! 567: d++; ! 568: DBDMA_BUILD(d, DBDMA_CMD_LOAD_QUAD, DBDMA_KEY_SYSTEM, ! 569: 1, KVTOPHYS((vm_offset_t) &mace.ereg->ir), DBDMA_INT_ALWAYS, ! 570: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); ! 571: d++; ! 572: DBDMA_BUILD(d, DBDMA_CMD_STOP, 0, 0, 0, 0, 0, 0); ! 573: flush_cache_v((vm_offset_t)mace.tx_dma, sizeof(dbdma_command_t) * TX_NUM_DBDMA); ! 574: dbdma_start(DBDMA_ETHERNET_TX, mace.tx_dma); ! 575: return; ! 576: ! 577: } ! 578: ! 579: static void ! 580: waitForDBDMADone(char * msg) ! 581: { ! 582: { ! 583: /* wait for tx dma completion */ ! 584: volatile dbdma_regmap_t * dmap = DBDMA_REGMAP(DBDMA_ETHERNET_TX); ! 585: int i; ! 586: volatile unsigned long val; ! 587: ! 588: i = 0; ! 589: do { ! 590: val = dbdma_ld4_endian(&dmap->d_status); eieio(); ! 591: delay(50); ! 592: i++; ! 593: } while ((i < 100000) && (val & DBDMA_CNTRL_ACTIVE)); ! 594: if (i == 100000) ! 595: printf("mace(%s): tx_dbdma poll timed out 0x%x", msg, val); ! 596: } ! 597: } ! 598: ! 599: void ! 600: mace_service_queue(struct ifnet * ifp) ! 601: { ! 602: unsigned char * buf_p; ! 603: struct mbuf * m; ! 604: struct mbuf * mp; ! 605: int len; ! 606: ! 607: if (mace.tx_busy) { /* transmit in progress? */ ! 608: return; ! 609: } ! 610: ! 611: IF_DEQUEUE(&(ifp->if_snd), m); ! 612: if (m == 0) { ! 613: return; ! 614: } ! 615: ! 616: len = m->m_pkthdr.len; ! 617: ! 618: if (len > ETHERMAXPACKET) { ! 619: printf("mace_start: packet too big (%d), dropping\n", len); ! 620: m_freem(m); ! 621: return; ! 622: ! 623: } ! 624: buf_p = mace.tx_dma_area; ! 625: if (m->m_nextpkt) { ! 626: printf("mace: sending more than one mbuf\n"); ! 627: } ! 628: for (mp = m; mp; mp = mp->m_next) { ! 629: if (mp->m_len == 0) ! 630: continue; ! 631: bcopy(mtod(mp, caddr_t), buf_p, min(mp->m_len, len)); ! 632: len -= mp->m_len; ! 633: buf_p += mp->m_len; ! 634: } ! 635: m_freem(m); ! 636: ! 637: #if NBPFILTER > 0 ! 638: if (ifp->if_bpf) ! 639: BPF_TAP(ifp->if_bpf, mace.tx_dma_area, m->m_pkthdr.len); ! 640: #endif ! 641: ! 642: #if 0 ! 643: printf("tx packet %d\n", m->m_pkthdr.len); ! 644: printContiguousEtherPacket(mace.tx_dma_area, m->m_pkthdr.len); ! 645: #endif ! 646: ! 647: /* fill in the dbdma records and kick off the dma */ ! 648: tx_dbdma(mace.tx_dma_area, m->m_pkthdr.len); ! 649: mace.tx_busy = 1; ! 650: return; ! 651: } ! 652: ! 653: #ifdef MACE_DEBUG ! 654: static int ! 655: mace_watchdog() ! 656: { ! 657: struct ifnet * ifp = &mace.en_arpcom.ac_if; ! 658: int s; ! 659: ! 660: mace.txwatchdog++; ! 661: s = splnet(); ! 662: if (mace.rxintr == 0) { ! 663: printf("rx is hung up\n"); ! 664: rx_intr(); ! 665: } ! 666: mace.rxintr = 0; ! 667: #if 0 ! 668: if (mace.txintr == 0 && ifp->if_snd.ifq_head) { ! 669: if (mace.tx_busy) ! 670: dbdma_stop(DBDMA_ETHERNET_TX); ! 671: mace.tx_busy = 0; ! 672: mace_service_queue(ifp); ! 673: } ! 674: mace.txintr = 0; ! 675: #endif ! 676: timeout(mace_watchdog, 0, 10*hz); /* just in case we drop an interrupt */ ! 677: return (0); ! 678: } ! 679: #endif /* MACE_DEBUG */ ! 680: ! 681: static int ! 682: mace_start(struct ifnet * ifp) ! 683: { ! 684: // int i = mace.tx_busy; ! 685: ! 686: // printf("mace_start %s\n", mace.tx_busy ? "(txBusy)" : ""); ! 687: mace_service_queue(ifp); ! 688: ! 689: // if (mace.tx_busy && !i) ! 690: // printf("(txStarted)\n"); ! 691: return 0; ! 692: } ! 693: ! 694: int ! 695: mace_recv_pkt(funcptr pktfunc, void * p) ! 696: { ! 697: vm_offset_t address; ! 698: struct mace_board * board; ! 699: long bytes; ! 700: int done = 0; ! 701: int doContinue = 0; ! 702: mace_t * m; ! 703: unsigned long resid; ! 704: unsigned short status; ! 705: int tail; ! 706: ! 707: m = &mace; ! 708: board = m->ereg; ! 709: ! 710: /* remember where the tail was */ ! 711: tail = m->rv_tail; ! 712: for (done = 0; (done == 0) && (m->rv_head != tail);) { ! 713: dbdma_command_t * dmaHead; ! 714: ! 715: dmaHead = &m->rv_dma[m->rv_head]; ! 716: resid = dbdma_ld4_endian(&dmaHead->d_status_resid); ! 717: status = (resid >> 16); ! 718: bytes = resid & 0xffff; ! 719: bytes = ETHERNET_BUF_SIZE - bytes - 8; /* strip off FCS/CRC */ ! 720: ! 721: if ((status & DBDMA_ETHERNET_EOP) == 0) { ! 722: /* no packets are ready yet */ ! 723: break; ! 724: } ! 725: doContinue = 1; ! 726: /* if the packet is good, pass it up */ ! 727: if (bytes >= (ETHER_MIN_PACKET - 4)) { ! 728: char * dmaPacket; ! 729: dmaPacket = &m->rv_dma_area[m->rv_head * ETHERNET_BUF_SIZE]; ! 730: done = (*pktfunc)(dmaPacket, bytes, p); ! 731: } ! 732: /* mark the head as the new tail in the dma channel command list */ ! 733: DBDMA_BUILD(dmaHead, DBDMA_CMD_STOP, 0, 0, 0, RECEIVE_INT, ! 734: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); ! 735: flush_cache_v((vm_offset_t)dmaHead, sizeof(*dmaHead)); ! 736: eieio(); ! 737: ! 738: /* make the tail an available dma'able entry */ ! 739: { ! 740: dbdma_command_t * dmaTail; ! 741: dmaTail = &m->rv_dma[m->rv_tail]; ! 742: address = KVTOPHYS((vm_offset_t) ! 743: &m->rv_dma_area[m->rv_tail*ETHERNET_BUF_SIZE]); ! 744: // this command is live so write it carefully ! 745: DBDMA_ST4_ENDIAN(&dmaTail->d_address, address); ! 746: dmaTail->d_status_resid = 0; ! 747: dmaTail->d_cmddep = 0; ! 748: eieio(); ! 749: DBDMA_ST4_ENDIAN(&dmaTail->d_cmd_count, ! 750: ((DBDMA_CMD_IN_LAST) << 28) | ((0) << 24) | ! 751: ((RECEIVE_INT) << 20) | ! 752: ((DBDMA_BRANCH_NEVER) << 18) | ((DBDMA_WAIT_NEVER) << 16) | ! 753: (ETHERNET_BUF_SIZE)); ! 754: eieio(); ! 755: flush_cache_v((vm_offset_t)dmaTail, sizeof(*dmaTail)); ! 756: } ! 757: /* head becomes the tail */ ! 758: m->rv_tail = m->rv_head; ! 759: ! 760: /* advance the head */ ! 761: m->rv_head++; ! 762: if (m->rv_head == (ETHER_RX_NUM_DBDMA_BUFS + 1)) ! 763: m->rv_head = 0; ! 764: } ! 765: if (doContinue) { ! 766: sync(); ! 767: dbdma_continue(DBDMA_ETHERNET_RV); ! 768: } ! 769: return (done); ! 770: } ! 771: ! 772: /* kdb handle buffer routines */ ! 773: struct kdbCopy { ! 774: int * len; ! 775: char * data; ! 776: }; ! 777: ! 778: static int ! 779: kdb_copy(char * pktBuf, int len, void * p) ! 780: { ! 781: struct kdbCopy * cp = (struct kdbCopy *)p; ! 782: ! 783: bcopy(pktBuf, cp->data, len); ! 784: *cp->len = len; ! 785: return (1); /* signal that we're done */ ! 786: } ! 787: ! 788: /* kdb debugger routines */ ! 789: static void ! 790: polled_send_pkt(char * data, int len) ! 791: { ! 792: waitForDBDMADone("mace: polled_send_pkt start"); ! 793: tx_dbdma(data, len); ! 794: waitForDBDMADone("mace: polled_send_pkt end"); ! 795: return; ! 796: } ! 797: ! 798: static void ! 799: polled_receive_pkt(char *data, int *len, int timeout_ms) ! 800: { ! 801: struct kdbCopy cp; ! 802: ! 803: cp.len = len; ! 804: cp.data = data; ! 805: ! 806: timeout_ms *= 1000; ! 807: *len = 0; ! 808: while (mace_recv_pkt(kdb_copy, (void *)&cp) == 0) { ! 809: if (timeout_ms <= 0) ! 810: break; ! 811: delay(50); ! 812: timeout_ms -= 50; ! 813: } ! 814: return; ! 815: } ! 816: ! 817: /* Bump to force ethernet data to be 4-byte aligned ! 818: * (since the ethernet header is 14 bytes, and the 802.3 header is ! 819: * 22 = 14+8 bytes). This assumes that m_data is word-aligned ! 820: * (which it is). ! 821: */ ! 822: #define ETHER_DATA_ALIGN 2 ! 823: ! 824: /* ! 825: * Function: rxpkt ! 826: * ! 827: * Purpose: ! 828: * Called from within mace_recv_pkt to deal with a packet of data. ! 829: * rxpkt() allocates an mbuf(+cluser) and passes it up to the stacks. ! 830: * Returns: ! 831: * 0 if the packet was copied to an mbuf, 1 otherwise ! 832: */ ! 833: static int ! 834: rxpkt(char * data, int len, void * p) ! 835: { ! 836: struct ether_header * eh_p = (struct ether_header *)data; ! 837: struct ifnet * ifp = &mace.en_arpcom.ac_if; ! 838: struct mbuf * m; ! 839: ! 840: int interesting; ! 841: ! 842: mace.rxintr++; ! 843: ! 844: /* mcast, bcast -- we're interested in either */ ! 845: interesting = eh_p->ether_dhost[0] & 1; ! 846: ! 847: #if NBPFILTER > 0 ! 848: /* ! 849: * Check if there's a bpf filter listening on this interface. ! 850: * If so, hand off the raw packet to bpf_tap(). ! 851: */ ! 852: if (ifp->if_bpf) { ! 853: BPF_TAP(ifp->if_bpf, data, len); ! 854: ! 855: /* ! 856: * Keep the packet if it's a broadcast or has our ! 857: * physical ethernet address (or if we support ! 858: * multicast and it's one). ! 859: */ ! 860: if ((interesting == 0) && bcmp(eh_p->ether_dhost, mace.macaddr, ! 861: sizeof(eh_p->ether_dhost)) != 0) { ! 862: return (1); ! 863: } ! 864: } ! 865: #endif ! 866: ! 867: /* ! 868: * We "know" a full-sized packet fits in one cluster. Set up the ! 869: * packet header, and if the length is sufficient, attempt to allocate ! 870: * a cluster. If that fails, fall back to the old way (m_devget()). ! 871: * Here, we take the simple approach of cluster vs. single mbuf. ! 872: */ ! 873: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 874: if (m == 0) { ! 875: #ifdef MACE_DEBUG ! 876: printf("mget failed\n"); ! 877: #endif ! 878: return (1); ! 879: } ! 880: ! 881: if (len > (MHLEN - ETHER_DATA_ALIGN)) ! 882: { MCLGET(m, M_DONTWAIT); ! 883: if (m->m_flags&M_EXT) /* MCLGET succeeded */ ! 884: { m->m_data += ETHER_DATA_ALIGN; ! 885: bcopy(data, mtod(m, caddr_t), (unsigned)len); ! 886: } else ! 887: { ! 888: #ifdef MACE_DEBUG ! 889: printf("no clusters\n"); ! 890: #endif ! 891: m_free(m); ! 892: m = (struct mbuf *)m_devget(data, len, 0, ifp, 0); ! 893: if (m == 0) ! 894: return (1); ! 895: } ! 896: } else ! 897: { m->m_data += ETHER_DATA_ALIGN; ! 898: bcopy(data, mtod(m, caddr_t), (unsigned)len); ! 899: } ! 900: ! 901: /* ! 902: * Current code up the line assumes that the media header's been ! 903: * stripped, but we'd like to preserve it, just in case someone ! 904: * wants to peek. ! 905: */ ! 906: m->m_pkthdr.len = len; ! 907: m->m_len = len; ! 908: m->m_pkthdr.rcvif = ifp; ! 909: m->m_data += sizeof(*eh_p); ! 910: m->m_len -= sizeof (*eh_p); ! 911: m->m_pkthdr.len -= sizeof(*eh_p); ! 912: ether_input(ifp, eh_p, m); ! 913: ! 914: return (0); ! 915: } ! 916: ! 917: ! 918: static void ! 919: rx_intr() ! 920: { ! 921: mace_recv_pkt(rxpkt, 0); ! 922: } ! 923: ! 924: void ! 925: mace_dbdma_rx_intr(int unit, void *ignored, void * arp) ! 926: { ! 927: if (!mace.ready) ! 928: return; ! 929: ! 930: thread_call_func((thread_call_func_t)rx_intr, 0, TRUE); ! 931: } ! 932: ! 933: ! 934: int ! 935: mace_ioctl(struct ifnet * ifp,u_long cmd, caddr_t data) ! 936: { ! 937: struct arpcom * ar; ! 938: unsigned error = 0; ! 939: struct ifaddr * ifa = (struct ifaddr *)data; ! 940: struct ifreq * ifr = (struct ifreq *)data; ! 941: struct sockaddr_in * sin; ! 942: ! 943: sin = (struct sockaddr_in *)(&((struct ifreq *)data)->ifr_addr); ! 944: ar = (struct arpcom *)ifp; ! 945: ! 946: switch (cmd) { ! 947: case SIOCAUTOADDR: ! 948: error = in_bootp(ifp, sin, &mace.en_arpcom.ac_enaddr); ! 949: break; ! 950: ! 951: case SIOCSIFADDR: ! 952: #if NeXT ! 953: ifp->if_flags |= (IFF_UP | IFF_RUNNING); ! 954: #else ! 955: ifp->if_flags |= IFF_UP; ! 956: #endif ! 957: switch (ifa->ifa_addr->sa_family) { ! 958: case AF_INET: ! 959: /* ! 960: * See if another station has *our* IP address. ! 961: * i.e.: There is an address conflict! If a ! 962: * conflict exists, a message is sent to the ! 963: * console. ! 964: */ ! 965: if (IA_SIN(ifa)->sin_addr.s_addr != 0) { /* don't bother for 0.0.0.0 */ ! 966: ar->ac_ipaddr = IA_SIN(ifa)->sin_addr; ! 967: arpwhohas(ar, &IA_SIN(ifa)->sin_addr); ! 968: } ! 969: break; ! 970: default: ! 971: break; ! 972: } ! 973: break; ! 974: ! 975: case SIOCSIFFLAGS: ! 976: /* ! 977: * If interface is marked down and it is running, then stop it ! 978: */ ! 979: if ((ifp->if_flags & IFF_UP) == 0 && ! 980: (ifp->if_flags & IFF_RUNNING) != 0) { ! 981: /* ! 982: * If interface is marked down and it is running, then ! 983: * stop it. ! 984: */ ! 985: ifp->if_flags &= ~IFF_RUNNING; ! 986: } else if ((ifp->if_flags & IFF_UP) != 0 && ! 987: (ifp->if_flags & IFF_RUNNING) == 0) { ! 988: /* ! 989: * If interface is marked up and it is stopped, then ! 990: * start it. ! 991: */ ! 992: ifp->if_flags |= IFF_RUNNING; ! 993: } ! 994: ! 995: /* ! 996: * If the state of the promiscuous bit changes, the ! 997: * interface must be reset to effect the change. ! 998: */ ! 999: if (((ifp->if_flags ^ mace.promisc) & IFF_PROMISC) && ! 1000: (ifp->if_flags & IFF_RUNNING)) { ! 1001: mace.promisc = ifp->if_flags & IFF_PROMISC; ! 1002: mace_sync_promisc(ifp); ! 1003: } ! 1004: ! 1005: break; ! 1006: ! 1007: case SIOCADDMULTI: ! 1008: if ((error = ether_addmulti(ifr, ar)) == ENETRESET) ! 1009: { if ((error = mace_addmulti(ifr, ar)) != 0) ! 1010: { error = 0; ! 1011: mace_sync_mcast(ifp); ! 1012: } ! 1013: } ! 1014: break; ! 1015: ! 1016: case SIOCDELMULTI: ! 1017: { ! 1018: struct ether_addr enaddr[2]; /* [0] - addrlo, [1] - addrhi */ ! 1019: ! 1020: if ((error = ether_delmulti(ifr, ar, enaddr)) == ENETRESET) { ! 1021: if ((error = mace_delmulti(ifr, ar, enaddr)) != 0) { ! 1022: error = 0; ! 1023: mace_sync_mcast(ifp); ! 1024: } ! 1025: } ! 1026: } ! 1027: break; ! 1028: ! 1029: default: ! 1030: error = EINVAL; ! 1031: break; ! 1032: } ! 1033: return (error); ! 1034: } ! 1035: ! 1036: void ! 1037: mace_init() ! 1038: { ! 1039: struct ifnet * ifp = &mace.en_arpcom.ac_if; ! 1040: ! 1041: /* ! 1042: * Only use in-kernel driver for early debugging (bootargs: kdp=1|3) ! 1043: */ ! 1044: if ( (kdp_flag & 1) == 0 ) ! 1045: { ! 1046: return; ! 1047: } ! 1048: ! 1049: mace.tx_busy = 0; ! 1050: mace.txintr = 0; ! 1051: mace.promisc = 0; ! 1052: ! 1053: bzero((caddr_t)ifp, sizeof(struct ifnet)); ! 1054: bcopy(&mace.macaddr, &mace.en_arpcom.ac_enaddr, NUM_EN_ADDR_BYTES); ! 1055: ! 1056: ifp->if_name = "en"; ! 1057: ifp->if_unit = 0; ! 1058: ifp->if_private = 0; ! 1059: ifp->if_ioctl = mace_ioctl; ! 1060: ifp->if_start = mace_start; ! 1061: ifp->if_watchdog = 0; ! 1062: ifp->if_flags = ! 1063: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; ! 1064: #if NBPFILTER > 0 ! 1065: bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); ! 1066: #endif ! 1067: if_attach(ifp); ! 1068: ether_ifattach(ifp); ! 1069: ! 1070: mace.rxintr = 0; ! 1071: ! 1072: /* wire in the interrupt routines */ ! 1073: pmac_register_int(PMAC_DMA_ETHERNET_RX, SPLNET, ! 1074: mace_dbdma_rx_intr, 0); ! 1075: pmac_register_int(PMAC_DMA_ETHERNET_TX, SPLNET, ! 1076: mace_dbdma_tx_intr, 0); ! 1077: ! 1078: // pmac_register_int(PMAC_DEV_ETHERNET, SPLNET, mace_pci_intr); ! 1079: mace.ready = 1; ! 1080: #ifdef MACE_DEBUG ! 1081: timeout(mace_watchdog, 0, 10*hz); /* just in case we drop an interrupt */ ! 1082: #endif ! 1083: return; ! 1084: } ! 1085: ! 1086: /* ! 1087: * mace_pci_intr ! 1088: * ! 1089: * Service MACE interrupt ! 1090: */ ! 1091: ! 1092: void ! 1093: mace_pci_intr(int device, void *ssp) ! 1094: { ! 1095: unsigned char ir, retry, frame, packet, length; ! 1096: ! 1097: ir = mace.ereg->ir; eieio(); /* Clear Interrupt */ ! 1098: packet = mace.ereg->mpc; eieio(); ! 1099: length = mace.ereg->rntpc; eieio(); ! 1100: ! 1101: printf("(txI)"); ! 1102: ! 1103: if (ir & IR_XMTINT) { ! 1104: retry = mace.ereg->xmtrc; eieio(); /* Grab transmit retry count */ ! 1105: frame = mace.ereg->xmtfs; eieio(); ! 1106: // if (mace.ready) ! 1107: // mace_dbdma_tx_intr(device, ssp); ! 1108: } ! 1109: return; ! 1110: } ! 1111: ! 1112: static void ! 1113: tx_intr() ! 1114: { ! 1115: mace.txintr++; ! 1116: mace.tx_busy = 0; ! 1117: mace_service_queue(&mace.en_arpcom.ac_if); ! 1118: } ! 1119: ! 1120: /* ! 1121: * mace_dbdma_tx_intr ! 1122: * ! 1123: * DBDMA interrupt routine ! 1124: */ ! 1125: void ! 1126: mace_dbdma_tx_intr(int unit, void *ignored, void * arg) ! 1127: { ! 1128: if (!mace.ready) ! 1129: return; ! 1130: ! 1131: thread_call_func((thread_call_func_t)tx_intr, 0, TRUE); ! 1132: return; ! 1133: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.