Annotation of sys/dev/isa/if_ie.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ie.c,v 1.33 2006/04/16 00:46:32 pascoe Exp $ */
! 2: /* $NetBSD: if_ie.c,v 1.51 1996/05/12 23:52:48 mycroft Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1993, 1994, 1995 Charles Hannum.
! 6: * Copyright (c) 1992, 1993, University of Vermont and State
! 7: * Agricultural College.
! 8: * Copyright (c) 1992, 1993, Garrett A. Wollman.
! 9: *
! 10: * Portions:
! 11: * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes
! 12: * Copyright (c) 1994, 1995, Rafal K. Boni
! 13: * Copyright (c) 1990, 1991, William F. Jolitz
! 14: * Copyright (c) 1990, The Regents of the University of California
! 15: *
! 16: * All rights reserved.
! 17: *
! 18: * Redistribution and use in source and binary forms, with or without
! 19: * modification, are permitted provided that the following conditions
! 20: * are met:
! 21: * 1. Redistributions of source code must retain the above copyright
! 22: * notice, this list of conditions and the following disclaimer.
! 23: * 2. Redistributions in binary form must reproduce the above copyright
! 24: * notice, this list of conditions and the following disclaimer in the
! 25: * documentation and/or other materials provided with the distribution.
! 26: * 3. All advertising materials mentioning features or use of this software
! 27: * must display the following acknowledgement:
! 28: * This product includes software developed by Charles Hannum, by the
! 29: * University of Vermont and State Agricultural College and Garrett A.
! 30: * Wollman, by William F. Jolitz, and by the University of California,
! 31: * Berkeley, Lawrence Berkeley Laboratory, and its contributors.
! 32: * 4. Neither the names of the Universities nor the names of the authors
! 33: * may be used to endorse or promote products derived from this software
! 34: * without specific prior written permission.
! 35: *
! 36: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 37: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 38: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 39: * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
! 40: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 41: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 42: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 44: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 45: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 46: * SUCH DAMAGE.
! 47: */
! 48:
! 49: /*
! 50: * Intel 82586 Ethernet chip
! 51: * Register, bit, and structure definitions.
! 52: *
! 53: * Original StarLAN driver written by Garrett Wollman with reference to the
! 54: * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
! 55: *
! 56: * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
! 57: *
! 58: * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
! 59: *
! 60: * Intel EtherExpress 16 support taken from FreeBSD's if_ix.c, written
! 61: * by Rodney W. Grimes.
! 62: *
! 63: * Majorly cleaned up and 3C507 code merged by Charles Hannum.
! 64: */
! 65:
! 66: /*
! 67: * The i82586 is a very versatile chip, found in many implementations.
! 68: * Programming this chip is mostly the same, but certain details differ
! 69: * from card to card. This driver is written so that different cards
! 70: * can be automatically detected at run-time.
! 71: */
! 72:
! 73: /*
! 74: Mode of operation:
! 75:
! 76: We run the 82586 in a standard Ethernet mode. We keep NFRAMES received frame
! 77: descriptors around for the receiver to use, and NRXBUF associated receive
! 78: buffer descriptors, both in a circular list. Whenever a frame is received, we
! 79: rotate both lists as necessary. (The 586 treats both lists as a simple
! 80: queue.) We also keep a transmit command around so that packets can be sent
! 81: off quickly.
! 82:
! 83: We configure the adapter in AL-LOC = 1 mode, which means that the
! 84: Ethernet/802.3 MAC header is placed at the beginning of the receive buffer
! 85: rather than being split off into various fields in the RFD. This also means
! 86: that we must include this header in the transmit buffer as well.
! 87:
! 88: By convention, all transmit commands, and only transmit commands, shall have
! 89: the I (IE_CMD_INTR) bit set in the command. This way, when an interrupt
! 90: arrives at ieintr(), it is immediately possible to tell what precisely caused
! 91: it. ANY OTHER command-sending routines should run at splnet(), and should
! 92: post an acknowledgement to every interrupt they generate.
! 93:
! 94: The 82586 has a 24-bit address space internally, and the adaptor's memory is
! 95: located at the top of this region. However, the value we are given in
! 96: configuration is the CPU's idea of where the adaptor RAM is. So, we must go
! 97: through a few gyrations to come up with a kernel virtual address which
! 98: represents the actual beginning of the 586 address space. First, we autosize
! 99: the RAM by running through several possible sizes and trying to initialize the
! 100: adapter under the assumption that the selected size is correct. Then, knowing
! 101: the correct RAM size, we set up our pointers in the softc. `sc_maddr'
! 102: represents the computed base of the 586 address space. `iomembot' represents
! 103: the actual configured base of adapter RAM. Finally, `sc_msize' represents the
! 104: calculated size of 586 RAM. Then, when laying out commands, we use the
! 105: interval [sc_maddr, sc_maddr + sc_msize); to make 24-pointers, we subtract
! 106: iomem, and to make 16-pointers, we subtract sc_maddr and and with 0xffff.
! 107: */
! 108:
! 109: #include "bpfilter.h"
! 110:
! 111: #include <sys/param.h>
! 112: #include <sys/systm.h>
! 113: #include <sys/mbuf.h>
! 114: #include <sys/buf.h>
! 115: #include <sys/protosw.h>
! 116: #include <sys/socket.h>
! 117: #include <sys/ioctl.h>
! 118: #include <sys/errno.h>
! 119: #include <sys/syslog.h>
! 120: #include <sys/device.h>
! 121: #include <sys/timeout.h>
! 122:
! 123: #include <net/if.h>
! 124: #include <net/if_types.h>
! 125: #include <net/if_dl.h>
! 126: #include <net/netisr.h>
! 127: #include <net/route.h>
! 128:
! 129: #if NBPFILTER > 0
! 130: #include <net/bpf.h>
! 131: #endif
! 132:
! 133: #ifdef INET
! 134: #include <netinet/in.h>
! 135: #include <netinet/in_systm.h>
! 136: #include <netinet/in_var.h>
! 137: #include <netinet/ip.h>
! 138: #include <netinet/if_ether.h>
! 139: #endif
! 140:
! 141: #include <machine/cpu.h>
! 142: #include <machine/bus.h>
! 143: #include <machine/intr.h>
! 144:
! 145: #include <dev/isa/isareg.h>
! 146: #include <dev/isa/isavar.h>
! 147: #include <i386/isa/isa_machdep.h> /* XXX USES ISA HOLE DIRECTLY */
! 148: #include <dev/ic/i82586reg.h>
! 149: #include <dev/isa/if_ieatt.h>
! 150: #include <dev/isa/if_ie507.h>
! 151: #include <dev/isa/if_iee16.h>
! 152: #include <dev/isa/elink.h>
! 153:
! 154: #define IED_RINT 0x01
! 155: #define IED_TINT 0x02
! 156: #define IED_RNR 0x04
! 157: #define IED_CNA 0x08
! 158: #define IED_READFRAME 0x10
! 159: #define IED_ENQ 0x20
! 160: #define IED_XMIT 0x40
! 161: #define IED_ALL 0x7f
! 162:
! 163: /*
! 164: sizeof(iscp) == 1+1+2+4 == 8
! 165: sizeof(scb) == 2+2+2+2+2+2+2+2 == 16
! 166: NFRAMES * sizeof(rfd) == NFRAMES*(2+2+2+2+6+6+2+2) == NFRAMES*24 == 384
! 167: sizeof(xmit_cmd) == 2+2+2+2+6+2 == 18
! 168: sizeof(transmit buffer) == ETHER_MAX_LEN == 1518
! 169: sizeof(transmit buffer desc) == 8
! 170: -----
! 171: 1952
! 172:
! 173: NRXBUF * sizeof(rbd) == NRXBUF*(2+2+4+2+2) == NRXBUF*12
! 174: NRXBUF * IE_RBUF_SIZE == NRXBUF*256
! 175:
! 176: NRXBUF should be (16384 - 1952) / (256 + 12) == 14432 / 268 == 53
! 177:
! 178: With NRXBUF == 48, this leaves us 1568 bytes for another command or
! 179: more buffers. Another transmit command would be 18+8+1518 == 1544
! 180: ---just barely fits!
! 181:
! 182: Obviously all these would have to be reduced for smaller memory sizes.
! 183: With a larger memory, it would be possible to roughly double the number of
! 184: both transmit and receive buffers.
! 185: */
! 186:
! 187: #define NFRAMES 16 /* number of receive frames */
! 188: #define NRXBUF 48 /* number of buffers to allocate */
! 189: #define IE_RBUF_SIZE 256 /* size of each receive buffer;
! 190: MUST BE POWER OF TWO */
! 191: #define NTXBUF 2 /* number of transmit commands */
! 192: #define IE_TBUF_SIZE ETHER_MAX_LEN /* length of transmit buffer */
! 193:
! 194:
! 195: enum ie_hardware {
! 196: IE_STARLAN10,
! 197: IE_EN100,
! 198: IE_SLFIBER,
! 199: IE_3C507,
! 200: IE_EE16,
! 201: IE_UNKNOWN
! 202: };
! 203:
! 204: const char *ie_hardware_names[] = {
! 205: "StarLAN 10",
! 206: "EN100",
! 207: "StarLAN Fiber",
! 208: "3C507",
! 209: "EtherExpress 16",
! 210: "Unknown"
! 211: };
! 212:
! 213: /*
! 214: * Ethernet status, per interface.
! 215: */
! 216: struct ie_softc {
! 217: struct device sc_dev;
! 218: void *sc_ih;
! 219:
! 220: int sc_iobase;
! 221: caddr_t sc_maddr;
! 222: u_int sc_msize;
! 223:
! 224: struct arpcom sc_arpcom;
! 225:
! 226: void (*reset_586)(struct ie_softc *);
! 227: void (*chan_attn)(struct ie_softc *);
! 228:
! 229: enum ie_hardware hard_type;
! 230: int hard_vers;
! 231:
! 232: int want_mcsetup;
! 233: int promisc;
! 234: volatile struct ie_int_sys_conf_ptr *iscp;
! 235: volatile struct ie_sys_ctl_block *scb;
! 236:
! 237: int rfhead, rftail, rbhead, rbtail;
! 238: volatile struct ie_recv_frame_desc *rframes[NFRAMES];
! 239: volatile struct ie_recv_buf_desc *rbuffs[NRXBUF];
! 240: volatile char *cbuffs[NRXBUF];
! 241:
! 242: int xmit_busy;
! 243: int xchead, xctail;
! 244: volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF];
! 245: volatile struct ie_xmit_buf *xmit_buffs[NTXBUF];
! 246: u_char *xmit_cbuffs[NTXBUF];
! 247:
! 248: struct ie_en_addr mcast_addrs[MAXMCAST + 1];
! 249: int mcast_count;
! 250:
! 251: u_short irq_encoded; /* encoded interrupt on IEE16 */
! 252:
! 253: #ifdef IEDEBUG
! 254: int sc_debug;
! 255: #endif
! 256: };
! 257:
! 258: void iewatchdog(struct ifnet *);
! 259: int ieintr(void *);
! 260: void iestop(struct ie_softc *);
! 261: int ieinit(struct ie_softc *);
! 262: int ieioctl(struct ifnet *, u_long, caddr_t);
! 263: void iestart(struct ifnet *);
! 264: static void el_reset_586(struct ie_softc *);
! 265: static void sl_reset_586(struct ie_softc *);
! 266: static void el_chan_attn(struct ie_softc *);
! 267: static void sl_chan_attn(struct ie_softc *);
! 268: static void slel_get_address(struct ie_softc *);
! 269:
! 270: static void ee16_reset_586(struct ie_softc *);
! 271: static void ee16_chan_attn(struct ie_softc *);
! 272: static void ee16_interrupt_enable(struct ie_softc *);
! 273: void ee16_eeprom_outbits(struct ie_softc *, int, int);
! 274: void ee16_eeprom_clock(struct ie_softc *, int);
! 275: u_short ee16_read_eeprom(struct ie_softc *, int);
! 276: int ee16_eeprom_inbits(struct ie_softc *);
! 277:
! 278: void iereset(struct ie_softc *);
! 279: void ie_readframe(struct ie_softc *, int);
! 280: void ie_drop_packet_buffer(struct ie_softc *);
! 281: void ie_find_mem_size(struct ie_softc *);
! 282: static int command_and_wait(struct ie_softc *, int,
! 283: void volatile *, int);
! 284: void ierint(struct ie_softc *);
! 285: void ietint(struct ie_softc *);
! 286: void iexmit(struct ie_softc *);
! 287: struct mbuf *ieget(struct ie_softc *,
! 288: struct ether_header *, int *);
! 289: void iememinit(void *, struct ie_softc *);
! 290: static int mc_setup(struct ie_softc *, void *);
! 291: static void mc_reset(struct ie_softc *);
! 292:
! 293: #ifdef IEDEBUG
! 294: void print_rbd(volatile struct ie_recv_buf_desc *);
! 295:
! 296: int in_ierint = 0;
! 297: int in_ietint = 0;
! 298: #endif
! 299:
! 300: int ieprobe(struct device *, void *, void *);
! 301: void ieattach(struct device *, struct device *, void *);
! 302: int sl_probe(struct ie_softc *, struct isa_attach_args *);
! 303: int el_probe(struct ie_softc *, struct isa_attach_args *);
! 304: int ee16_probe(struct ie_softc *, struct isa_attach_args *);
! 305: int check_ie_present(struct ie_softc *, caddr_t, u_int);
! 306:
! 307: static __inline void ie_setup_config(volatile struct ie_config_cmd *,
! 308: int, int);
! 309: static __inline void ie_ack(struct ie_softc *, u_int);
! 310: static __inline int ether_equal(u_char *, u_char *);
! 311: static __inline int check_eh(struct ie_softc *, struct ether_header *,
! 312: int *);
! 313: static __inline int ie_buflen(struct ie_softc *, int);
! 314: static __inline int ie_packet_len(struct ie_softc *);
! 315:
! 316: static void run_tdr(struct ie_softc *, struct ie_tdr_cmd *);
! 317:
! 318: struct cfattach ie_isa_ca = {
! 319: sizeof(struct ie_softc), ieprobe, ieattach
! 320: };
! 321:
! 322: struct cfdriver ie_cd = {
! 323: NULL, "ie", DV_IFNET
! 324: };
! 325:
! 326: #define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base))
! 327: #define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr))
! 328:
! 329: #define PORT sc->sc_iobase
! 330: #define MEM sc->sc_maddr
! 331:
! 332: /*
! 333: * Here are a few useful functions. We could have done these as macros, but
! 334: * since we have the inline facility, it makes sense to use that instead.
! 335: */
! 336: static __inline void
! 337: ie_setup_config(cmd, promiscuous, manchester)
! 338: volatile struct ie_config_cmd *cmd;
! 339: int promiscuous, manchester;
! 340: {
! 341:
! 342: cmd->ie_config_count = 0x0c;
! 343: cmd->ie_fifo = 8;
! 344: cmd->ie_save_bad = 0x40;
! 345: cmd->ie_addr_len = 0x2e;
! 346: cmd->ie_priority = 0;
! 347: cmd->ie_ifs = 0x60;
! 348: cmd->ie_slot_low = 0;
! 349: cmd->ie_slot_high = 0xf2;
! 350: cmd->ie_promisc = promiscuous | manchester << 2;
! 351: cmd->ie_crs_cdt = 0;
! 352: cmd->ie_min_len = 64;
! 353: cmd->ie_junk = 0xff;
! 354: }
! 355:
! 356: static __inline void
! 357: ie_ack(sc, mask)
! 358: struct ie_softc *sc;
! 359: u_int mask;
! 360: {
! 361: volatile struct ie_sys_ctl_block *scb = sc->scb;
! 362:
! 363: scb->ie_command = scb->ie_status & mask;
! 364: (sc->chan_attn)(sc);
! 365:
! 366: while (scb->ie_command)
! 367: ; /* Spin Lock */
! 368: }
! 369:
! 370: int
! 371: ieprobe(parent, match, aux)
! 372: struct device *parent;
! 373: void *match, *aux;
! 374: {
! 375: struct ie_softc *sc = match;
! 376: struct isa_attach_args *ia = aux;
! 377:
! 378: if (sl_probe(sc, ia))
! 379: return 1;
! 380: if (el_probe(sc, ia))
! 381: return 1;
! 382: if (ee16_probe(sc, ia))
! 383: return 1;
! 384: return 0;
! 385: }
! 386:
! 387: int
! 388: sl_probe(sc, ia)
! 389: struct ie_softc *sc;
! 390: struct isa_attach_args *ia;
! 391: {
! 392: u_char c;
! 393:
! 394: sc->sc_iobase = ia->ia_iobase;
! 395:
! 396: /* Need this for part of the probe. */
! 397: sc->reset_586 = sl_reset_586;
! 398: sc->chan_attn = sl_chan_attn;
! 399:
! 400: c = inb(PORT + IEATT_REVISION);
! 401: switch (SL_BOARD(c)) {
! 402: case SL10_BOARD:
! 403: sc->hard_type = IE_STARLAN10;
! 404: break;
! 405: case EN100_BOARD:
! 406: sc->hard_type = IE_EN100;
! 407: break;
! 408: case SLFIBER_BOARD:
! 409: sc->hard_type = IE_SLFIBER;
! 410: break;
! 411:
! 412: default:
! 413: /* Anything else is not recognized or cannot be used. */
! 414: #if 0
! 415: printf("%s: unknown AT&T board type code %d\n",
! 416: sc->sc_dev.dv_xname, SL_BOARD(c));
! 417: #endif
! 418: return 0;
! 419: }
! 420:
! 421: sc->hard_vers = SL_REV(c);
! 422:
! 423: if (ia->ia_irq == IRQUNK || ia->ia_maddr == MADDRUNK) {
! 424: printf("%s: %s does not have soft configuration\n",
! 425: sc->sc_dev.dv_xname, ie_hardware_names[sc->hard_type]);
! 426: return 0;
! 427: }
! 428:
! 429: /*
! 430: * Divine memory size on-board the card. Ususally 16k.
! 431: */
! 432: sc->sc_maddr = ISA_HOLE_VADDR(ia->ia_maddr);
! 433: ie_find_mem_size(sc);
! 434:
! 435: if (!sc->sc_msize) {
! 436: printf("%s: can't find shared memory\n", sc->sc_dev.dv_xname);
! 437: return 0;
! 438: }
! 439:
! 440: if (!ia->ia_msize)
! 441: ia->ia_msize = sc->sc_msize;
! 442: else if (ia->ia_msize != sc->sc_msize) {
! 443: printf("%s: msize mismatch; kernel configured %d != board configured %d\n",
! 444: sc->sc_dev.dv_xname, ia->ia_msize, sc->sc_msize);
! 445: return 0;
! 446: }
! 447:
! 448: slel_get_address(sc);
! 449:
! 450: ia->ia_iosize = 16;
! 451: return 1;
! 452: }
! 453:
! 454: int
! 455: el_probe(sc, ia)
! 456: struct ie_softc *sc;
! 457: struct isa_attach_args *ia;
! 458: {
! 459: bus_space_tag_t iot = ia->ia_iot;
! 460: bus_space_handle_t ioh;
! 461: u_char c;
! 462: int i, rval = 0;
! 463: u_char signature[] = "*3COM*";
! 464:
! 465: sc->sc_iobase = ia->ia_iobase;
! 466:
! 467: /* Need this for part of the probe. */
! 468: sc->reset_586 = el_reset_586;
! 469: sc->chan_attn = el_chan_attn;
! 470:
! 471: /*
! 472: * Map the Etherlink ID port for the probe sequence.
! 473: */
! 474: if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
! 475: printf("3c507 probe: can't map Etherlink ID port\n");
! 476: return 0;
! 477: }
! 478:
! 479: /*
! 480: * Reset and put card in CONFIG state without changing address.
! 481: * XXX Indirect brokenness here!
! 482: */
! 483: elink_reset(iot, ioh, sc->sc_dev.dv_parent->dv_unit);
! 484: elink_idseq(iot, ioh, ELINK_507_POLY);
! 485: elink_idseq(iot, ioh, ELINK_507_POLY);
! 486: outb(ELINK_ID_PORT, 0xff);
! 487:
! 488: /* Check for 3COM signature before proceeding. */
! 489: outb(PORT + IE507_CTRL, inb(PORT + IE507_CTRL) & 0xfc); /* XXX */
! 490: for (i = 0; i < 6; i++)
! 491: if (inb(PORT + i) != signature[i])
! 492: goto out;
! 493:
! 494: c = inb(PORT + IE507_MADDR);
! 495: if (c & 0x20) {
! 496: printf("%s: can't map 3C507 RAM in high memory\n",
! 497: sc->sc_dev.dv_xname);
! 498: goto out;
! 499: }
! 500:
! 501: /* Go to RUN state. */
! 502: outb(ELINK_ID_PORT, 0x00);
! 503: elink_idseq(iot, ioh, ELINK_507_POLY);
! 504: outb(ELINK_ID_PORT, 0x00);
! 505:
! 506: /* Set bank 2 for version info and read BCD version byte. */
! 507: outb(PORT + IE507_CTRL, EL_CTRL_NRST | EL_CTRL_BNK2);
! 508: i = inb(PORT + 3);
! 509:
! 510: sc->hard_type = IE_3C507;
! 511: sc->hard_vers = 10*(i / 16) + (i % 16) - 1;
! 512:
! 513: i = inb(PORT + IE507_IRQ) & 0x0f;
! 514:
! 515: if (ia->ia_irq != IRQUNK) {
! 516: if (ia->ia_irq != i) {
! 517: printf("%s: irq mismatch; kernel configured %d != board configured %d\n",
! 518: sc->sc_dev.dv_xname, ia->ia_irq, i);
! 519: goto out;
! 520: }
! 521: } else
! 522: ia->ia_irq = i;
! 523:
! 524: i = ((inb(PORT + IE507_MADDR) & 0x1c) << 12) + 0xc0000;
! 525:
! 526: if (ia->ia_maddr != MADDRUNK) {
! 527: if (ia->ia_maddr != i) {
! 528: printf("%s: maddr mismatch; kernel configured %x != board configured %x\n",
! 529: sc->sc_dev.dv_xname, ia->ia_maddr, i);
! 530: goto out;
! 531: }
! 532: } else
! 533: ia->ia_maddr = i;
! 534:
! 535: outb(PORT + IE507_CTRL, EL_CTRL_NORMAL);
! 536:
! 537: /*
! 538: * Divine memory size on-board the card.
! 539: */
! 540: sc->sc_maddr = ISA_HOLE_VADDR(ia->ia_maddr);
! 541: ie_find_mem_size(sc);
! 542:
! 543: if (!sc->sc_msize) {
! 544: printf("%s: can't find shared memory\n", sc->sc_dev.dv_xname);
! 545: outb(PORT + IE507_CTRL, EL_CTRL_NRST);
! 546: goto out;
! 547: }
! 548:
! 549: if (!ia->ia_msize)
! 550: ia->ia_msize = sc->sc_msize;
! 551: else if (ia->ia_msize != sc->sc_msize) {
! 552: printf("%s: msize mismatch; kernel configured %d != board configured %d\n",
! 553: sc->sc_dev.dv_xname, ia->ia_msize, sc->sc_msize);
! 554: outb(PORT + IE507_CTRL, EL_CTRL_NRST);
! 555: goto out;
! 556: }
! 557:
! 558: slel_get_address(sc);
! 559:
! 560: /* Clear the interrupt latch just in case. */
! 561: outb(PORT + IE507_ICTRL, 1);
! 562:
! 563: ia->ia_iosize = 16;
! 564: rval = 1;
! 565:
! 566: out:
! 567: bus_space_unmap(iot, ioh, 1);
! 568: return rval;
! 569: }
! 570:
! 571: /* Taken almost exactly from Rod's if_ix.c. */
! 572:
! 573: int
! 574: ee16_probe(sc, ia)
! 575: struct ie_softc *sc;
! 576: struct isa_attach_args *ia;
! 577: {
! 578: int i;
! 579: u_short board_id, id_var1, id_var2, checksum = 0;
! 580: u_short eaddrtemp, irq;
! 581: u_short pg, adjust, decode, edecode;
! 582: u_char bart_config;
! 583:
! 584: short irq_translate[] = {0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0};
! 585:
! 586: /* Need this for part of the probe. */
! 587: sc->reset_586 = ee16_reset_586;
! 588: sc->chan_attn = ee16_chan_attn;
! 589:
! 590: /* reset any ee16 at the current iobase */
! 591: outb(ia->ia_iobase + IEE16_ECTRL, IEE16_RESET_ASIC);
! 592: outb(ia->ia_iobase + IEE16_ECTRL, 0);
! 593: delay(240);
! 594:
! 595: /* now look for ee16. */
! 596: board_id = id_var1 = id_var2 = 0;
! 597: for (i=0; i<4 ; i++) {
! 598: id_var1 = inb(ia->ia_iobase + IEE16_ID_PORT);
! 599: id_var2 = ((id_var1 & 0x03) << 2);
! 600: board_id |= (( id_var1 >> 4) << id_var2);
! 601: }
! 602:
! 603: if (board_id != IEE16_ID)
! 604: return 0;
! 605:
! 606: /* need sc->sc_iobase for ee16_read_eeprom */
! 607: sc->sc_iobase = ia->ia_iobase;
! 608: sc->hard_type = IE_EE16;
! 609:
! 610: /*
! 611: * If ia->maddr == MADDRUNK, use value in eeprom location 6.
! 612: *
! 613: * The shared RAM location on the EE16 is encoded into bits
! 614: * 3-7 of EEPROM location 6. We zero the upper byte, and
! 615: * shift the 5 bits right 3. The resulting number tells us
! 616: * the RAM location. Because the EE16 supports either 16k or 32k
! 617: * of shared RAM, we only worry about the 32k locations.
! 618: *
! 619: * NOTE: if a 64k EE16 exists, it should be added to this switch.
! 620: * then the ia->ia_msize would need to be set per case statement.
! 621: *
! 622: * value msize location
! 623: * ===== ===== ========
! 624: * 0x03 0x8000 0xCC000
! 625: * 0x06 0x8000 0xD0000
! 626: * 0x0C 0x8000 0xD4000
! 627: * 0x18 0x8000 0xD8000
! 628: *
! 629: */
! 630:
! 631: if ((ia->ia_maddr == MADDRUNK) || (ia->ia_msize == 0)) {
! 632: i = (ee16_read_eeprom(sc, 6) & 0x00ff ) >> 3;
! 633: switch(i) {
! 634: case 0x03:
! 635: ia->ia_maddr = 0xCC000;
! 636: break;
! 637: case 0x06:
! 638: ia->ia_maddr = 0xD0000;
! 639: break;
! 640: case 0x0c:
! 641: ia->ia_maddr = 0xD4000;
! 642: break;
! 643: case 0x18:
! 644: ia->ia_maddr = 0xD8000;
! 645: break;
! 646: default:
! 647: return 0 ;
! 648: break; /* NOTREACHED */
! 649: }
! 650: ia->ia_msize = 0x8000;
! 651: }
! 652:
! 653: /* need to set these after checking for MADDRUNK */
! 654: sc->sc_maddr = ISA_HOLE_VADDR(ia->ia_maddr);
! 655: sc->sc_msize = ia->ia_msize;
! 656:
! 657: /* need to put the 586 in RESET, and leave it */
! 658: outb( PORT + IEE16_ECTRL, IEE16_RESET_586);
! 659:
! 660: /* read the eeprom and checksum it, should == IEE16_ID */
! 661: for(i=0 ; i< 0x40 ; i++)
! 662: checksum += ee16_read_eeprom(sc, i);
! 663:
! 664: if (checksum != IEE16_ID)
! 665: return 0;
! 666:
! 667: /*
! 668: * Size and test the memory on the board. The size of the memory
! 669: * can be one of 16k, 32k, 48k or 64k. It can be located in the
! 670: * address range 0xC0000 to 0xEFFFF on 16k boundaries.
! 671: *
! 672: * If the size does not match the passed in memory allocation size
! 673: * issue a warning, but continue with the minimum of the two sizes.
! 674: */
! 675:
! 676: switch (ia->ia_msize) {
! 677: case 65536:
! 678: case 32768: /* XXX Only support 32k and 64k right now */
! 679: break;
! 680: case 16384:
! 681: case 49512:
! 682: default:
! 683: printf("ieprobe mapped memory size out of range\n");
! 684: return 0;
! 685: break; /* NOTREACHED */
! 686: }
! 687:
! 688: if ((kvtop(sc->sc_maddr) < 0xC0000) ||
! 689: (kvtop(sc->sc_maddr) + sc->sc_msize > 0xF0000)) {
! 690: printf("ieprobe mapped memory address out of range\n");
! 691: return 0;
! 692: }
! 693:
! 694: pg = (kvtop(sc->sc_maddr) & 0x3C000) >> 14;
! 695: adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2;
! 696: decode = ((1 << (sc->sc_msize / 16384)) - 1) << pg;
! 697: edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
! 698:
! 699: /* ZZZ This should be checked against eeprom location 6, low byte */
! 700: outb(PORT + IEE16_MEMDEC, decode & 0xFF);
! 701: /* ZZZ This should be checked against eeprom location 1, low byte */
! 702: outb(PORT + IEE16_MCTRL, adjust);
! 703: /* ZZZ Now if I could find this one I would have it made */
! 704: outb(PORT + IEE16_MPCTRL, (~decode & 0xFF));
! 705: /* ZZZ I think this is location 6, high byte */
! 706: outb(PORT + IEE16_MECTRL, edecode); /*XXX disable Exxx */
! 707:
! 708: /*
! 709: * first prime the stupid bart DRAM controller so that it
! 710: * works, then zero out all of memory.
! 711: */
! 712: bzero(sc->sc_maddr, 32);
! 713: bzero(sc->sc_maddr, sc->sc_msize);
! 714:
! 715: /*
! 716: * Get the encoded interrupt number from the EEPROM, check it
! 717: * against the passed in IRQ. Issue a warning if they do not
! 718: * match, and fail the probe. If irq is 'IRQUNK' then we
! 719: * use the EEPROM irq, and continue.
! 720: */
! 721: irq = ee16_read_eeprom(sc, IEE16_EEPROM_CONFIG1);
! 722: irq = (irq & IEE16_EEPROM_IRQ) >> IEE16_EEPROM_IRQ_SHIFT;
! 723: sc->irq_encoded = irq;
! 724: irq = irq_translate[irq];
! 725: if (ia->ia_irq != IRQUNK) {
! 726: if (irq != ia->ia_irq) {
! 727: #ifdef DIAGNOSTIC
! 728: printf("\nie%d: fatal: board IRQ %d does not match kernel\n", sc->sc_dev.dv_unit, irq);
! 729: #endif /* DIAGNOSTIC */
! 730: return 0; /* _must_ match or probe fails */
! 731: }
! 732: } else
! 733: ia->ia_irq = irq;
! 734:
! 735: /*
! 736: * Get the hardware ethernet address from the EEPROM and
! 737: * save it in the softc for use by the 586 setup code.
! 738: */
! 739: eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_HIGH);
! 740: sc->sc_arpcom.ac_enaddr[1] = eaddrtemp & 0xFF;
! 741: sc->sc_arpcom.ac_enaddr[0] = eaddrtemp >> 8;
! 742: eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_MID);
! 743: sc->sc_arpcom.ac_enaddr[3] = eaddrtemp & 0xFF;
! 744: sc->sc_arpcom.ac_enaddr[2] = eaddrtemp >> 8;
! 745: eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_LOW);
! 746: sc->sc_arpcom.ac_enaddr[5] = eaddrtemp & 0xFF;
! 747: sc->sc_arpcom.ac_enaddr[4] = eaddrtemp >> 8;
! 748:
! 749: /* disable the board interrupts */
! 750: outb(PORT + IEE16_IRQ, sc->irq_encoded);
! 751:
! 752: /* enable loopback to keep bad packets off the wire */
! 753: if(sc->hard_type == IE_EE16) {
! 754: bart_config = inb(PORT + IEE16_CONFIG);
! 755: bart_config |= IEE16_BART_LOOPBACK;
! 756: bart_config |= IEE16_BART_MCS16_TEST; /* inb doesn't get bit! */
! 757: outb(PORT + IEE16_CONFIG, bart_config);
! 758: bart_config = inb(PORT + IEE16_CONFIG);
! 759: }
! 760:
! 761: outb(PORT + IEE16_ECTRL, 0);
! 762: delay(100);
! 763: if (!check_ie_present(sc, sc->sc_maddr, sc->sc_msize))
! 764: return 0;
! 765:
! 766: ia->ia_iosize = 16; /* the number of I/O ports */
! 767: return 1; /* found */
! 768: }
! 769:
! 770: /*
! 771: * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
! 772: */
! 773: void
! 774: ieattach(parent, self, aux)
! 775: struct device *parent, *self;
! 776: void *aux;
! 777: {
! 778: struct ie_softc *sc = (void *)self;
! 779: struct isa_attach_args *ia = aux;
! 780: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 781:
! 782: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 783: ifp->if_softc = sc;
! 784: ifp->if_start = iestart;
! 785: ifp->if_ioctl = ieioctl;
! 786: ifp->if_watchdog = iewatchdog;
! 787: ifp->if_flags =
! 788: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 789: IFQ_SET_READY(&ifp->if_snd);
! 790:
! 791: /* Attach the interface. */
! 792: if_attach(ifp);
! 793: ether_ifattach(ifp);
! 794:
! 795: printf(": address %s, type %s R%d\n",
! 796: ether_sprintf(sc->sc_arpcom.ac_enaddr),
! 797: ie_hardware_names[sc->hard_type], sc->hard_vers + 1);
! 798:
! 799: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
! 800: IPL_NET, ieintr, sc, sc->sc_dev.dv_xname);
! 801: }
! 802:
! 803: /*
! 804: * Device timeout/watchdog routine. Entered if the device neglects to generate
! 805: * an interrupt after a transmit has been started on it.
! 806: */
! 807: void
! 808: iewatchdog(ifp)
! 809: struct ifnet *ifp;
! 810: {
! 811: struct ie_softc *sc = ifp->if_softc;
! 812:
! 813: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 814: ++sc->sc_arpcom.ac_if.if_oerrors;
! 815: iereset(sc);
! 816: }
! 817:
! 818: /*
! 819: * What to do upon receipt of an interrupt.
! 820: */
! 821: int
! 822: ieintr(arg)
! 823: void *arg;
! 824: {
! 825: struct ie_softc *sc = arg;
! 826: register u_short status;
! 827:
! 828: /* Clear the interrupt latch on the 3C507. */
! 829: if (sc->hard_type == IE_3C507)
! 830: outb(PORT + IE507_ICTRL, 1);
! 831:
! 832: /* disable interrupts on the EE16. */
! 833: if (sc->hard_type == IE_EE16)
! 834: outb(PORT + IEE16_IRQ, sc->irq_encoded);
! 835:
! 836: status = sc->scb->ie_status & IE_ST_WHENCE;
! 837: if (status == 0)
! 838: return 0;
! 839:
! 840: loop:
! 841: /* Ack interrupts FIRST in case we receive more during the ISR. */
! 842: ie_ack(sc, status);
! 843:
! 844: if (status & (IE_ST_FR | IE_ST_RNR)) {
! 845: #ifdef IEDEBUG
! 846: in_ierint++;
! 847: if (sc->sc_debug & IED_RINT)
! 848: printf("%s: rint\n", sc->sc_dev.dv_xname);
! 849: #endif
! 850: ierint(sc);
! 851: #ifdef IEDEBUG
! 852: in_ierint--;
! 853: #endif
! 854: }
! 855:
! 856: if (status & IE_ST_CX) {
! 857: #ifdef IEDEBUG
! 858: in_ietint++;
! 859: if (sc->sc_debug & IED_TINT)
! 860: printf("%s: tint\n", sc->sc_dev.dv_xname);
! 861: #endif
! 862: ietint(sc);
! 863: #ifdef IEDEBUG
! 864: in_ietint--;
! 865: #endif
! 866: }
! 867:
! 868: if (status & IE_ST_RNR) {
! 869: printf("%s: receiver not ready\n", sc->sc_dev.dv_xname);
! 870: sc->sc_arpcom.ac_if.if_ierrors++;
! 871: iereset(sc);
! 872: }
! 873:
! 874: #ifdef IEDEBUG
! 875: if ((status & IE_ST_CNA) && (sc->sc_debug & IED_CNA))
! 876: printf("%s: cna\n", sc->sc_dev.dv_xname);
! 877: #endif
! 878:
! 879: /* Clear the interrupt latch on the 3C507. */
! 880: if (sc->hard_type == IE_3C507)
! 881: outb(PORT + IE507_ICTRL, 1);
! 882:
! 883: status = sc->scb->ie_status & IE_ST_WHENCE;
! 884: if (status == 0) {
! 885: /* enable interrupts on the EE16. */
! 886: if (sc->hard_type == IE_EE16)
! 887: outb(PORT + IEE16_IRQ, sc->irq_encoded | IEE16_IRQ_ENABLE);
! 888: return 1;
! 889: }
! 890:
! 891: goto loop;
! 892: }
! 893:
! 894: /*
! 895: * Process a received-frame interrupt.
! 896: */
! 897: void
! 898: ierint(sc)
! 899: struct ie_softc *sc;
! 900: {
! 901: volatile struct ie_sys_ctl_block *scb = sc->scb;
! 902: int i, status;
! 903: static int timesthru = 1024;
! 904:
! 905: i = sc->rfhead;
! 906: for (;;) {
! 907: status = sc->rframes[i]->ie_fd_status;
! 908:
! 909: if ((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
! 910: if (!--timesthru) {
! 911: sc->sc_arpcom.ac_if.if_ierrors +=
! 912: scb->ie_err_crc + scb->ie_err_align +
! 913: scb->ie_err_resource + scb->ie_err_overrun;
! 914: scb->ie_err_crc = scb->ie_err_align =
! 915: scb->ie_err_resource = scb->ie_err_overrun =
! 916: 0;
! 917: timesthru = 1024;
! 918: }
! 919: ie_readframe(sc, i);
! 920: } else {
! 921: if ((status & IE_FD_RNR) != 0 &&
! 922: (scb->ie_status & IE_RU_READY) == 0) {
! 923: sc->rframes[0]->ie_fd_buf_desc =
! 924: MK_16(MEM, sc->rbuffs[0]);
! 925: scb->ie_recv_list = MK_16(MEM, sc->rframes[0]);
! 926: command_and_wait(sc, IE_RU_START, 0, 0);
! 927: }
! 928: break;
! 929: }
! 930: i = (i + 1) % NFRAMES;
! 931: }
! 932: }
! 933:
! 934: /*
! 935: * Process a command-complete interrupt. These are only generated by the
! 936: * transmission of frames. This routine is deceptively simple, since most of
! 937: * the real work is done by iestart().
! 938: */
! 939: void
! 940: ietint(sc)
! 941: struct ie_softc *sc;
! 942: {
! 943: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 944: int status;
! 945:
! 946: ifp->if_timer = 0;
! 947: ifp->if_flags &= ~IFF_OACTIVE;
! 948:
! 949: status = sc->xmit_cmds[sc->xctail]->ie_xmit_status;
! 950:
! 951: if (!(status & IE_STAT_COMPL) || (status & IE_STAT_BUSY))
! 952: printf("ietint: command still busy!\n");
! 953:
! 954: if (status & IE_STAT_OK) {
! 955: ifp->if_opackets++;
! 956: ifp->if_collisions += status & IE_XS_MAXCOLL;
! 957: } else {
! 958: ifp->if_oerrors++;
! 959: /*
! 960: * XXX
! 961: * Check SQE and DEFERRED?
! 962: * What if more than one bit is set?
! 963: */
! 964: if (status & IE_STAT_ABORT)
! 965: printf("%s: send aborted\n", sc->sc_dev.dv_xname);
! 966: else if (status & IE_XS_LATECOLL)
! 967: printf("%s: late collision\n", sc->sc_dev.dv_xname);
! 968: else if (status & IE_XS_NOCARRIER)
! 969: printf("%s: no carrier\n", sc->sc_dev.dv_xname);
! 970: else if (status & IE_XS_LOSTCTS)
! 971: printf("%s: lost CTS\n", sc->sc_dev.dv_xname);
! 972: else if (status & IE_XS_UNDERRUN)
! 973: printf("%s: DMA underrun\n", sc->sc_dev.dv_xname);
! 974: else if (status & IE_XS_EXCMAX) {
! 975: printf("%s: too many collisions\n", sc->sc_dev.dv_xname);
! 976: ifp->if_collisions += 16;
! 977: }
! 978: }
! 979:
! 980: /*
! 981: * If multicast addresses were added or deleted while transmitting,
! 982: * mc_reset() set the want_mcsetup flag indicating that we should do
! 983: * it.
! 984: */
! 985: if (sc->want_mcsetup) {
! 986: mc_setup(sc, (caddr_t)sc->xmit_cbuffs[sc->xctail]);
! 987: sc->want_mcsetup = 0;
! 988: }
! 989:
! 990: /* Done with the buffer. */
! 991: sc->xmit_busy--;
! 992: sc->xctail = (sc->xctail + 1) % NTXBUF;
! 993:
! 994: /* Start the next packet, if any, transmitting. */
! 995: if (sc->xmit_busy > 0)
! 996: iexmit(sc);
! 997:
! 998: iestart(ifp);
! 999: }
! 1000:
! 1001: /*
! 1002: * Compare two Ether/802 addresses for equality, inlined and unrolled for
! 1003: * speed. I'd love to have an inline assembler version of this...
! 1004: */
! 1005: static __inline int
! 1006: ether_equal(one, two)
! 1007: u_char *one, *two;
! 1008: {
! 1009:
! 1010: if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] ||
! 1011: one[3] != two[3] || one[4] != two[4] || one[5] != two[5])
! 1012: return 0;
! 1013: return 1;
! 1014: }
! 1015:
! 1016: /*
! 1017: * Check for a valid address. to_bpf is filled in with one of the following:
! 1018: * 0 -> BPF doesn't get this packet
! 1019: * 1 -> BPF does get this packet
! 1020: * 2 -> BPF does get this packet, but we don't
! 1021: * Return value is true if the packet is for us, and false otherwise.
! 1022: *
! 1023: * This routine is a mess, but it's also critical that it be as fast
! 1024: * as possible. It could be made cleaner if we can assume that the
! 1025: * only client which will fiddle with IFF_PROMISC is BPF. This is
! 1026: * probably a good assumption, but we do not make it here. (Yet.)
! 1027: */
! 1028: static __inline int
! 1029: check_eh(sc, eh, to_bpf)
! 1030: struct ie_softc *sc;
! 1031: struct ether_header *eh;
! 1032: int *to_bpf;
! 1033: {
! 1034: int i;
! 1035:
! 1036: switch (sc->promisc) {
! 1037: case IFF_ALLMULTI:
! 1038: /*
! 1039: * Receiving all multicasts, but no unicasts except those
! 1040: * destined for us.
! 1041: */
! 1042: #if NBPFILTER > 0
! 1043: *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0); /* BPF gets this packet if anybody cares */
! 1044: #endif
! 1045: if (eh->ether_dhost[0] & 1)
! 1046: return 1;
! 1047: if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
! 1048: return 1;
! 1049: return 0;
! 1050:
! 1051: case IFF_PROMISC:
! 1052: /*
! 1053: * Receiving all packets. These need to be passed on to BPF.
! 1054: */
! 1055: #if NBPFILTER > 0
! 1056: *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0) ||
! 1057: (sc->sc_arpcom.ac_if.if_bridge != NULL);
! 1058: #else
! 1059: *to_bpf = (sc->sc_arpcom.ac_if.if_bridge != NULL);
! 1060: #endif
! 1061: /* If for us, accept and hand up to BPF */
! 1062: if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
! 1063: return 1;
! 1064:
! 1065: #if NBPFILTER > 0
! 1066: if (*to_bpf && sc->sc_arpcom.ac_if.if_bridge == NULL)
! 1067: *to_bpf = 2; /* we don't need to see it */
! 1068: #endif
! 1069:
! 1070: /*
! 1071: * Not a multicast, so BPF wants to see it but we don't.
! 1072: */
! 1073: if (!(eh->ether_dhost[0] & 1))
! 1074: return 1;
! 1075:
! 1076: /*
! 1077: * If it's one of our multicast groups, accept it and pass it
! 1078: * up.
! 1079: */
! 1080: for (i = 0; i < sc->mcast_count; i++) {
! 1081: if (ether_equal(eh->ether_dhost, (u_char *)&sc->mcast_addrs[i])) {
! 1082: #if NBPFILTER > 0
! 1083: if (*to_bpf)
! 1084: *to_bpf = 1;
! 1085: #endif
! 1086: return 1;
! 1087: }
! 1088: }
! 1089: return 1;
! 1090:
! 1091: case IFF_ALLMULTI | IFF_PROMISC:
! 1092: /*
! 1093: * Acting as a multicast router, and BPF running at the same
! 1094: * time. Whew! (Hope this is a fast machine...)
! 1095: */
! 1096: #if NBPFILTER > 0
! 1097: *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0) ||
! 1098: (sc->sc_arpcom.ac_if.if_bridge != NULL);
! 1099: #else
! 1100: *to_bpf = (sc->sc_arpcom.ac_if.if_bridge != NULL);
! 1101: #endif
! 1102: /* We want to see multicasts. */
! 1103: if (eh->ether_dhost[0] & 1)
! 1104: return 1;
! 1105:
! 1106: /* We want to see our own packets */
! 1107: if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
! 1108: return 1;
! 1109:
! 1110: /* Anything else goes to BPF but nothing else. */
! 1111: #if NBPFILTER > 0
! 1112: if (*to_bpf && sc->sc_arpcom.ac_if.if_bridge == NULL)
! 1113: *to_bpf = 2;
! 1114: #endif
! 1115: return 1;
! 1116:
! 1117: case 0:
! 1118: /*
! 1119: * Only accept unicast packets destined for us, or multicasts
! 1120: * for groups that we belong to. For now, we assume that the
! 1121: * '586 will only return packets that we asked it for. This
! 1122: * isn't strictly true (it uses hashing for the multicast
! 1123: * filter), but it will do in this case, and we want to get out
! 1124: * of here as quickly as possible.
! 1125: */
! 1126: #if NBPFILTER > 0
! 1127: *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
! 1128: #endif
! 1129: return 1;
! 1130: }
! 1131:
! 1132: #ifdef DIAGNOSTIC
! 1133: panic("check_eh: impossible");
! 1134: #endif
! 1135: return 0;
! 1136: }
! 1137:
! 1138: /*
! 1139: * We want to isolate the bits that have meaning... This assumes that
! 1140: * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
! 1141: * the size of the buffer, then we are screwed anyway.
! 1142: */
! 1143: static __inline int
! 1144: ie_buflen(sc, head)
! 1145: struct ie_softc *sc;
! 1146: int head;
! 1147: {
! 1148:
! 1149: return (sc->rbuffs[head]->ie_rbd_actual
! 1150: & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
! 1151: }
! 1152:
! 1153: static __inline int
! 1154: ie_packet_len(sc)
! 1155: struct ie_softc *sc;
! 1156: {
! 1157: int i;
! 1158: int head = sc->rbhead;
! 1159: int acc = 0;
! 1160:
! 1161: do {
! 1162: if (!(sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED))
! 1163: return -1;
! 1164:
! 1165: i = sc->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
! 1166:
! 1167: acc += ie_buflen(sc, head);
! 1168: head = (head + 1) % NRXBUF;
! 1169: } while (!i);
! 1170:
! 1171: return acc;
! 1172: }
! 1173:
! 1174: /*
! 1175: * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
! 1176: * command to the chip to be executed. On the way, if we have a BPF listener
! 1177: * also give him a copy.
! 1178: */
! 1179: void
! 1180: iexmit(sc)
! 1181: struct ie_softc *sc;
! 1182: {
! 1183:
! 1184: #ifdef IEDEBUG
! 1185: if (sc->sc_debug & IED_XMIT)
! 1186: printf("%s: xmit buffer %d\n", sc->sc_dev.dv_xname,
! 1187: sc->xctail);
! 1188: #endif
! 1189:
! 1190: #if NBPFILTER > 0
! 1191: /*
! 1192: * If BPF is listening on this interface, let it see the packet before
! 1193: * we push it on the wire.
! 1194: */
! 1195: if (sc->sc_arpcom.ac_if.if_bpf)
! 1196: bpf_tap(sc->sc_arpcom.ac_if.if_bpf,
! 1197: sc->xmit_cbuffs[sc->xctail],
! 1198: sc->xmit_buffs[sc->xctail]->ie_xmit_flags,
! 1199: BPF_DIRECTION_OUT);
! 1200: #endif
! 1201:
! 1202: sc->xmit_buffs[sc->xctail]->ie_xmit_flags |= IE_XMIT_LAST;
! 1203: sc->xmit_buffs[sc->xctail]->ie_xmit_next = 0xffff;
! 1204: sc->xmit_buffs[sc->xctail]->ie_xmit_buf =
! 1205: MK_24(MEM, sc->xmit_cbuffs[sc->xctail]);
! 1206:
! 1207: sc->xmit_cmds[sc->xctail]->com.ie_cmd_link = 0xffff;
! 1208: sc->xmit_cmds[sc->xctail]->com.ie_cmd_cmd =
! 1209: IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
! 1210:
! 1211: sc->xmit_cmds[sc->xctail]->ie_xmit_status = 0;
! 1212: sc->xmit_cmds[sc->xctail]->ie_xmit_desc =
! 1213: MK_16(MEM, sc->xmit_buffs[sc->xctail]);
! 1214:
! 1215: sc->scb->ie_command_list = MK_16(MEM, sc->xmit_cmds[sc->xctail]);
! 1216: command_and_wait(sc, IE_CU_START, 0, 0);
! 1217:
! 1218: sc->sc_arpcom.ac_if.if_timer = 5;
! 1219: }
! 1220:
! 1221: /*
! 1222: * Read data off the interface, and turn it into an mbuf chain.
! 1223: *
! 1224: * This code is DRAMATICALLY different from the previous version; this version
! 1225: * tries to allocate the entire mbuf chain up front, given the length of the
! 1226: * data available. This enables us to allocate mbuf clusters in many
! 1227: * situations where before we would have had a long chain of partially-full
! 1228: * mbufs. This should help to speed up the operation considerably. (Provided
! 1229: * that it works, of course.)
! 1230: */
! 1231: struct mbuf *
! 1232: ieget(sc, ehp, to_bpf)
! 1233: struct ie_softc *sc;
! 1234: struct ether_header *ehp;
! 1235: int *to_bpf;
! 1236: {
! 1237: struct mbuf *top, **mp, *m;
! 1238: int len, totlen, resid;
! 1239: int thisrboff, thismboff;
! 1240: int head;
! 1241:
! 1242: resid = totlen = ie_packet_len(sc);
! 1243: if (totlen <= 0)
! 1244: return 0;
! 1245:
! 1246: head = sc->rbhead;
! 1247:
! 1248: /*
! 1249: * Snarf the Ethernet header.
! 1250: */
! 1251: bcopy((caddr_t)sc->cbuffs[head], (caddr_t)ehp, sizeof *ehp);
! 1252:
! 1253: /*
! 1254: * As quickly as possible, check if this packet is for us.
! 1255: * If not, don't waste a single cycle copying the rest of the
! 1256: * packet in.
! 1257: * This is only a consideration when FILTER is defined; i.e., when
! 1258: * we are either running BPF or doing multicasting.
! 1259: */
! 1260: if (!check_eh(sc, ehp, to_bpf)) {
! 1261: sc->sc_arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
! 1262: return 0;
! 1263: }
! 1264:
! 1265: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1266: if (m == 0)
! 1267: return 0;
! 1268: m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
! 1269: m->m_pkthdr.len = totlen;
! 1270: len = MHLEN;
! 1271: top = 0;
! 1272: mp = ⊤
! 1273:
! 1274: /*
! 1275: * This loop goes through and allocates mbufs for all the data we will
! 1276: * be copying in. It does not actually do the copying yet.
! 1277: */
! 1278: while (totlen > 0) {
! 1279: if (top) {
! 1280: MGET(m, M_DONTWAIT, MT_DATA);
! 1281: if (m == 0) {
! 1282: m_freem(top);
! 1283: return 0;
! 1284: }
! 1285: len = MLEN;
! 1286: }
! 1287: if (totlen >= MINCLSIZE) {
! 1288: MCLGET(m, M_DONTWAIT);
! 1289: if (m->m_flags & M_EXT)
! 1290: len = MCLBYTES;
! 1291: }
! 1292: m->m_len = len = min(totlen, len);
! 1293: totlen -= len;
! 1294: *mp = m;
! 1295: mp = &m->m_next;
! 1296: }
! 1297:
! 1298: m = top;
! 1299: thisrboff = 0;
! 1300: thismboff = 0;
! 1301:
! 1302: /*
! 1303: * Now we take the mbuf chain (hopefully only one mbuf most of the
! 1304: * time) and stuff the data into it. There are no possible failures at
! 1305: * or after this point.
! 1306: */
! 1307: while (resid > 0) {
! 1308: int thisrblen = ie_buflen(sc, head) - thisrboff,
! 1309: thismblen = m->m_len - thismboff;
! 1310: len = min(thisrblen, thismblen);
! 1311:
! 1312: bcopy((caddr_t)(sc->cbuffs[head] + thisrboff),
! 1313: mtod(m, caddr_t) + thismboff, (u_int)len);
! 1314: resid -= len;
! 1315:
! 1316: if (len == thismblen) {
! 1317: m = m->m_next;
! 1318: thismboff = 0;
! 1319: } else
! 1320: thismboff += len;
! 1321:
! 1322: if (len == thisrblen) {
! 1323: head = (head + 1) % NRXBUF;
! 1324: thisrboff = 0;
! 1325: } else
! 1326: thisrboff += len;
! 1327: }
! 1328:
! 1329: /*
! 1330: * Unless something changed strangely while we were doing the copy, we
! 1331: * have now copied everything in from the shared memory.
! 1332: * This means that we are done.
! 1333: */
! 1334: return top;
! 1335: }
! 1336:
! 1337: /*
! 1338: * Read frame NUM from unit UNIT (pre-cached as IE).
! 1339: *
! 1340: * This routine reads the RFD at NUM, and copies in the buffers from the list
! 1341: * of RBD, then rotates the RBD and RFD lists so that the receiver doesn't
! 1342: * start complaining. Trailers are DROPPED---there's no point in wasting time
! 1343: * on confusing code to deal with them. Hopefully, this machine will never ARP
! 1344: * for trailers anyway.
! 1345: */
! 1346: void
! 1347: ie_readframe(sc, num)
! 1348: struct ie_softc *sc;
! 1349: int num; /* frame number to read */
! 1350: {
! 1351: int status;
! 1352: struct mbuf *m = 0;
! 1353: struct ether_header eh;
! 1354: #if NBPFILTER > 0
! 1355: int bpf_gets_it = 0;
! 1356: #endif
! 1357:
! 1358: status = sc->rframes[num]->ie_fd_status;
! 1359:
! 1360: /* Advance the RFD list, since we're done with this descriptor. */
! 1361: sc->rframes[num]->ie_fd_status = 0;
! 1362: sc->rframes[num]->ie_fd_last |= IE_FD_LAST;
! 1363: sc->rframes[sc->rftail]->ie_fd_last &= ~IE_FD_LAST;
! 1364: sc->rftail = (sc->rftail + 1) % NFRAMES;
! 1365: sc->rfhead = (sc->rfhead + 1) % NFRAMES;
! 1366:
! 1367: if (status & IE_FD_OK) {
! 1368: #if NBPFILTER > 0
! 1369: m = ieget(sc, &eh, &bpf_gets_it);
! 1370: #else
! 1371: m = ieget(sc, &eh, 0);
! 1372: #endif
! 1373: ie_drop_packet_buffer(sc);
! 1374: }
! 1375: if (m == 0) {
! 1376: sc->sc_arpcom.ac_if.if_ierrors++;
! 1377: return;
! 1378: }
! 1379:
! 1380: #ifdef IEDEBUG
! 1381: if (sc->sc_debug & IED_READFRAME)
! 1382: printf("%s: frame from ether %s type %x\n", sc->sc_dev.dv_xname,
! 1383: ether_sprintf(eh.ether_shost), (u_int)eh.ether_type);
! 1384: #endif
! 1385:
! 1386: #if NBPFILTER > 0
! 1387: /* Check for a BPF filter; if so, hand it up. */
! 1388: if (bpf_gets_it) {
! 1389: /* Pass it up. */
! 1390: bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m, BPF_DIRECTION_IN);
! 1391:
! 1392: /*
! 1393: * A signal passed up from the filtering code indicating that
! 1394: * the packet is intended for BPF but not for the protocol
! 1395: * machinery. We can save a few cycles by not handing it off
! 1396: * to them.
! 1397: */
! 1398: if (bpf_gets_it == 2) {
! 1399: m_freem(m);
! 1400: return;
! 1401: }
! 1402: }
! 1403: #endif /* NBPFILTER > 0 */
! 1404:
! 1405: /*
! 1406: * In here there used to be code to check destination addresses upon
! 1407: * receipt of a packet. We have deleted that code, and replaced it
! 1408: * with code to check the address much earlier in the cycle, before
! 1409: * copying the data in; this saves us valuable cycles when operating
! 1410: * as a multicast router or when using BPF.
! 1411: */
! 1412:
! 1413: /*
! 1414: * Finally pass this packet up to higher layers.
! 1415: */
! 1416: ether_input_mbuf(&sc->sc_arpcom.ac_if, m);
! 1417: sc->sc_arpcom.ac_if.if_ipackets++;
! 1418: }
! 1419:
! 1420: void
! 1421: ie_drop_packet_buffer(sc)
! 1422: struct ie_softc *sc;
! 1423: {
! 1424: int i;
! 1425:
! 1426: do {
! 1427: /*
! 1428: * This means we are somehow out of sync. So, we reset the
! 1429: * adapter.
! 1430: */
! 1431: if (!(sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
! 1432: #ifdef IEDEBUG
! 1433: print_rbd(sc->rbuffs[sc->rbhead]);
! 1434: #endif
! 1435: log(LOG_ERR, "%s: receive descriptors out of sync at %d\n",
! 1436: sc->sc_dev.dv_xname, sc->rbhead);
! 1437: iereset(sc);
! 1438: return;
! 1439: }
! 1440:
! 1441: i = sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_LAST;
! 1442:
! 1443: sc->rbuffs[sc->rbhead]->ie_rbd_length |= IE_RBD_LAST;
! 1444: sc->rbuffs[sc->rbhead]->ie_rbd_actual = 0;
! 1445: sc->rbhead = (sc->rbhead + 1) % NRXBUF;
! 1446: sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
! 1447: sc->rbtail = (sc->rbtail + 1) % NRXBUF;
! 1448: } while (!i);
! 1449: }
! 1450:
! 1451: /*
! 1452: * Start transmission on an interface.
! 1453: */
! 1454: void
! 1455: iestart(ifp)
! 1456: struct ifnet *ifp;
! 1457: {
! 1458: struct ie_softc *sc = ifp->if_softc;
! 1459: struct mbuf *m0, *m;
! 1460: u_char *buffer;
! 1461: u_short len;
! 1462:
! 1463: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1464: return;
! 1465:
! 1466: for (;;) {
! 1467: if (sc->xmit_busy == NTXBUF) {
! 1468: ifp->if_flags |= IFF_OACTIVE;
! 1469: break;
! 1470: }
! 1471:
! 1472: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 1473: if (m0 == 0)
! 1474: break;
! 1475:
! 1476: /* We need to use m->m_pkthdr.len, so require the header */
! 1477: if ((m0->m_flags & M_PKTHDR) == 0)
! 1478: panic("iestart: no header mbuf");
! 1479:
! 1480: #if NBPFILTER > 0
! 1481: /* Tap off here if there is a BPF listener. */
! 1482: if (ifp->if_bpf)
! 1483: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 1484: #endif
! 1485:
! 1486: #ifdef IEDEBUG
! 1487: if (sc->sc_debug & IED_ENQ)
! 1488: printf("%s: fill buffer %d\n", sc->sc_dev.dv_xname,
! 1489: sc->xchead);
! 1490: #endif
! 1491:
! 1492: len = 0;
! 1493: buffer = sc->xmit_cbuffs[sc->xchead];
! 1494:
! 1495: for (m = m0; m != NULL && (len + m->m_len) < IE_TBUF_SIZE;
! 1496: m = m->m_next) {
! 1497: bcopy(mtod(m, caddr_t), buffer, m->m_len);
! 1498: buffer += m->m_len;
! 1499: len += m->m_len;
! 1500: }
! 1501: if (m != NULL)
! 1502: printf("%s: tbuf overflow\n", sc->sc_dev.dv_xname);
! 1503:
! 1504: m_freem(m0);
! 1505:
! 1506: if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
! 1507: bzero(buffer, ETHER_MIN_LEN - ETHER_CRC_LEN - len);
! 1508: len = ETHER_MIN_LEN - ETHER_CRC_LEN;
! 1509: buffer += ETHER_MIN_LEN - ETHER_CRC_LEN;
! 1510: }
! 1511:
! 1512: sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len;
! 1513:
! 1514: /* Start the first packet transmitting. */
! 1515: if (sc->xmit_busy == 0)
! 1516: iexmit(sc);
! 1517:
! 1518: sc->xchead = (sc->xchead + 1) % NTXBUF;
! 1519: sc->xmit_busy++;
! 1520: }
! 1521: }
! 1522:
! 1523: /*
! 1524: * Check to see if there's an 82586 out there.
! 1525: */
! 1526: int
! 1527: check_ie_present(sc, where, size)
! 1528: struct ie_softc *sc;
! 1529: caddr_t where;
! 1530: u_int size;
! 1531: {
! 1532: volatile struct ie_sys_conf_ptr *scp;
! 1533: volatile struct ie_int_sys_conf_ptr *iscp;
! 1534: volatile struct ie_sys_ctl_block *scb;
! 1535: u_long realbase;
! 1536: int s;
! 1537:
! 1538: s = splnet();
! 1539:
! 1540: realbase = (u_long)where + size - (1 << 24);
! 1541:
! 1542: scp = (volatile struct ie_sys_conf_ptr *)(realbase + IE_SCP_ADDR);
! 1543: bzero((char *)scp, sizeof *scp);
! 1544:
! 1545: /*
! 1546: * First we put the ISCP at the bottom of memory; this tests to make
! 1547: * sure that our idea of the size of memory is the same as the
! 1548: * controller's. This is NOT where the ISCP will be in normal
! 1549: * operation.
! 1550: */
! 1551: iscp = (volatile struct ie_int_sys_conf_ptr *)where;
! 1552: bzero((char *)iscp, sizeof *iscp);
! 1553:
! 1554: scb = (volatile struct ie_sys_ctl_block *)where;
! 1555: bzero((char *)scb, sizeof *scb);
! 1556:
! 1557: scp->ie_bus_use = 0; /* 16-bit */
! 1558: scp->ie_iscp_ptr = (caddr_t)((volatile caddr_t)iscp -
! 1559: (volatile caddr_t)realbase);
! 1560:
! 1561: iscp->ie_busy = 1;
! 1562: iscp->ie_scb_offset = MK_16(realbase, scb) + 256;
! 1563:
! 1564: (sc->reset_586)(sc);
! 1565: (sc->chan_attn)(sc);
! 1566:
! 1567: delay(100); /* wait a while... */
! 1568:
! 1569: if (iscp->ie_busy) {
! 1570: splx(s);
! 1571: return 0;
! 1572: }
! 1573:
! 1574: /*
! 1575: * Now relocate the ISCP to its real home, and reset the controller
! 1576: * again.
! 1577: */
! 1578: iscp = (void *)ALIGN(realbase + IE_SCP_ADDR - sizeof(*iscp));
! 1579: bzero((char *)iscp, sizeof *iscp);
! 1580:
! 1581: scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
! 1582:
! 1583: iscp->ie_busy = 1;
! 1584: iscp->ie_scb_offset = MK_16(realbase, scb);
! 1585:
! 1586: (sc->reset_586)(sc);
! 1587: (sc->chan_attn)(sc);
! 1588:
! 1589: delay(100);
! 1590:
! 1591: if (iscp->ie_busy) {
! 1592: splx(s);
! 1593: return 0;
! 1594: }
! 1595:
! 1596: sc->sc_msize = size;
! 1597: sc->sc_maddr = (caddr_t)realbase;
! 1598:
! 1599: sc->iscp = iscp;
! 1600: sc->scb = scb;
! 1601:
! 1602: /*
! 1603: * Acknowledge any interrupts we may have caused...
! 1604: */
! 1605: ie_ack(sc, IE_ST_WHENCE);
! 1606: splx(s);
! 1607:
! 1608: return 1;
! 1609: }
! 1610:
! 1611: /*
! 1612: * Divine the memory size of ie board UNIT.
! 1613: * Better hope there's nothing important hiding just below the ie card...
! 1614: */
! 1615: void
! 1616: ie_find_mem_size(sc)
! 1617: struct ie_softc *sc;
! 1618: {
! 1619: u_int size;
! 1620:
! 1621: sc->sc_msize = 0;
! 1622:
! 1623: for (size = 65536; size >= 16384; size -= 16384)
! 1624: if (check_ie_present(sc, sc->sc_maddr, size))
! 1625: return;
! 1626:
! 1627: return;
! 1628: }
! 1629:
! 1630: void
! 1631: el_reset_586(sc)
! 1632: struct ie_softc *sc;
! 1633: {
! 1634:
! 1635: outb(PORT + IE507_CTRL, EL_CTRL_RESET);
! 1636: delay(100);
! 1637: outb(PORT + IE507_CTRL, EL_CTRL_NORMAL);
! 1638: delay(100);
! 1639: }
! 1640:
! 1641: void
! 1642: sl_reset_586(sc)
! 1643: struct ie_softc *sc;
! 1644: {
! 1645:
! 1646: outb(PORT + IEATT_RESET, 0);
! 1647: }
! 1648:
! 1649: void
! 1650: ee16_reset_586(sc)
! 1651: struct ie_softc *sc;
! 1652: {
! 1653:
! 1654: outb(PORT + IEE16_ECTRL, IEE16_RESET_586);
! 1655: delay(100);
! 1656: outb(PORT + IEE16_ECTRL, 0);
! 1657: delay(100);
! 1658: }
! 1659:
! 1660: void
! 1661: el_chan_attn(sc)
! 1662: struct ie_softc *sc;
! 1663: {
! 1664:
! 1665: outb(PORT + IE507_ATTN, 1);
! 1666: }
! 1667:
! 1668: void
! 1669: sl_chan_attn(sc)
! 1670: struct ie_softc *sc;
! 1671: {
! 1672:
! 1673: outb(PORT + IEATT_ATTN, 0);
! 1674: }
! 1675:
! 1676: void
! 1677: ee16_chan_attn(sc)
! 1678: struct ie_softc *sc;
! 1679: {
! 1680: outb(PORT + IEE16_ATTN, 0);
! 1681: }
! 1682:
! 1683: u_short
! 1684: ee16_read_eeprom(sc, location)
! 1685: struct ie_softc *sc;
! 1686: int location;
! 1687: {
! 1688: int ectrl, edata;
! 1689:
! 1690: ectrl = inb(PORT + IEE16_ECTRL);
! 1691: ectrl &= IEE16_ECTRL_MASK;
! 1692: ectrl |= IEE16_ECTRL_EECS;
! 1693: outb(PORT + IEE16_ECTRL, ectrl);
! 1694:
! 1695: ee16_eeprom_outbits(sc, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1);
! 1696: ee16_eeprom_outbits(sc, location, IEE16_EEPROM_ADDR_SIZE);
! 1697: edata = ee16_eeprom_inbits(sc);
! 1698: ectrl = inb(PORT + IEE16_ECTRL);
! 1699: ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS);
! 1700: outb(PORT + IEE16_ECTRL, ectrl);
! 1701: ee16_eeprom_clock(sc, 1);
! 1702: ee16_eeprom_clock(sc, 0);
! 1703: return edata;
! 1704: }
! 1705:
! 1706: void
! 1707: ee16_eeprom_outbits(sc, edata, count)
! 1708: struct ie_softc *sc;
! 1709: int edata, count;
! 1710: {
! 1711: int ectrl, i;
! 1712:
! 1713: ectrl = inb(PORT + IEE16_ECTRL);
! 1714: ectrl &= ~IEE16_RESET_ASIC;
! 1715: for (i = count - 1; i >= 0; i--) {
! 1716: ectrl &= ~IEE16_ECTRL_EEDI;
! 1717: if (edata & (1 << i)) {
! 1718: ectrl |= IEE16_ECTRL_EEDI;
! 1719: }
! 1720: outb(PORT + IEE16_ECTRL, ectrl);
! 1721: delay(1); /* eeprom data must be setup for 0.4 uSec */
! 1722: ee16_eeprom_clock(sc, 1);
! 1723: ee16_eeprom_clock(sc, 0);
! 1724: }
! 1725: ectrl &= ~IEE16_ECTRL_EEDI;
! 1726: outb(PORT + IEE16_ECTRL, ectrl);
! 1727: delay(1); /* eeprom data must be held for 0.4 uSec */
! 1728: }
! 1729:
! 1730: int
! 1731: ee16_eeprom_inbits(sc)
! 1732: struct ie_softc *sc;
! 1733: {
! 1734: int ectrl, edata, i;
! 1735:
! 1736: ectrl = inb(PORT + IEE16_ECTRL);
! 1737: ectrl &= ~IEE16_RESET_ASIC;
! 1738: for (edata = 0, i = 0; i < 16; i++) {
! 1739: edata = edata << 1;
! 1740: ee16_eeprom_clock(sc, 1);
! 1741: ectrl = inb(PORT + IEE16_ECTRL);
! 1742: if (ectrl & IEE16_ECTRL_EEDO) {
! 1743: edata |= 1;
! 1744: }
! 1745: ee16_eeprom_clock(sc, 0);
! 1746: }
! 1747: return (edata);
! 1748: }
! 1749:
! 1750: void
! 1751: ee16_eeprom_clock(sc, state)
! 1752: struct ie_softc *sc;
! 1753: int state;
! 1754: {
! 1755: int ectrl;
! 1756:
! 1757: ectrl = inb(PORT + IEE16_ECTRL);
! 1758: ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK);
! 1759: if (state) {
! 1760: ectrl |= IEE16_ECTRL_EESK;
! 1761: }
! 1762: outb(PORT + IEE16_ECTRL, ectrl);
! 1763: delay(9); /* EESK must be stable for 8.38 uSec */
! 1764: }
! 1765:
! 1766: static inline void
! 1767: ee16_interrupt_enable(sc)
! 1768: struct ie_softc *sc;
! 1769: {
! 1770: delay(100);
! 1771: outb(PORT + IEE16_IRQ, sc->irq_encoded | IEE16_IRQ_ENABLE);
! 1772: delay(100);
! 1773: }
! 1774: void
! 1775: slel_get_address(sc)
! 1776: struct ie_softc *sc;
! 1777: {
! 1778: u_char *addr = sc->sc_arpcom.ac_enaddr;
! 1779: int i;
! 1780:
! 1781: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 1782: addr[i] = inb(PORT + i);
! 1783: }
! 1784:
! 1785: void
! 1786: iereset(sc)
! 1787: struct ie_softc *sc;
! 1788: {
! 1789: int s = splnet();
! 1790:
! 1791: iestop(sc);
! 1792:
! 1793: /*
! 1794: * Stop i82586 dead in its tracks.
! 1795: */
! 1796: if (command_and_wait(sc, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
! 1797: printf("%s: abort commands timed out\n", sc->sc_dev.dv_xname);
! 1798:
! 1799: if (command_and_wait(sc, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
! 1800: printf("%s: disable commands timed out\n", sc->sc_dev.dv_xname);
! 1801:
! 1802: ieinit(sc);
! 1803:
! 1804: splx(s);
! 1805: }
! 1806:
! 1807: /*
! 1808: * Send a command to the controller and wait for it to either complete or be
! 1809: * accepted, depending on the command. If the command pointer is null, then
! 1810: * pretend that the command is not an action command. If the command pointer
! 1811: * is not null, and the command is an action command, wait for
! 1812: * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
! 1813: * to become true.
! 1814: */
! 1815: static int
! 1816: command_and_wait(sc, cmd, pcmd, mask)
! 1817: struct ie_softc *sc;
! 1818: int cmd;
! 1819: volatile void *pcmd;
! 1820: int mask;
! 1821: {
! 1822: volatile struct ie_cmd_common *cc = pcmd;
! 1823: volatile struct ie_sys_ctl_block *scb = sc->scb;
! 1824: int i;
! 1825:
! 1826: scb->ie_command = (u_short)cmd;
! 1827:
! 1828: if (IE_ACTION_COMMAND(cmd) && pcmd) {
! 1829: (sc->chan_attn)(sc);
! 1830:
! 1831: /*
! 1832: * According to the packet driver, the minimum timeout should
! 1833: * be .369 seconds, which we round up to .4.
! 1834: *
! 1835: * Now spin-lock waiting for status. This is not a very nice
! 1836: * thing to do, but I haven't figured out how, or indeed if, we
! 1837: * can put the process waiting for action to sleep. (We may
! 1838: * be getting called through some other timeout running in the
! 1839: * kernel.)
! 1840: */
! 1841: for (i = 36900; i--; DELAY(10))
! 1842: if ((cc->ie_cmd_status & mask))
! 1843: break;
! 1844:
! 1845: return i < 0;
! 1846: } else {
! 1847: /*
! 1848: * Otherwise, just wait for the command to be accepted.
! 1849: */
! 1850: (sc->chan_attn)(sc);
! 1851:
! 1852: while (scb->ie_command)
! 1853: ; /* spin lock */
! 1854:
! 1855: return 0;
! 1856: }
! 1857: }
! 1858:
! 1859: /*
! 1860: * Run the time-domain reflectometer.
! 1861: */
! 1862: static void
! 1863: run_tdr(sc, cmd)
! 1864: struct ie_softc *sc;
! 1865: struct ie_tdr_cmd *cmd;
! 1866: {
! 1867: int result;
! 1868:
! 1869: cmd->com.ie_cmd_status = 0;
! 1870: cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
! 1871: cmd->com.ie_cmd_link = 0xffff;
! 1872:
! 1873: sc->scb->ie_command_list = MK_16(MEM, cmd);
! 1874: cmd->ie_tdr_time = 0;
! 1875:
! 1876: if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
! 1877: !(cmd->com.ie_cmd_status & IE_STAT_OK))
! 1878: result = 0x10000;
! 1879: else
! 1880: result = cmd->ie_tdr_time;
! 1881:
! 1882: ie_ack(sc, IE_ST_WHENCE);
! 1883:
! 1884: if (result & IE_TDR_SUCCESS)
! 1885: return;
! 1886:
! 1887: if (result & 0x10000)
! 1888: printf("%s: TDR command failed\n", sc->sc_dev.dv_xname);
! 1889: else if (result & IE_TDR_XCVR)
! 1890: printf("%s: transceiver problem\n", sc->sc_dev.dv_xname);
! 1891: else if (result & IE_TDR_OPEN)
! 1892: printf("%s: TDR detected an open %d clocks away\n",
! 1893: sc->sc_dev.dv_xname, result & IE_TDR_TIME);
! 1894: else if (result & IE_TDR_SHORT)
! 1895: printf("%s: TDR detected a short %d clocks away\n",
! 1896: sc->sc_dev.dv_xname, result & IE_TDR_TIME);
! 1897: else
! 1898: printf("%s: TDR returned unknown status %x\n",
! 1899: sc->sc_dev.dv_xname, result);
! 1900: }
! 1901:
! 1902: #define _ALLOC(p, n) (bzero(p, n), p += n, p - n)
! 1903: #define ALLOC(p, n) _ALLOC(p, ALIGN(n))
! 1904:
! 1905: /*
! 1906: * Here is a helper routine for ieinit(). This sets up the buffers.
! 1907: */
! 1908: void
! 1909: iememinit(ptr, sc)
! 1910: void *ptr;
! 1911: struct ie_softc *sc;
! 1912: {
! 1913: int i;
! 1914:
! 1915: /* First lay them out. */
! 1916: for (i = 0; i < NFRAMES; i++)
! 1917: sc->rframes[i] = ALLOC(ptr, sizeof(*sc->rframes[i]));
! 1918:
! 1919: /* Now link them together. */
! 1920: for (i = 0; i < NFRAMES; i++)
! 1921: sc->rframes[i]->ie_fd_next =
! 1922: MK_16(MEM, sc->rframes[(i + 1) % NFRAMES]);
! 1923:
! 1924: /* Finally, set the EOL bit on the last one. */
! 1925: sc->rframes[NFRAMES - 1]->ie_fd_last |= IE_FD_LAST;
! 1926:
! 1927: /*
! 1928: * Now lay out some buffers for the incoming frames. Note that we set
! 1929: * aside a bit of slop in each buffer, to make sure that we have enough
! 1930: * space to hold a single frame in every buffer.
! 1931: */
! 1932: for (i = 0; i < NRXBUF; i++) {
! 1933: sc->rbuffs[i] = ALLOC(ptr, sizeof(*sc->rbuffs[i]));
! 1934: sc->rbuffs[i]->ie_rbd_length = IE_RBUF_SIZE;
! 1935: sc->rbuffs[i]->ie_rbd_buffer = MK_24(MEM, ptr);
! 1936: sc->cbuffs[i] = ALLOC(ptr, IE_RBUF_SIZE);
! 1937: }
! 1938:
! 1939: /* Now link them together. */
! 1940: for (i = 0; i < NRXBUF; i++)
! 1941: sc->rbuffs[i]->ie_rbd_next =
! 1942: MK_16(MEM, sc->rbuffs[(i + 1) % NRXBUF]);
! 1943:
! 1944: /* Tag EOF on the last one. */
! 1945: sc->rbuffs[NRXBUF - 1]->ie_rbd_length |= IE_RBD_LAST;
! 1946:
! 1947: /*
! 1948: * We use the head and tail pointers on receive to keep track of the
! 1949: * order in which RFDs and RBDs are used.
! 1950: */
! 1951: sc->rfhead = 0;
! 1952: sc->rftail = NFRAMES - 1;
! 1953: sc->rbhead = 0;
! 1954: sc->rbtail = NRXBUF - 1;
! 1955:
! 1956: sc->scb->ie_recv_list = MK_16(MEM, sc->rframes[0]);
! 1957: sc->rframes[0]->ie_fd_buf_desc = MK_16(MEM, sc->rbuffs[0]);
! 1958:
! 1959: /*
! 1960: * Finally, the transmit command and buffer are the last little bit of
! 1961: * work.
! 1962: */
! 1963: for (i = 0; i < NTXBUF; i++) {
! 1964: sc->xmit_cmds[i] = ALLOC(ptr, sizeof(*sc->xmit_cmds[i]));
! 1965: sc->xmit_buffs[i] = ALLOC(ptr, sizeof(*sc->xmit_buffs[i]));
! 1966: }
! 1967:
! 1968: for (i = 0; i < NTXBUF; i++)
! 1969: sc->xmit_cbuffs[i] = ALLOC(ptr, IE_TBUF_SIZE);
! 1970:
! 1971: /* Pointers to last packet sent and next available transmit buffer. */
! 1972: sc->xchead = sc->xctail = 0;
! 1973:
! 1974: /* Clear transmit-busy flag and set number of free transmit buffers. */
! 1975: sc->xmit_busy = 0;
! 1976: }
! 1977:
! 1978: /*
! 1979: * Run the multicast setup command.
! 1980: * Called at splnet().
! 1981: */
! 1982: static int
! 1983: mc_setup(sc, ptr)
! 1984: struct ie_softc *sc;
! 1985: void *ptr;
! 1986: {
! 1987: volatile struct ie_mcast_cmd *cmd = ptr;
! 1988:
! 1989: cmd->com.ie_cmd_status = 0;
! 1990: cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
! 1991: cmd->com.ie_cmd_link = 0xffff;
! 1992:
! 1993: bcopy((caddr_t)sc->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
! 1994: sc->mcast_count * sizeof *sc->mcast_addrs);
! 1995:
! 1996: cmd->ie_mcast_bytes = sc->mcast_count * ETHER_ADDR_LEN; /* grrr... */
! 1997:
! 1998: sc->scb->ie_command_list = MK_16(MEM, cmd);
! 1999: if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
! 2000: !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
! 2001: printf("%s: multicast address setup command failed\n",
! 2002: sc->sc_dev.dv_xname);
! 2003: return 0;
! 2004: }
! 2005: return 1;
! 2006: }
! 2007:
! 2008: /*
! 2009: * This routine takes the environment generated by check_ie_present() and adds
! 2010: * to it all the other structures we need to operate the adapter. This
! 2011: * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
! 2012: * the receiver unit, and clearing interrupts.
! 2013: *
! 2014: * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
! 2015: */
! 2016: int
! 2017: ieinit(sc)
! 2018: struct ie_softc *sc;
! 2019: {
! 2020: volatile struct ie_sys_ctl_block *scb = sc->scb;
! 2021: void *ptr;
! 2022:
! 2023: ptr = (void *)ALIGN(scb + 1);
! 2024:
! 2025: /*
! 2026: * Send the configure command first.
! 2027: */
! 2028: {
! 2029: volatile struct ie_config_cmd *cmd = ptr;
! 2030:
! 2031: scb->ie_command_list = MK_16(MEM, cmd);
! 2032: cmd->com.ie_cmd_status = 0;
! 2033: cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
! 2034: cmd->com.ie_cmd_link = 0xffff;
! 2035:
! 2036: ie_setup_config(cmd, sc->promisc != 0,
! 2037: sc->hard_type == IE_STARLAN10);
! 2038:
! 2039: if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
! 2040: !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
! 2041: printf("%s: configure command failed\n",
! 2042: sc->sc_dev.dv_xname);
! 2043: return 0;
! 2044: }
! 2045: }
! 2046:
! 2047: /*
! 2048: * Now send the Individual Address Setup command.
! 2049: */
! 2050: {
! 2051: volatile struct ie_iasetup_cmd *cmd = ptr;
! 2052:
! 2053: scb->ie_command_list = MK_16(MEM, cmd);
! 2054: cmd->com.ie_cmd_status = 0;
! 2055: cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
! 2056: cmd->com.ie_cmd_link = 0xffff;
! 2057:
! 2058: bcopy(sc->sc_arpcom.ac_enaddr, (caddr_t)&cmd->ie_address,
! 2059: sizeof cmd->ie_address);
! 2060:
! 2061: if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
! 2062: !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
! 2063: printf("%s: individual address setup command failed\n",
! 2064: sc->sc_dev.dv_xname);
! 2065: return 0;
! 2066: }
! 2067: }
! 2068:
! 2069: /*
! 2070: * Now run the time-domain reflectometer.
! 2071: */
! 2072: run_tdr(sc, ptr);
! 2073:
! 2074: /*
! 2075: * Acknowledge any interrupts we have generated thus far.
! 2076: */
! 2077: ie_ack(sc, IE_ST_WHENCE);
! 2078:
! 2079: /*
! 2080: * Set up the RFA.
! 2081: */
! 2082: iememinit(ptr, sc);
! 2083:
! 2084: sc->sc_arpcom.ac_if.if_flags |= IFF_RUNNING;
! 2085: sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
! 2086:
! 2087: sc->scb->ie_recv_list = MK_16(MEM, sc->rframes[0]);
! 2088: command_and_wait(sc, IE_RU_START, 0, 0);
! 2089:
! 2090: ie_ack(sc, IE_ST_WHENCE);
! 2091:
! 2092: /* take the ee16 out of loopback */
! 2093: {
! 2094: u_char bart_config;
! 2095:
! 2096: if(sc->hard_type == IE_EE16) {
! 2097: bart_config = inb(PORT + IEE16_CONFIG);
! 2098: bart_config &= ~IEE16_BART_LOOPBACK;
! 2099: bart_config |= IEE16_BART_MCS16_TEST; /* inb doesn't get bit! */
! 2100: outb(PORT + IEE16_CONFIG, bart_config);
! 2101: ee16_interrupt_enable(sc);
! 2102: ee16_chan_attn(sc);
! 2103: }
! 2104: }
! 2105: return 0;
! 2106: }
! 2107:
! 2108: void
! 2109: iestop(sc)
! 2110: struct ie_softc *sc;
! 2111: {
! 2112:
! 2113: command_and_wait(sc, IE_RU_DISABLE, 0, 0);
! 2114: }
! 2115:
! 2116: int
! 2117: ieioctl(ifp, cmd, data)
! 2118: register struct ifnet *ifp;
! 2119: u_long cmd;
! 2120: caddr_t data;
! 2121: {
! 2122: struct ie_softc *sc = ifp->if_softc;
! 2123: struct ifaddr *ifa = (struct ifaddr *)data;
! 2124: struct ifreq *ifr = (struct ifreq *)data;
! 2125: int s, error = 0;
! 2126:
! 2127: s = splnet();
! 2128:
! 2129: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 2130: splx(s);
! 2131: return error;
! 2132: }
! 2133:
! 2134: switch (cmd) {
! 2135:
! 2136: case SIOCSIFADDR:
! 2137: ifp->if_flags |= IFF_UP;
! 2138:
! 2139: switch (ifa->ifa_addr->sa_family) {
! 2140: #ifdef INET
! 2141: case AF_INET:
! 2142: ieinit(sc);
! 2143: arp_ifinit(&sc->sc_arpcom, ifa);
! 2144: break;
! 2145: #endif
! 2146: default:
! 2147: ieinit(sc);
! 2148: break;
! 2149: }
! 2150: break;
! 2151:
! 2152: case SIOCSIFFLAGS:
! 2153: sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
! 2154: if ((ifp->if_flags & IFF_UP) == 0 &&
! 2155: (ifp->if_flags & IFF_RUNNING) != 0) {
! 2156: /*
! 2157: * If interface is marked down and it is running, then
! 2158: * stop it.
! 2159: */
! 2160: iestop(sc);
! 2161: ifp->if_flags &= ~IFF_RUNNING;
! 2162: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 2163: (ifp->if_flags & IFF_RUNNING) == 0) {
! 2164: /*
! 2165: * If interface is marked up and it is stopped, then
! 2166: * start it.
! 2167: */
! 2168: ieinit(sc);
! 2169: } else {
! 2170: /*
! 2171: * Reset the interface to pick up changes in any other
! 2172: * flags that affect hardware registers.
! 2173: */
! 2174: iestop(sc);
! 2175: ieinit(sc);
! 2176: }
! 2177: #ifdef IEDEBUG
! 2178: if (ifp->if_flags & IFF_DEBUG)
! 2179: sc->sc_debug = IED_ALL;
! 2180: else
! 2181: sc->sc_debug = 0;
! 2182: #endif
! 2183: break;
! 2184:
! 2185: case SIOCADDMULTI:
! 2186: case SIOCDELMULTI:
! 2187: error = (cmd == SIOCADDMULTI) ?
! 2188: ether_addmulti(ifr, &sc->sc_arpcom):
! 2189: ether_delmulti(ifr, &sc->sc_arpcom);
! 2190:
! 2191: if (error == ENETRESET) {
! 2192: /*
! 2193: * Multicast list has changed; set the hardware filter
! 2194: * accordingly.
! 2195: */
! 2196: if (ifp->if_flags & IFF_RUNNING)
! 2197: mc_reset(sc);
! 2198: error = 0;
! 2199: }
! 2200: break;
! 2201:
! 2202: default:
! 2203: error = EINVAL;
! 2204: }
! 2205: splx(s);
! 2206: return error;
! 2207: }
! 2208:
! 2209: static void
! 2210: mc_reset(sc)
! 2211: struct ie_softc *sc;
! 2212: {
! 2213: struct ether_multi *enm;
! 2214: struct ether_multistep step;
! 2215:
! 2216: /*
! 2217: * Step through the list of addresses.
! 2218: */
! 2219: sc->mcast_count = 0;
! 2220: ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
! 2221: while (enm) {
! 2222: if (sc->mcast_count >= MAXMCAST ||
! 2223: bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
! 2224: sc->sc_arpcom.ac_if.if_flags |= IFF_ALLMULTI;
! 2225: ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
! 2226: goto setflag;
! 2227: }
! 2228:
! 2229: bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6);
! 2230: sc->mcast_count++;
! 2231: ETHER_NEXT_MULTI(step, enm);
! 2232: }
! 2233: setflag:
! 2234: sc->want_mcsetup = 1;
! 2235: }
! 2236:
! 2237: #ifdef IEDEBUG
! 2238: void
! 2239: print_rbd(rbd)
! 2240: volatile struct ie_recv_buf_desc *rbd;
! 2241: {
! 2242:
! 2243: printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
! 2244: "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
! 2245: rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
! 2246: rbd->mbz);
! 2247: }
! 2248: #endif
! 2249:
CVSweb