if_fxp.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,926 行 · 第 1/4 页
C
1,926 行
/* * Copyright (c) 1995, David Greenman * All rights reserved. * * Modifications to support NetBSD and media selection: * Copyright (c) 1997 Jason R. Thorpe. 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 unmodified, 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $Id: if_fxp.c,v 1.59.2.3 1999/03/30 04:51:43 wes Exp $ *//* * Intel EtherExpress Pro/100B PCI Fast Ethernet driver */#include "bpfilter.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/malloc.h>#include <sys/kernel.h>#include <sys/socket.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_media.h>#ifdef NS#include <netns/ns.h>#include <netns/ns_if.h>#endif#if NBPFILTER > 0#include <net/bpf.h>#endif#if defined(__NetBSD__)#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/device.h>#include <net/if_dl.h>#include <net/if_ether.h>#include <netinet/if_inarp.h>#include <vm/vm.h>#include <machine/cpu.h>#include <machine/bus.h>#include <machine/intr.h>#include <dev/pci/if_fxpreg.h>#include <dev/pci/if_fxpvar.h>#include <dev/pci/pcivar.h>#include <dev/pci/pcireg.h>#include <dev/pci/pcidevs.h>#ifdef __alpha__ /* XXX *//* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */#undef vtophys#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))#endif /* __alpha__ */#else /* __FreeBSD__ */#include <sys/sockio.h>#include <net/ethernet.h>#include <net/if_arp.h>#include <vm/vm.h> /* for vtophys */#include <vm/pmap.h> /* for vtophys */#include <machine/clock.h> /* for DELAY */#include <pci/pcivar.h>#include <pci/pcireg.h> /* for PCIM_CMD_xxx */#include <pci/if_fxpreg.h>#include <pci/if_fxpvar.h>#endif /* __NetBSD__ */#include "opt_bdg.h"#ifdef BRIDGE#include <net/if_types.h>#include <net/bridge.h>#endif/* * NOTE! On the Alpha, we have an alignment constraint. The * card DMAs the packet immediately following the RFA. However, * the first thing in the packet is a 14-byte Ethernet header. * This means that the packet is misaligned. To compensate, * we actually offset the RFA 2 bytes into the cluster. This * alignes the packet after the Ethernet header at a 32-bit * boundary. HOWEVER! This means that the RFA is misaligned! */#define RFA_ALIGNMENT_FUDGE 2/* * Inline function to copy a 16-bit aligned 32-bit quantity. */static __inline void fxp_lwcopy __P((volatile u_int32_t *, volatile u_int32_t *));static __inline voidfxp_lwcopy(src, dst) volatile u_int32_t *src, *dst;{ volatile u_int16_t *a = (u_int16_t *)src; volatile u_int16_t *b = (u_int16_t *)dst; b[0] = a[0]; b[1] = a[1];}/* * Template for default configuration parameters. * See struct fxp_cb_config for the bit definitions. */static u_char fxp_cb_config_template[] = { 0x0, 0x0, /* cb_status */ 0x80, 0x2, /* cb_command */ 0xff, 0xff, 0xff, 0xff, /* link_addr */ 0x16, /* 0 */ 0x8, /* 1 */ 0x0, /* 2 */ 0x0, /* 3 */ 0x0, /* 4 */ 0x80, /* 5 */ 0xb2, /* 6 */ 0x3, /* 7 */ 0x1, /* 8 */ 0x0, /* 9 */ 0x26, /* 10 */ 0x0, /* 11 */ 0x60, /* 12 */ 0x0, /* 13 */ 0xf2, /* 14 */ 0x48, /* 15 */ 0x0, /* 16 */ 0x40, /* 17 */ 0xf3, /* 18 */ 0x0, /* 19 */ 0x3f, /* 20 */ 0x5 /* 21 */};/* Supported media types. */struct fxp_supported_media { const int fsm_phy; /* PHY type */ const int *fsm_media; /* the media array */ const int fsm_nmedia; /* the number of supported media */ const int fsm_defmedia; /* default media for this PHY */};static const int fxp_media_standard[] = { IFM_ETHER|IFM_10_T, IFM_ETHER|IFM_10_T|IFM_FDX, IFM_ETHER|IFM_100_TX, IFM_ETHER|IFM_100_TX|IFM_FDX, IFM_ETHER|IFM_AUTO,};#define FXP_MEDIA_STANDARD_DEFMEDIA (IFM_ETHER|IFM_AUTO)static const int fxp_media_default[] = { IFM_ETHER|IFM_MANUAL, /* XXX IFM_AUTO ? */};#define FXP_MEDIA_DEFAULT_DEFMEDIA (IFM_ETHER|IFM_MANUAL)static const struct fxp_supported_media fxp_media[] = { { FXP_PHY_DP83840, fxp_media_standard, sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), FXP_MEDIA_STANDARD_DEFMEDIA }, { FXP_PHY_DP83840A, fxp_media_standard, sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), FXP_MEDIA_STANDARD_DEFMEDIA }, { FXP_PHY_82553A, fxp_media_standard, sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), FXP_MEDIA_STANDARD_DEFMEDIA }, { FXP_PHY_82553C, fxp_media_standard, sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), FXP_MEDIA_STANDARD_DEFMEDIA }, { FXP_PHY_82555, fxp_media_standard, sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), FXP_MEDIA_STANDARD_DEFMEDIA }, { FXP_PHY_82555B, fxp_media_standard, sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), FXP_MEDIA_STANDARD_DEFMEDIA }, { FXP_PHY_80C24, fxp_media_default, sizeof(fxp_media_default) / sizeof(fxp_media_default[0]), FXP_MEDIA_DEFAULT_DEFMEDIA },};#define NFXPMEDIA (sizeof(fxp_media) / sizeof(fxp_media[0]))static int fxp_mediachange __P((struct ifnet *));static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));static void fxp_set_media __P((struct fxp_softc *, int));static __inline void fxp_scb_wait __P((struct fxp_softc *));static FXP_INTR_TYPE fxp_intr __P((void *));static void fxp_start __P((struct ifnet *));static int fxp_ioctl __P((struct ifnet *, FXP_IOCTLCMD_TYPE, caddr_t));static void fxp_init __P((void *));static void fxp_stop __P((struct fxp_softc *));static void fxp_watchdog __P((struct ifnet *));static int fxp_add_rfabuf __P((struct fxp_softc *, struct mbuf *));static int fxp_mdi_read __P((struct fxp_softc *, int, int));static void fxp_mdi_write __P((struct fxp_softc *, int, int, int));static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *, int, int));static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));static void fxp_stats_update __P((void *));static void fxp_mc_setup __P((struct fxp_softc *));/* * Set initial transmit threshold at 64 (512 bytes). This is * increased by 64 (512 bytes) at a time, to maximum of 192 * (1536 bytes), if an underrun occurs. */static int tx_threshold = 64;/* * Number of transmit control blocks. This determines the number * of transmit buffers that can be chained in the CB list. * This must be a power of two. */#define FXP_NTXCB 128/* * Number of completed TX commands at which point an interrupt * will be generated to garbage collect the attached buffers. * Must be at least one less than FXP_NTXCB, and should be * enough less so that the transmitter doesn't becomes idle * during the buffer rundown (which would reduce performance). */#define FXP_CXINT_THRESH 120/* * TxCB list index mask. This is used to do list wrap-around. */#define FXP_TXCB_MASK (FXP_NTXCB - 1)/* * Number of receive frame area buffers. These are large so chose * wisely. */#define FXP_NRFABUFS 64/* * Maximum number of seconds that the receiver can be idle before we * assume it's dead and attempt to reset it by reprogramming the * multicast filter. This is part of a work-around for a bug in the * NIC. See fxp_stats_update(). */#define FXP_MAX_RX_IDLE 15/* * Wait for the previous command to be accepted (but not necessarily * completed). */static __inline voidfxp_scb_wait(sc) struct fxp_softc *sc;{ int i = 10000; while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);}/************************************************************* * Operating system-specific autoconfiguration glue *************************************************************/#if defined(__NetBSD__)#ifdef __BROKEN_INDIRECT_CONFIGstatic int fxp_match __P((struct device *, void *, void *));#elsestatic int fxp_match __P((struct device *, struct cfdata *, void *));#endifstatic void fxp_attach __P((struct device *, struct device *, void *));static void fxp_shutdown __P((void *));/* Compensate for lack of a generic ether_ioctl() */static int fxp_ether_ioctl __P((struct ifnet *, FXP_IOCTLCMD_TYPE, caddr_t));#define ether_ioctl fxp_ether_ioctlstruct cfattach fxp_ca = { sizeof(struct fxp_softc), fxp_match, fxp_attach};struct cfdriver fxp_cd = { NULL, "fxp", DV_IFNET};/* * Check if a device is an 82557. */static intfxp_match(parent, match, aux) struct device *parent;#ifdef __BROKEN_INDIRECT_CONFIG void *match;#else struct cfdata *match;#endif void *aux;{ struct pci_attach_args *pa = aux; if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) return (0); switch (PCI_PRODUCT(pa->pa_id)) { case PCI_PRODUCT_INTEL_82557: return (1); } return (0);}static voidfxp_attach(parent, self, aux) struct device *parent, *self; void *aux;{ struct fxp_softc *sc = (struct fxp_softc *)self; struct pci_attach_args *pa = aux; pci_chipset_tag_t pc = pa->pa_pc; pci_intr_handle_t ih; const char *intrstr = NULL; u_int8_t enaddr[6]; struct ifnet *ifp; /* * Map control/status registers. */ if (pci_mapreg_map(pa, FXP_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, NULL, NULL)) { printf(": can't map registers\n"); return; } printf(": Intel EtherExpress Pro 10/100B Ethernet\n"); /* * Allocate our interrupt. */ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, pa->pa_intrline, &ih)) { printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); return; } intrstr = pci_intr_string(pc, ih); sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc); if (sc->sc_ih == NULL) { printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname); if (intrstr != NULL) printf(" at %s", intrstr); printf("\n"); return; } printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); /* Do generic parts of attach. */ if (fxp_attach_common(sc, enaddr)) { /* Failed! */ return; } printf("%s: Ethernet address %s%s\n", sc->sc_dev.dv_xname, ether_sprintf(enaddr), sc->phy_10Mbps_only ? ", 10Mbps" : ""); ifp = &sc->sc_ethercom.ec_if; bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = fxp_ioctl; ifp->if_start = fxp_start; ifp->if_watchdog = fxp_watchdog; /* * Attach the interface. */ if_attach(ifp); /* * Let the system queue as many packets as we have available * TX descriptors. */ ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1; ether_ifattach(ifp, enaddr);#if NBPFILTER > 0 bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif /* * Add shutdown hook so that DMA is disabled prior to reboot. Not * doing do could allow DMA to corrupt kernel memory during the * reboot before the driver initializes. */ shutdownhook_establish(fxp_shutdown, sc);}/* * Device shutdown routine. Called at system shutdown after sync. The * main purpose of this routine is to shut off receiver DMA so that * kernel memory doesn't get clobbered during warmboot. */static voidfxp_shutdown(sc) void *sc;{ fxp_stop((struct fxp_softc *) sc);}static intfxp_ether_ioctl(ifp, cmd, data) struct ifnet *ifp; FXP_IOCTLCMD_TYPE cmd; caddr_t data;{ struct ifaddr *ifa = (struct ifaddr *) data; struct fxp_softc *sc = ifp->if_softc; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: fxp_init(sc); arp_ifinit(ifp, ifa); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *) LLADDR(ifp->if_sadl); else bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), ifp->if_addrlen); /* Set new address. */ fxp_init(sc); break; }#endif default: fxp_init(sc); break; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?