📄 i82586.c
字号:
/* $NetBSD: i82586.c,v 1.38 2001/07/07 05:35:39 thorpej Exp $ *//*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Paul Kranenburg and Charles M. Hannum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *//*- * Copyright (c) 1997 Paul Kranenburg. * Copyright (c) 1992, 1993, University of Vermont and State * Agricultural College. * Copyright (c) 1992, 1993, Garrett A. Wollman. * * Portions: * Copyright (c) 1994, 1995, Rafal K. Boni * Copyright (c) 1990, 1991, William F. Jolitz * Copyright (c) 1990, The Regents of the University of California * * RTEMS: * Copyright (c) 2001, Chris Johns, Cybertec Pty Ltd, * http://www.cybertec.com.au/. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of Vermont * and State Agricultural College and Garrett A. Wollman, by William F. * Jolitz, and by the University of California, Berkeley, Lawrence * Berkeley Laboratory, and its contributors. * 4. Neither the names of the Universities nor the names of the authors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * Intel 82586 Ethernet chip * Register, bit, and structure definitions. * * Original StarLAN driver written by Garrett Wollman with reference to the * Clarkson Packet Driver code for this chip written by Russ Nelson and others. * * BPF support code taken from hpdev/if_le.c, supplied with tcpdump. * * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni. * * Majorly cleaned up and 3C507 code merged by Charles Hannum. * * Converted to SUN ie driver by Charles D. Cranor, * October 1994, January 1995. * This sun version based on i386 version 1.30. *//* * The i82586 is a very painful chip, found in sun3's, sun-4/100's * sun-4/200's, and VME based suns. The byte order is all wrong for a * SUN, making life difficult. Programming this chip is mostly the same, * but certain details differ from system to system. This driver is * written so that different "ie" interfaces can be controled by the same * driver. *//*Mode of operation: We run the 82586 in a standard Ethernet mode. We keep NFRAMES received frame descriptors around for the receiver to use, and NRXBUF associated receive buffer descriptors, both in a circular list. Whenever a frame is received, we rotate both lists as necessary. (The 586 treats both lists as a simple queue.) We also keep a transmit command around so that packets can be sent off quickly. We configure the adapter in AL-LOC = 1 mode, which means that the Ethernet/802.3 MAC header is placed at the beginning of the receive buffer rather than being split off into various fields in the RFD. This also means that we must include this header in the transmit buffer as well. By convention, all transmit commands, and only transmit commands, shall have the I (IE_CMD_INTR) bit set in the command. This way, when an interrupt arrives at i82586_intr(), it is immediately possible to tell what precisely caused it. ANY OTHER command-sending routines should run at splnet(), and should post an acknowledgement to every interrupt they generate. To save the expense of shipping a command to 82586 every time we want to send a frame, we use a linked list of commands consisting of alternate XMIT and NOP commands. The links of these elements are manipulated (in iexmit()) such that the NOP command loops back to itself whenever the following XMIT command is not yet ready to go. Whenever an XMIT is ready, the preceding NOP link is pointed at it, while its own link field points to the following NOP command. Thus, a single transmit command sets off an interlocked traversal of the xmit command chain, with the host processor in control of the synchronization.*/#include <rtems.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <ctype.h>#include <stdio.h>#include <string.h>#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <net/ethernet.h>#include <net/if.h>#include <net/if_types.h>#include <net/if_dl.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include "i82586reg.h"#include "i82586var.h"/* * A global way to change all async cmd requests at once. For RTEMS and running * as tasks I wanted to see if the tx race condition is effected by this. */#define ASYNC_OPTION (1)void i82586_reset (struct ie_softc *, int);void i82586_watchdog (struct ifnet *);void i82586_init (void *);int i82586_ioctl (struct ifnet *, int cmd, caddr_t data);void i82586_start (struct ifnet *);void i82586_stop (struct ifnet *, int);int i82586_rint (struct ie_softc *, int);int i82586_tint (struct ie_softc *, int);int i82586_mediachange (struct ifnet *);void i82586_mediastatus (struct ifnet *, struct ifmediareq *);static void i82586_tx_task(void *arg);static void i82586_start_tx(struct ie_softc *sc);static int ie_readframe (struct ie_softc *, int);static struct mbuf *ieget (struct ie_softc *, int, int);static int i82586_get_rbd_list (struct ie_softc *, u_int16_t *, u_int16_t *, int *);static void i82586_release_rbd_list (struct ie_softc *, u_int16_t, u_int16_t);static int i82586_drop_frames (struct ie_softc *);static int i82586_chk_rx_ring (struct ie_softc *);static __inline__ void ie_ack (struct ie_softc *, u_int);static __inline__ void iexmit (struct ie_softc *);static void i82586_start_transceiver (struct ie_softc *);static void i82586_count_errors (struct ie_softc *);static void i82586_rx_errors (struct ie_softc *, int, int);static void i82586_setup_bufs (struct ie_softc *);static void setup_simple_command (struct ie_softc *, int, int);static int ie_cfg_setup (struct ie_softc *, int, int, int);static int ie_ia_setup (struct ie_softc *, int);static void ie_run_tdr (struct ie_softc *, int);static int ie_mc_setup (struct ie_softc *, int);static void ie_mc_reset (struct ie_softc *);static int i82586_start_cmd (struct ie_softc *, int, int, int, int);static int i82586_cmd_wait (struct ie_softc *);#if I82586_DEBUGstatic void print_softie(struct ie_softc *sc);static void print_rbd (struct ie_softc *, int);#endif#define min(l,r) ((l) < (r) ? (l) : (r))#define max(l,r) ((l) > (r) ? (l) : (r))#define delay(p) rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (p))#define i82586_WAKE_EVENT RTEMS_EVENT_1#define i82586_TX_EVENT RTEMS_EVENT_2char *bitmask_snprintf(unsigned long value, const char *format, char *buf, int blen){ char *b = buf; int bit = 31; while (bit-- > *format) value <<= 1; format++; while (*format) { if (value & 0x80000000) while (isalnum(*format)) *b++ = *format; else *b++ = '0'; *b++ = ','; while (bit-- > *format) value <<= 1; format++; } *b = '\0'; return buf;}char *ether_sprintf(unsigned char *addr){ static char buf[32]; char *b = buf; int i; for (i = 0; i < ETHER_ADDR_LEN; i++) { sprintf(b, "%02x:", *addr++); b += 3; } b--; b = "\0"; return buf;}/* * Front-ends call this function to attach to the MI driver. * * The front-end has responsibility for managing the ICP and ISCP * structures. Both of these are opaque to us. Also, the front-end * chooses a location for the SCB which is expected to be addressable * (through `sc->scb') as an offset against the shared-memory bus handle. * * The following MD interface function must be setup by the front-end * before calling here: * * hwreset - board dependent reset * hwinit - board dependent initialization * chan_attn - channel attention * intrhook - board dependent interrupt processing * memcopyin - shared memory copy: board to KVA * memcopyout - shared memory copy: KVA to board * ie_bus_read16 - read a sixteen-bit i82586 pointer * ie_bus_write16 - write a sixteen-bit i82586 pointer * ie_bus_write24 - write a twenty-four-bit i82586 pointer * */inti82586_attach(struct rtems_bsdnet_ifconfig *config, int attaching){ struct ie_softc *sc; struct ifnet *ifp; char *name; int unit; int mtu; /* * Parse driver name */ if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0) return 0; sc = config->drv_ctrl; ifp = &sc->arpcom.ac_if; #if I82586_DEBUG sc->sc_debug = 0; //IED_TINT | IED_XMIT;#endif if (attaching) { if (ifp->if_softc) { printf ("Driver `%s' already in use.\n", config->name); return 0; } /* * Process options */ memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); if (config->mtu) mtu = config->mtu; else mtu = ETHERMTU; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = name; ifp->if_mtu = mtu; ifp->if_init = i82586_init; ifp->if_ioctl = i82586_ioctl; ifp->if_start = i82586_start; ifp->if_output = ether_output; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; /* Attach the interface. */ if_attach(ifp); ether_ifattach(ifp); return 1; } return 0;}/* * Interrupt Acknowledge. Mask in native byte-order. */static __inline__ voidie_ack(struct ie_softc *sc, u_int mask){ u_int status; IE_BUS_BARRIER(sc, 0, 0, BUS_SPACE_BARRIER_READ); status = sc->ie_bus_read16(sc, IE_SCB_STATUS(sc->scb)); i82586_start_cmd(sc, status & mask, 0, 0, 0); if (sc->intrhook) sc->intrhook(sc, INTR_ACK);}/* * Read data off the interface, and turn it into an mbuf chain. * * This code is DRAMATICALLY different from the previous version; this * version tries to allocate the entire mbuf chain up front, given the * length of the data available. This enables us to allocate mbuf * clusters in many situations where before we would have had a long * chain of partially-full mbufs. This should help to speed up the * operation considerably. (Provided that it works, of course.) */static __inline struct mbuf *ieget(struct ie_softc *sc, int head, int totlen){ struct mbuf *m, *m0, *newm; int len, resid; int thisrboff, thismboff; struct ether_header eh; /* * Snarf the Ethernet header. */ (sc->memcopyin)(sc, &eh, IE_RBUF_ADDR(sc, head), sizeof(struct ether_header)); resid = totlen; MGETHDR(m0, M_DONTWAIT, MT_DATA); if (m0 == 0) return (0); m0->m_pkthdr.rcvif = &sc->arpcom.ac_if; m0->m_pkthdr.len = totlen; len = MHLEN; m = m0; /* * This loop goes through and allocates mbufs for all the data we will * be copying in. It does not actually do the copying yet. */ while (totlen > 0) { if (totlen >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) goto bad; len = MCLBYTES; } if (m == m0) { caddr_t newdata = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header)) - sizeof(struct ether_header); len -= newdata - m->m_data; m->m_data = newdata; } m->m_len = len = min(totlen, len); totlen -= len; if (totlen > 0) { MGET(newm, M_DONTWAIT, MT_DATA); if (newm == 0) goto bad; len = MLEN; m = m->m_next = newm; } } m = m0; thismboff = 0; /* * Copy the Ethernet header into the mbuf chain. */ memcpy(mtod(m, caddr_t), &eh, sizeof(struct ether_header)); thismboff = sizeof(struct ether_header); thisrboff = sizeof(struct ether_header); resid -= sizeof(struct ether_header); /* * Now we take the mbuf chain (hopefully only one mbuf most of the * time) and stuff the data into it. There are no possible failures * at or after this point. */ while (resid > 0) { int thisrblen = IE_RBUF_SIZE - thisrboff, thismblen = m->m_len - thismboff; len = min(thisrblen, thismblen); (sc->memcopyin)(sc, mtod(m, caddr_t) + thismboff, IE_RBUF_ADDR(sc,head) + thisrboff, (u_int)len); resid -= len; if (len == thismblen) { m = m->m_next; thismboff = 0; } else thismboff += len; if (len == thisrblen) { if (++head == sc->nrxbuf) head = 0; thisrboff = 0; } else thisrboff += len; } /* * Unless something changed strangely while we were doing the copy, * we have now copied everything in from the shared memory. * This means that we are done. */ return (m0); bad: m_freem(m0); return (0);}/* * Setup all necessary artifacts for an XMIT command, and then pass the XMIT * command to the chip to be executed. */static __inline__ voidiexmit(struct ie_softc *sc){ int off; int cur, prev; cur = sc->xctail;#if I82586_DEBUG I82586_TRACE(sc, I82586_TX_EMIT, cur);#endif #if I82586_DEBUG if (sc->sc_debug & IED_XMIT) printf("%s: xmit buffer %d\n", sc->arpcom.ac_if.if_name, cur);#endif /* * Setup the transmit command. */ sc->ie_bus_write16(sc, IE_CMD_XMIT_DESC(sc->xmit_cmds, cur), IE_XBD_ADDR(sc->xbds, cur)); sc->ie_bus_write16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds, cur), 0); if (sc->do_xmitnopchain) { /* * Gate this XMIT command to the following NOP */ sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds, cur), IE_CMD_NOP_ADDR(sc->nop_cmds, cur)); sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur), IE_CMD_XMIT | IE_CMD_INTR); /* * Loopback at following NOP */ sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, cur), 0); sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, cur), IE_CMD_NOP_ADDR(sc->nop_cmds, cur)); /* * Gate preceding NOP to this XMIT command */ prev = (cur + NTXBUF - 1) % NTXBUF; sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, prev), 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -