📄 if_de.c
字号:
/* $Id: if_de.c,v 1.1.1.1 2003/11/08 08:41:45 wlin Exp $ *//* $OpenBSD: if_de.c,v 1.41 1999/07/18 03:20:18 csapuntz 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#define TULIP_NOIFMEDIA#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 */#include <sys/device.h>#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>#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(__OpenBSD__)#include <netinet/if_ether.h>#endif#if defined(__OpenBSD__)#include <machine/bus.h>#include <dev/pci/pcireg.h>#include <dev/pci/pcivar.h>#include <dev/pci/pcidevs.h>#include <dev/ic/dc21040reg.h>#define DEVAR_INCLUDE "dev/pci/if_devar.h"#endif /* __OpenBSD__ *//* * Intel CPUs should use I/O mapped access. */#if defined(__i386__)#define TULIP_IOMAPPED#endif/* * This turns on all sort of debugging stuff and make the * driver much larger. */#if 0#define TULIP_DEBUG#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; 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; 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_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 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, tulip_media_t media){ if ((sc->tulip_flags & TULIP_LINKUP) == 0) sc->tulip_flags |= TULIP_PRINTLINKUP; sc->tulip_flags |= TULIP_LINKUP; sc->tulip_if.if_flags &= ~IFF_OACTIVE;#if 0 /* XXX how does with work with ifmedia? */ if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { if (TULIP_CAN_MEDIA_FD(media) && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) media = TULIP_FD_MEDIA_OF(media); } else { if (TULIP_IS_MEDIA_FD(media) && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) media = TULIP_HD_MEDIA_OF(media); } }#endif if (sc->tulip_media != media) {#ifdef TULIP_DEBUG sc->tulip_dbg.dbg_last_media = sc->tulip_media;#endif sc->tulip_media = media; sc->tulip_flags |= TULIP_PRINTMEDIA; if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; } } /* * We could set probe_timeout to 0 but setting to 3000 puts this * in one central place and the only matters is tulip_link is * followed by a tulip_timeout. Therefore setting it should not * result in aberrant behavour. */ sc->tulip_probe_timeout = 3000; sc->tulip_probe_state = TULIP_PROBE_INACTIVE; sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); if (sc->tulip_flags & TULIP_INRESET) { tulip_media_set(sc, sc->tulip_media); } else if (sc->tulip_probe_media != sc->tulip_media) { /* * No reason to change media if we have the right media. */ tulip_reset(sc); } tulip_init(sc);}static voidtulip_media_print( tulip_softc_t * const sc){ if ((sc->tulip_flags & TULIP_LINKUP) == 0) return; if (sc->tulip_flags & TULIP_PRINTMEDIA) { printf(TULIP_PRINTF_FMT ": enabling %s port\n", TULIP_PRINTF_ARGS, tulip_mediums[sc->tulip_media]); sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS); sc->tulip_flags &= ~TULIP_PRINTLINKUP; }}#if defined(TULIP_DO_GPR_SENSE)static tulip_media_ttulip_21140_gpr_media_sense( tulip_softc_t * const sc){ tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; tulip_media_t media; /* * If one of the media blocks contained a default media flag, * use that. */ for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { const tulip_media_info_t *mi; /* * Media is not supported (or is full-duplex). */ if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) continue; if (mi->mi_type != TULIP_MEDIAINFO_GPR) continue; /* * Remember the media is this is the "default" media. */ if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) maybe_media = media; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -