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 + -
显示快捷键?