Annotation of sys/dev/isa/if_ex.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ex.c,v 1.16 2007/06/06 09:44:30 henning Exp $ */
! 2: /*
! 3: * Copyright (c) 1997, Donald A. Schmidt
! 4: * Copyright (c) 1996, Javier Martín Rueda (jmrueda@diatel.upm.es)
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice unmodified, this list of conditions, and the following
! 12: * disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * Intel EtherExpress Pro/10 Ethernet driver
! 32: *
! 33: * Revision history:
! 34: *
! 35: * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast.
! 36: */
! 37:
! 38: #include "ex.h"
! 39: #if NEX > 0
! 40: #include "bpfilter.h"
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/conf.h>
! 45: #include <sys/sockio.h>
! 46: #include <sys/mbuf.h>
! 47: #include <sys/socket.h>
! 48: #include <sys/device.h>
! 49:
! 50: #include <net/if.h>
! 51:
! 52: #ifdef INET
! 53: #include <netinet/in.h>
! 54: #include <netinet/if_ether.h>
! 55: #endif
! 56:
! 57: #if NBPFILTER > 0
! 58: #include <net/bpf.h>
! 59: #endif
! 60:
! 61: #include <machine/cpu.h>
! 62: #include <machine/bus.h>
! 63:
! 64: #include <dev/isa/isavar.h>
! 65: #include <dev/isa/if_exreg.h>
! 66:
! 67:
! 68: #ifdef EXDEBUG
! 69: #define Start_End 1
! 70: #define Rcvd_Pkts 2
! 71: #define Sent_Pkts 4
! 72: #define Status 8
! 73: static int debug_mask = 0;
! 74: static int exintr_count = 0;
! 75: #define DODEBUG(level, action) if (level & debug_mask) action
! 76: #else
! 77: #define DODEBUG(level, action)
! 78: #endif
! 79:
! 80:
! 81: #define Conn_BNC 1
! 82: #define Conn_TPE 2
! 83: #define Conn_AUI 3
! 84:
! 85: struct ex_softc {
! 86: struct arpcom arpcom; /* Ethernet common data */
! 87: int iobase; /* I/O base address. */
! 88: u_short connector; /* Connector type. */
! 89: u_short irq_no; /* IRQ number. */
! 90: u_int mem_size; /* Total memory size, in bytes. */
! 91: u_int rx_mem_size; /* Rx memory size (by default, first 3/4 of
! 92: total memory). */
! 93: u_int rx_lower_limit,
! 94: rx_upper_limit; /* Lower and upper limits of receive buffer. */
! 95: u_int rx_head; /* Head of receive ring buffer. */
! 96: u_int tx_mem_size; /* Tx memory size (by default, last quarter of
! 97: total memory). */
! 98: u_int tx_lower_limit,
! 99: tx_upper_limit; /* Lower and upper limits of transmit buffer. */
! 100: u_int tx_head, tx_tail; /* Head and tail of transmit ring buffer. */
! 101: u_int tx_last; /* Pointer to beginning of last frame in the
! 102: chain. */
! 103: bus_space_tag_t sc_iot; /* ISA i/o space tag */
! 104: bus_space_handle_t sc_ioh; /* ISA i/o space handle */
! 105: void *sc_ih; /* Device interrupt handler */
! 106: };
! 107:
! 108: /* static struct ex_softc ex_sc[NEX]; XXX would it be better to malloc(3)
! 109: the memory? */
! 110:
! 111: static char irq2eemap[] = { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1,
! 112: -1, -1 };
! 113: static u_char ee2irqmap[] = { 9, 3, 5, 10, 11, 0, 0, 0 };
! 114:
! 115: static int ex_probe(struct device *, void *, void *);
! 116: static void ex_attach(struct device *, struct device *, void *);
! 117: static void ex_init(struct ex_softc *);
! 118: static void ex_start(struct ifnet *);
! 119: static void ex_stop(struct ex_softc *);
! 120: static int ex_ioctl(struct ifnet *, u_long, caddr_t);
! 121: static void ex_reset(struct ex_softc *);
! 122: static void ex_watchdog(struct ifnet *);
! 123:
! 124: static u_short eeprom_read(struct ex_softc *, int);
! 125: static int look_for_card(struct isa_attach_args *, struct ex_softc *sc);
! 126: static int exintr(void *);
! 127: static void ex_tx_intr(struct ex_softc *);
! 128: static void ex_rx_intr(struct ex_softc *);
! 129:
! 130:
! 131: struct cfattach ex_ca = {
! 132: sizeof(struct ex_softc), ex_probe, ex_attach
! 133: };
! 134:
! 135: struct cfdriver ex_cd = {
! 136: NULL, "ex", DV_IFNET
! 137: };
! 138:
! 139: #define BANK_SEL(X) bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMD_REG, \
! 140: (X))
! 141: #define ISA_GET(offset) bus_space_read_1(sc->sc_iot, sc->sc_ioh, (offset))
! 142: #define ISA_PUT(offset, value) bus_space_write_1(sc->sc_iot, sc->sc_ioh, \
! 143: (offset), (value))
! 144: #define ISA_GET_2(offset) bus_space_read_2(sc->sc_iot, sc->sc_ioh, \
! 145: (offset))
! 146: #define ISA_PUT_2(offset, value) bus_space_write_2(sc->sc_iot, sc->sc_ioh, \
! 147: (offset), (value))
! 148: #define ISA_GET_2_MULTI(offset, addr, count) bus_space_read_multi_2( \
! 149: sc->sc_iot, sc->sc_ioh, (offset), (addr), (count))
! 150: #define ISA_PUT_2_MULTI(offset, addr, count) bus_space_write_multi_2( \
! 151: sc->sc_iot, sc->sc_ioh, (offset), (addr), (count))
! 152:
! 153:
! 154: static int
! 155: look_for_card(ia, sc)
! 156: struct isa_attach_args *ia;
! 157: struct ex_softc *sc;
! 158: {
! 159: int count1, count2;
! 160:
! 161: /*
! 162: * Check for the i82595 signature, and check that the round robin
! 163: * counter actually advances.
! 164: */
! 165: if (((count1 = ISA_GET(ID_REG)) & Id_Mask) != Id_Sig)
! 166: return(0);
! 167: count2 = ISA_GET(ID_REG);
! 168: count2 = ISA_GET(ID_REG);
! 169: count2 = ISA_GET(ID_REG);
! 170: if ((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits))
! 171: return(1);
! 172: else
! 173: return(0);
! 174: }
! 175:
! 176:
! 177: int
! 178: ex_probe(parent, match, aux)
! 179: struct device *parent;
! 180: void *match, *aux;
! 181: {
! 182: struct ex_softc *sc = match;
! 183: struct isa_attach_args *ia = aux;
! 184: u_short eaddr_tmp;
! 185: int tmp;
! 186:
! 187: DODEBUG(Start_End, printf("ex_probe: start\n"););
! 188:
! 189: if ((ia->ia_iobase >= 0x200) && (ia->ia_iobase <= 0x3a0)) {
! 190: sc->sc_iot = ia->ia_iot;
! 191: if(bus_space_map(sc->sc_iot, ia->ia_iobase, EX_IOSIZE, 0,
! 192: &sc->sc_ioh))
! 193: return(0);
! 194:
! 195: if (!look_for_card(ia, sc)) {
! 196: bus_space_unmap(sc->sc_iot, sc->sc_ioh, EX_IOSIZE);
! 197: return(0);
! 198: }
! 199: } else
! 200: return(0);
! 201:
! 202: ia->ia_iosize = EX_IOSIZE;
! 203:
! 204: /*
! 205: * Reset the card.
! 206: */
! 207: ISA_PUT(CMD_REG, Reset_CMD);
! 208: delay(200);
! 209:
! 210: /*
! 211: * Fill in several fields of the softc structure:
! 212: * - I/O base address.
! 213: * - Hardware Ethernet address.
! 214: * - IRQ number (if not supplied in config file, read it from
! 215: * EEPROM).
! 216: * - Connector type.
! 217: */
! 218: sc->iobase = ia->ia_iobase;
! 219: eaddr_tmp = eeprom_read(sc, EE_Eth_Addr_Lo);
! 220: sc->arpcom.ac_enaddr[5] = eaddr_tmp & 0xff;
! 221: sc->arpcom.ac_enaddr[4] = eaddr_tmp >> 8;
! 222: eaddr_tmp = eeprom_read(sc, EE_Eth_Addr_Mid);
! 223: sc->arpcom.ac_enaddr[3] = eaddr_tmp & 0xff;
! 224: sc->arpcom.ac_enaddr[2] = eaddr_tmp >> 8;
! 225: eaddr_tmp = eeprom_read(sc, EE_Eth_Addr_Hi);
! 226: sc->arpcom.ac_enaddr[1] = eaddr_tmp & 0xff;
! 227: sc->arpcom.ac_enaddr[0] = eaddr_tmp >> 8;
! 228: tmp = eeprom_read(sc, EE_IRQ_No) & IRQ_No_Mask;
! 229: if (ia->ia_irq > 0) {
! 230: if (ee2irqmap[tmp] != ia->ia_irq)
! 231: printf("ex: WARING: board's EEPROM is configured for IRQ %d, using %d\n", ee2irqmap[tmp], ia->ia_irq);
! 232: sc->irq_no = ia->ia_irq;
! 233: }
! 234: else {
! 235: sc->irq_no = ee2irqmap[tmp];
! 236: ia->ia_irq = sc->irq_no;
! 237: }
! 238: if (sc->irq_no == 0) {
! 239: printf("ex: invalid IRQ.\n");
! 240: return(0);
! 241: }
! 242: BANK_SEL(Bank2_Sel);
! 243: tmp = ISA_GET(REG3);
! 244: if (tmp & TPE_bit)
! 245: sc->connector = Conn_TPE;
! 246: else if (tmp & BNC_bit)
! 247: sc->connector = Conn_BNC;
! 248: else
! 249: sc->connector = Conn_AUI;
! 250: sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card
! 251: itself. */
! 252:
! 253: BANK_SEL(Bank0_Sel);
! 254:
! 255: DODEBUG(Start_End, printf("ex_probe: finish\n"););
! 256: return(1);
! 257: }
! 258:
! 259:
! 260: void
! 261: ex_attach(parent, self, aux)
! 262: struct device *parent, *self;
! 263: void *aux;
! 264: {
! 265: struct ex_softc *sc = (void *)self;
! 266: struct isa_attach_args *ia = aux;
! 267: struct ifnet *ifp = &sc->arpcom.ac_if;
! 268:
! 269: /* struct ifaddr *ifa; XXX what are these for? */
! 270: /* struct sockaddr_dl *sdl; */
! 271:
! 272: DODEBUG(Start_End, printf("ex_attach: start\n"););
! 273:
! 274: /*
! 275: * Initialize the ifnet structure.
! 276:
! 277: */
! 278: ifp->if_softc = sc;
! 279: bcopy(self->dv_xname, ifp->if_xname, IFNAMSIZ);
! 280: ifp->if_start = ex_start;
! 281: ifp->if_ioctl = ex_ioctl;
! 282: ifp->if_watchdog = ex_watchdog;
! 283: ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; /* XXX not done yet.
! 284: | IFF_MULTICAST */
! 285: IFQ_SET_READY(&ifp->if_snd);
! 286:
! 287: /*
! 288: * Attach the interface.
! 289: */
! 290: if_attach(ifp);
! 291: ether_ifattach(ifp);
! 292: printf(": address %s, connecter ",
! 293: ether_sprintf(sc->arpcom.ac_enaddr));
! 294: switch(sc->connector) {
! 295: case Conn_TPE: printf("TPE\n"); break;
! 296: case Conn_BNC: printf("BNC\n"); break;
! 297: case Conn_AUI: printf("AUI\n"); break;
! 298: default: printf("???\n");
! 299: }
! 300:
! 301: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
! 302: IPL_NET, exintr, sc, self->dv_xname);
! 303: ex_init(sc);
! 304:
! 305: DODEBUG(Start_End, printf("ex_attach: finish\n"););
! 306: }
! 307:
! 308:
! 309: void
! 310: ex_init(sc)
! 311: struct ex_softc *sc;
! 312: {
! 313: struct ifnet *ifp = &sc->arpcom.ac_if;
! 314: int s, i;
! 315: unsigned short temp_reg;
! 316:
! 317: DODEBUG(Start_End, printf("ex_init: start\n"););
! 318:
! 319: if (TAILQ_EMPTY(&ifp->if_addrlist))
! 320: return;
! 321: s = splnet();
! 322: sc->arpcom.ac_if.if_timer = 0;
! 323:
! 324: /*
! 325: * Load the ethernet address into the card.
! 326: */
! 327: BANK_SEL(Bank2_Sel);
! 328: temp_reg = ISA_GET(EEPROM_REG);
! 329: if (temp_reg & Trnoff_Enable)
! 330: ISA_PUT(EEPROM_REG, temp_reg & ~Trnoff_Enable);
! 331: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 332: ISA_PUT(I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]);
! 333: /*
! 334: * - Setup transmit chaining and discard bad received frames.
! 335: * - Match broadcast.
! 336: * - Clear test mode.
! 337: * - Set receiving mode.
! 338: * - Set IRQ number.
! 339: */
! 340: ISA_PUT(REG1, ISA_GET(REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp |
! 341: Disc_Bad_Fr);
! 342: ISA_PUT(REG2, ISA_GET(REG2) | No_SA_Ins | RX_CRC_InMem);
! 343: ISA_PUT(REG3, (ISA_GET(REG3) & 0x3f));
! 344: BANK_SEL(Bank1_Sel);
! 345: ISA_PUT(INT_NO_REG, (ISA_GET(INT_NO_REG) & 0xf8) |
! 346: irq2eemap[sc->irq_no]);
! 347:
! 348: /*
! 349: * Divide the available memory in the card into rcv and xmt buffers.
! 350: * By default, I use the first 3/4 of the memory for the rcv buffer,
! 351: * and the remaining 1/4 of the memory for the xmt buffer.
! 352: */
! 353: sc->rx_mem_size = sc->mem_size * 3 / 4;
! 354: sc->tx_mem_size = sc->mem_size - sc->rx_mem_size;
! 355: sc->rx_lower_limit = 0x0000;
! 356: sc->rx_upper_limit = sc->rx_mem_size - 2;
! 357: sc->tx_lower_limit = sc->rx_mem_size;
! 358: sc->tx_upper_limit = sc->mem_size - 2;
! 359: ISA_PUT(RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8);
! 360: ISA_PUT(RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8);
! 361: ISA_PUT(XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8);
! 362: ISA_PUT(XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8);
! 363:
! 364: /*
! 365: * Enable receive and transmit interrupts, and clear any pending int.
! 366: */
! 367: ISA_PUT(REG1, ISA_GET(REG1) | TriST_INT);
! 368: BANK_SEL(Bank0_Sel);
! 369: ISA_PUT(MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
! 370: ISA_PUT(STATUS_REG, All_Int);
! 371:
! 372: /*
! 373: * Initialize receive and transmit ring buffers.
! 374: */
! 375: ISA_PUT_2(RCV_BAR, sc->rx_lower_limit);
! 376: sc->rx_head = sc->rx_lower_limit;
! 377: ISA_PUT_2(RCV_STOP_REG, sc->rx_upper_limit | 0xfe);
! 378: ISA_PUT_2(XMT_BAR, sc->tx_lower_limit);
! 379: sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
! 380:
! 381: ifp->if_flags |= IFF_RUNNING;
! 382: ifp->if_flags &= ~IFF_OACTIVE;
! 383: DODEBUG(Status, printf("OIDLE init\n"););
! 384:
! 385: /*
! 386: * Final reset of the board, and enable operation.
! 387: */
! 388: ISA_PUT(CMD_REG, Sel_Reset_CMD);
! 389: delay(2);
! 390: ISA_PUT(CMD_REG, Rcv_Enable_CMD);
! 391:
! 392: ex_start(ifp);
! 393: splx(s);
! 394:
! 395: DODEBUG(Start_End, printf("ex_init: finish\n"););
! 396: }
! 397:
! 398:
! 399: void
! 400: ex_start(ifp)
! 401: struct ifnet *ifp;
! 402: {
! 403: register struct ex_softc *sc = ifp->if_softc;
! 404: int i, s, len, data_len, avail, dest, next;
! 405: unsigned char tmp16[2];
! 406: struct mbuf *opkt;
! 407: register struct mbuf *m;
! 408:
! 409: DODEBUG(Start_End, printf("ex_start: start\n"););
! 410:
! 411: s = splnet();
! 412:
! 413: /*
! 414: * Main loop: send outgoing packets to network card until there are no
! 415: * more packets left, or the card cannot accept any more yet.
! 416: */
! 417: while (!(ifp->if_flags & IFF_OACTIVE)) {
! 418: IFQ_POLL(&ifp->if_snd, opkt);
! 419: if (opkt == NULL)
! 420: break;
! 421:
! 422: /*
! 423: * Ensure there is enough free transmit buffer space for this
! 424: * packet, including its header. Note: the header cannot wrap
! 425: * around the end of the transmit buffer and must be kept
! 426: * together, so we allow space for twice the length of the
! 427: * header, just in case.
! 428: */
! 429: for (len = 0, m = opkt; m != NULL; m = m->m_next)
! 430: len += m->m_len;
! 431: data_len = len;
! 432: DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len););
! 433: if (len & 1)
! 434: len += XMT_HEADER_LEN + 1;
! 435: else
! 436: len += XMT_HEADER_LEN;
! 437: if ((i = sc->tx_tail - sc->tx_head) >= 0)
! 438: avail = sc->tx_mem_size - i;
! 439: else
! 440: avail = -i;
! 441: DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail););
! 442: if (avail >= len + XMT_HEADER_LEN) {
! 443: IFQ_DEQUEUE(&ifp->if_snd, opkt);
! 444:
! 445: #ifdef EX_PSA_INTR
! 446: /*
! 447: * Disable rx and tx interrupts, to avoid corruption of
! 448: * the host address register by interrupt service
! 449: * routines. XXX Is this necessary with splnet()
! 450: * enabled?
! 451: */
! 452: ISA_WRITE(MASK_REG, All_Int);
! 453: #endif
! 454:
! 455: /*
! 456: * Compute the start and end addresses of this frame
! 457: * in the tx buffer.
! 458: */
! 459: dest = sc->tx_tail;
! 460: next = dest + len;
! 461: if (next > sc->tx_upper_limit) {
! 462: if ((sc->tx_upper_limit + 2 - sc->tx_tail) <=
! 463: XMT_HEADER_LEN) {
! 464: dest = sc->tx_lower_limit;
! 465: next = dest + len;
! 466: } else
! 467: next = sc->tx_lower_limit + next -
! 468: sc->tx_upper_limit - 2;
! 469: }
! 470:
! 471: /* Build the packet frame in the card's ring buffer. */
! 472: DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next););
! 473: ISA_PUT_2(HOST_ADDR_REG, dest);
! 474: ISA_PUT_2(IO_PORT_REG, Transmit_CMD);
! 475: ISA_PUT_2(IO_PORT_REG, 0);
! 476: ISA_PUT_2(IO_PORT_REG, next);
! 477: ISA_PUT_2(IO_PORT_REG, data_len);
! 478:
! 479: /*
! 480: * Output the packet data to the card. Ensure all
! 481: * transfers are 16-bit wide, even if individual mbufs
! 482: * have odd length.
! 483: */
! 484:
! 485: for (m = opkt, i = 0; m != NULL; m = m->m_next) {
! 486: DODEBUG(Sent_Pkts, printf("[%d]", m->m_len););
! 487: if (i) {
! 488: tmp16[1] = *(mtod(m, caddr_t));
! 489: ISA_PUT_2_MULTI(IO_PORT_REG, tmp16, 1);
! 490: }
! 491: ISA_PUT_2_MULTI(IO_PORT_REG, mtod(m, caddr_t)
! 492: + i, (m->m_len - i) / 2);
! 493: if ((i = (m->m_len - i) & 1))
! 494: tmp16[0] = *(mtod(m, caddr_t) +
! 495: m->m_len - 1);
! 496: }
! 497: if (i)
! 498: ISA_PUT_2_MULTI(IO_PORT_REG, tmp16, 1);
! 499:
! 500: /*
! 501: * If there were other frames chained, update the
! 502: * chain in the last one.
! 503: */
! 504: if (sc->tx_head != sc->tx_tail) {
! 505: if (sc->tx_tail != dest) {
! 506: ISA_PUT_2(HOST_ADDR_REG,
! 507: sc->tx_last + XMT_Chain_Point);
! 508: ISA_PUT_2(IO_PORT_REG, dest);
! 509: }
! 510: ISA_PUT_2(HOST_ADDR_REG, sc->tx_last +
! 511: XMT_Byte_Count);
! 512: i = ISA_GET_2(IO_PORT_REG);
! 513: ISA_PUT_2(HOST_ADDR_REG, sc->tx_last +
! 514: XMT_Byte_Count);
! 515: ISA_PUT_2(IO_PORT_REG, i | Ch_bit);
! 516: }
! 517:
! 518: /*
! 519: * Resume normal operation of the card:
! 520: * -Make a dummy read to flush the DRAM write pipeline.
! 521: * -Enable receive and transmit interrupts.
! 522: * -Send Transmit or Resume_XMT command, as appropriate.
! 523: */
! 524: ISA_GET_2(IO_PORT_REG);
! 525: #ifdef EX_PSA_INTR
! 526: ISA_PUT_2(MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
! 527: #endif
! 528: if (sc->tx_head == sc->tx_tail) {
! 529: ISA_PUT_2(XMT_BAR, dest);
! 530: ISA_PUT(CMD_REG, Transmit_CMD);
! 531: sc->tx_head = dest;
! 532: DODEBUG(Sent_Pkts, printf("Transmit\n"););
! 533: } else {
! 534: ISA_PUT(CMD_REG, Resume_XMT_List_CMD);
! 535: DODEBUG(Sent_Pkts, printf("Resume\n"););
! 536: }
! 537: sc->tx_last = dest;
! 538: sc->tx_tail = next;
! 539: #if NBPFILTER > 0
! 540: if (ifp->if_bpf != NULL)
! 541: bpf_mtap(ifp->if_bpf, opkt,
! 542: BPF_DIRECTION_OUT);
! 543: #endif
! 544: ifp->if_timer = 2;
! 545: ifp->if_opackets++;
! 546: m_freem(opkt);
! 547: } else {
! 548: ifp->if_flags |= IFF_OACTIVE;
! 549: DODEBUG(Status, printf("OACTIVE start\n"););
! 550: }
! 551: }
! 552:
! 553: splx(s);
! 554:
! 555: DODEBUG(Start_End, printf("ex_start: finish\n"););
! 556: }
! 557:
! 558:
! 559: void
! 560: ex_stop(sc)
! 561: struct ex_softc *sc;
! 562: {
! 563: DODEBUG(Start_End, printf("ex_stop: start\n"););
! 564:
! 565: /*
! 566: * Disable card operation:
! 567: * - Disable the interrupt line.
! 568: * - Flush transmission and disable reception.
! 569: * - Mask and clear all interrupts.
! 570: * - Reset the 82595.
! 571: */
! 572: BANK_SEL(Bank1_Sel);
! 573: ISA_PUT(REG1, ISA_GET(REG1) & ~TriST_INT);
! 574: BANK_SEL(Bank0_Sel);
! 575: ISA_PUT(CMD_REG, Rcv_Stop);
! 576: sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
! 577: sc->tx_last = 0; /* XXX I think these two lines are not necessary,
! 578: because ex_init will always be called again
! 579: to reinit the interface. */
! 580: ISA_PUT(MASK_REG, All_Int);
! 581: ISA_PUT(STATUS_REG, All_Int);
! 582: ISA_PUT(CMD_REG, Reset_CMD);
! 583: delay(200);
! 584:
! 585: DODEBUG(Start_End, printf("ex_stop: finish\n"););
! 586: }
! 587:
! 588:
! 589: int
! 590: exintr(arg)
! 591: void *arg;
! 592: {
! 593: struct ex_softc *sc = arg;
! 594: struct ifnet *ifp = &sc->arpcom.ac_if;
! 595: int int_status, send_pkts;
! 596: int handled;
! 597:
! 598: DODEBUG(Start_End, printf("exintr: start\n"););
! 599:
! 600: #ifdef EXDEBUG
! 601: if (++exintr_count != 1)
! 602: printf("WARNING: nested interrupt (%d). Mail the author.\n",
! 603: exintr_count);
! 604: #endif
! 605:
! 606: send_pkts = 0;
! 607: while ((int_status = ISA_GET(STATUS_REG)) & (Tx_Int | Rx_Int)) {
! 608: if (int_status & Rx_Int) {
! 609: ISA_PUT(STATUS_REG, Rx_Int);
! 610: handled = 1;
! 611: ex_rx_intr(sc);
! 612: } else if (int_status & Tx_Int) {
! 613: ISA_PUT(STATUS_REG, Tx_Int);
! 614: handled = 1;
! 615: ex_tx_intr(sc);
! 616: send_pkts = 1;
! 617: } else
! 618: handled = 0;
! 619: }
! 620:
! 621: /*
! 622: * If any packet has been transmitted, and there are queued packets to
! 623: * be sent, attempt to send more packets to the network card.
! 624: */
! 625:
! 626: if (send_pkts && IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 627: ex_start(ifp);
! 628: #ifdef EXDEBUG
! 629: exintr_count--;
! 630: #endif
! 631: DODEBUG(Start_End, printf("exintr: finish\n"););
! 632:
! 633: return handled;
! 634: }
! 635:
! 636:
! 637: void
! 638: ex_tx_intr(sc)
! 639: struct ex_softc *sc;
! 640: {
! 641: register struct ifnet *ifp = &sc->arpcom.ac_if;
! 642: int tx_status;
! 643:
! 644: DODEBUG(Start_End, printf("ex_tx_intr: start\n"););
! 645: /*
! 646: * - Cancel the watchdog.
! 647: * For all packets transmitted since last transmit interrupt:
! 648: * - Advance chain pointer to next queued packet.
! 649: * - Update statistics.
! 650: */
! 651: ifp->if_timer = 0;
! 652: while (sc->tx_head != sc->tx_tail) {
! 653: ISA_PUT_2(HOST_ADDR_REG, sc->tx_head);
! 654: if (! ISA_GET_2(IO_PORT_REG) & Done_bit)
! 655: break;
! 656: tx_status = ISA_GET_2(IO_PORT_REG);
! 657: sc->tx_head = ISA_GET_2(IO_PORT_REG);
! 658: if (tx_status & TX_OK_bit)
! 659: ifp->if_opackets++;
! 660: else
! 661: ifp->if_oerrors++;
! 662: ifp->if_collisions += tx_status & No_Collisions_bits;
! 663: }
! 664:
! 665: /* The card should be ready to accept more packets now. */
! 666: ifp->if_flags &= ~IFF_OACTIVE;
! 667: DODEBUG(Status, printf("OIDLE tx_intr\n"););
! 668:
! 669: DODEBUG(Start_End, printf("ex_tx_intr: finish\n"););
! 670: }
! 671:
! 672:
! 673: void
! 674: ex_rx_intr(sc)
! 675: struct ex_softc *sc;
! 676: {
! 677: register struct ifnet *ifp = &sc->arpcom.ac_if;
! 678: int rx_status, pkt_len, QQQ;
! 679: register struct mbuf *m, *ipkt;
! 680:
! 681: DODEBUG(Start_End, printf("ex_rx_intr: start\n"););
! 682: /*
! 683: * For all packets received since last receive interrupt:
! 684: * - If packet ok, read it into a new mbuf and queue it to interface,
! 685: * updating statistics.
! 686: * - If packet bad, just discard it, and update statistics.
! 687: * Finally, advance receive stop limit in card's memory to new location.
! 688: */
! 689: ISA_PUT_2(HOST_ADDR_REG, sc->rx_head);
! 690: while (ISA_GET_2(IO_PORT_REG) == RCV_Done) {
! 691: rx_status = ISA_GET_2(IO_PORT_REG);
! 692: sc->rx_head = ISA_GET_2(IO_PORT_REG);
! 693: QQQ = pkt_len = ISA_GET_2(IO_PORT_REG);
! 694: if (rx_status & RCV_OK_bit) {
! 695: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 696: ipkt = m;
! 697: if (ipkt == NULL)
! 698: ifp->if_iqdrops++;
! 699: else {
! 700: ipkt->m_pkthdr.rcvif = ifp;
! 701: ipkt->m_pkthdr.len = pkt_len;
! 702: ipkt->m_len = MHLEN;
! 703: while (pkt_len > 0) {
! 704: if (pkt_len > MINCLSIZE) {
! 705: MCLGET(m, M_DONTWAIT);
! 706: if (m->m_flags & M_EXT)
! 707: m->m_len = MCLBYTES;
! 708: else {
! 709: m_freem(ipkt);
! 710: ifp->if_iqdrops++;
! 711: goto rx_another;
! 712: }
! 713: }
! 714: m->m_len = min(m->m_len, pkt_len);
! 715: /*
! 716: * NOTE: I'm assuming that all mbufs
! 717: * allocated are of even length, except
! 718: * for the last one in an odd-length
! 719: * packet.
! 720: */
! 721: ISA_GET_2_MULTI(IO_PORT_REG,
! 722: mtod(m, caddr_t), m->m_len / 2);
! 723: if (m->m_len & 1)
! 724: *(mtod(m, caddr_t) +
! 725: m->m_len - 1) =
! 726: ISA_GET(IO_PORT_REG);
! 727: pkt_len -= m->m_len;
! 728: if (pkt_len > 0) {
! 729: MGET(m->m_next, M_DONTWAIT,
! 730: MT_DATA);
! 731: if (m->m_next == NULL) {
! 732: m_freem(ipkt);
! 733: ifp->if_iqdrops++;
! 734: goto rx_another;
! 735: }
! 736: m = m->m_next;
! 737: m->m_len = MLEN;
! 738: }
! 739: }
! 740: #ifdef EXDEBUG
! 741: if (debug_mask & Rcvd_Pkts) {
! 742: if ((eh->ether_dhost[5] != 0xff) ||
! 743: (eh->ether_dhost[0] != 0xff)) {
! 744: printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":");
! 745: printf("%6D\n", eh->ether_dhost, ":");
! 746: } /* QQQ */
! 747: }
! 748: #endif
! 749: #if NBPFILTER > 0
! 750: if (ifp->if_bpf != NULL)
! 751: bpf_mtap(ifp->if_bpf, ipkt,
! 752: BPF_DIRECTION_IN);
! 753: #endif
! 754: ether_input_mbuf(ifp, ipkt);
! 755: ifp->if_ipackets++;
! 756: }
! 757: } else
! 758: ifp->if_ierrors++;
! 759: ISA_PUT_2(HOST_ADDR_REG, sc->rx_head);
! 760: rx_another: ;
! 761: }
! 762: if (sc->rx_head < sc->rx_lower_limit + 2)
! 763: ISA_PUT_2(RCV_STOP_REG, sc->rx_upper_limit);
! 764: else
! 765: ISA_PUT_2(RCV_STOP_REG, sc->rx_head - 2);
! 766:
! 767: DODEBUG(Start_End, printf("ex_rx_intr: finish\n"););
! 768: }
! 769:
! 770:
! 771: int
! 772: ex_ioctl(ifp, cmd, data)
! 773: register struct ifnet *ifp;
! 774: u_long cmd;
! 775: caddr_t data;
! 776: {
! 777: register struct ifaddr *ifa = (struct ifaddr *) data;
! 778: struct ex_softc *sc = ifp->if_softc;
! 779: struct ifreq *ifr = (struct ifreq *) data;
! 780: int s, error = 0;
! 781:
! 782: DODEBUG(Start_End, printf("ex_ioctl: start "););
! 783:
! 784: s = splnet();
! 785:
! 786: switch(cmd) {
! 787: case SIOCSIFADDR:
! 788: DODEBUG(Start_End, printf("SIOCSIFADDR"););
! 789: ifp->if_flags |= IFF_UP;
! 790:
! 791: switch(ifa->ifa_addr->sa_family) {
! 792: #ifdef INET
! 793: case AF_INET:
! 794: ex_init(sc);
! 795: arp_ifinit((struct arpcom *) ifp, ifa);
! 796: break;
! 797: #endif
! 798: default:
! 799: ex_init(sc);
! 800: break;
! 801: }
! 802: break;
! 803: case SIOCGIFADDR:
! 804: {
! 805: struct sockaddr *sa;
! 806:
! 807: DODEBUG(Start_End, printf("SIOCGIFADDR"););
! 808: sa = (struct sockaddr *) &ifr->ifr_data;
! 809: bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data,
! 810: ETHER_ADDR_LEN);
! 811: }
! 812: break;
! 813: case SIOCSIFFLAGS:
! 814: DODEBUG(Start_End, printf("SIOCSIFFLAGS"););
! 815: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
! 816: ifp->if_flags &= ~IFF_RUNNING;
! 817: ex_stop(sc);
! 818: }
! 819: else
! 820: ex_init(sc);
! 821: break;
! 822: #ifdef NODEF
! 823: case SIOCGHWADDR:
! 824: DODEBUG(Start_End, printf("SIOCGHWADDR"););
! 825: bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr));
! 826: break;
! 827: #endif
! 828: case SIOCSIFMTU:
! 829: DODEBUG(Start_End, printf("SIOCSIFMTU"););
! 830: if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
! 831: error = EINVAL;
! 832: } else if (ifp->if_mtu != ifr->ifr_mtu) {
! 833: ifp->if_mtu = ifr->ifr_mtu;
! 834: }
! 835: break;
! 836: case SIOCADDMULTI:
! 837: DODEBUG(Start_End, printf("SIOCADDMULTI"););
! 838: case SIOCDELMULTI:
! 839: DODEBUG(Start_End, printf("SIOCDELMULTI"););
! 840: /* XXX Support not done yet. */
! 841: error = EINVAL;
! 842: break;
! 843: default:
! 844: DODEBUG(Start_End, printf("unknown"););
! 845: error = EINVAL;
! 846: }
! 847:
! 848: splx(s);
! 849:
! 850: DODEBUG(Start_End, printf("\nex_ioctl: finish\n"););
! 851: return(error);
! 852: }
! 853:
! 854:
! 855: void
! 856: ex_reset(sc)
! 857: struct ex_softc *sc;
! 858: {
! 859: int s;
! 860:
! 861: DODEBUG(Start_End, printf("ex_reset: start\n"););
! 862:
! 863: s = splnet();
! 864: ex_stop(sc);
! 865: ex_init(sc);
! 866: splx(s);
! 867:
! 868: DODEBUG(Start_End, printf("ex_reset: finish\n"););
! 869: }
! 870:
! 871:
! 872: void
! 873: ex_watchdog(ifp)
! 874: struct ifnet *ifp;
! 875: {
! 876: struct ex_softc *sc = ifp->if_softc;
! 877:
! 878: DODEBUG(Start_End, printf("ex_watchdog: start\n"););
! 879:
! 880: ifp->if_flags &= ~IFF_OACTIVE;
! 881: DODEBUG(Status, printf("OIDLE watchdog\n"););
! 882: ifp->if_oerrors++;
! 883: ex_reset(sc);
! 884: ex_start(ifp);
! 885:
! 886: DODEBUG(Start_End, printf("ex_watchdog: finish\n"););
! 887: }
! 888:
! 889:
! 890: static u_short
! 891: eeprom_read(sc, location)
! 892: struct ex_softc *sc;
! 893: int location;
! 894: {
! 895: int i;
! 896: u_short data = 0;
! 897: int read_cmd = location | EE_READ_CMD;
! 898: short ctrl_val = EECS;
! 899:
! 900: BANK_SEL(Bank2_Sel);
! 901: ISA_PUT(EEPROM_REG, EECS);
! 902: for (i = 8; i >= 0; i--) {
! 903: short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI :
! 904: ctrl_val;
! 905: ISA_PUT(EEPROM_REG, outval);
! 906: ISA_PUT(EEPROM_REG, outval | EESK);
! 907: delay(3);
! 908: ISA_PUT(EEPROM_REG, outval);
! 909: delay(2);
! 910: }
! 911: ISA_PUT(EEPROM_REG, ctrl_val);
! 912: for (i = 16; i > 0; i--) {
! 913: ISA_PUT(EEPROM_REG, ctrl_val | EESK);
! 914: delay(3);
! 915: data = (data << 1) | ((ISA_GET(EEPROM_REG) & EEDO) ? 1 : 0);
! 916: ISA_PUT(EEPROM_REG, ctrl_val);
! 917: delay(2);
! 918: }
! 919: ctrl_val &= ~EECS;
! 920: ISA_PUT(EEPROM_REG, ctrl_val | EESK);
! 921: delay(3);
! 922: ISA_PUT(EEPROM_REG, ctrl_val);
! 923: delay(2);
! 924: BANK_SEL(Bank0_Sel);
! 925: return(data);
! 926: }
! 927:
! 928: #endif /* NEX > 0 */
CVSweb