📄 if_de.c
字号:
/* $OpenBSD: if_de.c,v 1.31 1998/05/28 20:25:51 deraadt Exp $ *//* $NetBSD: if_de.c,v 1.45 1997/06/09 00:34:18 thorpej Exp $ *//*- * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) * 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. The name of the author may not be used to endorse or promote products * derived from this software withough specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * Id: if_de.c,v 1.89 1997/06/03 19:19:55 thomas Exp * *//* * DEC 21040 PCI Ethernet Controller * * Written by Matt Thomas * BPF support code stolen directly from if_ec.c * * This driver supports the DEC DE435 or any other PCI * board which support 21040, 21041, or 21140 (mostly). */#define TULIP_HDR_DATA#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/malloc.h>#include <sys/kernel.h>#include <sys/proc.h> /* only for declaration of wakeup() used by vm.h */#if defined(__FreeBSD__)#include <machine/clock.h>#elif defined(__bsdi__) || defined(__NetBSD__) || defined(__OpenBSD__)#include <sys/device.h>#endif#include <net/if.h>#if defined(SIOCSIFMEDIA) && !defined(TULIP_NOIFMEDIA)#include <net/if_media.h>#endif#include <net/if_types.h>#include <net/if_dl.h>#include <net/route.h>#include <net/netisr.h>#if defined(__bsdi__) && _BSDI_VERSION >= 199701#include <dev/mii/mii.h>#include <dev/mii/miivar.h>#endif#include "bpfilter.h"#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#endif#ifdef NS#include <netns/ns.h>#include <netns/ns_if.h>#endif#include <vm/vm.h>#include <vm/vm_param.h>#include <vm/vm_kern.h>#if defined(__FreeBSD__)#include <vm/pmap.h>#include <pci.h>#include <netinet/if_ether.h>#if NPCI > 0#include <pci/pcivar.h>#include <pci/dc21040reg.h>#define DEVAR_INCLUDE "pci/if_devar.h"#endif#endif /* __FreeBSD__ */#if defined(__bsdi__)#include <netinet/if_ether.h>#include <i386/pci/ic/dc21040reg.h>#include <i386/isa/isa.h>#include <i386/isa/icu.h>#include <i386/isa/dma.h>#include <i386/isa/isavar.h>#include <i386/pci/pci.h>#if _BSDI_VERSION < 199510#include <eisa.h>#else#define NEISA 0#endif#if NEISA > 0 && _BSDI_VERSION >= 199401#include <i386/eisa/eisa.h>#define TULIP_EISA#endif#define DEVAR_INCLUDE "i386/pci/if_devar.h"#endif /* __bsdi__ */#if defined(__NetBSD__) #include <net/if_ether.h>#if defined(INET)#include <netinet/if_inarp.h>#endif#endif#if defined(__OpenBSD__)#include <netinet/if_ether.h>#endif#if defined(__NetBSD__) || defined(__OpenBSD__)#include <machine/bus.h>#if defined(__alpha__)#include <machine/intr.h>#endif#include <dev/pci/pcireg.h>#include <dev/pci/pcivar.h>#include <dev/ic/dc21040reg.h>#define DEVAR_INCLUDE "dev/pci/if_devar.h"#endif /* __NetBSD__ */#if defined(PROM)#include <machine/endian.h>#include <netinet/if_ether.h>#include <sys/syslog.h>#include "pci/pcivar.h"#include "pci/device.h"#include "dc21040reg.h"#include "mips.h"#include "sbd.h"#define DEVAR_INCLUDE "if_devar.h"/*#define vtophys(va) KVA_TO_PA(va)*/#ifndef sbd_clean_dcache#ifdef R4000#define sbd_clean_dcache mips_clean_dcache#define sbd_inval_dcache mips_clean_dcache#else#define sbd_clean_dcache r3k_dclean#define sbd_inval_dcache r3k_dclean#endif#endif#define clean_dcache sbd_clean_dcache#define inval_dcache sbd_inval_dcachetypedef int ifnet_ret_t;typedef int ioctl_cmd_t;extern struct cfdriver decd;#define TULIP_UNIT_TO_SOFTC(unit) ((tulip_softc_t *) decd.cd_devs[unit])#define TULIP_IFP_TO_SOFTC(ifp) TULIP_UNIT_TO_SOFTC((ifp)->if_unit)#define IFF_LINK0 IFF_LLC0#define IFF_LINK1 IFF_LLC1#define IFF_LINK2 IFF_LLC2#define loudprintf printf#define __BROKEN_INDIRECT_CONFIG#endif/* * Intel CPUs should use I/O mapped access. */#if defined(__i386__) || defined(TULIP_EISA)#define TULIP_IOMAPPED#endif#if 0/* * This turns on all sort of debugging stuff and make the * driver much larger. */#define TULIP_DEBUG/* * This turns on even more debug code to find out why * the driver does stupid things sometimes */#if 1#define TULIP_MEGADEBUG#endif#endif#if 0#define TULIP_USE_SOFTINTR#endif#define TULIP_HZ 10#include DEVAR_INCLUDE/* * This module supports * the DEC 21040 PCI Ethernet Controller. * the DEC 21041 PCI Ethernet Controller. * the DEC 21140 PCI Fast Ethernet Controller. */static void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr);static tulip_intrfunc_t tulip_intr_shared(void *arg);static tulip_intrfunc_t tulip_intr_normal(void *arg);static void tulip_init(tulip_softc_t * const sc);static void tulip_reset(tulip_softc_t * const sc);static ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp);static ifnet_ret_t tulip_ifstart(struct ifnet *ifp);static struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m);static void tulip_txput_setup(tulip_softc_t * const sc);static void tulip_rx_intr(tulip_softc_t * const sc);static void tulip_addr_filter(tulip_softc_t * const sc);static unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno);static void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data);static int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities);static tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc);static int tulip_srom_decode(tulip_softc_t * const sc);#if defined(IFM_ETHER)static int tulip_ifmedia_change(struct ifnet * const ifp);static void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req);#endif/* static void tulip_21140_map_media(tulip_softc_t *sc); */static voidtulip_timeout_callback( void *arg){ tulip_softc_t * const sc = arg; tulip_spl_t s = TULIP_RAISESPL(); sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; sc->tulip_probe_timeout -= 1000 / TULIP_HZ; (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); TULIP_RESTORESPL(s);}static voidtulip_timeout( tulip_softc_t * const sc){ if (sc->tulip_flags & TULIP_TIMEOUTPENDING) return; sc->tulip_flags |= TULIP_TIMEOUTPENDING; timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ);}#if defined(TULIP_NEED_FASTTIMEOUT)static voidtulip_fasttimeout_callback( void *arg){ tulip_softc_t * const sc = arg; tulip_spl_t s = TULIP_RAISESPL(); sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); TULIP_RESTORESPL(s);}static voidtulip_fasttimeout( tulip_softc_t * const sc){ if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) return; sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; timeout(tulip_fasttimeout_callback, sc, 1);}#endifstatic inttulip_txprobe( tulip_softc_t * const sc){ struct mbuf *m; /* * Before we are sure this is the right media we need * to send a small packet to make sure there's carrier. * Strangely, BNC and AUI will "see" receive data if * either is connected so the transmit is the only way * to verify the connectivity. */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return 0; /* * Construct a LLC TEST message which will point to ourselves. */ bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); mtod(m, struct ether_header *)->ether_type = htons(3); mtod(m, unsigned char *)[14] = 0; mtod(m, unsigned char *)[15] = 0; mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; /* * send it! */ sc->tulip_cmdmode |= TULIP_CMD_TXRUN; sc->tulip_intrmask |= TULIP_STS_TXINTR; sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); if ((m = tulip_txput(sc, m)) != NULL) m_freem(m); sc->tulip_probe.probe_txprobes++; return 1;}#ifdef BIG_PACKET#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0)#else#define TULIP_SIAGEN_WATCHDOG 0#endifstatic voidtulip_media_set( tulip_softc_t * const sc, tulip_media_t media){ const tulip_media_info_t *mi = sc->tulip_mediums[media]; if (mi == NULL) return; /* * If we are switching media, make sure we don't think there's * any stale RX activity */ sc->tulip_flags &= ~TULIP_RXACT; if (mi->mi_type == TULIP_MEDIAINFO_SIA) { TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); if (sc->tulip_features & TULIP_HAVE_SIAGP) { TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); DELAY(50); TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); } else { TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); } TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) /* * If the cmdmode bits don't match the currently operating mode, * set the cmdmode appropriately and reset the chip. */ if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; sc->tulip_cmdmode |= mi->mi_cmdmode;#if defined(TULIP_MEGADEBUG) printf ("tulip_reset: tulip_media_set/TULIP_MEDIAINFO_GPR\n");#endif tulip_reset(sc); } TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); DELAY(10); TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { /* * If the cmdmode bits don't match the currently operating mode, * set the cmdmode appropriately and reset the chip. */ if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; sc->tulip_cmdmode |= mi->mi_cmdmode;#if defined(TULIP_MEGADEBUG) printf ("tulip_reset: tulip_media_set/TULIP_MEDIAINFO_SYM\n");#endif tulip_reset(sc); } TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); } else if (mi->mi_type == TULIP_MEDIAINFO_MII && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { int idx; if (sc->tulip_features & TULIP_HAVE_SIAGP) { const u_int8_t *dp; dp = &sc->tulip_rombuf[mi->mi_reset_offset]; for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { DELAY(10); TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); } sc->tulip_phyaddr = mi->mi_phyaddr; dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { DELAY(10); TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); } } else { for (idx = 0; idx < mi->mi_reset_length; idx++) { DELAY(10); TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); } sc->tulip_phyaddr = mi->mi_phyaddr; for (idx = 0; idx < mi->mi_gpr_length; idx++) { DELAY(10); TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); } } if (sc->tulip_flags & TULIP_TRYNWAY) { tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); data &= ~(PHYCTL_SELECT_100MB|PHYCTL_AUTONEG_ENABLE|PHYCTL_FULL_DUPLEX); data &= ~(PHYCTL_POWERDOWN|PHYCTL_ISOLATE); sc->tulip_flags &= ~TULIP_DIDNWAY; if (TULIP_IS_MEDIA_FD(media)) data |= PHYCTL_FULL_DUPLEX; if (TULIP_IS_MEDIA_100MB(media)) data |= PHYCTL_SELECT_100MB; tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); } }}static voidtulip_linkup( tulip_softc_t * const sc,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -