Annotation of sys/dev/ic/i82596.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: i82596.c,v 1.26 2006/03/25 22:41:43 djm Exp $ */
! 2: /* $NetBSD: i82586.c,v 1.18 1998/08/15 04:42:42 mycroft Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Paul Kranenburg and Charles M. Hannum.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39: /*-
! 40: * Copyright (c) 1997 Paul Kranenburg.
! 41: * Copyright (c) 1992, 1993, University of Vermont and State
! 42: * Agricultural College.
! 43: * Copyright (c) 1992, 1993, Garrett A. Wollman.
! 44: *
! 45: * Portions:
! 46: * Copyright (c) 1994, 1995, Rafal K. Boni
! 47: * Copyright (c) 1990, 1991, William F. Jolitz
! 48: * Copyright (c) 1990, The Regents of the University of California
! 49: *
! 50: * All rights reserved.
! 51: *
! 52: * Redistribution and use in source and binary forms, with or without
! 53: * modification, are permitted provided that the following conditions
! 54: * are met:
! 55: * 1. Redistributions of source code must retain the above copyright
! 56: * notice, this list of conditions and the following disclaimer.
! 57: * 2. Redistributions in binary form must reproduce the above copyright
! 58: * notice, this list of conditions and the following disclaimer in the
! 59: * documentation and/or other materials provided with the distribution.
! 60: * 3. All advertising materials mentioning features or use of this software
! 61: * must display the following acknowledgement:
! 62: * This product includes software developed by the University of Vermont
! 63: * and State Agricultural College and Garrett A. Wollman, by William F.
! 64: * Jolitz, and by the University of California, Berkeley, Lawrence
! 65: * Berkeley Laboratory, and its contributors.
! 66: * 4. Neither the names of the Universities nor the names of the authors
! 67: * may be used to endorse or promote products derived from this software
! 68: * without specific prior written permission.
! 69: *
! 70: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 71: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 72: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 73: * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
! 74: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 75: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 76: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 77: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 78: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 79: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 80: * SUCH DAMAGE.
! 81: */
! 82: /*
! 83: * Intel 82586/82596 Ethernet chip
! 84: * Register, bit, and structure definitions.
! 85: *
! 86: * Original StarLAN driver written by Garrett Wollman with reference to the
! 87: * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
! 88: *
! 89: * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
! 90: *
! 91: * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
! 92: *
! 93: * Majorly cleaned up and 3C507 code merged by Charles Hannum.
! 94: *
! 95: * Converted to SUN ie driver by Charles D. Cranor,
! 96: * October 1994, January 1995.
! 97: * This sun version based on i386 version 1.30.
! 98: */
! 99: /*
! 100: * The i82596 is a very painful chip, found in sun3's, sun-4/100's
! 101: * sun-4/200's, and VME based suns. The byte order is all wrong for a
! 102: * SUN, making life difficult. Programming this chip is mostly the same,
! 103: * but certain details differ from system to system. This driver is
! 104: * written so that different "ie" interfaces can be controled by the same
! 105: * driver.
! 106: */
! 107:
! 108: /*
! 109: Mode of operation:
! 110:
! 111: We run the 82596 in a standard Ethernet mode. We keep NFRAMES
! 112: received frame descriptors around for the receiver to use, and
! 113: NRXBUF associated receive buffer descriptors, both in a circular
! 114: list. Whenever a frame is received, we rotate both lists as
! 115: necessary. (The 596 treats both lists as a simple queue.) We also
! 116: keep a transmit command around so that packets can be sent off
! 117: quickly.
! 118:
! 119: We configure the adapter in AL-LOC = 1 mode, which means that the
! 120: Ethernet/802.3 MAC header is placed at the beginning of the receive
! 121: buffer rather than being split off into various fields in the RFD.
! 122: This also means that we must include this header in the transmit
! 123: buffer as well.
! 124:
! 125: By convention, all transmit commands, and only transmit commands,
! 126: shall have the I (IE_CMD_INTR) bit set in the command. This way,
! 127: when an interrupt arrives at i82596_intr(), it is immediately possible
! 128: to tell what precisely caused it. ANY OTHER command-sending
! 129: routines should run at splnet(), and should post an acknowledgement
! 130: to every interrupt they generate.
! 131:
! 132: To save the expense of shipping a command to 82596 every time we
! 133: want to send a frame, we use a linked list of commands consisting
! 134: of alternate XMIT and NOP commands. The links of these elements
! 135: are manipulated (in i82596_xmit()) such that the NOP command loops back
! 136: to itself whenever the following XMIT command is not yet ready to
! 137: go. Whenever an XMIT is ready, the preceding NOP link is pointed
! 138: at it, while its own link field points to the following NOP command.
! 139: Thus, a single transmit command sets off an interlocked traversal
! 140: of the xmit command chain, with the host processor in control of
! 141: the synchronization.
! 142: */
! 143:
! 144: #include "bpfilter.h"
! 145:
! 146: #include <sys/param.h>
! 147: #include <sys/systm.h>
! 148: #include <sys/mbuf.h>
! 149: #include <sys/socket.h>
! 150: #include <sys/ioctl.h>
! 151: #include <sys/errno.h>
! 152: #include <sys/syslog.h>
! 153: #include <sys/device.h>
! 154:
! 155: #include <net/if.h>
! 156: #include <net/if_dl.h>
! 157: #include <net/if_types.h>
! 158: #include <net/if_media.h>
! 159:
! 160: #if NBPFILTER > 0
! 161: #include <net/bpf.h>
! 162: #endif
! 163:
! 164: #ifdef INET
! 165: #include <netinet/in.h>
! 166: #include <netinet/in_systm.h>
! 167: #include <netinet/in_var.h>
! 168: #include <netinet/ip.h>
! 169: #include <netinet/if_ether.h>
! 170: #endif
! 171:
! 172: #include <uvm/uvm_extern.h>
! 173:
! 174: #include <machine/bus.h>
! 175:
! 176: #include <dev/ic/i82596reg.h>
! 177: #include <dev/ic/i82596var.h>
! 178:
! 179: static char *padbuf;
! 180:
! 181: void i82596_reset(struct ie_softc *, int);
! 182: void i82596_watchdog(struct ifnet *);
! 183: int i82596_init(struct ie_softc *);
! 184: int i82596_ioctl(struct ifnet *, u_long, caddr_t);
! 185: void i82596_start(struct ifnet *);
! 186:
! 187: int i82596_rint(struct ie_softc *, int);
! 188: int i82596_tint(struct ie_softc *, int);
! 189:
! 190: int i82596_mediachange(struct ifnet *);
! 191: void i82596_mediastatus(struct ifnet *, struct ifmediareq *);
! 192:
! 193: int i82596_readframe(struct ie_softc *, int);
! 194: int i82596_get_rbd_list(struct ie_softc *,
! 195: u_int16_t *, u_int16_t *, int *);
! 196: void i82596_release_rbd_list(struct ie_softc *, u_int16_t, u_int16_t);
! 197: int i82596_drop_frames(struct ie_softc *);
! 198: int i82596_chk_rx_ring(struct ie_softc *);
! 199:
! 200: void i82596_start_transceiver(struct ie_softc *);
! 201: void i82596_stop(struct ie_softc *);
! 202: void i82596_xmit(struct ie_softc *);
! 203:
! 204: void i82596_setup_bufs(struct ie_softc *);
! 205: void i82596_simple_command(struct ie_softc *, int, int);
! 206: int ie_cfg_setup(struct ie_softc *, int, int, int);
! 207: int ie_ia_setup(struct ie_softc *, int);
! 208: void ie_run_tdr(struct ie_softc *, int);
! 209: int ie_mc_setup(struct ie_softc *, int);
! 210: void ie_mc_reset(struct ie_softc *);
! 211: int i82596_cmd_wait(struct ie_softc *);
! 212:
! 213: #ifdef I82596_DEBUG
! 214: void print_rbd(struct ie_softc *, int);
! 215: #endif
! 216:
! 217: struct cfdriver ie_cd = {
! 218: NULL, "ie", DV_IFNET
! 219: };
! 220:
! 221: /*
! 222: * generic i82596 probe routine
! 223: */
! 224: int
! 225: i82596_probe(sc)
! 226: struct ie_softc *sc;
! 227: {
! 228: int i;
! 229:
! 230: sc->scp = sc->sc_msize - IE_SCP_SZ;
! 231: sc->iscp = 0;
! 232: sc->scb = 32;
! 233:
! 234: (sc->ie_bus_write16)(sc, IE_ISCP_BUSY(sc->iscp), 1);
! 235: (sc->ie_bus_write16)(sc, IE_ISCP_SCB(sc->iscp), sc->scb);
! 236: (sc->ie_bus_write24)(sc, IE_ISCP_BASE(sc->iscp), sc->sc_maddr);
! 237: (sc->ie_bus_write24)(sc, IE_SCP_ISCP(sc->scp), sc->sc_maddr);
! 238: (sc->ie_bus_write16)(sc, IE_SCP_BUS_USE(sc->scp), sc->sysbus);
! 239:
! 240: (sc->hwreset)(sc, IE_CARD_RESET);
! 241:
! 242: if ((sc->ie_bus_read16)(sc, IE_ISCP_BUSY(sc->iscp))) {
! 243: #ifdef I82596_DEBUG
! 244: printf("%s: ISCP set failed\n", sc->sc_dev.dv_xname);
! 245: #endif
! 246: return 0;
! 247: }
! 248:
! 249: if (sc->port) {
! 250: (sc->ie_bus_write24)(sc, sc->scp, 0);
! 251: (sc->ie_bus_write24)(sc, IE_SCP_TEST(sc->scp), -1);
! 252: (sc->port)(sc, IE_PORT_TEST);
! 253: for (i = 9000; i-- &&
! 254: (sc->ie_bus_read16)(sc, IE_SCP_TEST(sc->scp));
! 255: DELAY(100))
! 256: ;
! 257: }
! 258:
! 259: return 1;
! 260: }
! 261:
! 262: /*
! 263: * Front-ends call this function to attach to the MI driver.
! 264: *
! 265: * The front-end has responsibility for managing the ICP and ISCP
! 266: * structures. Both of these are opaque to us. Also, the front-end
! 267: * chooses a location for the SCB which is expected to be addressable
! 268: * (through `sc->scb') as an offset against the shared-memory bus handle.
! 269: *
! 270: * The following MD interface function must be setup by the front-end
! 271: * before calling here:
! 272: *
! 273: * hwreset - board dependent reset
! 274: * hwinit - board dependent initialization
! 275: * chan_attn - channel attention
! 276: * intrhook - board dependent interrupt processing
! 277: * memcopyin - shared memory copy: board to KVA
! 278: * memcopyout - shared memory copy: KVA to board
! 279: * ie_bus_read16 - read a sixteen-bit i82596 pointer
! 280: * ie_bus_write16 - write a sixteen-bit i82596 pointer
! 281: * ie_bus_write24 - write a twenty-four-bit i82596 pointer
! 282: *
! 283: */
! 284: void
! 285: i82596_attach(sc, name, etheraddr, media, nmedia, defmedia)
! 286: struct ie_softc *sc;
! 287: const char *name;
! 288: u_int8_t *etheraddr;
! 289: int *media, nmedia, defmedia;
! 290: {
! 291: int i;
! 292: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 293:
! 294: /* Setup SCP+ISCP */
! 295: (sc->ie_bus_write16)(sc, IE_ISCP_BUSY(sc->iscp), 1);
! 296: (sc->ie_bus_write16)(sc, IE_ISCP_SCB(sc->iscp), sc->scb);
! 297: (sc->ie_bus_write24)(sc, IE_ISCP_BASE(sc->iscp), sc->sc_maddr);
! 298: (sc->ie_bus_write24)(sc, IE_SCP_ISCP(sc->scp), sc->sc_maddr +sc->iscp);
! 299: (sc->ie_bus_write16)(sc, IE_SCP_BUS_USE(sc->scp), sc->sysbus);
! 300: (sc->hwreset)(sc, IE_CARD_RESET);
! 301:
! 302: /* Setup Iface */
! 303: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 304: ifp->if_softc = sc;
! 305: ifp->if_start = i82596_start;
! 306: ifp->if_ioctl = i82596_ioctl;
! 307: ifp->if_watchdog = i82596_watchdog;
! 308: ifp->if_flags =
! 309: #ifdef I82596_DEBUG
! 310: IFF_DEBUG |
! 311: #endif
! 312: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 313: IFQ_SET_READY(&ifp->if_snd);
! 314:
! 315: /* Initialize media goo. */
! 316: ifmedia_init(&sc->sc_media, 0, i82596_mediachange, i82596_mediastatus);
! 317: if (media != NULL) {
! 318: for (i = 0; i < nmedia; i++)
! 319: ifmedia_add(&sc->sc_media, media[i], 0, NULL);
! 320: ifmedia_set(&sc->sc_media, defmedia);
! 321: } else {
! 322: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
! 323: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
! 324: }
! 325:
! 326: if (padbuf == NULL) {
! 327: padbuf = malloc(ETHER_MIN_LEN - ETHER_CRC_LEN, M_DEVBUF,
! 328: M_NOWAIT);
! 329: if (padbuf == NULL) {
! 330: printf("%s: can't allocate pad buffer\n",
! 331: sc->sc_dev.dv_xname);
! 332: return;
! 333: }
! 334: bzero(padbuf, ETHER_MIN_LEN - ETHER_CRC_LEN);
! 335: }
! 336:
! 337: /* Attach the interface. */
! 338: if_attach(ifp);
! 339: ether_ifattach(ifp);
! 340:
! 341: printf(" %s v%d.%d, address %s\n", name, sc->sc_vers / 10,
! 342: sc->sc_vers % 10, ether_sprintf(etheraddr));
! 343: }
! 344:
! 345:
! 346: /*
! 347: * Device timeout/watchdog routine.
! 348: * Entered if the device neglects to generate an interrupt after a
! 349: * transmit has been started on it.
! 350: */
! 351: void
! 352: i82596_watchdog(ifp)
! 353: struct ifnet *ifp;
! 354: {
! 355: struct ie_softc *sc = ifp->if_softc;
! 356:
! 357: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 358: ++ifp->if_oerrors;
! 359:
! 360: i82596_reset(sc, 1);
! 361: }
! 362:
! 363: int
! 364: i82596_cmd_wait(sc)
! 365: struct ie_softc *sc;
! 366: {
! 367: /* spin on i82596 command acknowledge; wait at most 0.9 (!) seconds */
! 368: int i, off;
! 369:
! 370: for (i = 180000; i--; DELAY(5)) {
! 371: /* Read the command word */
! 372: off = IE_SCB_CMD(sc->scb);
! 373: bus_space_barrier(sc->bt, sc->bh, off, 2,
! 374: BUS_SPACE_BARRIER_READ);
! 375: if ((sc->ie_bus_read16)(sc, off) == 0) {
! 376: #ifdef I82596_DEBUG
! 377: if (sc->sc_debug & IED_CMDS)
! 378: printf("%s: cmd_wait after %d usec\n",
! 379: sc->sc_dev.dv_xname, (180000 - i) * 5);
! 380: #endif
! 381: return (0);
! 382: }
! 383: }
! 384:
! 385: #ifdef I82596_DEBUG
! 386: if (sc->sc_debug & IED_CMDS)
! 387: printf("i82596_cmd_wait: timo(%ssync): scb status: %b\n",
! 388: sc->async_cmd_inprogress? "a" : "",
! 389: sc->ie_bus_read16(sc, IE_SCB_STATUS(sc->scb)),
! 390: IE_STAT_BITS);
! 391: #endif
! 392: return (1); /* Timeout */
! 393: }
! 394:
! 395: /*
! 396: * Send a command to the controller and wait for it to either complete
! 397: * or be accepted, depending on the command. If the command pointer
! 398: * is null, then pretend that the command is not an action command.
! 399: * If the command pointer is not null, and the command is an action
! 400: * command, wait for one of the MASK bits to turn on in the command's
! 401: * status field.
! 402: * If ASYNC is set, we just call the chip's attention and return.
! 403: * We may have to wait for the command's acceptance later though.
! 404: */
! 405: int
! 406: i82596_start_cmd(sc, cmd, iecmdbuf, mask, async)
! 407: struct ie_softc *sc;
! 408: int cmd;
! 409: int iecmdbuf;
! 410: int mask;
! 411: int async;
! 412: {
! 413: int i, off;
! 414:
! 415: #ifdef I82596_DEBUG
! 416: if (sc->sc_debug & IED_CMDS)
! 417: printf("start_cmd: %p, %x, %x, %b, %ssync\n",
! 418: sc, cmd, iecmdbuf, mask, IE_STAT_BITS, async?"a":"");
! 419: #endif
! 420: if (sc->async_cmd_inprogress != 0) {
! 421: /*
! 422: * If previous command was issued asynchronously, wait
! 423: * for it now.
! 424: */
! 425: if (i82596_cmd_wait(sc) != 0)
! 426: return (1);
! 427: sc->async_cmd_inprogress = 0;
! 428: }
! 429:
! 430: off = IE_SCB_CMD(sc->scb);
! 431: (sc->ie_bus_write16)(sc, off, cmd);
! 432: bus_space_barrier(sc->bt, sc->bh, off, 2, BUS_SPACE_BARRIER_WRITE);
! 433: (sc->chan_attn)(sc);
! 434:
! 435: if (async) {
! 436: sc->async_cmd_inprogress = 1;
! 437: return (0);
! 438: }
! 439:
! 440: if (IE_ACTION_COMMAND(cmd) && iecmdbuf) {
! 441: int status;
! 442: /*
! 443: * Now spin-lock waiting for status. This is not a very nice
! 444: * thing to do, and can kill performance pretty well...
! 445: * According to the packet driver, the minimum timeout
! 446: * should be .369 seconds.
! 447: */
! 448: for (i = 73800; i--; DELAY(5)) {
! 449: /* Read the command status */
! 450: off = IE_CMD_COMMON_STATUS(iecmdbuf);
! 451: bus_space_barrier(sc->bt, sc->bh, off, 2,
! 452: BUS_SPACE_BARRIER_READ);
! 453: status = (sc->ie_bus_read16)(sc, off);
! 454: if (status & mask) {
! 455: #ifdef I82596_DEBUG
! 456: if (sc->sc_debug & IED_CMDS)
! 457: printf("%s: cmd status %b\n",
! 458: sc->sc_dev.dv_xname,
! 459: status, IE_STAT_BITS);
! 460: #endif
! 461: return (0);
! 462: }
! 463: }
! 464:
! 465: } else {
! 466: /*
! 467: * Otherwise, just wait for the command to be accepted.
! 468: */
! 469: return (i82596_cmd_wait(sc));
! 470: }
! 471:
! 472: /* Timeout */
! 473: return (1);
! 474: }
! 475:
! 476: /*
! 477: * Transfer accumulated chip error counters to IF.
! 478: */
! 479: static __inline void
! 480: i82596_count_errors(struct ie_softc *sc)
! 481: {
! 482: int scb = sc->scb;
! 483:
! 484: sc->sc_arpcom.ac_if.if_ierrors +=
! 485: sc->ie_bus_read16(sc, IE_SCB_ERRCRC(scb)) +
! 486: sc->ie_bus_read16(sc, IE_SCB_ERRALN(scb)) +
! 487: sc->ie_bus_read16(sc, IE_SCB_ERRRES(scb)) +
! 488: sc->ie_bus_read16(sc, IE_SCB_ERROVR(scb));
! 489:
! 490: /* Clear error counters */
! 491: sc->ie_bus_write16(sc, IE_SCB_ERRCRC(scb), 0);
! 492: sc->ie_bus_write16(sc, IE_SCB_ERRALN(scb), 0);
! 493: sc->ie_bus_write16(sc, IE_SCB_ERRRES(scb), 0);
! 494: sc->ie_bus_write16(sc, IE_SCB_ERROVR(scb), 0);
! 495: }
! 496:
! 497: static __inline void
! 498: i82596_rx_errors(struct ie_softc *sc, int fn, int status)
! 499: {
! 500: log(LOG_ERR, "%s: rx error (frame# %d): %b\n", sc->sc_dev.dv_xname, fn,
! 501: status, IE_FD_STATUSBITS);
! 502: }
! 503:
! 504: /*
! 505: * i82596 interrupt entry point.
! 506: */
! 507: int
! 508: i82596_intr(v)
! 509: void *v;
! 510: {
! 511: register struct ie_softc *sc = v;
! 512: register u_int status;
! 513: register int off;
! 514:
! 515: off = IE_SCB_STATUS(sc->scb);
! 516: bus_space_barrier(sc->bt, sc->bh, off, 2, BUS_SPACE_BARRIER_READ);
! 517: status = sc->ie_bus_read16(sc, off) /* & IE_ST_WHENCE */;
! 518:
! 519: if ((status & IE_ST_WHENCE) == 0) {
! 520: if (sc->intrhook)
! 521: (sc->intrhook)(sc, IE_INTR_EXIT);
! 522:
! 523: return (0);
! 524: }
! 525:
! 526: loop:
! 527: /* Ack interrupts FIRST in case we receive more during the ISR. */
! 528: i82596_start_cmd(sc, status & IE_ST_WHENCE, 0, 0, 1);
! 529:
! 530: if (status & (IE_ST_FR | IE_ST_RNR)) {
! 531: if (sc->intrhook)
! 532: (sc->intrhook)(sc, IE_INTR_ENRCV);
! 533:
! 534: if (i82596_rint(sc, status) != 0)
! 535: goto reset;
! 536: }
! 537:
! 538: if (status & IE_ST_CX) {
! 539: if (sc->intrhook)
! 540: (sc->intrhook)(sc, IE_INTR_ENSND);
! 541:
! 542: if (i82596_tint(sc, status) != 0)
! 543: goto reset;
! 544: }
! 545:
! 546: #ifdef I82596_DEBUG
! 547: if ((status & IE_ST_CNA) && (sc->sc_debug & IED_CNA))
! 548: printf("%s: cna; status=%b\n", sc->sc_dev.dv_xname,
! 549: status, IE_ST_BITS);
! 550: #endif
! 551: if (sc->intrhook)
! 552: (sc->intrhook)(sc, IE_INTR_LOOP);
! 553:
! 554: /*
! 555: * Interrupt ACK was posted asynchronously; wait for
! 556: * completion here before reading SCB status again.
! 557: *
! 558: * If ACK fails, try to reset the chip, in hopes that
! 559: * it helps.
! 560: */
! 561: if (i82596_cmd_wait(sc))
! 562: goto reset;
! 563:
! 564: bus_space_barrier(sc->bt, sc->bh, off, 2, BUS_SPACE_BARRIER_READ);
! 565: status = sc->ie_bus_read16(sc, off);
! 566: if ((status & IE_ST_WHENCE) != 0)
! 567: goto loop;
! 568:
! 569: out:
! 570: if (sc->intrhook)
! 571: (sc->intrhook)(sc, IE_INTR_EXIT);
! 572: return (1);
! 573:
! 574: reset:
! 575: i82596_cmd_wait(sc);
! 576: i82596_reset(sc, 1);
! 577: goto out;
! 578: }
! 579:
! 580: /*
! 581: * Process a received-frame interrupt.
! 582: */
! 583: int
! 584: i82596_rint(sc, scbstatus)
! 585: struct ie_softc *sc;
! 586: int scbstatus;
! 587: {
! 588: static int timesthru = 1024;
! 589: register int i, status, off;
! 590:
! 591: #ifdef I82596_DEBUG
! 592: if (sc->sc_debug & IED_RINT)
! 593: printf("%s: rint: status %b\n",
! 594: sc->sc_dev.dv_xname, scbstatus, IE_ST_BITS);
! 595: #endif
! 596:
! 597: for (;;) {
! 598: register int drop = 0;
! 599:
! 600: i = sc->rfhead;
! 601: off = IE_RFRAME_STATUS(sc->rframes, i);
! 602: bus_space_barrier(sc->bt, sc->bh, off, 2,
! 603: BUS_SPACE_BARRIER_READ);
! 604: status = sc->ie_bus_read16(sc, off);
! 605:
! 606: #ifdef I82596_DEBUG
! 607: if (sc->sc_debug & IED_RINT)
! 608: printf("%s: rint: frame(%d) status %b\n",
! 609: sc->sc_dev.dv_xname, i, status, IE_ST_BITS);
! 610: #endif
! 611: if ((status & IE_FD_COMPLETE) == 0) {
! 612: if ((status & IE_FD_OK) != 0) {
! 613: printf("%s: rint: weird: ",
! 614: sc->sc_dev.dv_xname);
! 615: i82596_rx_errors(sc, i, status);
! 616: break;
! 617: }
! 618: if (--timesthru == 0) {
! 619: /* Account the accumulated errors */
! 620: i82596_count_errors(sc);
! 621: timesthru = 1024;
! 622: }
! 623: break;
! 624: } else if ((status & IE_FD_OK) == 0) {
! 625: /*
! 626: * If the chip is configured to automatically
! 627: * discard bad frames, the only reason we can
! 628: * get here is an "out-of-resource" condition.
! 629: */
! 630: i82596_rx_errors(sc, i, status);
! 631: drop = 1;
! 632: }
! 633:
! 634: #ifdef I82596_DEBUG
! 635: if ((status & IE_FD_BUSY) != 0)
! 636: printf("%s: rint: frame(%d) busy; status=%x\n",
! 637: sc->sc_dev.dv_xname, i, status, IE_ST_BITS);
! 638: #endif
! 639:
! 640: /*
! 641: * Advance the RFD list, since we're done with
! 642: * this descriptor.
! 643: */
! 644:
! 645: /* Clear frame status */
! 646: sc->ie_bus_write16(sc, off, 0);
! 647:
! 648: /* Put fence at this frame (the head) */
! 649: off = IE_RFRAME_LAST(sc->rframes, i);
! 650: sc->ie_bus_write16(sc, off, IE_FD_EOL|IE_FD_SUSP);
! 651:
! 652: /* and clear RBD field */
! 653: off = IE_RFRAME_BUFDESC(sc->rframes, i);
! 654: sc->ie_bus_write16(sc, off, 0xffff);
! 655:
! 656: /* Remove fence from current tail */
! 657: off = IE_RFRAME_LAST(sc->rframes, sc->rftail);
! 658: sc->ie_bus_write16(sc, off, 0);
! 659:
! 660: if (++sc->rftail == sc->nframes)
! 661: sc->rftail = 0;
! 662: if (++sc->rfhead == sc->nframes)
! 663: sc->rfhead = 0;
! 664:
! 665: /* Pull the frame off the board */
! 666: if (drop) {
! 667: i82596_drop_frames(sc);
! 668: if ((status & IE_FD_RNR) != 0)
! 669: sc->rnr_expect = 1;
! 670: sc->sc_arpcom.ac_if.if_ierrors++;
! 671: } else if (i82596_readframe(sc, i) != 0)
! 672: return (1);
! 673: }
! 674:
! 675: if ((scbstatus & IE_ST_RNR) != 0) {
! 676:
! 677: /*
! 678: * Receiver went "Not Ready". We try to figure out
! 679: * whether this was an expected event based on past
! 680: * frame status values.
! 681: */
! 682:
! 683: if ((scbstatus & IE_RUS_SUSPEND) != 0) {
! 684: /*
! 685: * We use the "suspend on last frame" flag.
! 686: * Send a RU RESUME command in response, since
! 687: * we should have dealt with all completed frames
! 688: * by now.
! 689: */
! 690: printf("RINT: SUSPENDED; scbstatus=%b\n",
! 691: scbstatus, IE_ST_BITS);
! 692: if (i82596_start_cmd(sc, IE_RUC_RESUME, 0, 0, 0) == 0)
! 693: return (0);
! 694: printf("%s: RU RESUME command timed out\n",
! 695: sc->sc_dev.dv_xname);
! 696: return (1); /* Ask for a reset */
! 697: }
! 698:
! 699: if (sc->rnr_expect != 0) {
! 700: /*
! 701: * The RNR condition was announced in the previously
! 702: * completed frame. Assume the receive ring is Ok,
! 703: * so restart the receiver without further delay.
! 704: */
! 705: i82596_start_transceiver(sc);
! 706: sc->rnr_expect = 0;
! 707: return (0);
! 708:
! 709: } else if ((scbstatus & IE_RUS_NOSPACE) != 0) {
! 710: /*
! 711: * We saw no previous IF_FD_RNR flag.
! 712: * We check our ring invariants and, if ok,
! 713: * just restart the receiver at the current
! 714: * point in the ring.
! 715: */
! 716: if (i82596_chk_rx_ring(sc) != 0)
! 717: return (1);
! 718:
! 719: i82596_start_transceiver(sc);
! 720: sc->sc_arpcom.ac_if.if_ierrors++;
! 721: return (0);
! 722: } else
! 723: printf("%s: receiver not ready; scbstatus=%b\n",
! 724: sc->sc_dev.dv_xname, scbstatus, IE_ST_BITS);
! 725:
! 726: sc->sc_arpcom.ac_if.if_ierrors++;
! 727: return (1); /* Ask for a reset */
! 728: }
! 729:
! 730: return (0);
! 731: }
! 732:
! 733: /*
! 734: * Process a command-complete interrupt. These are only generated by the
! 735: * transmission of frames. This routine is deceptively simple, since most
! 736: * of the real work is done by i82596_start().
! 737: */
! 738: int
! 739: i82596_tint(sc, scbstatus)
! 740: struct ie_softc *sc;
! 741: int scbstatus;
! 742: {
! 743: register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 744: register int off, status;
! 745:
! 746: ifp->if_timer = 0;
! 747: ifp->if_flags &= ~IFF_OACTIVE;
! 748:
! 749: #ifdef I82596_DEBUG
! 750: if (sc->xmit_busy <= 0) {
! 751: printf("%s: i82596_tint: WEIRD:"
! 752: "xmit_busy=%d, xctail=%d, xchead=%d\n",
! 753: sc->sc_dev.dv_xname,
! 754: sc->xmit_busy, sc->xctail, sc->xchead);
! 755: return (0);
! 756: }
! 757: #endif
! 758:
! 759: off = IE_CMD_XMIT_STATUS(sc->xmit_cmds, sc->xctail);
! 760: status = sc->ie_bus_read16(sc, off);
! 761:
! 762: #ifdef I82596_DEBUG
! 763: if (sc->sc_debug & IED_TINT)
! 764: printf("%s: tint: SCB status %b; xmit status %b\n",
! 765: sc->sc_dev.dv_xname, scbstatus, IE_ST_BITS,
! 766: status, IE_XS_BITS);
! 767: #endif
! 768:
! 769: if ((status & (IE_STAT_COMPL|IE_STAT_BUSY)) == IE_STAT_BUSY) {
! 770: printf("%s: i82596_tint: command still busy;"
! 771: "status=%b; tail=%d\n", sc->sc_dev.dv_xname,
! 772: status, IE_XS_BITS, sc->xctail);
! 773: printf("iestatus = %b\n", scbstatus, IE_ST_BITS);
! 774: }
! 775:
! 776: if (status & IE_STAT_OK) {
! 777: ifp->if_opackets++;
! 778: ifp->if_collisions += (status & IE_XS_MAXCOLL);
! 779: } else {
! 780: ifp->if_oerrors++;
! 781: /*
! 782: * Check SQE and DEFERRED?
! 783: * What if more than one bit is set?
! 784: */
! 785: if (status & IE_STAT_ABORT)
! 786: printf("%s: send aborted\n", sc->sc_dev.dv_xname);
! 787: else if (status & IE_XS_NOCARRIER)
! 788: printf("%s: no carrier\n", sc->sc_dev.dv_xname);
! 789: else if (status & IE_XS_LOSTCTS)
! 790: printf("%s: lost CTS\n", sc->sc_dev.dv_xname);
! 791: else if (status & IE_XS_UNDERRUN)
! 792: printf("%s: DMA underrun\n", sc->sc_dev.dv_xname);
! 793: else if (status & IE_XS_EXCMAX) {
! 794: printf("%s: too many collisions\n",
! 795: sc->sc_dev.dv_xname);
! 796: sc->sc_arpcom.ac_if.if_collisions += 16;
! 797: }
! 798: }
! 799:
! 800: /*
! 801: * If multicast addresses were added or deleted while transmitting,
! 802: * ie_mc_reset() set the want_mcsetup flag indicating that we
! 803: * should do it.
! 804: */
! 805: if (sc->want_mcsetup) {
! 806: ie_mc_setup(sc, IE_XBUF_ADDR(sc, sc->xctail));
! 807: sc->want_mcsetup = 0;
! 808: }
! 809:
! 810: /* Done with the buffer. */
! 811: sc->xmit_busy--;
! 812: sc->xctail = (sc->xctail + 1) % NTXBUF;
! 813:
! 814: /* Start the next packet, if any, transmitting. */
! 815: if (sc->xmit_busy > 0)
! 816: i82596_xmit(sc);
! 817:
! 818: i82596_start(ifp);
! 819: return (0);
! 820: }
! 821:
! 822: /*
! 823: * Get a range of receive buffer descriptors that represent one packet.
! 824: */
! 825: int
! 826: i82596_get_rbd_list(sc, start, end, pktlen)
! 827: struct ie_softc *sc;
! 828: u_int16_t *start;
! 829: u_int16_t *end;
! 830: int *pktlen;
! 831: {
! 832: int off, rbbase = sc->rbds;
! 833: int rbindex, count = 0;
! 834: int plen = 0;
! 835: int rbdstatus;
! 836:
! 837: *start = rbindex = sc->rbhead;
! 838:
! 839: do {
! 840: off = IE_RBD_STATUS(rbbase, rbindex);
! 841: bus_space_barrier(sc->bt, sc->bh, off, 2,
! 842: BUS_SPACE_BARRIER_READ);
! 843: rbdstatus = sc->ie_bus_read16(sc, off);
! 844: if ((rbdstatus & IE_RBD_USED) == 0) {
! 845: /*
! 846: * This means we are somehow out of sync. So, we
! 847: * reset the adapter.
! 848: */
! 849: #ifdef I82596_DEBUG
! 850: print_rbd(sc, rbindex);
! 851: #endif
! 852: log(LOG_ERR,
! 853: "%s: receive descriptors out of sync at %d\n",
! 854: sc->sc_dev.dv_xname, rbindex);
! 855: return (0);
! 856: }
! 857: plen += (rbdstatus & IE_RBD_CNTMASK);
! 858:
! 859: if (++rbindex == sc->nrxbuf)
! 860: rbindex = 0;
! 861:
! 862: ++count;
! 863: } while ((rbdstatus & IE_RBD_LAST) == 0);
! 864: *end = rbindex;
! 865: *pktlen = plen;
! 866: return (count);
! 867: }
! 868:
! 869:
! 870: /*
! 871: * Release a range of receive buffer descriptors after we've copied the packet.
! 872: */
! 873: void
! 874: i82596_release_rbd_list(sc, start, end)
! 875: struct ie_softc *sc;
! 876: u_int16_t start;
! 877: u_int16_t end;
! 878: {
! 879: register int off, rbbase = sc->rbds;
! 880: register int rbindex = start;
! 881:
! 882: do {
! 883: /* Clear buffer status */
! 884: off = IE_RBD_STATUS(rbbase, rbindex);
! 885: sc->ie_bus_write16(sc, off, 0);
! 886: if (++rbindex == sc->nrxbuf)
! 887: rbindex = 0;
! 888: } while (rbindex != end);
! 889:
! 890: /* Mark EOL at new tail */
! 891: rbindex = ((rbindex == 0) ? sc->nrxbuf : rbindex) - 1;
! 892: off = IE_RBD_BUFLEN(rbbase, rbindex);
! 893: sc->ie_bus_write16(sc, off, IE_RBUF_SIZE|IE_RBD_EOL);
! 894:
! 895: /* Remove EOL from current tail */
! 896: off = IE_RBD_BUFLEN(rbbase, sc->rbtail);
! 897: sc->ie_bus_write16(sc, off, IE_RBUF_SIZE);
! 898:
! 899: /* New head & tail pointer */
! 900: /* hmm, why have both? head is always (tail + 1) % NRXBUF */
! 901: sc->rbhead = end;
! 902: sc->rbtail = rbindex;
! 903: }
! 904:
! 905: /*
! 906: * Drop the packet at the head of the RX buffer ring.
! 907: * Called if the frame descriptor reports an error on this packet.
! 908: * Returns 1 if the buffer descriptor ring appears to be corrupt;
! 909: * and 0 otherwise.
! 910: */
! 911: int
! 912: i82596_drop_frames(sc)
! 913: struct ie_softc *sc;
! 914: {
! 915: u_int16_t bstart, bend;
! 916: int pktlen;
! 917:
! 918: if (!i82596_get_rbd_list(sc, &bstart, &bend, &pktlen))
! 919: return (1);
! 920: i82596_release_rbd_list(sc, bstart, bend);
! 921: return (0);
! 922: }
! 923:
! 924: /*
! 925: * Check the RX frame & buffer descriptor lists for our invariants,
! 926: * i.e.: EOL bit set iff. it is pointed at by the r*tail pointer.
! 927: *
! 928: * Called when the receive unit has stopped unexpectedly.
! 929: * Returns 1 if an inconsistency is detected; 0 otherwise.
! 930: *
! 931: * The Receive Unit is expected to be NOT RUNNING.
! 932: */
! 933: int
! 934: i82596_chk_rx_ring(sc)
! 935: struct ie_softc *sc;
! 936: {
! 937: int n, off, val;
! 938:
! 939: for (n = 0; n < sc->nrxbuf; n++) {
! 940: off = IE_RBD_BUFLEN(sc->rbds, n);
! 941: val = sc->ie_bus_read16(sc, off);
! 942: if ((n == sc->rbtail) ^ ((val & IE_RBD_EOL) != 0)) {
! 943: /* `rbtail' and EOL flag out of sync */
! 944: log(LOG_ERR,
! 945: "%s: rx buffer descriptors out of sync at %d\n",
! 946: sc->sc_dev.dv_xname, n);
! 947: return (1);
! 948: }
! 949:
! 950: /* Take the opportunity to clear the status fields here ? */
! 951: }
! 952:
! 953: for (n = 0; n < sc->nframes; n++) {
! 954: off = IE_RFRAME_LAST(sc->rframes, n);
! 955: val = sc->ie_bus_read16(sc, off);
! 956: if ((n == sc->rftail) ^ ((val & (IE_FD_EOL|IE_FD_SUSP)) != 0)) {
! 957: /* `rftail' and EOL flag out of sync */
! 958: log(LOG_ERR,
! 959: "%s: rx frame list out of sync at %d\n",
! 960: sc->sc_dev.dv_xname, n);
! 961: return (1);
! 962: }
! 963: }
! 964:
! 965: return (0);
! 966: }
! 967:
! 968: /*
! 969: * Read data off the interface, and turn it into an mbuf chain.
! 970: *
! 971: * This code is DRAMATICALLY different from the previous version; this
! 972: * version tries to allocate the entire mbuf chain up front, given the
! 973: * length of the data available. This enables us to allocate mbuf
! 974: * clusters in many situations where before we would have had a long
! 975: * chain of partially-full mbufs. This should help to speed up the
! 976: * operation considerably. (Provided that it works, of course.)
! 977: */
! 978: static __inline__ struct mbuf *
! 979: i82596_get(struct ie_softc *sc, int head, int totlen)
! 980: {
! 981: struct mbuf *m, *m0, *newm;
! 982: int off, len, resid;
! 983: int thisrboff, thismboff;
! 984: struct ether_header eh;
! 985:
! 986: /*
! 987: * Snarf the Ethernet header.
! 988: */
! 989: (sc->memcopyin)(sc, &eh, IE_RBUF_ADDR(sc, head),
! 990: sizeof(struct ether_header));
! 991:
! 992: resid = totlen;
! 993:
! 994: MGETHDR(m0, M_DONTWAIT, MT_DATA);
! 995: if (m0 == 0)
! 996: return (0);
! 997: m0->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
! 998: m0->m_pkthdr.len = totlen;
! 999: len = MHLEN;
! 1000: m = m0;
! 1001:
! 1002: /*
! 1003: * This loop goes through and allocates mbufs for all the data we will
! 1004: * be copying in. It does not actually do the copying yet.
! 1005: */
! 1006: while (totlen > 0) {
! 1007: if (totlen >= MINCLSIZE) {
! 1008: MCLGET(m, M_DONTWAIT);
! 1009: if ((m->m_flags & M_EXT) == 0)
! 1010: goto bad;
! 1011: len = MCLBYTES;
! 1012: }
! 1013:
! 1014: if (m == m0) {
! 1015: caddr_t newdata = (caddr_t)
! 1016: ALIGN(m->m_data + sizeof(struct ether_header)) -
! 1017: sizeof(struct ether_header);
! 1018: len -= newdata - m->m_data;
! 1019: m->m_data = newdata;
! 1020: }
! 1021:
! 1022: m->m_len = len = min(totlen, len);
! 1023:
! 1024: totlen -= len;
! 1025: if (totlen > 0) {
! 1026: MGET(newm, M_DONTWAIT, MT_DATA);
! 1027: if (newm == 0)
! 1028: goto bad;
! 1029: len = MLEN;
! 1030: m = m->m_next = newm;
! 1031: }
! 1032: }
! 1033:
! 1034: m = m0;
! 1035: thismboff = 0;
! 1036:
! 1037: /*
! 1038: * Copy the Ethernet header into the mbuf chain.
! 1039: */
! 1040: bcopy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
! 1041: thismboff = sizeof(struct ether_header);
! 1042: thisrboff = sizeof(struct ether_header);
! 1043: resid -= sizeof(struct ether_header);
! 1044:
! 1045: /*
! 1046: * Now we take the mbuf chain (hopefully only one mbuf most of the
! 1047: * time) and stuff the data into it. There are no possible failures
! 1048: * at or after this point.
! 1049: */
! 1050: while (resid > 0) {
! 1051: int thisrblen = IE_RBUF_SIZE - thisrboff,
! 1052: thismblen = m->m_len - thismboff;
! 1053: len = min(thisrblen, thismblen);
! 1054:
! 1055: off = IE_RBUF_ADDR(sc,head) + thisrboff;
! 1056: (sc->memcopyin)(sc, mtod(m, caddr_t) + thismboff, off, len);
! 1057: resid -= len;
! 1058:
! 1059: if (len == thismblen) {
! 1060: m = m->m_next;
! 1061: thismboff = 0;
! 1062: } else
! 1063: thismboff += len;
! 1064:
! 1065: if (len == thisrblen) {
! 1066: if (++head == sc->nrxbuf)
! 1067: head = 0;
! 1068: thisrboff = 0;
! 1069: } else
! 1070: thisrboff += len;
! 1071: }
! 1072:
! 1073: /*
! 1074: * Unless something changed strangely while we were doing the copy,
! 1075: * we have now copied everything in from the shared memory.
! 1076: * This means that we are done.
! 1077: */
! 1078: return (m0);
! 1079:
! 1080: bad:
! 1081: m_freem(m0);
! 1082: return (NULL);
! 1083: }
! 1084:
! 1085: /*
! 1086: * Read frame NUM from unit UNIT (pre-cached as IE).
! 1087: *
! 1088: * This routine reads the RFD at NUM, and copies in the buffers from the list
! 1089: * of RBD, then rotates the RBD list so that the receiver doesn't start
! 1090: * complaining. Trailers are DROPPED---there's no point in wasting time
! 1091: * on confusing code to deal with them. Hopefully, this machine will
! 1092: * never ARP for trailers anyway.
! 1093: */
! 1094: int
! 1095: i82596_readframe(sc, num)
! 1096: struct ie_softc *sc;
! 1097: int num; /* frame number to read */
! 1098: {
! 1099: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1100: struct mbuf *m;
! 1101: u_int16_t bstart, bend;
! 1102: int pktlen;
! 1103:
! 1104: if (i82596_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0) {
! 1105: ifp->if_ierrors++;
! 1106: return (1);
! 1107: }
! 1108:
! 1109: m = i82596_get(sc, bstart, pktlen);
! 1110: i82596_release_rbd_list(sc, bstart, bend);
! 1111:
! 1112: if (m == 0) {
! 1113: sc->sc_arpcom.ac_if.if_ierrors++;
! 1114: return (0);
! 1115: }
! 1116:
! 1117: #ifdef I82596_DEBUG
! 1118: if (sc->sc_debug & IED_READFRAME) {
! 1119: struct ether_header *eh = mtod(m, struct ether_header *);
! 1120:
! 1121: printf("%s: frame from ether %s type 0x%x len %d\n",
! 1122: sc->sc_dev.dv_xname, ether_sprintf(eh->ether_shost),
! 1123: (u_int)eh->ether_type, pktlen);
! 1124: }
! 1125: #endif
! 1126:
! 1127: #if NBPFILTER > 0
! 1128: /* Check for a BPF filter; if so, hand it up. */
! 1129: if (ifp->if_bpf)
! 1130: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1131: #endif /* NBPFILTER > 0 */
! 1132:
! 1133: /*
! 1134: * Finally pass this packet up to higher layers.
! 1135: */
! 1136: ether_input_mbuf(ifp, m);
! 1137: ifp->if_ipackets++;
! 1138: return (0);
! 1139: }
! 1140:
! 1141:
! 1142: /*
! 1143: * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
! 1144: * command to the chip to be executed.
! 1145: */
! 1146: void
! 1147: i82596_xmit(sc)
! 1148: struct ie_softc *sc;
! 1149: {
! 1150: int off, cur, prev;
! 1151:
! 1152: cur = sc->xctail;
! 1153:
! 1154: #ifdef I82596_DEBUG
! 1155: if (sc->sc_debug & IED_XMIT)
! 1156: printf("%s: xmit buffer %d\n", sc->sc_dev.dv_xname, cur);
! 1157: #endif
! 1158:
! 1159: /*
! 1160: * Setup the transmit command.
! 1161: */
! 1162: sc->ie_bus_write16(sc, IE_CMD_XMIT_DESC(sc->xmit_cmds, cur),
! 1163: IE_XBD_ADDR(sc->xbds, cur));
! 1164:
! 1165: sc->ie_bus_write16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds, cur), 0);
! 1166:
! 1167: if (sc->do_xmitnopchain) {
! 1168: /*
! 1169: * Gate this XMIT command to the following NOP
! 1170: */
! 1171: sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds, cur),
! 1172: IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
! 1173: sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
! 1174: IE_CMD_XMIT | IE_CMD_INTR);
! 1175:
! 1176: /*
! 1177: * Loopback at following NOP
! 1178: */
! 1179: sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, cur), 0);
! 1180: sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, cur),
! 1181: IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
! 1182:
! 1183: /*
! 1184: * Gate preceding NOP to this XMIT command
! 1185: */
! 1186: prev = (cur + NTXBUF - 1) % NTXBUF;
! 1187: sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, prev), 0);
! 1188: sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, prev),
! 1189: IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
! 1190:
! 1191: off = IE_SCB_STATUS(sc->scb);
! 1192: bus_space_barrier(sc->bt, sc->bh, off, 2,
! 1193: BUS_SPACE_BARRIER_READ);
! 1194: if ((sc->ie_bus_read16(sc, off) & IE_CUS_ACTIVE) == 0) {
! 1195: printf("i82596_xmit: CU not active\n");
! 1196: i82596_start_transceiver(sc);
! 1197: }
! 1198: } else {
! 1199: sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds,cur),
! 1200: 0xffff);
! 1201:
! 1202: sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
! 1203: IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST);
! 1204:
! 1205: off = IE_SCB_CMDLST(sc->scb);
! 1206: sc->ie_bus_write16(sc, off, IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
! 1207: bus_space_barrier(sc->bt, sc->bh, off, 2,
! 1208: BUS_SPACE_BARRIER_WRITE);
! 1209:
! 1210: if (i82596_start_cmd(sc, IE_CUC_START, 0, 0, 1)) {
! 1211: #ifdef I82596_DEBUG
! 1212: if (sc->sc_debug & IED_XMIT)
! 1213: printf("%s: i82596_xmit: "
! 1214: "start xmit command timed out\n",
! 1215: sc->sc_dev.dv_xname);
! 1216: #endif
! 1217: }
! 1218: }
! 1219:
! 1220: sc->sc_arpcom.ac_if.if_timer = 5;
! 1221: }
! 1222:
! 1223:
! 1224: /*
! 1225: * Start transmission on an interface.
! 1226: */
! 1227: void
! 1228: i82596_start(ifp)
! 1229: struct ifnet *ifp;
! 1230: {
! 1231: struct ie_softc *sc = ifp->if_softc;
! 1232: struct mbuf *m0, *m;
! 1233: int buffer, head, xbase;
! 1234: u_short len;
! 1235:
! 1236: #ifdef I82596_DEBUG
! 1237: if (sc->sc_debug & IED_ENQ)
! 1238: printf("i82596_start(%p)\n", ifp);
! 1239: #endif
! 1240:
! 1241: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1242: return;
! 1243:
! 1244: for (;;) {
! 1245: if (sc->xmit_busy == NTXBUF) {
! 1246: ifp->if_flags |= IFF_OACTIVE;
! 1247: break;
! 1248: }
! 1249:
! 1250: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 1251: if (m0 == 0)
! 1252: break;
! 1253:
! 1254: /* We need to use m->m_pkthdr.len, so require the header */
! 1255: if ((m0->m_flags & M_PKTHDR) == 0)
! 1256: panic("i82596_start: no header mbuf");
! 1257:
! 1258: #if NBPFILTER > 0
! 1259: /* Tap off here if there is a BPF listener. */
! 1260: if (ifp->if_bpf)
! 1261: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 1262: #endif
! 1263:
! 1264: if (m0->m_pkthdr.len > IE_TBUF_SIZE)
! 1265: printf("%s: tbuf overflow\n", sc->sc_dev.dv_xname);
! 1266:
! 1267: head = sc->xchead;
! 1268: sc->xchead = (head + 1) % NTXBUF;
! 1269: buffer = IE_XBUF_ADDR(sc, head);
! 1270:
! 1271: #ifdef I82596_DEBUG
! 1272: if (sc->sc_debug & IED_ENQ)
! 1273: printf("%s: fill buffer %d offset %x",
! 1274: sc->sc_dev.dv_xname, head, buffer);
! 1275: #endif
! 1276:
! 1277: for (m = m0; m != 0; m = m->m_next) {
! 1278: #ifdef I82596_DEBUG
! 1279: if (sc->sc_debug & IED_ENQ) {
! 1280: u_int8_t *e, *p = mtod(m, u_int8_t *);
! 1281: static int i;
! 1282: if (m == m0)
! 1283: i = 0;
! 1284: for (e = p + m->m_len; p < e; i++, p += 2) {
! 1285: if (!(i % 8))
! 1286: printf("\n%s:",
! 1287: sc->sc_dev.dv_xname);
! 1288: printf(" %02x%02x", p[0], p[1]);
! 1289: }
! 1290: }
! 1291: #endif
! 1292: (sc->memcopyout)(sc, mtod(m,caddr_t), buffer, m->m_len);
! 1293: buffer += m->m_len;
! 1294: }
! 1295:
! 1296: len = m0->m_pkthdr.len;
! 1297: if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
! 1298: (sc->memcopyout)(sc, padbuf, buffer,
! 1299: ETHER_MIN_LEN - ETHER_CRC_LEN - len);
! 1300: buffer += ETHER_MIN_LEN - ETHER_CRC_LEN - len;
! 1301: len = ETHER_MIN_LEN - ETHER_CRC_LEN;
! 1302: }
! 1303:
! 1304: #ifdef I82596_DEBUG
! 1305: if (sc->sc_debug & IED_ENQ)
! 1306: printf("\n");
! 1307: #endif
! 1308:
! 1309: m_freem(m0);
! 1310:
! 1311: /*
! 1312: * Setup the transmit buffer descriptor here, while we
! 1313: * know the packet's length.
! 1314: */
! 1315: xbase = sc->xbds;
! 1316: sc->ie_bus_write16(sc, IE_XBD_FLAGS(xbase, head),
! 1317: len | IE_TBD_EOL);
! 1318: sc->ie_bus_write16(sc, IE_XBD_NEXT(xbase, head), 0xffff);
! 1319: sc->ie_bus_write24(sc, IE_XBD_BUF(xbase, head),
! 1320: sc->sc_maddr + IE_XBUF_ADDR(sc, head));
! 1321:
! 1322: /* Start the first packet transmitting. */
! 1323: if (sc->xmit_busy++ == 0)
! 1324: i82596_xmit(sc);
! 1325: }
! 1326: }
! 1327:
! 1328: /*
! 1329: * Probe IE's ram setup [ Move all this into MD front-end!? ]
! 1330: * Use only if SCP and ISCP represent offsets into shared ram space.
! 1331: */
! 1332: int
! 1333: i82596_proberam(sc)
! 1334: struct ie_softc *sc;
! 1335: {
! 1336: int result, off;
! 1337:
! 1338: /* Put in 16-bit mode */
! 1339: off = IE_SCP_BUS_USE(sc->scp);
! 1340: (sc->ie_bus_write16)(sc, off, 0);
! 1341: bus_space_barrier(sc->bt, sc->bh, off, 2, BUS_SPACE_BARRIER_WRITE);
! 1342:
! 1343: /* Set the ISCP `busy' bit */
! 1344: off = IE_ISCP_BUSY(sc->iscp);
! 1345: (sc->ie_bus_write16)(sc, off, 1);
! 1346: bus_space_barrier(sc->bt, sc->bh, off, 2, BUS_SPACE_BARRIER_WRITE);
! 1347:
! 1348: if (sc->hwreset)
! 1349: (sc->hwreset)(sc, IE_CHIP_PROBE);
! 1350:
! 1351: (sc->chan_attn) (sc);
! 1352:
! 1353: DELAY(100); /* wait a while... */
! 1354:
! 1355: /* Read back the ISCP `busy' bit; it should be clear by now */
! 1356: off = IE_ISCP_BUSY(sc->iscp);
! 1357: bus_space_barrier(sc->bt, sc->bh, off, 1, BUS_SPACE_BARRIER_READ);
! 1358: result = (sc->ie_bus_read16)(sc, off) == 0;
! 1359:
! 1360: /* Acknowledge any interrupts we may have caused. */
! 1361: ie_ack(sc, IE_ST_WHENCE);
! 1362:
! 1363: return (result);
! 1364: }
! 1365:
! 1366: void
! 1367: i82596_reset(sc, hard)
! 1368: struct ie_softc *sc;
! 1369: int hard;
! 1370: {
! 1371: int s = splnet();
! 1372:
! 1373: #ifdef I82596_DEBUG
! 1374: if (hard)
! 1375: printf("%s: reset\n", sc->sc_dev.dv_xname);
! 1376: #endif
! 1377:
! 1378: /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */
! 1379: sc->sc_arpcom.ac_if.if_timer = 0;
! 1380: sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
! 1381:
! 1382: /*
! 1383: * Stop i82596 dead in its tracks.
! 1384: */
! 1385: if (i82596_start_cmd(sc, IE_RUC_ABORT | IE_CUC_ABORT, 0, 0, 0)) {
! 1386: #ifdef I82596_DEBUG
! 1387: printf("%s: abort commands timed out\n", sc->sc_dev.dv_xname);
! 1388: #endif
! 1389: }
! 1390:
! 1391: /*
! 1392: * This can really slow down the i82596_reset() on some cards, but it's
! 1393: * necessary to unwedge other ones (eg, the Sun VME ones) from certain
! 1394: * lockups.
! 1395: */
! 1396: if (hard && sc->hwreset)
! 1397: (sc->hwreset)(sc, IE_CARD_RESET);
! 1398:
! 1399: DELAY(100);
! 1400: ie_ack(sc, IE_ST_WHENCE);
! 1401:
! 1402: if ((sc->sc_arpcom.ac_if.if_flags & IFF_UP) != 0) {
! 1403: int retries=0; /* XXX - find out why init sometimes fails */
! 1404: while (retries++ < 2)
! 1405: if (i82596_init(sc) == 1)
! 1406: break;
! 1407: }
! 1408:
! 1409: splx(s);
! 1410: }
! 1411:
! 1412: void
! 1413: i82596_simple_command(sc, cmd, cmdbuf)
! 1414: struct ie_softc *sc;
! 1415: int cmd;
! 1416: int cmdbuf;
! 1417: {
! 1418: /* Setup a simple command */
! 1419: sc->ie_bus_write16(sc, IE_CMD_COMMON_STATUS(cmdbuf), 0);
! 1420: sc->ie_bus_write16(sc, IE_CMD_COMMON_CMD(cmdbuf), cmd | IE_CMD_LAST);
! 1421: sc->ie_bus_write16(sc, IE_CMD_COMMON_LINK(cmdbuf), 0xffff);
! 1422:
! 1423: /* Assign the command buffer to the SCB command list */
! 1424: sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb), cmdbuf);
! 1425: }
! 1426:
! 1427: /*
! 1428: * Run the time-domain reflectometer.
! 1429: */
! 1430: void
! 1431: ie_run_tdr(sc, cmd)
! 1432: struct ie_softc *sc;
! 1433: int cmd;
! 1434: {
! 1435: int result, clocks;
! 1436:
! 1437: i82596_simple_command(sc, IE_CMD_TDR, cmd);
! 1438: (sc->ie_bus_write16)(sc, IE_CMD_TDR_TIME(cmd), 0);
! 1439:
! 1440: if (i82596_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0) ||
! 1441: !(sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd)) & IE_STAT_OK))
! 1442: result = 0x10000; /* XXX */
! 1443: else
! 1444: result = sc->ie_bus_read16(sc, IE_CMD_TDR_TIME(cmd));
! 1445:
! 1446: /* Squash any pending interrupts */
! 1447: ie_ack(sc, IE_ST_WHENCE);
! 1448:
! 1449: if (result & IE_TDR_SUCCESS)
! 1450: return;
! 1451:
! 1452: clocks = result & IE_TDR_TIME;
! 1453: if (result & 0x10000)
! 1454: printf("%s: TDR command failed\n", sc->sc_dev.dv_xname);
! 1455: else if (result & IE_TDR_XCVR)
! 1456: printf("%s: transceiver problem\n", sc->sc_dev.dv_xname);
! 1457: else if (result & IE_TDR_OPEN)
! 1458: printf("%s: TDR detected an open %d clock%s away\n",
! 1459: sc->sc_dev.dv_xname, clocks, clocks == 1? "":"s");
! 1460: else if (result & IE_TDR_SHORT)
! 1461: printf("%s: TDR detected a short %d clock%s away\n",
! 1462: sc->sc_dev.dv_xname, clocks, clocks == 1? "":"s");
! 1463: else
! 1464: printf("%s: TDR returned unknown status 0x%x\n",
! 1465: sc->sc_dev.dv_xname, result);
! 1466: }
! 1467:
! 1468: /*
! 1469: * i82596_setup_bufs: set up the buffers
! 1470: *
! 1471: * We have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
! 1472: * this is to be used for the buffers. The chip indexs its control data
! 1473: * structures with 16 bit offsets, and it indexes actual buffers with
! 1474: * 24 bit addresses. So we should allocate control buffers first so that
! 1475: * we don't overflow the 16 bit offset field. The number of transmit
! 1476: * buffers is fixed at compile time.
! 1477: *
! 1478: */
! 1479: void
! 1480: i82596_setup_bufs(sc)
! 1481: struct ie_softc *sc;
! 1482: {
! 1483: int n, r, ptr = sc->buf_area; /* memory pool */
! 1484: int cl = 32;
! 1485:
! 1486: /*
! 1487: * step 0: zero memory and figure out how many recv buffers and
! 1488: * frames we can have.
! 1489: */
! 1490: ptr = (ptr + cl - 1) & ~(cl - 1); /* set alignment and stick with it */
! 1491:
! 1492: /*
! 1493: * step 1: lay out data structures in the shared-memory area
! 1494: */
! 1495:
! 1496: /* The no-op commands; used if "nop-chaining" is in effect */
! 1497: ptr += cl;
! 1498: sc->nop_cmds = ptr - 2;
! 1499: ptr += NTXBUF * 32;
! 1500:
! 1501: /* The transmit commands */
! 1502: ptr += cl;
! 1503: sc->xmit_cmds = ptr - 2;
! 1504: ptr += NTXBUF * 32;
! 1505:
! 1506: /* The transmit buffers descriptors */
! 1507: ptr += cl;
! 1508: sc->xbds = ptr - 2;
! 1509: ptr += NTXBUF * 32;
! 1510:
! 1511: /* The transmit buffers */
! 1512: sc->xbufs = ptr;
! 1513: ptr += NTXBUF * IE_TBUF_SIZE;
! 1514:
! 1515: ptr = (ptr + cl - 1) & ~(cl - 1); /* re-align.. just in case */
! 1516:
! 1517: /* Compute free space for RECV stuff */
! 1518: n = sc->buf_area_sz - (ptr - sc->buf_area);
! 1519:
! 1520: /* Compute size of one RECV frame */
! 1521: r = 64 + ((32 + IE_RBUF_SIZE) * B_PER_F);
! 1522:
! 1523: sc->nframes = n / r;
! 1524:
! 1525: if (sc->nframes <= 8)
! 1526: panic("ie: bogus buffer calc");
! 1527:
! 1528: sc->nrxbuf = sc->nframes * B_PER_F;
! 1529:
! 1530: /* The receive frame descriptors */
! 1531: ptr += cl;
! 1532: sc->rframes = ptr - 2;
! 1533: ptr += sc->nframes * 64;
! 1534:
! 1535: /* The receive buffer descriptors */
! 1536: ptr += cl;
! 1537: sc->rbds = ptr - 2;
! 1538: ptr += sc->nrxbuf * 32;
! 1539:
! 1540: /* The receive buffers */
! 1541: sc->rbufs = ptr;
! 1542: ptr += sc->nrxbuf * IE_RBUF_SIZE;
! 1543:
! 1544: #ifdef I82596_DEBUG
! 1545: printf("%s: %d frames %d bufs\n", sc->sc_dev.dv_xname, sc->nframes,
! 1546: sc->nrxbuf);
! 1547: #endif
! 1548:
! 1549: /*
! 1550: * step 2: link together the recv frames and set EOL on last one
! 1551: */
! 1552: for (n = 0; n < sc->nframes; n++) {
! 1553: int m = (n == sc->nframes - 1) ? 0 : n + 1;
! 1554:
! 1555: /* Clear status */
! 1556: sc->ie_bus_write16(sc, IE_RFRAME_STATUS(sc->rframes,n), 0);
! 1557:
! 1558: /* RBD link = NULL */
! 1559: sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,n),
! 1560: 0xffff);
! 1561:
! 1562: /* Make a circular list */
! 1563: sc->ie_bus_write16(sc, IE_RFRAME_NEXT(sc->rframes,n),
! 1564: IE_RFRAME_ADDR(sc->rframes,m));
! 1565:
! 1566: /* Mark last as EOL */
! 1567: sc->ie_bus_write16(sc, IE_RFRAME_LAST(sc->rframes,n),
! 1568: ((m==0)? (IE_FD_EOL|IE_FD_SUSP) : 0));
! 1569: }
! 1570:
! 1571: /*
! 1572: * step 3: link the RBDs and set EOL on last one
! 1573: */
! 1574: for (n = 0; n < sc->nrxbuf; n++) {
! 1575: int m = (n == sc->nrxbuf - 1) ? 0 : n + 1;
! 1576:
! 1577: /* Clear status */
! 1578: sc->ie_bus_write16(sc, IE_RBD_STATUS(sc->rbds,n), 0);
! 1579:
! 1580: /* Make a circular list */
! 1581: sc->ie_bus_write16(sc, IE_RBD_NEXT(sc->rbds,n),
! 1582: IE_RBD_ADDR(sc->rbds,m));
! 1583:
! 1584: /* Link to data buffers */
! 1585: sc->ie_bus_write24(sc, IE_RBD_BUFADDR(sc->rbds, n),
! 1586: sc->sc_maddr + IE_RBUF_ADDR(sc, n));
! 1587: sc->ie_bus_write16(sc, IE_RBD_BUFLEN(sc->rbds,n),
! 1588: IE_RBUF_SIZE | ((m==0)?IE_RBD_EOL:0));
! 1589: }
! 1590:
! 1591: /*
! 1592: * step 4: all xmit no-op commands loopback onto themselves
! 1593: */
! 1594: for (n = 0; n < NTXBUF; n++) {
! 1595: (sc->ie_bus_write16)(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, n), 0);
! 1596:
! 1597: (sc->ie_bus_write16)(sc, IE_CMD_NOP_CMD(sc->nop_cmds, n),
! 1598: IE_CMD_NOP);
! 1599:
! 1600: (sc->ie_bus_write16)(sc, IE_CMD_NOP_LINK(sc->nop_cmds, n),
! 1601: IE_CMD_NOP_ADDR(sc->nop_cmds, n));
! 1602: }
! 1603:
! 1604:
! 1605: /*
! 1606: * step 6: set the head and tail pointers on receive to keep track of
! 1607: * the order in which RFDs and RBDs are used.
! 1608: */
! 1609:
! 1610: /* Pointers to last packet sent and next available transmit buffer. */
! 1611: sc->xchead = sc->xctail = 0;
! 1612:
! 1613: /* Clear transmit-busy flag and set number of free transmit buffers. */
! 1614: sc->xmit_busy = 0;
! 1615:
! 1616: /*
! 1617: * Pointers to first and last receive frame.
! 1618: * The RFD pointed to by rftail is the only one that has EOL set.
! 1619: */
! 1620: sc->rfhead = 0;
! 1621: sc->rftail = sc->nframes - 1;
! 1622:
! 1623: /*
! 1624: * Pointers to first and last receive descriptor buffer.
! 1625: * The RBD pointed to by rbtail is the only one that has EOL set.
! 1626: */
! 1627: sc->rbhead = 0;
! 1628: sc->rbtail = sc->nrxbuf - 1;
! 1629:
! 1630: /* link in recv frames * and buffer into the scb. */
! 1631: #ifdef I82596_DEBUG
! 1632: printf("%s: reserved %d bytes\n",
! 1633: sc->sc_dev.dv_xname, ptr - sc->buf_area);
! 1634: #endif
! 1635: }
! 1636:
! 1637: int
! 1638: ie_cfg_setup(sc, cmd, promiscuous, manchester)
! 1639: struct ie_softc *sc;
! 1640: int cmd;
! 1641: int promiscuous, manchester;
! 1642: {
! 1643: int cmdresult, status;
! 1644:
! 1645: i82596_simple_command(sc, IE_CMD_CONFIG, cmd);
! 1646: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_CNT(cmd), 0x0c);
! 1647: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_FIFO(cmd), 8);
! 1648: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_SAVEBAD(cmd), 0x40);
! 1649: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_ADDRLEN(cmd), 0x2e);
! 1650: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_PRIORITY(cmd), 0);
! 1651: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_IFS(cmd), 0x60);
! 1652: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_SLOT_LOW(cmd), 0);
! 1653: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_SLOT_HIGH(cmd), 0xf2);
! 1654: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_PROMISC(cmd),
! 1655: !!promiscuous | manchester << 2);
! 1656: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_CRSCDT(cmd), 0);
! 1657: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_MINLEN(cmd), 64);
! 1658: bus_space_write_1(sc->bt, sc->bh, IE_CMD_CFG_JUNK(cmd), 0xff);
! 1659: bus_space_barrier(sc->bt, sc->bh, cmd, IE_CMD_CFG_SZ,
! 1660: BUS_SPACE_BARRIER_WRITE);
! 1661:
! 1662: cmdresult = i82596_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0);
! 1663: status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd));
! 1664: if (cmdresult != 0) {
! 1665: printf("%s: configure command timed out; status %b\n",
! 1666: sc->sc_dev.dv_xname, status, IE_STAT_BITS);
! 1667: return (0);
! 1668: }
! 1669: if ((status & IE_STAT_OK) == 0) {
! 1670: printf("%s: configure command failed; status %b\n",
! 1671: sc->sc_dev.dv_xname, status, IE_STAT_BITS);
! 1672: return (0);
! 1673: }
! 1674:
! 1675: /* Squash any pending interrupts */
! 1676: ie_ack(sc, IE_ST_WHENCE);
! 1677: return (1);
! 1678: }
! 1679:
! 1680: int
! 1681: ie_ia_setup(sc, cmdbuf)
! 1682: struct ie_softc *sc;
! 1683: int cmdbuf;
! 1684: {
! 1685: int cmdresult, status;
! 1686:
! 1687: i82596_simple_command(sc, IE_CMD_IASETUP, cmdbuf);
! 1688:
! 1689: (sc->memcopyout)(sc, sc->sc_arpcom.ac_enaddr,
! 1690: IE_CMD_IAS_EADDR(cmdbuf), ETHER_ADDR_LEN);
! 1691:
! 1692: cmdresult = i82596_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
! 1693: status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
! 1694: if (cmdresult != 0) {
! 1695: printf("%s: individual address command timed out; status %b\n",
! 1696: sc->sc_dev.dv_xname, status, IE_STAT_BITS);
! 1697: return (0);
! 1698: }
! 1699: if ((status & IE_STAT_OK) == 0) {
! 1700: printf("%s: individual address command failed; status %b\n",
! 1701: sc->sc_dev.dv_xname, status, IE_STAT_BITS);
! 1702: return (0);
! 1703: }
! 1704:
! 1705: /* Squash any pending interrupts */
! 1706: ie_ack(sc, IE_ST_WHENCE);
! 1707: return (1);
! 1708: }
! 1709:
! 1710: /*
! 1711: * Run the multicast setup command.
! 1712: * Called at splnet().
! 1713: */
! 1714: int
! 1715: ie_mc_setup(sc, cmdbuf)
! 1716: struct ie_softc *sc;
! 1717: int cmdbuf;
! 1718: {
! 1719: int cmdresult, status;
! 1720:
! 1721: if (sc->mcast_count == 0)
! 1722: return (1);
! 1723:
! 1724: i82596_simple_command(sc, IE_CMD_MCAST, cmdbuf);
! 1725:
! 1726: (sc->memcopyout)(sc, (caddr_t)sc->mcast_addrs,
! 1727: IE_CMD_MCAST_MADDR(cmdbuf),
! 1728: sc->mcast_count * ETHER_ADDR_LEN);
! 1729:
! 1730: sc->ie_bus_write16(sc, IE_CMD_MCAST_BYTES(cmdbuf),
! 1731: sc->mcast_count * ETHER_ADDR_LEN);
! 1732:
! 1733: /* Start the command */
! 1734: cmdresult = i82596_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
! 1735: status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
! 1736: if (cmdresult != 0) {
! 1737: printf("%s: multicast setup command timed out; status %b\n",
! 1738: sc->sc_dev.dv_xname, status, IE_STAT_BITS);
! 1739: return (0);
! 1740: }
! 1741: if ((status & IE_STAT_OK) == 0) {
! 1742: printf("%s: multicast setup command failed; status %b\n",
! 1743: sc->sc_dev.dv_xname, status, IE_STAT_BITS);
! 1744: return (0);
! 1745: }
! 1746:
! 1747: /* Squash any pending interrupts */
! 1748: ie_ack(sc, IE_ST_WHENCE);
! 1749: return (1);
! 1750: }
! 1751:
! 1752: /*
! 1753: * This routine takes the environment generated by check_ie_present() and adds
! 1754: * to it all the other structures we need to operate the adapter. This
! 1755: * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
! 1756: * the receiver unit, and clearing interrupts.
! 1757: *
! 1758: * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
! 1759: */
! 1760: int
! 1761: i82596_init(sc)
! 1762: struct ie_softc *sc;
! 1763: {
! 1764: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1765: int cmd;
! 1766:
! 1767: sc->async_cmd_inprogress = 0;
! 1768:
! 1769: cmd = sc->buf_area;
! 1770:
! 1771: /*
! 1772: * Send the configure command first.
! 1773: */
! 1774: if (ie_cfg_setup(sc, cmd, sc->promisc, 0) == 0)
! 1775: return (0);
! 1776:
! 1777: /*
! 1778: * Send the Individual Address Setup command.
! 1779: */
! 1780: if (ie_ia_setup(sc, cmd) == 0)
! 1781: return (0);
! 1782:
! 1783: /*
! 1784: * Run the time-domain reflectometer.
! 1785: */
! 1786: ie_run_tdr(sc, cmd);
! 1787:
! 1788: /*
! 1789: * Set the multi-cast filter, if any
! 1790: */
! 1791: if (ie_mc_setup(sc, cmd) == 0)
! 1792: return (0);
! 1793:
! 1794: /*
! 1795: * Acknowledge any interrupts we have generated thus far.
! 1796: */
! 1797: ie_ack(sc, IE_ST_WHENCE);
! 1798:
! 1799: /*
! 1800: * Set up the transmit and recv buffers.
! 1801: */
! 1802: i82596_setup_bufs(sc);
! 1803:
! 1804: if (sc->hwinit)
! 1805: (sc->hwinit)(sc);
! 1806:
! 1807: ifp->if_flags |= IFF_RUNNING;
! 1808: ifp->if_flags &= ~IFF_OACTIVE;
! 1809:
! 1810: if (NTXBUF < 2)
! 1811: sc->do_xmitnopchain = 0;
! 1812:
! 1813: i82596_start_transceiver(sc);
! 1814: return (1);
! 1815: }
! 1816:
! 1817: /*
! 1818: * Start the RU and possibly the CU unit
! 1819: */
! 1820: void
! 1821: i82596_start_transceiver(sc)
! 1822: struct ie_softc *sc;
! 1823: {
! 1824:
! 1825: /*
! 1826: * Start RU at current position in frame & RBD lists.
! 1827: */
! 1828: sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,sc->rfhead),
! 1829: IE_RBD_ADDR(sc->rbds, sc->rbhead));
! 1830:
! 1831: sc->ie_bus_write16(sc, IE_SCB_RCVLST(sc->scb),
! 1832: IE_RFRAME_ADDR(sc->rframes,sc->rfhead));
! 1833:
! 1834: if (sc->do_xmitnopchain) {
! 1835: /* Stop transmit command chain */
! 1836: if (i82596_start_cmd(sc, IE_CUC_SUSPEND|IE_RUC_SUSPEND, 0, 0, 0))
! 1837: printf("%s: CU/RU stop command timed out\n",
! 1838: sc->sc_dev.dv_xname);
! 1839:
! 1840: /* Start the receiver & transmitter chain */
! 1841: /* sc->scb->ie_command_list =
! 1842: IEADDR(sc->nop_cmds[(sc->xctail+NTXBUF-1) % NTXBUF]);*/
! 1843: sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb),
! 1844: IE_CMD_NOP_ADDR(
! 1845: sc->nop_cmds,
! 1846: (sc->xctail + NTXBUF - 1) % NTXBUF));
! 1847:
! 1848: if (i82596_start_cmd(sc, IE_CUC_START|IE_RUC_START, 0, 0, 0))
! 1849: printf("%s: CU/RU command timed out\n",
! 1850: sc->sc_dev.dv_xname);
! 1851: } else {
! 1852: if (i82596_start_cmd(sc, IE_RUC_START, 0, 0, 0))
! 1853: printf("%s: RU command timed out\n",
! 1854: sc->sc_dev.dv_xname);
! 1855: }
! 1856: }
! 1857:
! 1858: void
! 1859: i82596_stop(sc)
! 1860: struct ie_softc *sc;
! 1861: {
! 1862:
! 1863: if (i82596_start_cmd(sc, IE_RUC_SUSPEND | IE_CUC_SUSPEND, 0, 0, 0))
! 1864: printf("%s: i82596_stop: disable commands timed out\n",
! 1865: sc->sc_dev.dv_xname);
! 1866: }
! 1867:
! 1868: int
! 1869: i82596_ioctl(ifp, cmd, data)
! 1870: register struct ifnet *ifp;
! 1871: u_long cmd;
! 1872: caddr_t data;
! 1873: {
! 1874: struct ie_softc *sc = ifp->if_softc;
! 1875: struct ifaddr *ifa = (struct ifaddr *)data;
! 1876: struct ifreq *ifr = (struct ifreq *)data;
! 1877: int s, error = 0;
! 1878:
! 1879: s = splnet();
! 1880:
! 1881: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 1882: splx(s);
! 1883: return error;
! 1884: }
! 1885:
! 1886: switch(cmd) {
! 1887:
! 1888: case SIOCSIFADDR:
! 1889: ifp->if_flags |= IFF_UP;
! 1890:
! 1891: switch(ifa->ifa_addr->sa_family) {
! 1892: #ifdef INET
! 1893: case AF_INET:
! 1894: i82596_init(sc);
! 1895: arp_ifinit(&sc->sc_arpcom, ifa);
! 1896: break;
! 1897: #endif
! 1898: default:
! 1899: i82596_init(sc);
! 1900: break;
! 1901: }
! 1902: break;
! 1903:
! 1904: case SIOCSIFFLAGS:
! 1905: sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
! 1906: if ((ifp->if_flags & IFF_UP) == 0 &&
! 1907: (ifp->if_flags & IFF_RUNNING) != 0) {
! 1908: /*
! 1909: * If interface is marked down and it is running, then
! 1910: * stop it.
! 1911: */
! 1912: i82596_stop(sc);
! 1913: ifp->if_flags &= ~IFF_RUNNING;
! 1914: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 1915: (ifp->if_flags & IFF_RUNNING) == 0) {
! 1916: /*
! 1917: * If interface is marked up and it is stopped, then
! 1918: * start it.
! 1919: */
! 1920: i82596_init(sc);
! 1921: } else {
! 1922: /*
! 1923: * Reset the interface to pick up changes in any other
! 1924: * flags that affect hardware registers.
! 1925: */
! 1926: i82596_stop(sc);
! 1927: i82596_init(sc);
! 1928: }
! 1929: #ifdef I82596_DEBUG
! 1930: if (ifp->if_flags & IFF_DEBUG)
! 1931: sc->sc_debug = IED_ALL;
! 1932: else
! 1933: sc->sc_debug = 0;
! 1934: #endif
! 1935: break;
! 1936:
! 1937: case SIOCADDMULTI:
! 1938: case SIOCDELMULTI:
! 1939: error = (cmd == SIOCADDMULTI) ?
! 1940: ether_addmulti(ifr, &sc->sc_arpcom):
! 1941: ether_delmulti(ifr, &sc->sc_arpcom);
! 1942:
! 1943: if (error == ENETRESET) {
! 1944: /*
! 1945: * Multicast list has changed; set the hardware filter
! 1946: * accordingly.
! 1947: */
! 1948: if (ifp->if_flags & IFF_RUNNING)
! 1949: ie_mc_reset(sc);
! 1950: error = 0;
! 1951: }
! 1952: break;
! 1953:
! 1954: case SIOCGIFMEDIA:
! 1955: case SIOCSIFMEDIA:
! 1956: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 1957: break;
! 1958:
! 1959: default:
! 1960: error = EINVAL;
! 1961: }
! 1962: splx(s);
! 1963: return (error);
! 1964: }
! 1965:
! 1966: void
! 1967: ie_mc_reset(sc)
! 1968: struct ie_softc *sc;
! 1969: {
! 1970: struct ether_multi *enm;
! 1971: struct ether_multistep step;
! 1972: int size;
! 1973:
! 1974: /*
! 1975: * Step through the list of addresses.
! 1976: */
! 1977: again:
! 1978: size = 0;
! 1979: sc->mcast_count = 0;
! 1980: ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
! 1981: while (enm) {
! 1982: size += 6;
! 1983: if (sc->mcast_count >= IE_MAXMCAST ||
! 1984: bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
! 1985: sc->sc_arpcom.ac_if.if_flags |= IFF_ALLMULTI;
! 1986: i82596_ioctl(&sc->sc_arpcom.ac_if,
! 1987: SIOCSIFFLAGS, (void *)0);
! 1988: return;
! 1989: }
! 1990: ETHER_NEXT_MULTI(step, enm);
! 1991: }
! 1992:
! 1993: if (size > sc->mcast_addrs_size) {
! 1994: /* Need to allocate more space */
! 1995: if (sc->mcast_addrs_size)
! 1996: free(sc->mcast_addrs, M_IFMADDR);
! 1997: sc->mcast_addrs = (char *)
! 1998: malloc(size, M_IFMADDR, M_WAITOK);
! 1999: sc->mcast_addrs_size = size;
! 2000: }
! 2001:
! 2002: /*
! 2003: * We've got the space; now copy the addresses
! 2004: */
! 2005: ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
! 2006: while (enm) {
! 2007: if (sc->mcast_count >= IE_MAXMCAST)
! 2008: goto again; /* Just in case */
! 2009:
! 2010: bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6);
! 2011: sc->mcast_count++;
! 2012: ETHER_NEXT_MULTI(step, enm);
! 2013: }
! 2014: sc->want_mcsetup = 1;
! 2015: }
! 2016:
! 2017: /*
! 2018: * Media change callback.
! 2019: */
! 2020: int
! 2021: i82596_mediachange(ifp)
! 2022: struct ifnet *ifp;
! 2023: {
! 2024: struct ie_softc *sc = ifp->if_softc;
! 2025:
! 2026: if (sc->sc_mediachange)
! 2027: return ((*sc->sc_mediachange)(sc));
! 2028: return (EINVAL);
! 2029: }
! 2030:
! 2031: /*
! 2032: * Media status callback.
! 2033: */
! 2034: void
! 2035: i82596_mediastatus(ifp, ifmr)
! 2036: struct ifnet *ifp;
! 2037: struct ifmediareq *ifmr;
! 2038: {
! 2039: struct ie_softc *sc = ifp->if_softc;
! 2040:
! 2041: if (sc->sc_mediastatus)
! 2042: (*sc->sc_mediastatus)(sc, ifmr);
! 2043: }
! 2044:
! 2045: #ifdef I82596_DEBUG
! 2046: void
! 2047: print_rbd(sc, n)
! 2048: struct ie_softc *sc;
! 2049: int n;
! 2050: {
! 2051:
! 2052: printf("RBD at %08x:\n status %b, next %04x, buffer %lx\n"
! 2053: "length/EOL %04x\n", IE_RBD_ADDR(sc->rbds,n),
! 2054: sc->ie_bus_read16(sc, IE_RBD_STATUS(sc->rbds,n)), IE_STAT_BITS,
! 2055: sc->ie_bus_read16(sc, IE_RBD_NEXT(sc->rbds,n)),
! 2056: (u_long)0,/*bus_space_read_4(sc->bt, sc->bh, IE_RBD_BUFADDR(sc->rbds,n)),-* XXX */
! 2057: sc->ie_bus_read16(sc, IE_RBD_BUFLEN(sc->rbds,n)));
! 2058: }
! 2059: #endif
CVSweb