📄 if_tx.c
字号:
/* $OpenBSD: if_tx.c,v 1.3 1998/10/10 04:30:09 jason Exp $ *//* $Id: if_tx.c,v 1.20.2.3 1999/04/23 05:47:53 semenu Exp $ *//*- * Copyright (c) 1997 Semen Ustimenko (semen@iclub.nsu.ru) * 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. 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. * * *//* * EtherPower II 10/100 Fast Ethernet (tx0) * (aka SMC9432TX based on SMC83c170 EPIC chip) * * Thanks are going to Steve Bauer and Jason Wright. * * todo: * Deal with bus mastering, i.e. i realy don't know what to do with * it and how it can improve performance. * Implement FULL IFF_MULTICAST support. * Test, test and test again:-( * *//* We should define compile time options before if_txvar.h included *//*#define EPIC_NOIFMEDIA 1*//*#define EPIC_USEIOSPACE 1*/#define EARLY_RX 1/*#define EPIC_DEBUG 1*/#if defined(EPIC_DEBUG)#define dprintf(a) printf a#else#define dprintf(a)#endif/* Macro to get either mbuf cluster or nothing */#define EPIC_MGETCLUSTER(m) \ { MGETHDR((m),M_DONTWAIT,MT_DATA); \ if (m) { \ MCLGET((m),M_DONTWAIT); \ if( NULL == ((m)->m_flags & M_EXT) ){ \ m_freem(m); \ (m) = NULL; \ } \ } \ }#include "bpfilter.h"#include "pci.h"#include "opt_bdg.h"#if NPCI > 0#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 <sys/sockio.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#if !defined(SIOCSIFMEDIA) || defined(EPIC_NOIFMEDIA)#define EPIC_NOIFMEDIA 1#else#include <net/if_media.h>#endif#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#endif#ifdef IPX#include <netipx/ipx.h>#include <netipx/ipx_if.h>#endif#ifdef NS#include <netns/ns.h>#include <netns/ns_if.h>#endif#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#if defined(__OpenBSD__)#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/device.h>#include <netinet/if_ether.h>#include <vm/vm.h>#include <dev/pci/pcivar.h>#include <dev/pci/pcireg.h>#include <dev/pci/pcidevs.h>#include <dev/pci/if_txvar.h>#else /* __FreeBSD__ */#include <net/if_mib.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <vm/vm.h>#include <vm/pmap.h>#include <machine/clock.h>#include <pci/pcivar.h>#include <pci/if_txvar.h>#ifdef BRIDGE#include <net/bridge.h>#endif#endif#if defined(__FreeBSD__)#if __FreeBSD_version >= 300000#define EPIC_IFIOCTL_CMD_TYPE u_long#else#define EPIC_IFIOCTL_CMD_TYPE int#endif#define EPIC_INTR_RET_TYPE void#else /* __OpenBSD__ */#define EPIC_IFIOCTL_CMD_TYPE u_long#define EPIC_INTR_RET_TYPE int#endifstatic int epic_ifioctl __P((register struct ifnet *, EPIC_IFIOCTL_CMD_TYPE, caddr_t));static EPIC_INTR_RET_TYPE epic_intr __P((void *));static int epic_common_attach __P((epic_softc_t *));static void epic_ifstart __P((struct ifnet * const));static void epic_ifwatchdog __P((struct ifnet *));static int epic_init __P((epic_softc_t *));static void epic_stop __P((epic_softc_t *));static __inline void epic_rx_done __P((epic_softc_t *));static __inline void epic_tx_done __P((epic_softc_t *));static int epic_init_rings __P((epic_softc_t *));static void epic_free_rings __P((epic_softc_t *));static void epic_stop_activity __P((epic_softc_t *));static void epic_start_activity __P((epic_softc_t *));static void epic_set_rx_mode __P((epic_softc_t *));static void epic_set_tx_mode __P((epic_softc_t *));static void epic_set_mc_table __P((epic_softc_t *));static void epic_set_media_speed __P((epic_softc_t *));static void epic_init_phy __P((epic_softc_t *));static void epic_dump_state __P((epic_softc_t *));static int epic_autoneg __P((epic_softc_t *));static int epic_read_eeprom __P((epic_softc_t *,u_int16_t));static void epic_output_eepromw __P((epic_softc_t *, u_int16_t));static u_int16_t epic_input_eepromw __P((epic_softc_t *));static u_int8_t epic_eeprom_clock __P((epic_softc_t *,u_int8_t));static void epic_write_eepromreg __P((epic_softc_t *,u_int8_t));static u_int8_t epic_read_eepromreg __P((epic_softc_t *));static u_int16_t epic_read_phy_register __P((epic_softc_t *, u_int16_t));static void epic_write_phy_register __P((epic_softc_t *, u_int16_t, u_int16_t));#if !defined(EPIC_NOIFMEDIA)static int epic_ifmedia_change __P((struct ifnet *));static void epic_ifmedia_status __P((struct ifnet *, struct ifmediareq *));#endifint epic_mtypes [] = { 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_10_T | IFM_LOOP, IFM_ETHER | IFM_10_T | IFM_FDX | IFM_LOOP, IFM_ETHER | IFM_10_T | IFM_LOOP | IFM_FLAG1, IFM_ETHER | IFM_100_TX | IFM_LOOP, IFM_ETHER | IFM_100_TX | IFM_LOOP | IFM_FLAG1, IFM_ETHER | IFM_100_TX | IFM_FDX | IFM_LOOP, IFM_ETHER | IFM_AUTO};#define EPIC_MTYPESNUM (sizeof(epic_mtypes) / sizeof(epic_mtypes[0]))/* ------------------------------------------------------------------------- OS-specific part ------------------------------------------------------------------------- */#if defined(__OpenBSD__)/* -----------------------------OpenBSD------------------------------------- */static int epic_openbsd_probe __P((struct device *,void *,void *));static void epic_openbsd_attach __P((struct device *, struct device *, void *));static void epic_shutdown __P((void *));struct cfattach tx_ca = { sizeof(epic_softc_t), epic_openbsd_probe, epic_openbsd_attach };struct cfdriver tx_cd = { NULL,"tx",DV_IFNET};/* Synopsis: Check if device id corresponds with SMC83C170 id. */static int epic_openbsd_probe( struct device *parent, void *match, void *aux ){ struct pci_attach_args *pa = aux; if( PCI_VENDOR(pa->pa_id) != SMC_VENDORID ) return 0; if( PCI_PRODUCT(pa->pa_id) == CHIPID_83C170 ) return 1; return 0;}static voidepic_openbsd_attach( struct device *parent, struct device *self, void *aux ){ epic_softc_t *sc = (epic_softc_t*)self; struct pci_attach_args *pa = aux; pci_chipset_tag_t pc = pa->pa_pc; pci_intr_handle_t ih; const char *intrstr = NULL; struct ifnet *ifp; bus_space_tag_t iot = pa->pa_iot; bus_addr_t iobase; bus_size_t iosize; int i;#if !defined(EPIC_NOIFMEDIA) int tmp;#endif if( pci_io_find(pc, pa->pa_tag, PCI_CBIO, &iobase, &iosize)) { printf(": can't find i/o space\n"); return; } if( bus_space_map(iot, iobase, iosize, 0, &sc->sc_sh)) { printf(": can't map i/o space\n"); return; } sc->sc_st = iot; ifp = &sc->sc_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 = epic_ifioctl; ifp->if_start = epic_ifstart; ifp->if_watchdog = epic_ifwatchdog; /* Do common attach procedure */ if( epic_common_attach(sc) ) return; /* Map interrupt */ if( pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, pa->pa_intrline, &ih)) { printf(": can't map interrupt\n"); return; } intrstr = pci_intr_string(pc, ih); sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc, self->dv_xname); if( NULL == sc->sc_ih ) { printf(": can't establish interrupt"); if( intrstr )printf(" at %s",intrstr); printf("\n"); return; } printf(": %s",intrstr); /* Display some info */ printf(" address %s",ether_sprintf(sc->sc_macaddr)); /* Read current media config and display it too */ i = PHY_READ_2( sc, DP83840_BMCR );#if !defined(EPIC_NOIFMEDIA) tmp = IFM_ETHER;#endif if( i & BMCR_AUTONEGOTIATION ){ printf(", Auto-Neg "); /* To avoid bug in QS6612 read LPAR enstead of BMSR */ i = PHY_READ_2( sc, DP83840_LPAR ); if( i & (ANAR_100_TX|ANAR_100_TX_FD) ) printf("100Mbps"); else printf("10Mbps"); if( i & (ANAR_10_FD|ANAR_100_TX_FD) ) printf(" FD");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_AUTO;#endif } else {#if defined(EPIC_NOIFMEDIA) ifp->if_flags |= IFF_LINK0;#endif if( i & BMCR_100MBPS ) { printf(", 100Mbps");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_100_TX;#else ifp->if_flags |= IFF_LINK2;#endif } else { printf(", 10Mbps");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_10_T;#endif } if( i & BMCR_FULL_DUPLEX ) { printf(" FD");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_FDX;#else ifp->if_flags |= IFF_LINK1;#endif } } /* Init ifmedia interface */#if !defined(EPIC_NOIFMEDIA) ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); for (i=0; i<EPIC_MTYPESNUM; i++) ifmedia_add(&sc->ifmedia,epic_mtypes[i],0,NULL); ifmedia_set(&sc->ifmedia, tmp);#endif /* Attach os interface and bpf */ if_attach(ifp); ether_ifattach(ifp);#if NBPFILTER > 0 bpfattach(&sc->sc_if.if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif /* Set shutdown routine to stop DMA process */ shutdownhook_establish(epic_shutdown, sc); printf("\n");}/* Simple call epic_stop() */static voidepic_shutdown( void *sc){ epic_stop(sc);}#else /* __FreeBSD__ *//* -----------------------------FreeBSD------------------------------------- */static const char* epic_freebsd_probe __P((pcici_t, pcidi_t));static void epic_freebsd_attach __P((pcici_t, int));static void epic_shutdown __P((int, void *));/* Global variables */static u_long epic_pci_count;static struct pci_device txdevice = { "tx", epic_freebsd_probe, epic_freebsd_attach, &epic_pci_count, NULL };/* Append this driver to pci drivers list */DATA_SET ( pcidevice_set, txdevice );/* Synopsis: Check if device id corresponds with SMC83C170 id. */static const char*epic_freebsd_probe( pcici_t config_id, pcidi_t device_id){ if( PCI_VENDORID(device_id) != SMC_VENDORID ) return NULL; if( PCI_CHIPID(device_id) == CHIPID_83C170 ) return "SMC 83c170"; return NULL;}/* * Do FreeBSD-specific attach routine, like map registers, alloc softc * structure and etc. */static voidepic_freebsd_attach( pcici_t config_id, int unit){ struct ifnet *ifp; epic_softc_t *sc;#if defined(EPIC_USEIOSPACE) u_int32_t iobase;#else caddr_t pmembase;#endif int i,s,tmp; printf("tx%d",unit); /* Allocate memory for softc, hardware descriptors and frag lists */ sc = (epic_softc_t *) malloc( sizeof(epic_softc_t), M_DEVBUF, M_NOWAIT); if (sc == NULL) return; /* Preinitialize softc structure */ bzero(sc, sizeof(epic_softc_t)); sc->unit = unit; /* Fill ifnet structure */ ifp = &sc->sc_if; ifp->if_unit = unit; ifp->if_name = "tx"; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; ifp->if_ioctl = epic_ifioctl; ifp->if_start = epic_ifstart; ifp->if_watchdog = epic_ifwatchdog; ifp->if_init = (if_init_f_t*)epic_init; ifp->if_timer = 0; ifp->if_output = ether_output; ifp->if_snd.ifq_maxlen = TX_RING_SIZE; /* Get iobase or membase */#if defined(EPIC_USEIOSPACE) if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) { printf(": cannot map port\n"); free(sc, M_DEVBUF); return; }#else if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) { printf(": cannot map memory\n"); free(sc, M_DEVBUF); return; }#endif if( epic_common_attach(sc) ) return; /* Display ethernet address ,... */ printf(": address %02x:%02x:%02x:%02x:%02x:%02x,", sc->sc_macaddr[0],sc->sc_macaddr[1],sc->sc_macaddr[2], sc->sc_macaddr[3],sc->sc_macaddr[4],sc->sc_macaddr[5]); /* board type and ... */ printf(" type "); for(i=0x2c;i<0x32;i++) { tmp = epic_read_eeprom( sc, i ); if( ' ' == (u_int8_t)tmp ) break; printf("%c",(u_int8_t)tmp); tmp >>= 8; if( ' ' == (u_int8_t)tmp ) break; printf("%c",(u_int8_t)tmp); } /* Read current media config and display it too */ i = PHY_READ_2( sc, DP83840_BMCR );#if !defined(EPIC_NOIFMEDIA) tmp = IFM_ETHER;#endif if( i & BMCR_AUTONEGOTIATION ){ printf(", Auto-Neg "); /* To avoid bug in QS6612 read LPAR enstead of BMSR */ i = PHY_READ_2( sc, DP83840_LPAR ); if( i & (ANAR_100_TX|ANAR_100_TX_FD) ) printf("100Mbps "); else printf("10Mbps "); if( i & (ANAR_10_FD|ANAR_100_TX_FD) ) printf("FD");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_AUTO;#endif } else {#if defined(EPIC_NOIFMEDIA) ifp->if_flags |= IFF_LINK0;#endif if( i & BMCR_100MBPS ) { printf(", 100Mbps ");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_100_TX;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -