📄 am7990.c
字号:
/* $OpenBSD: am7990.c,v 1.15 1999/02/28 05:02:16 jason Exp $ *//* $NetBSD: am7990.c,v 1.22 1996/10/13 01:37:19 christos Exp $ *//*- * Copyright (c) 1995 Charles M. Hannum. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * 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 * California, Berkeley and its contributors. * 4. Neither the name of the University 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 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 REGENTS 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. * * @(#)if_le.c 8.2 (Berkeley) 11/16/93 */#ifdef PROM#include <sys/ioctl.h>#else#include "bpfilter.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h> #include <sys/syslog.h>#include <sys/socket.h>#include <sys/device.h>#include <sys/malloc.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <net/if.h>#include <net/if_media.h>#ifdef INET#include <netinet/in.h>#include <netinet/if_ether.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#endif#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#include <dev/ic/am7990reg.h>#include <dev/ic/am7990var.h>#endif#ifdef LEDEBUGvoid am7990_recv_print __P((struct am7990_softc *, int));void am7990_xmit_print __P((struct am7990_softc *, int));#endifintegrate void am7990_rint __P((struct am7990_softc *));integrate void am7990_tint __P((struct am7990_softc *));integrate int am7990_put __P((struct am7990_softc *, int, struct mbuf *));integrate struct mbuf *am7990_get __P((struct am7990_softc *, int, int));integrate void am7990_read __P((struct am7990_softc *, int, int)); hide void am7990_shutdown __P((void *));#define ifp (&sc->sc_arpcom.ac_if)#if 0 /* XXX what do we do about this?! --thorpej */static inline u_int16_t ether_cmp __P((void *, void *));/* * Compare two Ether/802 addresses for equality, inlined and * unrolled for speed. I'd love to have an inline assembler * version of this... XXX: Who wanted that? mycroft? * I wrote one, but the following is just as efficient. * This expands to 10 short m68k instructions! -gwr * Note: use this like bcmp() */static inline u_shortether_cmp(one, two) void *one, *two;{ register u_int16_t *a = (u_short *) one; register u_int16_t *b = (u_short *) two; register u_int16_t diff; diff = *a++ - *b++; diff |= *a++ - *b++; diff |= *a++ - *b++; return (diff);}#define ETHER_CMP ether_cmp#endif /* XXX */#ifndef ETHER_CMP#define ETHER_CMP(a, b) bcmp((a), (b), ETHER_ADDR_LEN)#endif#ifdef PROM#ifdef LEDEBUG#define printf(fmt, args...) _mon_printf(fmt , ## args)#endifstruct cfdriver le_cd = { 0, "le", le_pci_match, le_pci_attach, DV_IFNET, sizeof(struct le_softc)};#ifndef IFF_MULTICAST#define IFF_MULTICAST 0#endif#define UNIT_TO_SOFTC(unit) ((struct am7990_softc *) le_cd.cd_devs[unit])#define IFP_TO_SOFTC(ifp) UNIT_TO_SOFTC((ifp)->if_unit)#else#define IFP_TO_SOFTC(ifp) (ifp)->softc/* * am7990 configuration driver. Attachments are provided by * machine-dependent driver front-ends. */struct cfdriver le_cd = { NULL, "le", DV_IFNET};#endifvoidam7990_config(sc) struct am7990_softc *sc;{ int mem; /* Make sure the chip is stopped. */ am7990_stop(sc); /* Initialize ifnet structure. */#ifdef PROM { /* boost FIFO thresholds */ unsigned int val; val = 2 << 12; /* RCVFW=112 */ val |= 3 << 10; /* XMTSP=220 */ val |= 0 << 8; /* XMTFW=16 */ le_pci_wrcsr (sc, 80, val); }#else bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); ifp->if_softc = sc;#endif ifp->if_start = am7990_start; ifp->if_ioctl = am7990_ioctl; ifp->if_watchdog = am7990_watchdog; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;#ifdef LANCE_REVC_BUG ifp->if_flags &= ~IFF_MULTICAST;#endif /* Attach the interface. */#ifdef PROM ifp->if_name = "en"; ether_attach(ifp);#else if_attach(ifp); ether_ifattach(ifp);#endif#if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif if (sc->sc_memsize > 131072) sc->sc_memsize = 131072; switch (sc->sc_memsize) { case 8192: sc->sc_nrbuf = 4; sc->sc_ntbuf = 1; break; case 16384: sc->sc_nrbuf = 8; sc->sc_ntbuf = 2; break; case 32768: sc->sc_nrbuf = 16; sc->sc_ntbuf = 4; break; case 65536: sc->sc_nrbuf = 32; sc->sc_ntbuf = 8; break; case 131072: sc->sc_nrbuf = 64; sc->sc_ntbuf = 16; break; default:#ifdef PROM log(LOG_ERR, "am7990_config: weird memory size %d", sc->sc_memsize); panic("am7990_config: weird memory size");#else panic("am7990_config: weird memory size %d", sc->sc_memsize);#endif } printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); printf("%s: %d receive buffers, %d transmit buffers\n", sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);#ifndef PROM sc->sc_sh = shutdownhook_establish(am7990_shutdown, sc); if (sc->sc_sh == NULL) panic("am7990_config: can't establish shutdownhook");#endif mem = 0; sc->sc_initaddr = mem; mem += sizeof(struct leinit); sc->sc_rmdaddr = mem; mem += sizeof(struct lermd) * sc->sc_nrbuf; sc->sc_tmdaddr = mem; mem += sizeof(struct letmd) * sc->sc_ntbuf; sc->sc_rbufaddr = mem; mem += LEBLEN * sc->sc_nrbuf; sc->sc_tbufaddr = mem; mem += LEBLEN * sc->sc_ntbuf;#ifdef PROM #ifdef LEDEBUG printf ("am7990_config: initaddr=%x rmdaddr=%x tmdaddr=%x rbufaddr=%x tbufaddr=%x\n", sc->sc_initaddr, sc->sc_rmdaddr, sc->sc_tmdaddr, sc->sc_rbufaddr, sc->sc_tbufaddr);#endif#endif#ifdef notyet if (mem > ...) panic(...);#endif}voidam7990_reset(sc) struct am7990_softc *sc;{ int s; s = splimp(); am7990_init(sc); splx(s);}/* * Set up the initialization block and the descriptor rings. */voidam7990_meminit(sc) register struct am7990_softc *sc;{ u_long a; int bix; struct leinit init; struct lermd rmd; struct letmd tmd;#if NBPFILTER > 0 if (ifp->if_flags & IFF_PROMISC) init.init_mode = htoms(LE_MODE_NORMAL | LE_MODE_PROM); else#endif init.init_mode = htoms(LE_MODE_NORMAL);#ifdef PROM init.init_mode |= htoms(LE_MODE_PORTSEL);#endif init.init_padr[0] = htoms((sc->sc_arpcom.ac_enaddr[1] << 8) | sc->sc_arpcom.ac_enaddr[0]); init.init_padr[1] = htoms((sc->sc_arpcom.ac_enaddr[3] << 8) | sc->sc_arpcom.ac_enaddr[2]); init.init_padr[2] = htoms((sc->sc_arpcom.ac_enaddr[5] << 8) | sc->sc_arpcom.ac_enaddr[4]); am7990_setladrf(&sc->sc_arpcom, init.init_ladrf); sc->sc_last_rd = 0; sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; a = sc->sc_addr + LE_RMDADDR(sc, 0); init.init_rdra = htoms(a); init.init_rlen = htoms(((a >> 16) & 0xff) | ((ffs(sc->sc_nrbuf) - 1) << 13)); a = sc->sc_addr + LE_TMDADDR(sc, 0); init.init_tdra = htoms(a); init.init_tlen = htoms(((a >> 16) & 0xff) | ((ffs(sc->sc_ntbuf) - 1) << 13)); (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); /* * Set up receive ring descriptors. */ for (bix = 0; bix < sc->sc_nrbuf; bix++) { a = sc->sc_addr + LE_RBUFADDR(sc, bix); rmd.rmd0 = htoms(a); rmd.rmd1_hadr = a >> 16; rmd.rmd1_bits = LE_R1_OWN; rmd.rmd2 = htoms(-LEBLEN | LE_XMD2_ONES); rmd.rmd3 = htoms(0); (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), sizeof(rmd)); } /* * Set up transmit ring descriptors. */ for (bix = 0; bix < sc->sc_ntbuf; bix++) { a = sc->sc_addr + LE_TBUFADDR(sc, bix); tmd.tmd0 = htoms(a); tmd.tmd1_hadr = a >> 16; tmd.tmd1_bits = 0; tmd.tmd2 = htoms(0 | LE_XMD2_ONES); tmd.tmd3 = htoms(0); (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), sizeof(tmd)); }}voidam7990_stop(sc) struct am7990_softc *sc;{ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);}#ifdef PROMintam7990_linkstatus (struct am7990_softc *sc){ static int linkup = 0; int status = le_pci_rdanr(sc, 30, 1); if (status & 4) { status = le_pci_rdanr(sc, 30, 24); if (linkup == 0) { linkup = 1; printf ("%s: %dMb/s %cD link up\n", sc->sc_dev.dv_xname, (status & 1) ? 100 : 10, (status & 4) ? 'F' : 'H'); } } else { if (linkup != 0) { linkup = 0; printf ("%s: link down\n", sc->sc_dev.dv_xname); } } return linkup;}#endif/* * Initialization of interface; set up initialization block * and transmit/receive descriptor rings. */voidam7990_init(sc) register struct am7990_softc *sc;{ register int timo; u_long a; (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); DELAY(100); /* Newer LANCE chips have a reset register */ if (sc->sc_hwreset) (*sc->sc_hwreset)(sc); /* Set the correct byte swapping mode, etc. */ (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3); /* Set up LANCE init block. */ am7990_meminit(sc); /* Give LANCE the physical address of its init block. */ a = sc->sc_addr + LE_INITADDR(sc); (*sc->sc_wrcsr)(sc, LE_CSR1, a); (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16); /* Try to initialize the LANCE. */ DELAY(100); (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT); /* Wait for initialization to finish. */ for (timo = 100000; timo; timo--) if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) break; if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) { /* Start the LANCE. */ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT | LE_C0_IDON); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; ifp->if_timer = 0; am7990_start(ifp); } else printf("%s: controller failed to initialize\n", sc->sc_dev.dv_xname); if (sc->sc_hwinit) (*sc->sc_hwinit)(sc);#if PROM { /* wait a bit for the link to comw up */ int timeout = 2400; while (timeout > 0) { if (am7990_linkstatus (sc)) break; DELAY (100000); timeout -= 100; } }#endif}/* * Routine to copy from mbuf chain to transmit buffer in * network buffer memory. */integrate intam7990_put(sc, boff, m) struct am7990_softc *sc; int boff; register struct mbuf *m;{ register struct mbuf *n; register int len, tlen = 0; for (; m; m = n) { len = m->m_len; if (len == 0) { MFREE(m, n); continue; } (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len); boff += len; tlen += len; MFREE(m, n); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -