Date: Wed, 13 Aug 2003 17:50:30 +0200 From: Palle Girgensohn <girgen@pingpong.net> To: hardware@freebsd.org Subject: VIA VT8235 NIC driver question (if_fet.c) Message-ID: <6580000.1060789830@rambutan.pingpong.net>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] Hi! I just got an Asus A7V8X-X motherboard with an online NIC in the South bridge controller, VIA VT8235. I found a freebsd driver on VIA's site <http://www.viaarena.com/?PageID=71>, but it didn't build for FreeBSD 4.8. I removed some code, and it built, but I ususally don't hack network drivers, so I'd just like to check if my fix is safe or just plains stupid. The mbuf pkthdr struct has changed in 4.8 and no longer has the aux field, so I simply removed the code that handles this: --- /home/girgen/VT8235/FREEBSD/if_fet.c Wed Jan 15 19:03:54 2003 +++ if_fet.c Wed Aug 13 17:21:24 2003 @@ -1640,7 +1640,7 @@ * code does not call M_PREPEND properly. * (example: call to bpf_mtap from drivers) */ -#if __FreeBSD_version >= 410000 +#if __FreeBSD_version >= 410000 && __FreeBSD_version < 48000 if ((cur_tx->fet_mbuf->m_flags & M_PKTHDR) != 0 && cur_tx->fet_mbuf->m_pkthdr.aux) { m_freem(cur_tx->fet_mbuf->m_pkthdr.aux); cur_tx->fet_mbuf->m_pkthdr.aux = NULL; @@ -1697,7 +1697,7 @@ * code does not call M_PREPEND properly. * (example: call to bpf_mtap from drivers) */ -#if __FreeBSD_version >= 410000 +#if __FreeBSD_version >= 410000 && __FreeBSD_version < 48000 if ((cur_tx->fet_mbuf->m_flags & M_PKTHDR) != 0 && cur_tx->fet_mbuf->m_pkthdr.aux) { m_freem(cur_tx->fet_mbuf->m_pkthdr.aux); cur_tx->fet_mbuf->m_pkthdr.aux = NULL; @@ -1973,7 +1973,7 @@ if(m->m_len == 0) { tmp = m; m = m->m_next; -#if __FreeBSD_version >= 410000 +#if __FreeBSD_version >= 410000 && __FreeBSD_version < 48000 if ((tmp->m_flags & M_PKTHDR) != 0 && tmp->m_pkthdr.aux) { m_freem(tmp->m_pkthdr.aux); tmp->m_pkthdr.aux = NULL; I enclose the driver code as distributed from VIA. Thanks, Palle [-- Attachment #2 --] ** ** ** VIA Rhine Family Fast Ethernet Adapter ** ** FreeBSD driver ** ** v3.10 Jan. 2003 ** ** Introduction: ============= The Fast Ethernet 10/100M FreeBSD driver is enclosed. This document shows you how to setup the driver. Contents of the Subdirectory: ============================= freebsd.txt This file. freebsd.tar Tar file include the following file list if_fet.c The FreeBSD driver source code if_fet.h The FreeBSD driver header file Installation: ============= 1) Put the driver disc in Drive A. Under the prompt, type "mount_msdos /dev/fd0 /mnt". Then, type "cp /mnt/freebsd.tar /usr/src/sys/pci". 2) Type the following commands: (a) "cd /usr/src/sys/pci" (b) "tar xvf freebsd.tar" (c) "cd /usr/src/sys/conf" (d) "ee files" 3) Under editing file 'files' (a) In FREEBSD 3.x , please add one line as below: "pci/if_fet.c optional fet device-driver" and mark this line as below: "#pci/if_vr.c optional vr device-driver" (b) In FREEBSD 4.x , please add one line as below: "pci/if_fet.c optional fet" and mark this line as below: "#pci/if_vr.c optional vr" Then, save the file. It's important to mark if_vr.c, or you will use the old driver. 4) Type the following commands: (a) "cd /usr/src/sys/i386/conf" (b) "cp GENERIC SERVER" (c) "ee SERVER" 5) Under editing file 'SERVER', finding the division of NIC setting, and insert one line as below: "device fet0" And ,mark this line as below: "#device vr0" Then, save the file. It's important to mark device vr0, or you will use the old driver. 6) Now, it's ready to recompile kernel; type the following commands: (a) cd /usr/src/sys/i386/conf (b) config SERVER (c) cd /usr/src/sys/compile/SERVER (d) make depend all install 7) Before rebooting, make sure the network-related files under /etc are well-configured. The files are listed below: (a) /etc/hosts (b) /etc/resolv.conf (c) /etc/host.conf (d) /etc/rc.conf 8) Now, get ready to reboot, type "sync;sync;sync", and "shutdown -r now". 9) Under the newly compiled kernel, type "ifconfig -a", and you can see a new device fet0 (not vr0). Speed and duplex mode Setting: ============================== You can use ifconfig command to force speed and duplex mode of NIC, where # below is network interface number. We only support this function in FreeBSD 4.x now. (eg: Use "ifconfig fet0 media 100baseTX" command to force NIC to 100Mbps half-duplex mode) 1) Auto Mode (Autonegotiation) ifconfig fet# media auto 2) 100Mbps full-duplex mode ifconfig fet# media 100baseTX mediaopt full-duplex 3) 100Mbps half-duplex mode ifconfig fet# media 100baseTX 4) 10Mbps full-duplex mode ifconfig fet# media 10baseT/UTP mediaopt full-duplex 5) 10Mbps half-duplex mode ifconfig fet# media 10baseT/UTP Driver tunable parameters (Experts only) ======================================== You can tune up the performance of driver by modified the pre-define constants in header file if_fet.h. DMA_LENGTH_DEF: DMA_LENGTH_DEF is used for controlling the DMA length. 0: 8 DWORDs 1: 16 DWORDs (Default) 2: 32 DWORDs 3: 64 DWORDs 4: 128 DWORDs 5: 256 DWORDs 6: SF(flush till emply) 7: SF(flush till emply) TX_THRESH_DEF: TX_THRESH_DEF is used for controlling the transmit fifo threshold. 0: indicate the txfifo threshold is 128 bytes. (Default) 1: indicate the txfifo threshold is 256 bytes. 2: indicate the txfifo threshold is 512 bytes. 3: indicate the txfifo threshold is 1024 bytes. 4: indicate that we use store and forward QPACKET_DEF: QPACKET_DEF is used for controlling the enable/disable the transmit status write back queue. 0: Disable 1: Enable (Default) VAL_PKT_LEN: VAL_PKT_LEN is used to drop 802.3 frame with invalid length. 0: Disable (Default) 1: Enable [-- Attachment #3 --] /* * Copyright (c) 1996,2003 VIA Networking, Inc. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by VIA Technologies, Inc. * 4. Neither the name of the Company nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY VIA TECHNOLOGIES, INC. 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 VIA TECHNOLOGIES, INC. 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. * */ /* ** VIA Technologies, Inc. ** ** Ver. 3.10 ** **/ #include <sys/param.h> #if __FreeBSD_version < 400000 #include "bpfilter.h" #endif #include <sys/systm.h> #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> #include <net/if_dl.h> #include <net/if_media.h> #if (__FreeBSD_version < 400000 && NBPFILTER > 0) || __FreeBSD_version >= 400000 #include <net/bpf.h> #endif #if __FreeBSD_version >=400000 && __FreeBSD_version <410000 #include "opt_bdg.h" #ifdef BRIDGE #include <net/bridge.h> #endif /* BRIDGE */ #endif #include <vm/vm.h> /* for vtophys */ #include <vm/pmap.h> /* for vtophys */ #include <machine/clock.h> /* for DELAY */ #include <machine/bus_pio.h> #include <machine/bus_memio.h> #include <machine/bus.h> #if __FreeBSD_version >= 400000 #include <machine/resource.h> #include <sys/bus.h> #include <sys/rman.h> #endif #include <pci/pcireg.h> #include <pci/pcivar.h> #define FET_USEMEMSPACE /* #define FET_BACKGROUND_AUTONEG */ #include <pci/if_fet.h> /* * Various supported device vendors/types and their names. */ static struct fet_type fet_devs[] = { { VENDORID, DEVICEID_3043, "VIA VT86C100A Rhine Fast Ethernet Adapter " }, { VENDORID, DEVICEID_3065, "VIA Rhine II Fast Ethernet Adapter " }, { VENDORID, DEVICEID_3106, "VIA VT6105 Rhine III Fast Ethernet Adapter " }, { VENDORID, DEVICEID_3053, "VIA VT6105M Rhine III Management Adapter " }, { 0, 0, NULL } }; #if __FreeBSD_version >= 400000 static int fet_probe __P((device_t)); static int fet_attach __P((device_t)); static int fet_detach __P((device_t)); static int fet_newbuf __P((struct fet_softc *, struct fet_chain_onefrag *, struct mbuf *)); #elif __FreeBSD_version < 400000 static unsigned long fet_count = 0; static const char *fet_probe __P((pcici_t, pcidi_t)); static void fet_attach __P((pcici_t, int)); static int fet_newbuf __P((struct fet_softc *, struct fet_chain_onefrag *)); #endif static int fet_encap __P((struct fet_softc *, struct fet_chain *, struct mbuf * )); static void fet_rxeof __P((struct fet_softc *)); static void fet_txeof __P((struct fet_softc *)); static void fet_tx_drop_all __P((struct fet_softc *)); static void fet_txeoc __P((struct fet_softc *)); static void fet_set_tx_thresh __P((struct fet_softc *)); static void fet_set_rx_thresh __P((struct fet_softc *)); static int check_n_way_force __P((struct fet_softc *, int)); static void check_legacy_force __P((struct fet_softc *)); static void set_media_duplex_mode __P((struct fet_softc *)); static void set_flow_control __P((struct fet_softc *)); static void flow_control_ability __P((struct fet_softc *)); static void restart_autonegotiation __P((struct fet_softc *)); static void enable_autonegotiation __P((struct fet_softc *)); static void do_autonegotiation __P((struct fet_softc *)); static void fet_intr __P((void *)); static void fet_start __P((struct ifnet *)); static int fet_ioctl __P((struct ifnet *, u_long, caddr_t)); static void fet_init __P((void *)); static void fet_stop __P((struct fet_softc *)); static void fet_watchdog __P((struct ifnet *)); #if 0 static void CAM_data_read __P((struct fet_softc *, int, unsigned char, unsigned char *)); static unsigned int CAM_mask_read __P((struct fet_softc *, int , unsigned int)); #endif static void CAM_data_write __P((struct fet_softc *, int , unsigned char ,unsigned char *)); static void CAM_mask_write __P((struct fet_softc *, int, unsigned int)); static void VLAN_tagging __P((struct fet_softc *)); static void SafeDisableMiiAuto __P((struct fet_softc *)); static void EnableMiiAutoPoll __P((struct fet_softc *)); static void turn_on_MII_link __P((struct fet_softc *)); #if __FreeBSD_version >= 400000 static void fet_shutdown __P((device_t)); #elif __FreeBSD_version < 400000 static void fet_shutdown __P((int, void *)); #endif static int fet_ifmedia_upd __P((struct ifnet *)); static void fet_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); static void fet_link_change __P((struct fet_softc *)); static unsigned fet_read_mii __P((struct fet_softc *, char)); static void fet_write_mii __P((struct fet_softc *, char, unsigned )); static int fet_query_auto __P((struct fet_softc *)); static u_int8_t fet_calchash __P((u_int8_t *)); static void fet_setmulti __P((struct fet_softc *)); static void fet_reset __P((struct fet_softc *)); static int fet_list_rx_init __P((struct fet_softc *)); static int fet_list_tx_init __P((struct fet_softc *)); static int fet_safe_rx_off __P((struct fet_softc *)); #if __FreeBSD_version >= 400000 static device_method_t fet_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fet_probe), DEVMETHOD(device_attach, fet_attach), DEVMETHOD(device_detach, fet_detach), DEVMETHOD(device_shutdown, fet_shutdown), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), { 0, 0 } }; static driver_t fet_driver = { "fet", fet_methods, sizeof(struct fet_softc) }; static devclass_t fet_devclass; DRIVER_MODULE(if_fet, pci, fet_driver, fet_devclass, 0, 0); #endif #define FET_SETBIT(sc, reg, x) \ CSR_WRITE_1(sc, reg, \ CSR_READ_1(sc, reg) | x) #define FET_CLRBIT(sc, reg, x) \ CSR_WRITE_1(sc, reg, \ CSR_READ_1(sc, reg) & ~x) #define FET_SETBIT16(sc, reg, x) \ CSR_WRITE_2(sc, reg, \ CSR_READ_2(sc, reg) | x) #define FET_CLRBIT16(sc, reg, x) \ CSR_WRITE_2(sc, reg, \ CSR_READ_2(sc, reg) & ~x) #define FET_SETBIT32(sc, reg, x) \ CSR_WRITE_4(sc, reg, \ CSR_READ_4(sc, reg) | x) #define FET_CLRBIT32(sc, reg, x) \ CSR_WRITE_4(sc, reg, \ CSR_READ_4(sc, reg) & ~x) #define SIO_SET(x) \ CSR_WRITE_1(sc, FET_MIICR, \ CSR_READ_1(sc, FET_MIICR) | x) #define SIO_CLR(x) \ CSR_WRITE_1(sc, FET_MIICR, \ CSR_READ_1(sc, FET_MIICR) & ~x) #define FET_SET_MII(sc, reg, x) \ fet_write_mii(sc, reg, fet_read_mii (sc, reg)|x) #define FET_CLR_MII(sc, reg, x) \ fet_write_mii(sc, reg, fet_read_mii (sc, reg)& ~x) static int fet_safe_rx_off(sc) struct fet_softc *sc; { u_int16_t ww; FET_CLRBIT16(sc, FET_COMMAND, FET_CMD_RX_ON); DELAY(10000); for (ww = 0; ww < W_MAX_TIMEOUT; ww++) if (!(CSR_READ_2(sc, FET_COMMAND) & FET_CMD_RX_ON)) break; if (ww == W_MAX_TIMEOUT) { if(sc->fet_chip_revid < REV_ID_VT3065_A) return FALSE; else { /* set MAC to internal loopback */ FET_SETBIT(sc, FET_TXCFG, FET_TXCFG_LB0); /* enter FIFO test mode to issue RX reject */ FET_SETBIT(sc, FET_GFTEST, 0x01); FET_SETBIT(sc, FET_RFTCMD, 0x08); DELAY(10000); FET_SETBIT(sc, FET_GFTEST, 0x00); /* set MAC to normal */ FET_CLRBIT(sc, FET_TXCFG, FET_TXCFG_LB0); return TRUE; } } else return TRUE; } static unsigned fet_read_mii(sc, byMIIIndex) struct fet_softc *sc; char byMIIIndex; { unsigned ReturnMII; int ww; int s; s = splimp(); SafeDisableMiiAuto(sc); CSR_WRITE_1(sc, FET_MIIADDR, byMIIIndex); DELAY(1000); FET_SETBIT(sc, FET_MIICR, FET_MIICR_RCMD); for (ww=0;ww<0x3fff;ww++) if (!(CSR_READ_1(sc,FET_MIICR) & FET_MIICR_RCMD)) break; ReturnMII = CSR_READ_2(sc, FET_MIIDATA); if(sc->fet_chip_revid < REV_ID_VT3065_A) DELAY(1000); EnableMiiAutoPoll(sc); (void)splx(s); return(ReturnMII); } static void fet_write_mii(sc, byMIISetByte, byMIISetData) struct fet_softc *sc; char byMIISetByte; unsigned byMIISetData; { int s,ww; s = splimp(); SafeDisableMiiAuto(sc); CSR_WRITE_1(sc, FET_MIIADDR, byMIISetByte); CSR_WRITE_2(sc, FET_MIIDATA, byMIISetData); FET_SETBIT(sc, FET_MIICR, FET_MIICR_WCMD); for (ww=0;ww<0x3fff;ww++) if (!(CSR_READ_1(sc,FET_MIICR) & FET_MIICR_WCMD)) break; if(sc->fet_chip_revid < REV_ID_VT3065_A) DELAY(1000); EnableMiiAutoPoll(sc); (void)splx(s); } /* * Query duplex mode */ static int fet_query_auto(sc) struct fet_softc *sc; { if (sc->fet_chip_revid >= REV_ID_VT3106) return (CSR_READ_1(sc,FET_MIISR) & 0x04); if (fet_read_mii(sc,PHY_BMCR) & PHY_BMCR_AUTONEGENBL) { if (fet_read_mii(sc,PHY_ANAR) & PHY_ANAR_100BTXFULL) { if (fet_read_mii(sc,PHY_LPAR) & PHY_LPAR_100BTXFULL) return 1; } if (fet_read_mii(sc,PHY_ANAR) & PHY_ANAR_100BT4) { if (fet_read_mii(sc,PHY_LPAR) & PHY_LPAR_100BT4) return 0; } if (fet_read_mii(sc,PHY_ANAR) & PHY_ANAR_100BTXHALF) { if (fet_read_mii(sc,PHY_LPAR) & PHY_LPAR_100BTXHALF) return 0; } if (fet_read_mii(sc,PHY_ANAR) & PHY_ANAR_10BTFULL) { if (fet_read_mii(sc,PHY_LPAR) & PHY_LPAR_10BTFULL) return 1; } return 0; } else { if (!(fet_read_mii(sc,PHY_BMCR) & PHY_BMCR_DUPLEX)) return 0; else return 1; } } /* * process link status change in ISR */ static void fet_link_change(sc) struct fet_softc *sc; { /*check whether link fail */ if (CSR_READ_1(sc, FET_MIISR) & 0x02) { printf("fet%d: Link Fail.\n", sc->fet_unit); } else { if (sc->fet_chip_revid < 0x20 ) /* wait for writing back the ANLPAR in PHY and MIISR in MAC */ /* then we won't get the wrong value in do_autonegotiation function */ DELAY(100000); /* In auto mode, check the speed and duplex mode again */ /* In force mode, do nothing */ if (sc->fet_autoneg == 1) { do_autonegotiation(sc); } printf("fet%d: Link success.\n", sc->fet_unit); /* if VT3106 and VT3065 */ if (sc->fet_chip_revid >= REV_ID_VT3065_A) flow_control_ability (sc); } if (fet_query_auto(sc)) { FET_SETBIT16(sc, FET_COMMAND, FET_CMD_FDX); /* Set Chip Fullduplex mode */ sc->fet_full_duplex = 1; } else { FET_CLRBIT16(sc, FET_COMMAND, FET_CMD_FDX); /* Set Chip Halfduplex mode */ sc->fet_full_duplex = 0; } } /* * Calculate CRC of a multicast group address, return the lower 6 bits. */ static u_int8_t fet_calchash(addr) u_int8_t *addr; { u_int32_t crc, carry; int i, j; u_int8_t c; /* Compute CRC for the address value. */ crc = 0xFFFFFFFF; /* initial value */ for (i = 0; i < 6; i++) { c = *(addr + i); for (j = 0; j < 8; j++) { carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); crc <<= 1; c >>= 1; if (carry) crc = (crc ^ 0x04c11db6) | carry; } } /* return the filter bit position */ return((crc >> 26) & 0x0000003F); } /* * Program the 64-bit multicast hash filter. */ static void fet_setmulti(sc) struct fet_softc *sc; { struct ifnet *ifp; int h = 0; u_int32_t hashes[2] = { 0, 0 }; struct ifmultiaddr *ifma; u_int8_t rxfilt; int mcnt = 0; ifp = &sc->arpcom.ac_if; rxfilt = CSR_READ_1(sc, FET_RXCFG); if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { rxfilt |= FET_RXCFG_RX_MULTI; CSR_WRITE_1(sc, FET_RXCFG, rxfilt); CSR_WRITE_4(sc, FET_MAR0, 0xFFFFFFFF); CSR_WRITE_4(sc, FET_MAR1, 0xFFFFFFFF); return; } /* first, zot all the existing hash bits */ CSR_WRITE_4(sc, FET_MAR0, 0); CSR_WRITE_4(sc, FET_MAR1, 0); /* now program new ones */ if (sc->fet_chip_revid < REV_ID_VT3106_S) { for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; ifma = ifma->ifma_link.le_next) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = fet_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); mcnt++; } } else { for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; ifma = ifma->ifma_link.le_next) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; CAM_data_write(sc,0,mcnt,LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); mcnt++; } CAM_mask_write(sc,0,(0xFFFFFFFFUL>>(32-mcnt))); } if (mcnt) rxfilt |= FET_RXCFG_RX_MULTI; else rxfilt &= ~FET_RXCFG_RX_MULTI; CSR_WRITE_4(sc, FET_MAR0, hashes[0]); CSR_WRITE_4(sc, FET_MAR1, hashes[1]); CSR_WRITE_1(sc, FET_RXCFG, rxfilt); return; } static void fet_reset(sc) struct fet_softc *sc; { u_int16_t ww; FET_SETBIT16(sc, FET_COMMAND, FET_CMD_RESET); for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { DELAY(10); if (!(CSR_READ_2(sc, FET_COMMAND) & FET_CMD_RESET)) break; } if (ww == W_MAX_TIMEOUT) { if (sc->fet_chip_revid < REV_ID_VT3065_A) printf("fet%d: reset never completed!\n", sc->fet_unit); else /* turn on force reset */ FET_SETBIT(sc, FET_MISC_CR1, FET_MISCCR1_FORSRST); } /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); return; } /* * Probe for our chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. */ #if __FreeBSD_version >= 400000 static int fet_probe(dev) device_t dev; { struct fet_type *t; t = fet_devs; while(t->fet_name != NULL) { if ((pci_get_vendor(dev) == t->fet_vid) && (pci_get_device(dev) == t->fet_did)) { device_set_desc(dev, t->fet_name); return(0); } t++; } return(ENXIO); } #elif __FreeBSD_version < 400000 static const char * fet_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; { struct fet_type *t; t = fet_devs; while(t->fet_name != NULL) { if ((device_id & 0xFFFF) == t->fet_vid && ((device_id >> 16) & 0xFFFF) == t->fet_did) { return(t->fet_name); } t++; } return(NULL); } #endif /* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */ #if __FreeBSD_version >= 400000 static void enable_mmio(struct fet_softc *sc) { sc->fet_btag = rman_get_bustag(sc->fet_res1); sc->fet_bhandle = rman_get_bushandle(sc->fet_res1); while (CSR_READ_1(sc, FET_EECSR) & FET_EECSR_LOAD); if (sc->fet_chip_revid<REV_ID_VT3065_A) CSR_WRITE_1(sc, FET_CFGA, CSR_READ_1(sc,FET_CFGA)|0x20); else CSR_WRITE_1(sc, FET_CFGD, CSR_READ_1(sc,FET_CFGD)|0x80); sc->fet_btag = rman_get_bustag(sc->fet_res2); sc->fet_bhandle = rman_get_bushandle(sc->fet_res2); } static int fet_attach(dev) device_t dev; { int s, i; u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command, id; struct fet_softc *sc; struct ifnet *ifp; int unit, error = 0, rid,idx; u_int16_t nmedia, defmedia; const int *media; s = splimp(); sc = device_get_softc(dev); unit = device_get_unit(dev); bzero(sc, sizeof(struct fet_softc *)); /* * Handle power management nonsense. */ command = pci_read_config(dev, FET_PCI_CAPID, 4) & 0x000000FF; if (command == 0x01) { command = pci_read_config(dev, FET_PCI_PWRMGMTCTRL, 4); if (command & FET_PSTATE_MASK) { u_int32_t iobase, membase, irq; /* Save important PCI config data. */ iobase = pci_read_config(dev, FET_PCI_LOIO, 4); membase = pci_read_config(dev, FET_PCI_LOMEM, 4); irq = pci_read_config(dev, FET_PCI_INTLINE, 4); /* Reset the power state. */ printf("fet%d: chip is in D%d power mode " "-- setting to D0\n", unit, command & FET_PSTATE_MASK); command &= 0xFFFFFFFC; pci_write_config(dev, FET_PCI_PWRMGMTCTRL, command, 4); /* Restore PCI config data. */ pci_write_config(dev, FET_PCI_LOIO, iobase, 4); pci_write_config(dev, FET_PCI_LOMEM, membase, 4); pci_write_config(dev, FET_PCI_INTLINE, irq, 4); } } /* * Map control/status registers. */ command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4); command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); sc->fet_chip_revid = pci_read_config(dev, FET_PCI_REVID, 4) & 0x000000FF; id = pci_read_config(dev, FET_PCI_VENDOR_ID, 4); if (PCI_VENDORID(id) != VENDORID) { printf("fet%d: wrong vendor ID !\n", unit); goto fail; } if (!(PCI_CHIPID(id) == DEVICEID_3043 || PCI_CHIPID(id) == DEVICEID_3065 || PCI_CHIPID(id) == DEVICEID_3106 || PCI_CHIPID(id) == DEVICEID_3053)) { printf("fet%d: wrong device ID !\n", unit); goto fail; } #ifdef FET_USEIOSPACE if (!(command & PCIM_CMD_PORTEN)) { printf("fet%d: failed to enable I/O ports!\n", unit); free(sc, M_DEVBUF); goto fail; } #else if (!(command & PCIM_CMD_MEMEN)) { printf("fet%d: failed to enable memory mapping!\n", unit); goto fail; } #endif rid = FET_PCI_LOIO; sc->fet_res1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); if (sc->fet_res1 == NULL) { printf("fet%d: couldn't map ports/memory\n", unit); error = ENXIO; goto fail; } rid = FET_PCI_LOMEM; sc->fet_res2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE); if (sc->fet_res2 == NULL) { printf("fet%d: couldn't map ports/memory\n", unit); bus_release_resource(dev, SYS_RES_IOPORT, FET_PCI_LOIO, sc->fet_res1); error = ENXIO; goto fail; } enable_mmio(sc); sc->fet_btag = rman_get_bustag(sc->fet_res2); sc->fet_bhandle = rman_get_bushandle(sc->fet_res2); /* Allocate interrupt */ rid = 0; sc->fet_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->fet_irq == NULL) { printf("fet%d: couldn't map interrupt\n", unit); bus_release_resource(dev, SYS_RES_IOPORT, FET_PCI_LOIO, sc->fet_res1); bus_release_resource(dev, SYS_RES_MEMORY, FET_PCI_LOMEM, sc->fet_res2); error = ENXIO; goto fail; } error = bus_setup_intr(dev, sc->fet_irq, INTR_TYPE_NET, fet_intr, sc, &sc->fet_intrhand); if (error) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->fet_irq); bus_release_resource(dev, SYS_RES_IOPORT, FET_PCI_LOIO, sc->fet_res1); bus_release_resource(dev, SYS_RES_MEMORY, FET_PCI_LOMEM, sc->fet_res2); printf("fet%d: couldn't set up irq\n", unit); goto fail; } /* if vt3065 */ /* set the MAC to D0 before initialization */ if (sc->fet_chip_revid >= REV_ID_VT3065_A ) { /* clear sticky bit before reset & read ethernet address */ CSR_WRITE_1(sc, FET_STICKHW, CSR_READ_1(sc, FET_STICKHW) & 0xFC); /* disable force PME-enable */ CSR_WRITE_1(sc, FET_WOLCGCLR, 0x80); /* disable power-event config bit */ CSR_WRITE_1(sc, FET_WOLCRCLR, 0xFF); /* clear power status */ CSR_WRITE_1(sc, FET_PWRCSRCLR, 0xFF); } /* Reset the adapter. after turn to D0*/ fet_reset(sc); /* issue AUTOLoad in EECSR to reload eeprom */ enable_mmio(sc); /* if vt3065 delay after reset */ if (sc->fet_chip_revid >= REV_ID_VT3065_A ) { DELAY(10000); /* for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA turned on. it makes MAC receive magic packet automatically. So, driver turn it off. */ CSR_WRITE_1(sc, FET_CFGA,CSR_READ_1(sc, FET_CFGA) & 0xFE); } /* Turn on bit2 (MIION) in PCI configuration register 0x53 during initialization */ pci_write_config(dev, FET_PCI_MODE, pci_read_config(dev, FET_PCI_MODE, 4)|(FET_MODE3_MIION<<24), 4); /* * Get station address. The way the Rhine chips work, * you're not allowed to directly access the EEPROM once * they've been programmed a special way. Consequently, * we need to read the node address from the PAR0 and PAR1 * registers. */ for (i = 0; i < ETHER_ADDR_LEN; i++) eaddr[i] = CSR_READ_1(sc, FET_PAR0 + i); /* * A Rhine chip was detected. Inform the world. */ printf("fet%d: Ethernet address: %6D\n", unit, eaddr, ":"); /* print driver version */ printf("fet%d: if_fet.c: v3.10 \n", unit); sc->fet_unit = unit; bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->fet_ldata = contigmalloc(sizeof(struct fet_list_data), M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); if (sc->fet_ldata == NULL) { printf("fet%d: no memory for list buffers!\n", unit); bus_teardown_intr(dev, sc->fet_irq, sc->fet_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->fet_irq); bus_release_resource(dev, SYS_RES_IOPORT, FET_PCI_LOIO, sc->fet_res1); bus_release_resource(dev, SYS_RES_MEMORY, FET_PCI_LOMEM, sc->fet_res2); error = ENXIO; goto fail; } bzero(sc->fet_ldata, sizeof(struct fet_list_data)); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "fet"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = fet_ioctl; ifp->if_output = ether_output; ifp->if_start = fet_start; ifp->if_watchdog = fet_watchdog; ifp->if_init = fet_init; ifp->if_baudrate = 100000000; ifp->if_snd.ifq_maxlen = FET_TX_LIST_CNT - 1; /* turn on MII link change */ /* if the MAD4-0 is not 0x0001, then Link Fail will be on */ turn_on_MII_link(sc); if (sc->fet_chip_revid >= REV_ID_VT3106) set_flow_control(sc); set_media_duplex_mode(sc); if (sc->fet_chip_revid >= REV_ID_VT3065_A) flow_control_ability (sc); if (sc->fet_chip_revid >= REV_ID_VT3106) VLAN_tagging(sc); /* special treatment on LED for various phys */ if (sc->fet_chip_revid < REV_ID_VT3071_A) /* for NS or Mison phys, turn on bit 1 in register 17h, no effect to DAVICOM phy */ FET_SET_MII(sc,0x17,0x0002); else if (sc->fet_chip_revid < REV_ID_VT3065_A) /* for ESI phys, turn on bit 7 in register 17h */ FET_SET_MII(sc,0x17,0x0080); callout_handle_init(&sc->fet_stat_ch); #if __FreeBSD_version >= 400000 && __FreeBSD_version <410000 /* * Call MI attach routines. */ if_attach(ifp); ether_ifattach(ifp); bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); #elif __FreeBSD_version >=410000 && __FreeBSD_version < 500000 /* * Call MI attach routine. */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); #endif /* * Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, fet_ifmedia_upd, fet_ifmedia_sts); media = fet_media_standard; nmedia = sizeof(fet_media_standard) / sizeof(fet_media_standard[0]); defmedia = (IFM_ETHER|IFM_AUTO); for (idx = 0; idx < nmedia; idx++) { ifmedia_add(&sc->ifmedia, media[idx], 0, NULL); } ifmedia_set(&sc->ifmedia, defmedia); fail: splx(s); return(error); } static int fet_detach(dev) device_t dev; { struct fet_softc *sc; struct ifnet *ifp; int s; s = splimp(); sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; fet_stop(sc); #if __FreeBSD_version >= 400000 && __FreeBSD_version < 410000 if_detach(ifp); #elif __FreeBSD_version >=410000 && __FreeBSD_version < 500000 ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); #endif bus_generic_detach(dev); bus_teardown_intr(dev, sc->fet_irq, sc->fet_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->fet_irq); bus_release_resource(dev, SYS_RES_IOPORT, FET_PCI_LOIO, sc->fet_res1); bus_release_resource(dev, SYS_RES_MEMORY, FET_PCI_LOMEM, sc->fet_res2); ifmedia_removeall(&sc->ifmedia); contigfree(sc->fet_ldata, sizeof(struct fet_list_data), M_DEVBUF); splx(s); return(0); } #elif __FreeBSD_version < 400000 static void fet_attach(config_id, unit) pcici_t config_id; int unit; { int s, i; #ifndef FET_USEIOSPACE vm_offset_t pbase, vbase; #endif u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command, id; struct fet_softc *sc; struct ifnet *ifp; unsigned int round; caddr_t roundptr; u_int16_t nmedia, defmedia; const int *media; int idx; s = splimp(); sc = malloc(sizeof(struct fet_softc), M_DEVBUF, M_NOWAIT); if (sc == NULL) { printf("fet%d: no memory for softc struct!\n", unit); return; } bzero(sc, sizeof(struct fet_softc)); /* * Handle power management nonsense. */ command = pci_conf_read(config_id, FET_PCI_CAPID) & 0x000000FF; if (command == 0x01) { command = pci_conf_read(config_id, FET_PCI_PWRMGMTCTRL); if (command & FET_PSTATE_MASK) { u_int32_t iobase, membase, irq; /* Save important PCI config data. */ iobase = pci_conf_read(config_id, FET_PCI_LOIO); membase = pci_conf_read(config_id, FET_PCI_LOMEM); irq = pci_conf_read(config_id, FET_PCI_INTLINE); /* Reset the power state. */ printf("fet%d: chip is in D%d power mode " "-- setting to D0\n", unit, command & FET_PSTATE_MASK); command &= 0xFFFFFFFC; pci_conf_write(config_id, FET_PCI_PWRMGMTCTRL, command); /* Restore PCI config data. */ pci_conf_write(config_id, FET_PCI_LOIO, iobase); pci_conf_write(config_id, FET_PCI_LOMEM, membase); pci_conf_write(config_id, FET_PCI_INTLINE, irq); } } /* * Map control/status registers. */ command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); sc->fet_chip_revid = pci_conf_read(config_id, FET_PCI_REVID) & 0x000000FF; id = pci_conf_read(config_id, FET_PCI_VENDOR_ID); if (PCI_VENDORID(id) != VENDORID) { printf("fet%d: wrong vendor ID !\n", unit); goto fail; } if (!(PCI_CHIPID(id) == DEVICEID_3043 || PCI_CHIPID(id) == DEVICEID_3065 || PCI_CHIPID(id) == DEVICEID_3106 || PCI_CHIPID(id) == DEVICEID_3053)) { printf("fet%d: wrong device ID !\n", unit); goto fail; } #ifdef FET_USEIOSPACE if (!(command & PCIM_CMD_PORTEN)) { printf("fet%d: failed to enable I/O ports!\n", unit); free(sc, M_DEVBUF); goto fail; } if (!pci_map_port(config_id, FET_PCI_LOIO, (u_int16_t *)(&sc->fet_bhandle))) { printf ("fet%d: couldn't map ports\n", unit); goto fail; } sc->fet_btag = I386_BUS_SPACE_IO; #else if (!(command & PCIM_CMD_MEMEN)) { printf("fet%d: failed to enable memory mapping!\n", unit); goto fail; } if (!pci_map_mem(config_id, FET_PCI_LOMEM, &vbase, &pbase)) { printf ("fet%d: couldn't map memory\n", unit); goto fail; } sc->fet_bhandle = vbase; sc->fet_btag = I386_BUS_SPACE_MEM; #endif /* Allocate interrupt */ if (!pci_map_int(config_id, fet_intr, sc, &net_imask)) { printf("fet%d: couldn't map interrupt\n", unit); goto fail; } /* if vt3065 */ if (sc->fet_chip_revid >= REV_ID_VT3065_A ) { /* clear sticky bit before reset & read ethernet address */ CSR_WRITE_1(sc, FET_STICKHW, CSR_READ_1(sc, FET_STICKHW) & 0xFC); /* disable force PME-enable */ CSR_WRITE_1(sc, FET_WOLCGCLR, 0x80); /* disable power-event config bit */ CSR_WRITE_1(sc, FET_WOLCRCLR, 0xFF); /* clear power status */ CSR_WRITE_1(sc, FET_PWRCSRCLR, 0xFF); } /* Reset the adapter. */ fet_reset(sc); /* issue AUTOLoad in EECSR to reload eeprom */ FET_SETBIT(sc, FET_EECSR, FET_EECSR_LOAD); /* if vt3065 delay after reset */ if (sc->fet_chip_revid >= REV_ID_VT3065_A ) { DELAY(10000); /* for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA turned on. it makes MAC receive magic packet automatically. So, driver turn it off. */ CSR_WRITE_1(sc, FET_CFGA,CSR_READ_1(sc, FET_CFGA) & 0xFE); } /* Turn on bit2 (MIION) in PCI configuration register 0x53 during initialization */ pci_conf_write(config_id, FET_PCI_MODE, pci_conf_read(config_id,FET_PCI_MODE)|(FET_MODE3_MIION<<24)); /* * Get station address. The way the Rhine chips work, * you're not allowed to directly access the EEPROM once * they've been programmed a special way. Consequently, * we need to read the node address from the PAR0 and PAR1 * registers. */ for (i = 0; i < ETHER_ADDR_LEN; i++) eaddr[i] = CSR_READ_1(sc, FET_PAR0 + i); /* * A Rhine chip was detected. Inform the world. */ printf("fet%d: Ethernet address: %6D\n", unit, eaddr, ":"); /* print driver version */ printf("fet%d: if_fet.c: v3.10 \n", unit); sc->fet_unit = unit; bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->fet_ldata_ptr = malloc(sizeof(struct fet_list_data) + 8, M_DEVBUF, M_NOWAIT); if (sc->fet_ldata_ptr == NULL) { free(sc, M_DEVBUF); printf("fet%d: no memory for list buffers!\n", unit); return; } sc->fet_ldata = (struct fet_list_data *)sc->fet_ldata_ptr; round = (unsigned int)sc->fet_ldata_ptr & 0xF; roundptr = sc->fet_ldata_ptr; for (i = 0; i < 8; i++) { if (round % 8) { round++; roundptr++; } else break; } sc->fet_ldata = (struct fet_list_data *)roundptr; bzero(sc->fet_ldata, sizeof(struct fet_list_data)); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "fet"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = fet_ioctl; ifp->if_output = ether_output; ifp->if_start = fet_start; ifp->if_watchdog = fet_watchdog; ifp->if_init = fet_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = FET_TX_LIST_CNT - 1; /* turn on MII link change */ /* if the MAD4-0 is not 0x0001, then Link Fail will be on */ turn_on_MII_link(sc); if (sc->fet_chip_revid >= REV_ID_VT3106) set_flow_control(sc); set_media_duplex_mode(sc); if (sc->fet_chip_revid >= REV_ID_VT3065_A) flow_control_ability (sc); if (sc->fet_chip_revid >= REV_ID_VT3106) VLAN_tagging(sc); /* special treatment on LED for various phys */ if (sc->fet_chip_revid < REV_ID_VT3071_A) /* for NS or Mison phys, turn on bit 1 in register 17h, no effect to DAVICOM phy */ FET_SET_MII(sc,0x17,0x0002); else if (sc->fet_chip_revid < REV_ID_VT3065_A) /* for ESI phys, turn on bit 7 in register 17h */ FET_SET_MII(sc,0x17,0x0080); /* * Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, fet_ifmedia_upd, fet_ifmedia_sts); media = fet_media_standard; nmedia = sizeof(fet_media_standard) / sizeof(fet_media_standard[0]); defmedia = sc->ifmedia.ifm_media = (IFM_ETHER|IFM_AUTO); for (idx = 0; idx < nmedia; idx++) { ifmedia_add(&sc->ifmedia, media[idx], 0, NULL); } ifmedia_set(&sc->ifmedia, defmedia); /* * Call MI attach routines. */ if_attach(ifp); ether_ifattach(ifp); #if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif at_shutdown(fet_shutdown, sc, SHUTDOWN_POST_SYNC); fail: splx(s); return; } #endif /* * Initialize the transmit descriptors. */ static int fet_list_tx_init(sc) struct fet_softc *sc; { struct fet_chain_data *cd; struct fet_list_data *ld; int i; cd = &sc->fet_cdata; ld = sc->fet_ldata; for (i = 0; i < FET_TX_LIST_CNT; i++) { cd->fet_tx_chain[i].fet_ptr = &ld->fet_tx_list[i]; if (i == (FET_TX_LIST_CNT - 1)) cd->fet_tx_chain[i].fet_nextdesc = &cd->fet_tx_chain[0]; else cd->fet_tx_chain[i].fet_nextdesc = &cd->fet_tx_chain[i + 1]; } cd->fet_tx_free = &cd->fet_tx_chain[0]; cd->fet_tx_tail = cd->fet_tx_head = NULL; /* initial the number of free tx descriptorx */ cd->fet_free_tx_count=FET_TX_LIST_CNT; return(0); } /* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int fet_list_rx_init(sc) struct fet_softc *sc; { struct fet_chain_data *cd; struct fet_list_data *ld; int i; cd = &sc->fet_cdata; ld = sc->fet_ldata; for (i = 0; i < FET_RX_LIST_CNT; i++) { cd->fet_rx_chain[i].fet_ptr = (struct fet_desc *)&ld->fet_rx_list[i]; #if __FreeBSD_version >= 400000 if (fet_newbuf(sc, &cd->fet_rx_chain[i], NULL) == ENOBUFS) #elif __FreeBSD_version < 400000 if (fet_newbuf(sc, &cd->fet_rx_chain[i]) == ENOBUFS) #endif return(ENOBUFS); if (i == (FET_RX_LIST_CNT - 1)) { cd->fet_rx_chain[i].fet_nextdesc = &cd->fet_rx_chain[0]; ld->fet_rx_list[i].fet_next = vtophys(&ld->fet_rx_list[0]); } else { cd->fet_rx_chain[i].fet_nextdesc = &cd->fet_rx_chain[i + 1]; ld->fet_rx_list[i].fet_next = vtophys(&ld->fet_rx_list[i + 1]); } } cd->fet_rx_head = &cd->fet_rx_chain[0]; return(0); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ #if __FreeBSD_version >= 400000 static int fet_newbuf(sc, c, m) struct fet_softc *sc; struct fet_chain_onefrag *c; struct mbuf *m; { struct mbuf *m_new = NULL; if (m == NULL) { MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("fet%d: no memory for rx list " "-- packet dropped!\n", sc->fet_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("fet%d: no memory for rx list " "-- packet dropped!\n", sc->fet_unit); m_freem(m_new); return(ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; } else { m_new = m; m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; m_new->m_data = m_new->m_ext.ext_buf; } m_adj(m_new, sizeof(u_int64_t)); c->fet_mbuf = m_new; c->fet_ptr->fet_status = FET_RXSTAT; /*chenyp */ c->fet_ptr->fet_data = vtophys(mtod(m_new, caddr_t)); c->fet_ptr->fet_ctl = FET_RXCTL | FET_RXLEN; return(0); } #elif __FreeBSD_version < 400000 static int fet_newbuf(sc, c) struct fet_softc *sc; struct fet_chain_onefrag *c; { struct mbuf *m_new = NULL; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("fet%d: no memory for rx list -- packet dropped!\n", sc->fet_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("fet%d: no memory for rx list -- packet dropped!\n", sc->fet_unit); m_freem(m_new); return(ENOBUFS); } c->fet_mbuf = m_new; c->fet_ptr->fet_status = FET_RXSTAT; c->fet_ptr->fet_data = vtophys(mtod(m_new, caddr_t)); c->fet_ptr->fet_ctl = FET_RXCTL | FET_RXLEN; return(0); } #endif /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ static void fet_rxeof(sc) struct fet_softc *sc; { struct ether_header *eh; struct mbuf *m; struct ifnet *ifp; struct fet_chain_onefrag *cur_rx; int total_len = 0; u_int32_t rxstat; #if VAL_PKT_LEN == 1 u_int32_t wSAP=0, wLen=0, wActualLen=0; #endif ifp = &sc->arpcom.ac_if; while(!((rxstat = sc->fet_cdata.fet_rx_head->fet_ptr->fet_status) & FET_RXSTAT_OWN)) { #if __FreeBSD_version >= 400000 struct mbuf *m0 = NULL; #endif cur_rx = sc->fet_cdata.fet_rx_head; sc->fet_cdata.fet_rx_head = cur_rx->fet_nextdesc; m = cur_rx->fet_mbuf; if (!((rxstat & FET_RXSTAT_FIRSTFRAG) && (rxstat & FET_RXSTAT_LASTFRAG))) { #if __FreeBSD_version >= 400000 fet_newbuf(sc, cur_rx, m); #elif __FreeBSD_version < 400000 cur_rx->fet_ptr->fet_status = FET_RXSTAT; cur_rx->fet_ptr->fet_ctl = FET_RXCTL|FET_RXLEN; #endif /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); continue; } if (rxstat & FET_RXSTAT_RUNT) { if ( (!(cur_rx->fet_ptr->fet_ctl & FET_RXCTL_TAG)) || ((cur_rx->fet_ptr->fet_ctl & FET_RXCTL_TAG) && total_len < 60)) { #if __FreeBSD_version >= 400000 fet_newbuf(sc, cur_rx, m); #elif __FreeBSD_version < 400000 cur_rx->fet_ptr->fet_status = FET_RXSTAT; cur_rx->fet_ptr->fet_ctl = FET_RXCTL|FET_RXLEN; #endif /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); continue; } } total_len = FET_RXBYTES(cur_rx->fet_ptr->fet_status); /* * If an error occurs, update stats, clear the * status word and leave the mbuf cluster in place: * it should simply get re-used next time this descriptor * comes up in the ring. */ if ( rxstat & FET_RXSTAT_RXERR) { ifp->if_ierrors++; printf("fet%d: rx error: ", sc->fet_unit); switch(rxstat & 0x000000FF) { case FET_RXSTAT_CRCERR: printf("crc error\n"); break; case FET_RXSTAT_FRAMEALIGNERR: printf("frame alignment error\n"); break; case FET_RXSTAT_FIFOOFLOW: printf("FIFO overflow\n"); break; case FET_RXSTAT_GIANT: printf("received giant packet\n"); break; case FET_RXSTAT_RUNT: printf("received runt packet\n"); break; case FET_RXSTAT_BUSERR: printf("system bus error\n"); break; case FET_RXSTAT_BUFFERR: printf("rx buffer error\n"); break; default: printf("unknown rx error\n"); break; } #if __FreeBSD_version >= 400000 fet_newbuf(sc, cur_rx, m); #elif __FreeBSD_version < 400000 cur_rx->fet_ptr->fet_status = FET_RXSTAT; cur_rx->fet_ptr->fet_ctl = FET_RXCTL|FET_RXLEN; #endif /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); continue; } #if VAL_PKT_LEN == 1 /* For conforming IEEE 802.3 spec * If the incoming packet is IEE 802.3 frmae/IEEE 802.3 SNAP frame, get * RX_Length in RDES0 from the incoming packet, subtract Ethernet header * length and CRC length from it. Then, compare the result with L/T field * of the packet. If they're not equal, descard this packet. */ wLen = (((unsigned char)(*(mtod(cur_rx->fet_mbuf, caddr_t) + 12)) )<< 8) + (unsigned char)(*(mtod(cur_rx->fet_mbuf, caddr_t) + 13)) ; if (wLen >= 46 && wLen <= 1500) { /* IEEE 802.3/IEEE 802.3 SNAP frame */ wSAP = (((unsigned char)(*(mtod(cur_rx->fet_mbuf, caddr_t) + 14))) << 8) + (unsigned char)(*(mtod(cur_rx->fet_mbuf, caddr_t) + 15)); if (wSAP != 0xFFFF) { /* exclude Novell's Ethernet 802.3 frame */ wActualLen = total_len - U_HEADER_LEN - U_CRC_LEN; /* real packet length */ if (wLen != wActualLen ) { /* if not equal, drop this frame */ #if __FreeBSD_version >= 400000 fet_newbuf(sc, cur_rx, m); #elif __FreeBSD_version < 400000 cur_rx->fet_ptr->fet_status = FET_RXSTAT; cur_rx->fet_ptr->fet_ctl = FET_RXCTL|FET_RXLEN; #endif /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); continue; } } } #endif /* substract 4 bytes CRC */ total_len -= ETHER_CRC_LEN; #if __FreeBSD_version >= 400000 m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, total_len + ETHER_ALIGN, 0, ifp, NULL); fet_newbuf(sc, cur_rx, m); /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); if (m0 == NULL) { ifp->if_ierrors++; continue; } m_adj(m0, ETHER_ALIGN); m = m0; ifp->if_ipackets++; eh = mtod(m, struct ether_header *); #if __FreeBSD_version >=400000 && __FreeBSD_version < 410000 /* * Handle BPF listeners. Let the BPF user see the packet, but * don't pass it up to the ether_input() layer unless it's * a broadcast packet, multicast packet, matches our ethernet * address or the interface is in promiscuous mode. */ if (ifp->if_bpf) { bpf_mtap(ifp, m); if (ifp->if_flags & IFF_PROMISC && (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) { m_freem(m); continue; } } #ifdef BRIDGE if (do_bridge) { struct ifnet *bdg_ifp; bdg_ifp = bridge_in(m); if (bdg_ifp != BDG_LOCAL && bdg_ifp != BDG_DROP) bdg_forward(&m, bdg_ifp); if (((bdg_ifp != BDG_LOCAL) && (bdg_ifp != BDG_BCAST) && (bdg_ifp != BDG_MCAST)) || bdg_ifp == BDG_DROP) { m_freem(m); continue; } } #endif /* BRIDGE */ #endif #elif __FreeBSD_version < 400000 /* * Try to conjure up a new mbuf cluster. If that * fails, it means we have an out of memory condition and * should leave the buffer in place and continue. This will * result in a lost packet, but there's little else we * can do in this situation. */ if (fet_newbuf(sc, cur_rx) == ENOBUFS) { ifp->if_ierrors++; cur_rx->fet_ptr->fet_status = FET_RXSTAT; cur_rx->fet_ptr->fet_ctl = FET_RXCTL|FET_RXLEN; /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); continue; } else { /* For flow control, update RXRDU in FlowCR1 after return buffer to MAC. */ if (sc->fet_chip_revid >= REV_ID_VT3106) CSR_WRITE_1(sc, FET_FlowCR0, 1); } ifp->if_ipackets++; eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; #if NBPFILTER > 0 /* * Handle BPF listeners. Let the BPF user see the packet, but * don't pass it up to the ether_input() layer unless it's * a broadcast packet, multicast packet, matches our ethernet * address or the interface is in promiscuous mode. */ if (ifp->if_bpf) { bpf_mtap(ifp, m); if (ifp->if_flags & IFF_PROMISC && (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) { m_freem(m); continue; } } #endif #endif /* Remove header from mbuf and pass it on. */ m_adj(m, sizeof(struct ether_header)); ether_input(ifp, eh, m); } return; } /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ static void fet_txeof(sc) struct fet_softc *sc; { struct fet_chain *cur_tx; struct ifnet *ifp; register struct mbuf *n; ifp = &sc->arpcom.ac_if; /* Clear the timeout timer. */ ifp->if_timer = 0; /* Sanity check. */ if (sc->fet_cdata.fet_tx_head == NULL) return; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ while(sc->fet_cdata.fet_tx_head->fet_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->fet_cdata.fet_tx_head; if (cur_tx->fet_ptr->fet_ctl & FET_TXCTL_FIRSTFRAG) { txstat = cur_tx->fet_ptr->fet_status; if (txstat & FET_TXSTAT_OWN) break; if (txstat & (FET_TXSTAT_UDF)) { if (sc->tx_thresh<4) { sc->tx_thresh++; fet_set_tx_thresh(sc); } cur_tx->fet_ptr->fet_status=0; while(CSR_READ_2(sc,FET_COMMAND) & FET_CMD_TX_ON) ; FET_TXOWN(cur_tx) = FET_TXSTAT_OWN; CSR_WRITE_4(sc, FET_TXADDR, vtophys(cur_tx->fet_ptr)); break; } if (txstat & (FET_TXSTAT_ABT)) { cur_tx->fet_ptr->fet_status=0; printf("tx abort %x\n",txstat); while(CSR_READ_2(sc,FET_COMMAND) & FET_CMD_TX_ON) ; CSR_WRITE_4(sc, FET_TXADDR, vtophys(cur_tx->fet_nextdesc->fet_ptr)); } if (txstat & FET_TXSTAT_ERRSUM) { ifp->if_oerrors++; if (txstat & FET_TXSTAT_DEFER) ifp->if_collisions++; if (txstat & FET_TXSTAT_LATECOLL) ifp->if_collisions++; } ifp->if_collisions +=(txstat & FET_TXSTAT_COLLCNT); ifp->if_opackets++; } if (cur_tx->fet_mbuf != NULL) { /* * we do need to check non-first mbuf, since some of existing * code does not call M_PREPEND properly. * (example: call to bpf_mtap from drivers) */ #if __FreeBSD_version >= 410000 if ((cur_tx->fet_mbuf->m_flags & M_PKTHDR) != 0 && cur_tx->fet_mbuf->m_pkthdr.aux) { m_freem(cur_tx->fet_mbuf->m_pkthdr.aux); cur_tx->fet_mbuf->m_pkthdr.aux = NULL; } #endif MFREE(cur_tx->fet_mbuf, n); cur_tx->fet_mbuf = NULL; } sc->fet_cdata.fet_free_tx_count++; if (sc->fet_cdata.fet_tx_head == sc->fet_cdata.fet_tx_tail) { sc->fet_cdata.fet_tx_head = NULL; sc->fet_cdata.fet_tx_tail = NULL; break; } sc->fet_cdata.fet_tx_head = cur_tx->fet_nextdesc; } /*while*/ return; } static void fet_tx_drop_all(sc) struct fet_softc *sc; { struct fet_chain *cur_tx=sc->fet_cdata.fet_tx_head; struct ifnet *ifp; register struct mbuf *n; ifp = &sc->arpcom.ac_if; while(CSR_READ_2(sc,FET_COMMAND) & FET_CMD_TX_ON) ; /* Clear the timeout timer. */ ifp->if_timer = 0; /* Sanity check. */ if (sc->fet_cdata.fet_tx_head == NULL) return; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ while(sc->fet_cdata.fet_tx_head->fet_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->fet_cdata.fet_tx_head; txstat = cur_tx->fet_ptr->fet_status; if (txstat & FET_TXSTAT_OWN) break; if (cur_tx->fet_mbuf != NULL) { /* * we do need to check non-first mbuf, since some of existing * code does not call M_PREPEND properly. * (example: call to bpf_mtap from drivers) */ #if __FreeBSD_version >= 410000 if ((cur_tx->fet_mbuf->m_flags & M_PKTHDR) != 0 && cur_tx->fet_mbuf->m_pkthdr.aux) { m_freem(cur_tx->fet_mbuf->m_pkthdr.aux); cur_tx->fet_mbuf->m_pkthdr.aux = NULL; } #endif MFREE(cur_tx->fet_mbuf, n); cur_tx->fet_mbuf = NULL; } sc->fet_cdata.fet_free_tx_count++; if (sc->fet_cdata.fet_tx_head == sc->fet_cdata.fet_tx_tail) { sc->fet_cdata.fet_tx_head = NULL; sc->fet_cdata.fet_tx_tail = NULL; break; } sc->fet_cdata.fet_tx_head = cur_tx->fet_nextdesc; } CSR_WRITE_4(sc, FET_TXADDR, vtophys(cur_tx->fet_ptr)); FET_SETBIT16(sc, FET_COMMAND, FET_CMD_TX_ON); FET_SETBIT16(sc, FET_COMMAND, FET_CMD_TDMD1); } /* * TX 'end of channel' interrupt handler. */ static void fet_txeoc(sc) struct fet_softc *sc; { struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; if (sc->fet_cdata.fet_tx_head == NULL) { ifp->if_flags &= ~IFF_OACTIVE; sc->fet_cdata.fet_tx_tail = NULL; } return; } static void fet_intr(arg) void *arg; { struct fet_softc *sc; struct ifnet *ifp; u_int16_t status; u_int8_t byMISR; sc = arg; ifp = &sc->arpcom.ac_if; /* Supress unwanted interrupts. */ if (!(ifp->if_flags & IFF_UP)) { fet_stop(sc); return; } /* Disable interrupts. */ CSR_WRITE_2(sc, FET_IMR, 0x0000); CSR_WRITE_1(sc, FET_MIMR, 0); for (;;) { status = CSR_READ_2(sc, FET_ISR); byMISR = CSR_READ_1(sc, FET_MISR); if ((status==0) && (byMISR==0)) break; CSR_WRITE_2(sc, FET_ISR, status); CSR_WRITE_1(sc, FET_MISR, byMISR); if (status & FET_ISR_SRCI) { fet_link_change(sc); } if (byMISR & FET_MISR_TDWBRAI) { fet_tx_drop_all(sc); break; } if (status & FET_ISR_BE) { printf("fet%d: Hardware fatal error\n", sc->fet_unit); fet_stop(sc); break; } if (status & (FET_ISR_RXE|FET_ISR_PRX)) fet_rxeof(sc); if (status & (FET_ISR_PTX|FET_ISR_TXE|FET_ISR_TX_ABTI|FET_ISR_UDFI)) { fet_txeof(sc); if (status & (FET_ISR_UDFI|FET_ISR_TX_ABTI)) { ifp->if_oerrors++; if (sc->fet_cdata.fet_tx_head != NULL) { FET_SETBIT16(sc, FET_COMMAND, FET_CMD_TX_ON); FET_SETBIT16(sc, FET_COMMAND, FET_CMD_TDMD1); } } else fet_txeoc(sc); } } /* Re-enable interrupts. */ CSR_WRITE_2(sc, FET_IMR, IMRShadow); CSR_WRITE_1(sc, FET_MIMR, MIMRShadow); if (ifp->if_snd.ifq_head != NULL) { fet_start(ifp); } return; } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int fet_encap(sc, c, m_head) struct fet_softc *sc; struct fet_chain *c; struct mbuf *m_head; { int frag = 0; struct fet_desc *f = NULL; int total_len; struct mbuf *m; m = m_head; total_len = 0; /* * NIC wants packet buffers to be longword * aligned, but very often our mbufs aren't. Rather than * waste time trying to decide when to copy and when not * to copy, just do it all the time. */ if (m != NULL) { struct mbuf *m_new = NULL; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("fet%d: no memory for tx list", sc->fet_unit); return(1); } if (m_head->m_pkthdr.len > MHLEN) { MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { m_freem(m_new); printf("fet%d: no memory for tx list", sc->fet_unit); return(1); } } m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; m_freem(m_head); m_head = m_new; /* * The Rhine chip doesn't auto-pad, so we have to make * sure to pad zeros to short frames out to the minimum frame * length ourselves. */ if (m_head->m_len < FET_MIN_FRAMELEN) { bzero(mtod(m_new,char*)+m_new->m_pkthdr.len, FET_MIN_FRAMELEN - m_new->m_len); m_new->m_pkthdr.len += FET_MIN_FRAMELEN - m_new->m_len; m_new->m_len = m_new->m_pkthdr.len; } f = c->fet_ptr; f->fet_data = vtophys(mtod(m_new, caddr_t)); f->fet_ctl = total_len = m_new->m_len; f->fet_ctl |= FET_TXCTL_TLINK|FET_TXCTL_FIRSTFRAG; f->fet_status = 0; frag = 1; } c->fet_mbuf = m_head; c->fet_ptr->fet_ctl |= FET_TXCTL_LASTFRAG|FET_TXCTL_FINT; c->fet_ptr->fet_next = vtophys(c->fet_nextdesc->fet_ptr); return(0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit lists. We also save a * copy of the pointers since the transmit list fragment pointers are * physical addresses. */ static void fet_start(ifp) struct ifnet *ifp; { struct fet_softc *sc; struct mbuf *m_head = NULL, *m = NULL; struct fet_chain *cur_tx = NULL, *start_tx, *first_tx = NULL; int frag_count, frag_need=0; int s; s=splimp(); sc = ifp->if_softc; /* * check the transmit process is not proceeding now. */ if (ifp->if_flags & IFF_OACTIVE) { splx(s); return; } /* * Check for an available queue slot. If there are none, * punt. */ if (sc->fet_cdata.fet_tx_free->fet_mbuf != NULL) { ifp->if_flags |= IFF_OACTIVE; splx(s); return; } start_tx = sc->fet_cdata.fet_tx_free; while(sc->fet_cdata.fet_tx_free->fet_mbuf == NULL) { if (sc->fet_chip_revid >= REV_ID_VT3065_A) { struct mbuf *m_tmp; for (m_tmp=ifp->if_snd.ifq_head, frag_need=0; m_tmp!=NULL; m_tmp=m_tmp->m_next) if (m_tmp->m_len != 0) frag_need++; if( (sc->fet_cdata.fet_free_tx_count) < frag_need) { ifp->if_flags |= IFF_OACTIVE; break; } } IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; if ((sc->fet_chip_revid < REV_ID_VT3065_A) || (m_head->m_pkthdr.len < FET_MIN_FRAMELEN)){ /* Pick a descriptor off the free list. */ cur_tx = sc->fet_cdata.fet_tx_free; sc->fet_cdata.fet_tx_free = cur_tx->fet_nextdesc; /* Pack the data into the descriptor. */ fet_encap(sc, cur_tx, m_head); if (cur_tx != start_tx) FET_TXOWN(cur_tx) = FET_TXSTAT_OWN; #if __FreeBSD_version >= 400000 || (__FreeBSD_version < 400000 && NBPFILTER > 0) /* * If there's a BPF listener, bounce a copy of this frame * to him. */ if (ifp->if_bpf) bpf_mtap(ifp, cur_tx->fet_mbuf); #endif FET_TXOWN(cur_tx) = FET_TXSTAT_OWN; sc->fet_cdata.fet_free_tx_count--; } else { register struct mbuf *tmp, *n; frag_count = 1; for (m = m_head; m != NULL; ) { if(m->m_len == 0) { tmp = m; m = m->m_next; #if __FreeBSD_version >= 410000 if ((tmp->m_flags & M_PKTHDR) != 0 && tmp->m_pkthdr.aux) { m_freem(tmp->m_pkthdr.aux); tmp->m_pkthdr.aux = NULL; } #endif MFREE(tmp, n); continue; } /* Pick a descriptor off the free list. */ cur_tx = sc->fet_cdata.fet_tx_free; sc->fet_cdata.fet_tx_free = cur_tx->fet_nextdesc; sc->fet_cdata.fet_free_tx_count--; if (frag_count == 1) first_tx = cur_tx; cur_tx->fet_ptr->fet_data = vtophys(mtod(m, caddr_t)); /* pad the short frame to minimum frame length */ /* ps: Pad those packets which only occupy 1 fragment */ if (m->m_len < FET_MIN_FRAMELEN && frag_count == 1 && m->m_next == NULL) { cur_tx->fet_ptr->fet_ctl = FET_MIN_FRAMELEN; m->m_pkthdr.len += FET_MIN_FRAMELEN - m->m_len; m->m_len = m->m_pkthdr.len; } else cur_tx->fet_ptr->fet_ctl = m->m_len; if (frag_count == 1) cur_tx->fet_ptr->fet_ctl |= FET_TXCTL_FINT|FET_TXCTL_TLINK| \ FET_TXCTL_FIRSTFRAG; else cur_tx->fet_ptr->fet_ctl |= FET_TXCTL_FINT|FET_TXCTL_TLINK; cur_tx->fet_ptr->fet_status = 0; cur_tx->fet_mbuf = m; cur_tx->fet_ptr->fet_next = vtophys(cur_tx->fet_nextdesc->fet_ptr); frag_count++; #if __FreeBSD_version >= 400000 || (__FreeBSD_version < 400000 && NBPFILTER > 0) /* * If there's a BPF listener, bounce a copy of this frame * to him. */ if (ifp->if_bpf) bpf_mtap(ifp, cur_tx->fet_mbuf); #endif m = m->m_next; } /* end for */ cur_tx->fet_ptr->fet_ctl |= FET_TXCTL_LASTFRAG; FET_TXOWN(first_tx) = FET_TXSTAT_OWN; } /* end else */ FET_SETBIT16(sc, FET_COMMAND, FET_CMD_TDMD1); } /* * If there are no frames queued, bail. */ if (cur_tx == NULL) { splx(s); return; } sc->fet_cdata.fet_tx_tail = cur_tx; if (sc->fet_cdata.fet_tx_head == NULL) sc->fet_cdata.fet_tx_head = start_tx; /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 30; splx(s); return; } /* Do lagacy force if in force mode*/ static void check_legacy_force(sc) struct fet_softc *sc; { unsigned int FET_BCR1_temp = 0; /* If MEDEN bit in CFGC is on, then it's forced mode, otherwise, it use autonegotiation. Only for VT3065 and VT3043 */ if(sc->fet_chip_revid < 0x80 && CSR_READ_1(sc, FET_CFGC) & 0x80){ /* if MED2 bit in BCR0 is on, then it use autonegotiation*/ if (CSR_READ_1(sc, FET_BCR0) & 0x80) sc->fet_autoneg = 1; else { sc->fet_autoneg = 0; FET_BCR1_temp = CSR_READ_1(sc, FET_BCR1); FET_BCR1_temp = FET_BCR1_temp & 0xC0 ; /* Disable autonigotiation */ fet_write_mii(sc, 0, fet_read_mii(sc,0) & 0xEFFF); /* set loopback in MII to un-link in 100M mode, */ /* in 10M mode set this bit cannot make it un-link */ /* but it doesn't matter */ fet_write_mii(sc, 0 , fet_read_mii(sc, 0) | 0x4000); if (FET_BCR1_temp == 0x00) { printf("fet%d: Force to 10Mbps Half duplex mode.\n", sc->fet_unit); /* Set speed 10Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xDFFF); /* Set half duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xFEFF); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); sc->fet_speed=10; sc->fet_full_duplex = 0; } else if (FET_BCR1_temp == 0x40) { printf("fet%d: Force to 100Mbps Half duplex mode.\n", sc->fet_unit); /* Set speed 100Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x2000); /* Set half duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xFEFF); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); sc->fet_speed=100; sc->fet_full_duplex = 0; } else if (FET_BCR1_temp == 0x80) { printf("fet%d: Force to 10Mbps Full duplex mode.\n", sc->fet_unit); /* Set speed 10Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xDFFF); /* Set full duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x0100); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); sc->fet_speed=10; sc->fet_full_duplex = 1; } else if (FET_BCR1_temp == 0xC0) { printf("fet%d: Force to 100Mbps Full duplex mode.\n", sc->fet_unit); /* Set speed 100Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x2000); /* Set full duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x0100); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); sc->fet_speed=100; sc->fet_full_duplex = 1; } /* delay to avoid link down from force-10M to force-100M */ DELAY(300000); /* clear LPBK bit in BMCR register to re-link */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xBFFF); } } else { sc->fet_autoneg = 0; /* Disable autonigotiation */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xEFFF); /* set loopback in MII to un-link in 100M mode, */ /* in 10M mode set this bit cannot make it un-link */ /* but it doesn't matter */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x4000); if (sc->fet_speed == 100 && sc->fet_full_duplex == 0) { printf("fet%d: Force to 100Mbps Half duplex mode.\n", sc->fet_unit); /* Set speed 100Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x2000); /* Set half duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xFEFF); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); sc->fet_speed=100; sc->fet_full_duplex = 0; } else if (sc->fet_speed == 100 && sc->fet_full_duplex == 1) { printf("fet%d: Force to 100Mbps Full duplex mode.\n", sc->fet_unit); /* Set speed 100Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x2000); /* Set full duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x0100); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); sc->fet_speed=100; sc->fet_full_duplex = 1; } else if (sc->fet_speed == 10 && sc->fet_full_duplex == 0) { printf("fet%d: Force to 10Mbps Half duplex mode.\n", sc->fet_unit); /* Set speed 10Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xDFFF); /* Set half duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xFEFF); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); sc->fet_speed=10; sc->fet_full_duplex = 0; } else if (sc->fet_speed == 10 && sc->fet_full_duplex == 1) { printf("fet%d: Force to 10Mbps Full duplex mode.\n", sc->fet_unit); /* Set speed 10Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xDFFF); /* Set full duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x0100); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); sc->fet_speed=10; sc->fet_full_duplex = 1; } /* delay to avoid link down from force-10M to force-100M */ DELAY(300000); /* clear LPBK bit in BMCR register to re-link */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xBFFF); } } /* Do N-WAY force if in force mode */ static int check_n_way_force (sc, change_flag) struct fet_softc *sc; int change_flag; { unsigned int MII_BMCR_temp = 0, MII_ANAR_temp=0; /* Read original BMCR and ANAR value from MII */ MII_BMCR_temp = fet_read_mii(sc, 0) ; MII_ANAR_temp = fet_read_mii(sc, 4) & 0x01E0; sc->fet_autoneg = 0; /* Force to 100Mbps Half duplex */ if (sc->fet_speed == 100 && sc->fet_full_duplex == 0) { printf("fet%d: Force to 100Mbps Half duplex mode.\n", sc->fet_unit); sc->fet_NWAY_Force = 1; /* Compare user defined mode with original ANAR value*/ /* If the setting is the same, do nothing, or we msut write the new setting to ANAR */ if (MII_ANAR_temp != 0x0080) { change_flag |= 1; /*Write the new setting to ANAR */ fet_write_mii(sc, 4, (fet_read_mii(sc, 4) & 0xFE1F) | 0x0080); } /* Set speed 100Mbps */ fet_write_mii(sc, 0 , fet_read_mii(sc, 0) | 0x2000); /* Set half duplex */ fet_write_mii(sc, 0 , fet_read_mii(sc, 0) & 0xFEFF); /* If AUTO bit is on and the setting is changed, issue REAUTO in BMCR */ if ((MII_BMCR_temp & 0x1000) && (change_flag == 1)) restart_autonegotiation(sc); else if (!(MII_BMCR_temp & 0x1000)) enable_autonegotiation(sc); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); } /* Force to 100Mbps Full duplex mode */ else if (sc->fet_speed == 100 && sc->fet_full_duplex == 1) { printf("fet%d: Force to 100Mbps Full duplex mode.\n", sc->fet_unit); sc->fet_NWAY_Force = 1; /* Compare user defined mode with original ANAR value*/ /* If the setting is the same, do nothing, or we must write the new setting to ANAR */ if (MII_ANAR_temp != 0x0100) { change_flag |= 1; /*Write the new setting to ANAR */ fet_write_mii(sc,4, (fet_read_mii(sc, 4) & 0xFE1F) | 0x0100); } /* Set speed 100Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x2000); /* Set full duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x0100); /* If AUTO bit is on and the setting is changed, issue REAUTO in BMCR */ if ((MII_BMCR_temp & 0x1000) && (change_flag == 1)) restart_autonegotiation(sc); else if (!(MII_BMCR_temp & 0x1000)) enable_autonegotiation(sc); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); } /* Force to 10Mbps Half duplex mode */ else if (sc->fet_speed == 10 && sc->fet_full_duplex == 0) { printf("fet%d: Force to 10Mbps Half duplex mode.\n", sc->fet_unit); sc->fet_NWAY_Force = 1; /* Compare user defined mode with original ANAR value*/ /* If the setting is the same, do nothing, or we msut write the new setting to ANAR */ if (MII_ANAR_temp != 0x0020) { change_flag |= 1; /*Write the new setting to ANAR */ fet_write_mii(sc,4, (fet_read_mii(sc, 4) & 0xFE1F) | 0x0020); } /* Set speed 10Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xDFFF); /* Set half duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xFEFF); /* If AUTO bit is on and the setting is changed, issue REAUTO in BMCR */ if ((MII_BMCR_temp & 0x1000) && (change_flag == 1)) restart_autonegotiation(sc); else if (!(MII_BMCR_temp & 0x1000)) enable_autonegotiation(sc); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); } /* Force to 10Mbps Full duplex mode */ else if (sc->fet_speed == 10 && sc->fet_full_duplex == 1) { printf("fet%d: Force to 10Mbps Full duplex mode.\n", sc->fet_unit); sc->fet_NWAY_Force = 1; /* Compare user defined mode with original ANAR value*/ /* If the setting is the same, do nothing, or we msut write the new setting to ANAR */ if (MII_ANAR_temp != 0x0040) { change_flag |= 1; /*Write the new setting to ANAR */ fet_write_mii(sc,4, (fet_read_mii(sc, 4) & 0xFE1F) | 0x0040); } /* Set speed 10Mbps */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) & 0xDFFF); /* Set full duplex */ fet_write_mii(sc,0 , fet_read_mii(sc, 0) | 0x0100); /* If AUTO bit is on and the setting is changed, issue REAUTO in BMCR */ if ((MII_BMCR_temp & 0x1000) && (change_flag == 1)) restart_autonegotiation(sc); else if (!(MII_BMCR_temp & 0x1000)) enable_autonegotiation(sc); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); } else { sc->fet_autoneg = 1; sc->fet_NWAY_Force = 0; } return change_flag; } static void set_media_duplex_mode (sc) struct fet_softc *sc; { unsigned int change_flag = 0; if (sc->fet_chip_revid >= REV_ID_VT3106 || (sc->fet_chip_revid >= REV_ID_VT3065_A && sc->fet_chip_revid < REV_ID_VT3106 && !(CSR_READ_1(sc,FET_CFGC) & 0x80))) change_flag=check_n_way_force(sc, change_flag); else check_legacy_force(sc); /* For N-WAY force in VT3106 or VT3072 phy */ /* Make sure the PHY is VT3106's PHY or VT3072*/ /* So we check PHY REG 'h3 (PHY Identifier1) bit[9:4] is 6'b110100*/ if((fet_read_mii(sc, PHY_PHYID2) & 0x03f0) == 0x0340 || ((fet_read_mii(sc, PHY_PHYID2) & 0x03f0) == 0x0320 && (fet_read_mii(sc, PHY_PHYID2) & 0x000f) >= 5)) { /* if forced mode, turn on bit 0 else turn off bit 0 in MII 0x10 register */ if(sc->fet_NWAY_Force == 1 && (sc->fet_chip_revid >= REV_ID_VT3106 || (sc->fet_chip_revid >= REV_ID_VT3065_A && sc->fet_chip_revid < REV_ID_VT3106 && !(CSR_READ_1(sc, FET_CFGC) & 0x80)))) /* write PHY REG 'h10(PHY MODE CONFIG) bit[0] as 1'b1 */ fet_write_mii(sc, 0x10, fet_read_mii(sc, 0x10) | 0x0001); else /* write PHY REG 'h10(PHY MODE CONFIG) bit[0] as 1'b0 */ fet_write_mii(sc, 0x10, fet_read_mii(sc, 0x10) & 0xfffe); } if (sc->fet_autoneg == 1) { unsigned int PHY_BMCR_temp = 0; unsigned int PHY_ANAR_temp = 0; int restart_auto = 0; int i; PHY_BMCR_temp = fet_read_mii(sc, PHY_BMCR); PHY_ANAR_temp = fet_read_mii(sc, PHY_ANAR); /* Set Autonegotiation enable (ANEG_EN bit in Control register ) */ fet_write_mii(sc, PHY_BMCR, fet_read_mii(sc, PHY_BMCR) | 0x1000); /* check the ANAR value is correct */ /* if not, write back the correct value, and retrigger Autonegotiation */ if ((PHY_ANAR_temp & 0x01E0) != 0x01E0) { fet_write_mii(sc, PHY_ANAR, PHY_ANAR_temp | 0x01E0); /* Set 10_HDX bit*/ restart_auto = 1; } /* for VT3043(DAVICOM) only, fix DaviCom PHY's bug */ if (sc->fet_chip_revid < 0x20 ) { unsigned int phy_ID; phy_ID = (fet_read_mii(sc, PHY_PHYID1) << 16) | (fet_read_mii(sc, PHY_PHYID2)); if (phy_ID >= CID_DAVICOM && phy_ID < CID_DAVICOM_B) restart_auto = 1; } if (change_flag == 1) restart_auto = 1; if (restart_auto == 1) restart_autonegotiation(sc); /* Forced mode to auto mode, it will cause autonegotiation restart */ /* Wait until N-WAY finished*/ else if (!( PHY_BMCR_temp & 0x1000) && !(fet_read_mii(sc, PHY_BMSR) & 0x0020)) { DELAY(2500000); for (i=0; i<0x1ff; i++) if (fet_read_mii(sc, PHY_BMSR) & 0x0020) break; } } } /* set_media_duplex_mode */ /* * Function: set_flow_control * * Purpose: * Set flow control related bits. * */ static void set_flow_control(sc) struct fet_softc *sc; { unsigned int temp_FlowCR1=0; /* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1} depend on RD=64*/ /* Turn on XNOEN in FlowCR1*/ temp_FlowCR1 = (CSR_READ_1(sc, FET_FlowCR1) | 0xB8); CSR_WRITE_1(sc, FET_FlowCR1, temp_FlowCR1); /* Set TxPauseTimer to 0xFFFF */ CSR_WRITE_2(sc, FET_TxPauseTimer, 0xFFFF); /* Initialize RBRDU to Rx buffer count.*/ CSR_WRITE_1(sc, FET_FlowCR0, 64); } /* Set flow control capability accroding to ANAR and ANLPAR register in MII */ /* The half duplex flow control capability is turn off now, because it's not in the spec.*/ /* Follow the table 28B-3 in the IEEE Standard 802.3, 2000 Edition to set */ /* full duplex flow control capability*/ static void flow_control_ability(sc) struct fet_softc *sc; { unsigned int PHYANAR_temp, PHYANLPAR_temp, MIISR_temp, FlowCR1_temp, Micr0_temp; if (sc->fet_chip_revid >= REV_ID_VT3065_A && sc->fet_chip_revid < REV_ID_VT3106) { /* Read the old value of FlowCR1 register */ Micr0_temp = CSR_READ_1(sc, FET_Micr0); /*check whether NIC is operated in full duplex mode */ /* in full duplex mode*/ if (sc->fet_full_duplex == 1) { /* read PAUSE and ASM_DIR in PHYANAR and MIISR register*/ PHYANAR_temp = (fet_read_mii(sc, PHY_ANAR) & 0x0C00) >> 10; PHYANLPAR_temp = (fet_read_mii(sc, PHY_LPAR) & 0x0C00) >> 10; /* Local: ASM_DIR=1, PAUSE=0 Remote: ASM_DIR=1, PAUSE=1*/ if ( (PHYANAR_temp & 0x02) && (!(PHYANAR_temp & 0x01)) && (PHYANLPAR_temp & 0x02) && (PHYANLPAR_temp & 0x01)) { /* Disable PAUSE receive */ Micr0_temp = Micr0_temp & 0xF7; } /* Local: ASM_DIR=Don't care, PAUSE=1 Remote: ASM_DIR=Don't care, PAUSE=1*/ else if (PHYANAR_temp & 0x01 && PHYANLPAR_temp & 0x01) { /* Enable PAUSE receive */ Micr0_temp = Micr0_temp | 0x08; } /* Local: ASM_DIR=1, PAUSE=1 Remote: ASM_DIR=1, PAUSE=0*/ else if ( (PHYANAR_temp & 0x02) && (PHYANAR_temp & 0x01) && (PHYANLPAR_temp & 0x02) && (!(PHYANLPAR_temp & 0x01))) { /* Enable PAUSE receive */ Micr0_temp = Micr0_temp | 0x08; } /* Other conditions*/ else { /* Disable PAUSE receive */ Micr0_temp = Micr0_temp & 0xF7; } } /* in half duplex mode*/ else { /* Disable PAUSE receive */ Micr0_temp = Micr0_temp & 0xF7; } /* Disable half duplex flow control */ Micr0_temp = Micr0_temp & 0xFB; /* Disable full duplex PAUSE transmit */ Micr0_temp = Micr0_temp & 0xEF; /* Set the Micr0 register*/ CSR_WRITE_1(sc, FET_Micr0, Micr0_temp ); } else if (sc->fet_chip_revid >= REV_ID_VT3106) { /* Read the old value of FlowCR1 register */ FlowCR1_temp = CSR_READ_1(sc, FET_FlowCR1); /*check whether NIC is operated in full duplex mode */ /* in full duplex mode*/ if (sc->fet_full_duplex == 1) { /* read PAUSE and ASM_DIR in PHYANAR and MIISR register*/ PHYANAR_temp = (fet_read_mii(sc, PHY_ANAR) & 0x0C00) >> 10; MIISR_temp = (CSR_READ_1(sc, FET_MIISR) & 0x60) >> 5; /* Local: ASM_DIR=1, PAUSE=0 Remote: ASM_DIR=1, PAUSE=1*/ if ( (PHYANAR_temp & 0x02) && (!(PHYANAR_temp & 0x01)) && (MIISR_temp & 0x02) && (MIISR_temp & 0x01)) { /* Enable PAUSE transmit */ FlowCR1_temp = FlowCR1_temp | 0x04; /* Disable PAUSE receive */ FlowCR1_temp = FlowCR1_temp & 0xFD; } /* Local: ASM_DIR=Don't care, PAUSE=1 Remote: ASM_DIR=Don't care, PAUSE=1*/ else if (PHYANAR_temp & 0x01 && MIISR_temp & 0x01) { /* Enable PAUSE transmit */ FlowCR1_temp = FlowCR1_temp | 0x04; /* Enable PAUSE receive */ FlowCR1_temp = FlowCR1_temp | 0x02; } /* Local: ASM_DIR=1, PAUSE=1 Remote: ASM_DIR=1, PAUSE=0*/ else if ( (PHYANAR_temp & 0x02) && (PHYANAR_temp & 0x01) && (MIISR_temp & 0x02) && (!(MIISR_temp & 0x01))) { /* Disable PAUSE transmit */ FlowCR1_temp = FlowCR1_temp & 0xFB; /* Enable PAUSE receive */ FlowCR1_temp = FlowCR1_temp | 0x02; } /* Other conditions*/ else { /* Disable PAUSE transmit */ FlowCR1_temp = FlowCR1_temp & 0xFB; /* Disable PAUSE receive */ FlowCR1_temp = FlowCR1_temp & 0xFD; } } /* in half duplex mode*/ else { /* Disable PAUSE transmit */ FlowCR1_temp = FlowCR1_temp & 0xFB; /* Disable PAUSE receive */ FlowCR1_temp = FlowCR1_temp & 0xFD; } /* Disable half duplex flow control */ FlowCR1_temp = FlowCR1_temp & 0xFE; /* Set the FlowCR1 register*/ CSR_WRITE_1(sc, FET_FlowCR1, FlowCR1_temp); } } #if 0 /* * Function: CAM_data_read * * Purpose: * Read CAM data. * * if select_CAM=0, write MCAM , else if slect_CAM=1, write VCAM * */ static void CAM_data_read(sc, select_CAM, CAM_address, value) struct fet_softc *sc; int select_CAM ; unsigned char CAM_address; unsigned char *value; { int uu; unsigned char FET_CAMC_temp; /* invalid address */ if (CAM_address & 0xE0) printf("fet%d: the CAM address is invalid.\n", sc->fet_unit); /* enable/select CAM controller */ FET_CAMC_temp = CAMC_CAMEN | (select_CAM ? CAMC_VCAMSL : 0); CSR_WRITE_1(sc, FET_CAMC, FET_CAMC_temp); /* set CAM entry address */ CSR_WRITE_1(sc, FET_CAMADD, CAM_address); /* issue read command */ CSR_WRITE_1(sc, FET_CAMC, CAMC_CAMRD | FET_CAMC_temp); /* CAM access will be slow in 10Mbps mode */ /* delayed 2 micro-seconds to guarantee correct CAM access */ DELAY(10); if (select_CAM == CAMC_SELECT_VCAM) { /* read VID CAM data */ *((unsigned int *)value)= CSR_READ_1(sc, FET_VCAMD0); } else { /* read Multicast CAM data */ for (uu = 0; uu < 6; uu++) *(value + uu)=CSR_READ_1(sc, FET_MCAMD0 + uu); } /* disable CAMEN and return TRUE */ CSR_WRITE_1(sc, FET_CAMC, 0); return; } /* * Function: CAM_mask_read * * Purpose: * Read CAM mask. * * if select_CAM=0, write MCAM mask, else if slect_CAM=1, write VCAM mask * */ static unsigned int CAM_mask_read(sc, select_CAM, mask) struct fet_softc *sc; int select_CAM ; unsigned int mask; { unsigned int mask_temp; /* enable CAMEN */ CSR_WRITE_1(sc, FET_CAMC, CAMC_CAMEN | (select_CAM ? CAMC_VCAMSL : 0)); /* read mask */ mask_temp = inl(FET_CAMMSK); /* disable CAMEN */ CSR_WRITE_1(sc, FET_CAMC, 0); return mask_temp; } #endif /* * Function: CAM_data_write * * Purpose: * Write CAM data. * * if select_CAM=0, write MCAM , else if slect_CAM=1, write VCAM * */ static void CAM_data_write(sc, select_CAM, CAM_address, value) struct fet_softc *sc; int select_CAM ; unsigned char CAM_address; unsigned char *value; { /* unsigned long port; */ int uu; unsigned char FET_CAMC_temp; /* invalid address*/ if (CAM_address & 0xE0) printf("fet%d: the CAM address is invalid.\n", sc->fet_unit); /* enable/select CAM controller */ FET_CAMC_temp = CAMC_CAMEN | (select_CAM ? CAMC_VCAMSL : 0); CSR_WRITE_1(sc, FET_CAMC, FET_CAMC_temp); /* set CAM entry address */ CSR_WRITE_1(sc, FET_CAMADD, CAM_address); if (select_CAM == CAMC_SELECT_VCAM) { /* read VID CAM data */ CSR_WRITE_2(sc, FET_VCAMD0, *((unsigned int *)value)); } else { /* read Multicast CAM data */ for (uu = 0; uu < 6; uu++) CSR_WRITE_1(sc, FET_MCAMD0 + uu, *(value + uu)); } /* issue write command */ CSR_WRITE_1(sc, FET_CAMC, CAMC_CAMWR | FET_CAMC_temp); /* CAM access will be slow in 10Mbps mode */ /* delayed 2 micro-seconds to guarantee correct CAM access */ DELAY(2); /* disable CAMEN and return TRUE */ CSR_WRITE_1(sc, FET_CAMC, 0); } /* * Function: CAM_mask_write * * Purpose: * Write CAM mask. * * if select_CAM=0, write MCAM mask, else if slect_CAM=1, write VCAM mask * */ static void CAM_mask_write(sc, select_CAM, mask) struct fet_softc *sc; int select_CAM ; unsigned int mask; { /* enable CAMEN */ CSR_WRITE_1(sc, FET_CAMC, CAMC_CAMEN | (select_CAM ? CAMC_VCAMSL : 0)); /* write mask */ CSR_WRITE_4(sc, FET_CAMMSK, mask); /* disable CAMEN */ CSR_WRITE_1(sc, FET_CAMC, 0); } /* * Function: VLAN_tagging * * Purpose: * Implement 802.1/Q tagging. * 3106J=> Mode0: Tx:untagged packets, Rx:untagged or tagged packets; * NOT extract tag from tagged packets * 3106S=> Mode1: Tx:untagged packets, Rx:untagged or tagged priority packets; * extract tag from tagged packets */ static void VLAN_tagging(sc) struct fet_softc *sc; { unsigned int VCAM_temp = 0; VCAM_temp= 0; /* if 3106J, enter Mode 0*/ /* in this mode, tx: all packet un-tagged, rx: both untagged/tagged packets */ /* NOT extract tag from tagged packets */ if (sc->fet_chip_revid >= REV_ID_VT3106_J && sc->fet_chip_revid < REV_ID_VT3106_S) { /* set {PQEN, RTGOPT} = {0,0} in TCR */ CSR_WRITE_1(sc, FET_TXCFG, (CSR_READ_1(sc, FET_TXCFG) & 0xEE)); /* VLAN CAM mask = 0 */ CAM_mask_write(sc, 1, 0x00000000); /* set VIDFR =0 in BCR1, VLAN ID hardware filtering. */ CSR_WRITE_1(sc, FET_BCR1, CSR_READ_1(sc, FET_BCR1) & BCR1_VIDFR_DIS); } /* if 3106S, enter Mode 1*/ /* in this mode, tx: all packet tagged, rx: both untagged/tagged packets */ /* extract tag from tagged packets */ else if (sc->fet_chip_revid >= REV_ID_VT3106_S) { /* set {PQEN, RTGOPT} = {1,0} in TCR */ CSR_WRITE_1(sc, FET_TXCFG, (CSR_READ_1(sc, FET_TXCFG) & 0xEF) | 0x01); /* VLAN CAM[0]= 0 */ CAM_data_write(sc, 1, 0, (unsigned char *)&VCAM_temp); /* VLAN CAM mask = 1 */ CAM_mask_write(sc, 1, 0x00000001); /* set VIDFR =1 in BCR1, VLAN ID hardware filtering. */ CSR_WRITE_1(sc, FET_BCR1, CSR_READ_1(sc, FET_BCR1) | 0x80); } } static void SafeDisableMiiAuto(sc) struct fet_softc *sc; { int ww = 0; /* before read mii data, we must turn off mauto */ CSR_WRITE_1(sc, FET_MIICR, 0); /* for VT3043 only */ if (sc->fet_chip_revid < REV_ID_VT3065_A) { /* turn off MSRCEN NOTE.... address of MII should be 0x01, otherwise SRCI will invoked */ CSR_WRITE_1(sc, FET_MIIADDR, 0x01); DELAY(1000); /* turn on MAUTO */ CSR_WRITE_1(sc, FET_MIICR, 0x80); /* W_MAX_TIMEOUT is the timeout period */ for (ww = 0; ww < 0x3fff; ww++) { if (CSR_READ_1(sc, FET_MIIADDR) & 0x20) break; } /* as soon as MDONE is on, */ /* this is the right time to turn off MAUTO */ CSR_WRITE_1(sc, FET_MIICR, 0); } else { /* as soon as MIDLE is on, MAUTO is really stoped */ for (ww = 0; ww < 0x3fff; ww++) { if (CSR_READ_1(sc, FET_MIIADDR) & 0x80) break; } } } static void EnableMiiAutoPoll(sc) struct fet_softc *sc; { int ww; /*Turn off MAUTO*/ CSR_WRITE_1(sc,FET_MIICR,0); /*Turn MSRCEN, 0x01*/ CSR_WRITE_1(sc, FET_MIIADDR, 0x41); /*Turn on MAUTO*/ CSR_WRITE_1(sc, FET_MIICR, 0x80); for (ww = 0; ww < 0x3fff; ww++) if (CSR_READ_1(sc, FET_MIIADDR) & 0x20) break; /* turn on MSRCEN ater MDONE has turned on */ CSR_WRITE_1(sc, FET_MIIADDR, 0x40); } static void turn_on_MII_link(sc) struct fet_softc *sc; { unsigned int MIICRbak; int ww; MIICRbak = CSR_READ_1(sc, FET_MIICR); SafeDisableMiiAuto(sc); CSR_WRITE_1(sc, FET_MIIADDR, 0x01); CSR_WRITE_1(sc, FET_MIICR, MIICRbak | 0x80); for (ww = 0; ww < 0x3fff; ww++) if (CSR_READ_1(sc, FET_MIIADDR) & 0x20) break; /* turn on MSRCEN ater MDONE has turned on */ CSR_WRITE_1(sc, FET_MIIADDR, 0x40); DELAY(30000); } static void restart_autonegotiation(sc) struct fet_softc *sc; { unsigned int i; /* Restart autonegotiation */ FET_SET_MII(sc, PHY_BMCR, PHY_BMCR_AUTONEGRSTR); /* Wait until N-WAY finished*/ DELAY(2500000); /* delay for 2 seconds */ for (i=0; i<0x1ff; i++) if (fet_read_mii(sc, PHY_BMSR) & PHY_BMCR_AUTONEGRSTR) break; } /* restart_autonegotiation */ /* Turn on AUTO bit in MII regiser */ static void enable_autonegotiation(sc) struct fet_softc *sc; { unsigned int i; unsigned int PHY_BMCR_temp = 0; PHY_BMCR_temp = fet_read_mii(sc, PHY_BMCR); /* Set Autonegotiation enable (ANEG_EN bit in Control register ) */ fet_write_mii(sc, PHY_BMCR , fet_read_mii(sc, PHY_BMCR) | 0x1000); /* Forced mode to auto mode, it will cause autonegotiation restart */ /* Wait until N-WAY finished*/ if (!( PHY_BMCR_temp & 0x1000)) { DELAY(2500000); for (i=0; i<0x1ff; i++) if (fet_read_mii(sc, PHY_BMSR) & 0x0020) break; } }/* enable_autonegotiation */ static void fet_set_tx_thresh(sc) struct fet_softc *sc; { FET_CLRBIT(sc, FET_BCR1, 0x38); FET_SETBIT(sc, FET_BCR1, sc->tx_thresh<< 3); FET_CLRBIT(sc, FET_TXCFG, 0xC0); FET_SETBIT(sc, FET_TXCFG, sc->tx_thresh<<5); } static void fet_set_rx_thresh(sc) struct fet_softc *sc; { FET_CLRBIT(sc, FET_BCR0, 0x38); FET_SETBIT(sc, FET_BCR0, sc->rx_thresh<< 3); FET_CLRBIT(sc, FET_RXCFG, 0xC0); FET_SETBIT(sc, FET_RXCFG, sc->rx_thresh<<5); } static void do_autonegotiation(sc) struct fet_softc *sc; { /* check whether link fail */ if (CSR_READ_1(sc, FET_MIISR) & 0x02){ printf("fet%d: Link Fail.\n", sc->fet_unit); sc->fet_speed = 10; /* Set speed 10Mbps */ sc->fet_full_duplex = 0; /* Set half duplex */ return; } /* check speed*/ /* read N_SPD10 bit in MII Status Register */ if (CSR_READ_1(sc, FET_MIISR) & 0x01) { printf("fet%d: Autonegotiation result: 10Mbps", sc->fet_unit); sc->fet_speed = 10; /* Set speed 10Mbps */ } else { printf("fet%d: Autonegotiation result: 100Mbps", sc->fet_unit); sc->fet_speed = 100; /* Set speed 10Mbps */ } /* check duplex mode*/ /* if VT3106, check N_FDX bit in MII Status Register directly */ if (sc->fet_chip_revid >= REV_ID_VT3106) { if (CSR_READ_1(sc, FET_MIISR) & 0x04) { printf(" full duplex mode.\n"); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); sc->fet_full_duplex = 1; /* Set full duplex */ } else { printf(" half duplex mode.\n"); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); sc->fet_full_duplex = 0; /* Set half duplex */ } } else { /* if VT3065 or VT3043, check ANAR and ANLPAR in MII Registers of PHY */ if ((fet_read_mii(sc, PHY_ANAR) & fet_read_mii(sc, PHY_LPAR)) & 0x0140 ) { printf(" full duplex mode.\n"); /* Set MAC operating in Full Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) | 0x0400); sc->fet_full_duplex = 1; /* Set full duplex */ } else { printf(" half duplex mode.\n"); /* Set MAC operating in Half Duplex Mode*/ CSR_WRITE_2(sc, FET_COMMAND, CSR_READ_2(sc, FET_COMMAND) & 0xfbff); sc->fet_full_duplex = 0; /* Set half duplex */ } } /* special treatment for 3071B */ if (sc->fet_chip_revid == REV_ID_VT3071_B) { if (CSR_READ_1(sc, FET_MIISR) & MIISR_SPEED) /* if 10M -> turn off BCR0[6] */ CSR_WRITE_1(sc, FET_BCR0, CSR_READ_1(sc, FET_BCR0) & ~0x40); else /* if 100M -> turn on BCR0[6] */ CSR_WRITE_1(sc, FET_BCR0, CSR_READ_1(sc, FET_BCR0) | 0x40); } } static void fet_init(xsc) void *xsc; { struct fet_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int s,i; s = splimp(); /* * Cancel pending I/O and free all RX/TX buffers. */ fet_stop(sc); fet_reset(sc); #if __FreeBSD_version >= 400000 enable_mmio(sc); #endif for (i = 0; i < ETHER_ADDR_LEN; i++) CSR_WRITE_1(sc, FET_PAR0 + i, sc->arpcom.ac_enaddr[i]); /* set the MIIAD again because software reset will reset the value */ FET_SETBIT(sc, FET_MIIADDR, FET_MIIADDR_MSRCEN | FET_MIIADDR_MAD0); /* set TCR RCR threshold */ /* set DMAL to 000 (8 DWs) , and not to change REQOPT set in attach fucntion */ /* set (CRFT2, CRFT1, CRFT0)=(0, 0, 0) */ /* set (CTFT2, CTFT1, CTFT0)=(0, 0, 0) */ FET_CLRBIT(sc,FET_BCR0, 7); FET_SETBIT(sc,FET_BCR0, DMA_LENGTH_DEF); CSR_WRITE_1(sc, FET_BCR1, 0x00); /* Set RX threshhold */ sc->rx_thresh=0; fet_set_rx_thresh(sc); /* Set TX threshhold */ sc->tx_thresh=TX_THRESH_DEF; fet_set_tx_thresh(sc); /* Turn on bit3 (OFSET) in TCR during MAC initialization */ FET_SETBIT(sc, FET_TXCFG, FET_TXCFG_OFSET); /* QPacket setting */ if (sc->fet_chip_revid < REV_ID_VT3065_A) /* disable queue packet */ FET_SETBIT(sc, FET_CFGB, FET_CFGB_QPKTDIS); else { #if QPACKET_DEF==0 /* disable queue packet */ FET_SETBIT(sc, FET_CFGB, FET_CFGB_QPKTDIS); #else /* enalbe queue packet*/ FET_CLRBIT(sc,FET_CFGB, FET_CFGB_QPKTDIS); #endif } /* set backoff algorithm ,disable the right-most 4-bit off CFGD[0] during initialization */ FET_CLRBIT(sc, FET_CFGD,(FET_CFGD_CAP|FET_CFGD_CRADOM|FET_CFGD_MBA|FET_CFGD_BAKOPT)); /* Init circular RX list. */ if (fet_list_rx_init(sc) == ENOBUFS) { printf("fet%d: initialization failed: no " "memory for rx buffers\n", sc->fet_unit); fet_stop(sc); (void)splx(s); return; } /* * Init tx descriptors. */ fet_list_tx_init(sc); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) FET_SETBIT(sc, FET_RXCFG, FET_RXCFG_RX_PROMISC); else FET_CLRBIT(sc, FET_RXCFG, FET_RXCFG_RX_PROMISC); /* Set capture broadcast bit to capture broadcast frames. */ if (ifp->if_flags & IFF_BROADCAST) FET_SETBIT(sc, FET_RXCFG, FET_RXCFG_RX_BROAD); else FET_CLRBIT(sc, FET_RXCFG, FET_RXCFG_RX_BROAD); /* * Program the multicast filter, if necessary. */ fet_setmulti(sc); /* * Load the address of the RX list. */ CSR_WRITE_4(sc, FET_RXADDR, vtophys(sc->fet_cdata.fet_rx_head->fet_ptr)); CSR_WRITE_4(sc, FET_TXADDR, vtophys(&sc->fet_ldata->fet_tx_list[0])); if (sc->fet_chip_revid >= REV_ID_VT3065_A) flow_control_ability (sc); /* Enable receiver and transmitter. */ CSR_WRITE_1(sc, FET_COMMAND, FET_CMD_START| FET_CMD_TX_ON|FET_CMD_RX_ON); FET_SETBIT16(sc, FET_COMMAND, FET_CMD_TX_NOPOLL); /* * Enable interrupts. */ CSR_WRITE_2(sc, FET_IMR, IMRShadow); CSR_WRITE_1(sc, FET_MIMR, MIMRShadow); EnableMiiAutoPoll(sc); /* turn on MII link change */ /* if the MAD4-0 is not 0x0001, then Link Fail will be on */ turn_on_MII_link(sc); if (sc->fet_chip_revid >= REV_ID_VT3106) set_flow_control(sc); /* set_media_duplex_mode(sc);*/ if (sc->fet_chip_revid >= REV_ID_VT3065_A) flow_control_ability (sc); if (sc->fet_chip_revid >= REV_ID_VT3106) VLAN_tagging(sc); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; (void)splx(s); return; } /* * Set media options. */ static int fet_ifmedia_upd(ifp) struct ifnet *ifp; { struct fet_softc *sc; struct ifmedia *ifm = NULL; unsigned int PHY_BMCR_temp = 0; unsigned int PHY_ANAR_temp = 0; int restart_auto = 0, change_flag = 0; int i; ifp->if_timer=0; sc = ifp->if_softc; ifm = &sc->ifmedia; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return(EINVAL); switch(IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO : PHY_BMCR_temp = fet_read_mii(sc, PHY_BMCR); PHY_ANAR_temp = fet_read_mii(sc, PHY_ANAR); /* Set Autonegotiation enable (ANEG_EN bit in Control register ) */ FET_SET_MII(sc, PHY_BMCR, PHY_BMCR_AUTONEGENBL); /* check the ANAR value is correct */ /* if not, write back the correct value, and retrigger Autonegotiation */ if ((PHY_ANAR_temp & 0x01E0) != 0x01E0) { FET_SET_MII(sc, PHY_ANAR, 0x01E0); /* Set TX_FDX,TX_HDX,10_FDX,10_HDX, bit*/ restart_auto = 1; } /* for VT3043(DAVICOM) only, fix DaviCom PHY's bug */ if (sc->fet_chip_revid < REV_ID_VT3071_A ) { unsigned int phy_ID; phy_ID = (fet_read_mii(sc, PHY_PHYID1) << 16) | (fet_read_mii(sc, PHY_PHYID2)); if (phy_ID >= CID_DAVICOM && phy_ID < CID_DAVICOM_B) restart_auto = 1; } if (restart_auto == 1) restart_autonegotiation(sc); /* Forced mode to auto mode, it will cause autonegotiation restart */ /* Wait until N-WAY finished*/ else if (!( PHY_BMCR_temp & 0x1000) && !(fet_read_mii(sc, PHY_BMSR) & 0x0020)) { DELAY(2500000); for (i=0; i<0x1ff; i++) if (fet_read_mii(sc, PHY_BMSR) & 0x0020) break; } do_autonegotiation(sc); break; case IFM_100_TX : case IFM_100_FX : /* 100Mbps Full duplex mode*/ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { sc->fet_speed=100; sc->fet_full_duplex=1; } /* 100Mbps Half duplex mode*/ else { sc->fet_speed=100; sc->fet_full_duplex=0; } if (sc->fet_chip_revid >= 0x80 || (sc->fet_chip_revid >= 0x40 && sc->fet_chip_revid < 0x80 && !(CSR_READ_1(sc, FET_CFGC) & 0x80))) change_flag=check_n_way_force(sc, change_flag); else check_legacy_force(sc); break; case IFM_10_FL : case IFM_10_T : /* 10Mbps Full duplex mode*/ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { sc->fet_speed=10; sc->fet_full_duplex=1; } /* 10Mbps Half duplex mode*/ else { sc->fet_speed=10; sc->fet_full_duplex=0; } if (sc->fet_chip_revid >= 0x80 || (sc->fet_chip_revid >= 0x40 && sc->fet_chip_revid < 0x80 && !(CSR_READ_1(sc, FET_CFGC) & 0x80))) change_flag=check_n_way_force(sc, change_flag); else check_legacy_force(sc); break; } /* if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) fet_autoneg_mii(sc, FET_FLAG_SCHEDDELAY, 1); else fet_setmode_mii(sc, ifm->ifm_media); */ return(0); } static void mii_check_media_mode(struct fet_softc *sc) { u_int16_t wANAR; if (CSR_READ_1(sc,FET_MIISR) & 0x02) { /*Link fail, read ANAR*/ wANAR=fet_read_mii(sc,PHY_ANAR); if (wANAR & 0x0080) { sc->fet_speed=100; if (wANAR & 0x0100) sc->fet_full_duplex=1; else sc->fet_full_duplex=0; } else { sc->fet_speed=10; if (wANAR & 0x0040) sc->fet_full_duplex=1; else sc->fet_full_duplex=0; } } else { if (CSR_READ_1(sc,FET_MIISR) & 0x01) sc->fet_speed=10; else sc->fet_speed=100; if (fet_query_auto(sc)) { FET_SETBIT16(sc, FET_COMMAND, FET_CMD_FDX); /* Set Chip Fullduplex mode */ sc->fet_full_duplex=1; } else { FET_CLRBIT16(sc, FET_COMMAND, FET_CMD_FDX); sc->fet_full_duplex=0; } } sc->fet_autoneg=0; if (fet_read_mii(sc,PHY_BMCR) & 0x1000) { wANAR=fet_read_mii(sc,PHY_ANAR); if ((wANAR & 0x01E0)==0x01E0) sc->fet_autoneg=1; } } /* * Report current media status. */ static void fet_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct fet_softc *sc; sc = ifp->if_softc; ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; mii_check_media_mode(sc); if (!(CSR_READ_1(sc,FET_MIISR) & 0x02)) ifmr->ifm_status|=IFM_ACTIVE; if (sc->fet_autoneg) ifmr->ifm_active|=IFM_AUTO; if (sc->fet_speed == 100) ifmr->ifm_active |=IFM_100_TX; else ifmr->ifm_active |=IFM_10_T; if (sc->fet_full_duplex) ifmr->ifm_active |= IFM_FDX; return; } static int fet_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data; { struct fet_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; int s, error = 0; s = splimp(); switch(command) { case SIOCSIFADDR: case SIOCGIFADDR: case SIOCSIFMTU: error = ether_ioctl(ifp, command, data); break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { fet_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) fet_stop(sc); } error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: fet_setmulti(sc); error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; default: error = EINVAL; break; } (void)splx(s); return(error); } static void fet_watchdog(ifp) struct ifnet *ifp; { struct fet_softc *sc; sc = ifp->if_softc; /* if (sc->fet_autoneg) { fet_autoneg_mii(sc, FET_FLAG_DELAYTIMEO, 1); return; } */ ifp->if_oerrors++; printf("fet%d: watchdog timeout\n", sc->fet_unit); /* if (!(fet_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) printf("fet%d: no carrier - transceiver cable problem?\n", sc->fet_unit); */ fet_stop(sc); fet_reset(sc); fet_init(sc); if (ifp->if_snd.ifq_head != NULL) fet_start(ifp); return; } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ static void fet_stop(sc) struct fet_softc *sc; { register int i; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; FET_CLRBIT16(sc, FET_COMMAND, FET_CMD_TX_ON); if (!fet_safe_rx_off(sc)) printf("fet%d: RX shutdown error! \n", sc->fet_unit); FET_SETBIT16(sc, FET_COMMAND, FET_CMD_STOP); CSR_WRITE_2(sc, FET_IMR, 0x0000); CSR_WRITE_4(sc, FET_TXADDR, 0x00000000); CSR_WRITE_4(sc, FET_RXADDR, 0x00000000); /* * Free data in the RX lists. */ for (i = 0; i < FET_RX_LIST_CNT; i++) { if (sc->fet_cdata.fet_rx_chain[i].fet_mbuf != NULL) { m_freem(sc->fet_cdata.fet_rx_chain[i].fet_mbuf); sc->fet_cdata.fet_rx_chain[i].fet_mbuf = NULL; } } bzero((char *)&sc->fet_ldata->fet_rx_list, sizeof(sc->fet_ldata->fet_rx_list)); /* * Free the TX list buffers. */ for (i = 0; i < FET_TX_LIST_CNT; i++) { if (sc->fet_cdata.fet_tx_chain[i].fet_mbuf != NULL) { m_freem(sc->fet_cdata.fet_tx_chain[i].fet_mbuf); sc->fet_cdata.fet_tx_chain[i].fet_mbuf = NULL; } } bzero((char *)&sc->fet_ldata->fet_tx_list, sizeof(sc->fet_ldata->fet_tx_list)); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); return; } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ #if __FreeBSD_version >= 400000 static void fet_shutdown(dev) device_t dev; { struct fet_softc *sc; sc = device_get_softc(dev); fet_stop(sc); return; } #elif __FreeBSD_version < 400000 static void fet_shutdown(howto, arg) int howto; void *arg; { struct fet_softc *sc = (struct fet_softc *)arg; fet_stop(sc); return; } static struct pci_device fet_device = { "fet", fet_probe, fet_attach, &fet_count, NULL }; DATA_SET(pcidevice_set, fet_device); #endif [-- Attachment #4 --] /* * Copyright (c) 1996,2002 VIA Networking, Inc. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by VIA Technologies, Inc. * 4. Neither the name of the Company nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY VIA TECHNOLOGIES, INC. 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 VIA TECHNOLOGIES, INC. 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. * */ #ifndef __IF_FET_H #define __IF_FET_H /************************************************************************ * Driver tunable parameters *************************************************************************/ #define DMA_LENGTH_DEF (1) /* DMA_LENGTH_DEF is used for controlling the DMA length. 0: 8 DWORDs 1: 16 DWORDs 2: 32 DWORDs 3: 64 DWORDs 4: 128 DWORDs 5: 256 DWORDs 6: SF(flush till emply) 7: SF(flush till emply) */ #define TX_THRESH_DEF (0) /* TX_THRESH_DEF is used for controlling the transmit fifo threshold. 0: indicate the txfifo threshold is 128 bytes. 1: indicate the txfifo threshold is 256 bytes. 2: indicate the txfifo threshold is 512 bytes. 3: indicate the txfifo threshold is 1024 bytes. 4: indicate that we use store and forward */ #define QPACKET_DEF (1) /* QPACKET_DEF is used for controlling the enable/disable the transmit status write back queue. 0: Disable 1: Enable (Default) */ #define VAL_PKT_LEN (0) /* VAL_PKT_LEN is used for controlling the MAC to drop 802.3 frame with invalid packet length. 0: Disable 1: Enable (Default) */ #ifndef MFREE #define MFREE(x,n) do { (n)=m_free((x)); } while (0) #endif /* * Rhine register definitions. */ #define FET_PAR0 0x00 /* node address 0 to 4 */ #define FET_PAR1 0x04 /* node address 2 to 6 */ #define FET_RXCFG 0x06 /* receiver config register */ #define FET_TXCFG 0x07 /* transmit config register */ #define FET_COMMAND 0x08 /* command register */ #define FET_ISR 0x0C /* interrupt/status register */ #define FET_IMR 0x0E /* interrupt mask register */ #define FET_MAR0 0x10 /* multicast hash 0 */ #define FET_MAR1 0x14 /* multicast hash 1 */ #define FET_MCAMD0 0x10 #define FET_MCAMD4 0x14 #define FET_VCAMD0 0x16 #define FET_RXADDR 0x18 /* rx descriptor list start addr */ #define FET_TXADDR 0x1C /* tx descriptor list start addr */ #define FET_CURRXDESC0 0x20 #define FET_CURRXDESC1 0x24 #define FET_CURRXDESC2 0x28 #define FET_CURRXDESC3 0x2C #define FET_NEXTRXDESC0 0x30 #define FET_NEXTRXDESC1 0x34 #define FET_NEXTRXDESC2 0x38 #define FET_NEXTRXDESC3 0x3C #define FET_CURTXDESC0 0x40 #define FET_CURTXDESC1 0x44 #define FET_CURTXDESC2 0x48 #define FET_CURTXDESC3 0x4C #define FET_NEXTTXDESC0 0x50 #define FET_NEXTTXDESC1 0x54 #define FET_NEXTTXDESC2 0x58 #define FET_NEXTTXDESC3 0x5C #define FET_CURRXDMA 0x60 /* current RX DMA address */ #define FET_CURTXDMA 0x64 /* current TX DMA address */ #define FET_TALLYCNT 0x68 /* tally counter test register */ #define FET_PHYADDR 0x6C #define FET_MIISR 0x6D #define FET_BCR0 0x6E #define FET_BCR1 0x6F #define FET_MIICR 0x70 #define FET_MIIADDR 0x71 #define FET_MIIDATA 0x72 #define FET_EECSR 0x74 #define FET_MACREGCSR 0x75 #define FET_GPIO 0x76 #define FET_CFGA 0x78 #define FET_CFGB 0x79 #define FET_CFGC 0x7A #define FET_CFGD 0x7B #define FET_MPA_CNT 0x7C #define FET_CRC_CNT 0x7E #define FET_Micr0 0x80 #define FET_STICKHW 0x83 #define FET_MISR 0x84 #define FET_MIMR 0x86 #define FET_CAMMSK 0x88 #define FET_CAMC 0x92 #define FET_CAMADD 0x93 #define FET_PHYANAR 0x95 /* for VT3106 */ #define FET_FlowCR0 0x98 /* for VT3106 */ #define FET_FlowCR1 0x99 /* for VT3106 */ #define FET_TxPauseTimer 0x9A #define FET_WOLCR_CLR 0xA4 #define FET_WOLCG_CLR 0xA7 #define FET_PWRCSR_CLR 0xAC /* * registers for 3065 */ #define FET_GFTEST 0x54 #define FET_RFTCMD 0x55 #define FET_TFTCMD 0x56 #define FET_GFSTATUS 0x57 #define FET_RXMISSED 0x7c #define FET_TALLYCNTCRC 0x7d #define FET_RXCRCERRS 0x7e #define FET_MISC_CR0 0x80 #define FET_MISC_CR1 0x81 #define FET_WOLCRCLR 0xA4 #define FET_WOLCGCLR 0xA7 #define FET_PWRCSRCLR 0xAC /* * RX config bits. */ #define FET_RXCFG_RX_ERRPKTS 0x01 #define FET_RXCFG_RX_RUNT 0x02 #define FET_RXCFG_RX_MULTI 0x04 #define FET_RXCFG_RX_BROAD 0x08 #define FET_RXCFG_RX_PROMISC 0x10 #define FET_RXCFG_RX_THRESH 0xE0 #define FET_RXTHRESH_32BYTES 0x00 #define FET_RXTHRESH_64BYTES 0x20 #define FET_RXTHRESH_128BYTES 0x40 #define FET_RXTHRESH_256BYTES 0x60 #define FET_RXTHRESH_512BYTES 0x80 #define FET_RXTHRESH_768BYTES 0xA0 #define FET_RXTHRESH_1024BYTES 0xC0 #define FET_RXTHRESH_STORENFWD 0xE0 /* * TX config bits. */ #define FET_TXCFG_RSVD0 0x01 #define FET_TXCFG_LB0 0x02 #define FET_TXCFG_LB1 0x04 #define FET_TXCFG_OFSET 0x08 #define FET_TXCFG_RSVD1 0x10 #define FET_TXCFG_TX_THRESH 0xE0 #define FET_TXTHRESH_128BYTES 0x00 #define FET_TXTHRESH_256BYTES 0x20 #define FET_TXTHRESH_512BYTES 0x40 #define FET_TXTHRESH_1024BYTES 0x60 #define FET_TXTHRESH_STORENFWD 0x80 /* * Command register bits. */ #define FET_CMD_INIT 0x0001 #define FET_CMD_START 0x0002 #define FET_CMD_STOP 0x0004 #define FET_CMD_RX_ON 0x0008 #define FET_CMD_TX_ON 0x0010 #define FET_CMD_TDMD 0x0020 #define FET_CMD_RDMD 0x0040 #define FET_CMD_RSVD 0x0080 #define FET_CMD_RX_EARLY 0x0100 #define FET_CMD_TX_EARLY 0x0200 #define FET_CMD_FDX 0x0400 #define FET_CMD_TX_NOPOLL 0x0800 #define FET_CMD_KEYPAG 0x1000 #define FET_CMD_TDMD1 0x2000 #define FET_CMD_RDMD1 0x4000 #define FET_CMD_RESET 0x8000 /* DaviCom PHY ID */ #define CID_DAVICOM 0x0181B800 /* OUI = 00-60-6E , 0x0181 B800 */ #define CID_DAVICOM_B 0x0181B802 /* * Interrupt status bits. */ #define FET_ISR_PRX 0x0001 /* packet rx ok */ #define FET_ISR_PTX 0x0002 /* packet tx ok */ #define FET_ISR_RXE 0x0004 /* packet rx with err */ #define FET_ISR_TXE 0x0008 /* packet tx with error */ #define FET_ISR_TU 0x0010 /* tx buffer underflow */ #define FET_ISR_RU 0x0020 /* no rx buffer available */ #define FET_ISR_BE 0x0040 /* PCI bus error */ #define FET_ISR_CNT 0x0080 /* stats counter oflow */ #define FET_ISR_ERI 0x0100 /* rx early */ #define FET_ISR_ETI 0x0200 /* tx early, for 3043/3071 */ #define FET_ISR_UDFI 0x0200 /* Tx fifo underflow event, for 3065 */ #define FET_ISR_OVFI 0x0400 /* rx FIFO overflow */ #define FET_ISR_PKTRACE 0x0800 #define FET_ISR_RX_NORBF 0x1000 #define FET_ISR_TX_ABTI 0x2000 #define FET_ISR_SRCI 0x4000 #define FET_ISR_KEYI 0x8000 /* for 3043/3071 */ #define FET_ISR_GENI 0x8000 /* for 3065 */ #define FET_MISR_TDWBRAI 0x08 /* * Interrupt mask bits. */ #define FET_IMR_PRXM 0x0001 /* packet rx ok */ #define FET_IMR_PTXM 0x0002 /* packet tx ok */ #define FET_IMR_RXEM 0x0004 /* packet rx with err */ #define FET_IMR_TXEM 0x0008 /* tx aborted due to excess colls */ #define FET_IMR_TUM 0x0010 /* tx buffer underflow */ #define FET_IMR_RUM 0x0020 /* no rx buffer available */ #define FET_IMR_BEM 0x0040 /* PCI bus error */ #define FET_IMR_CNTM 0x0080 /* stats counter oflow */ #define FET_IMR_ERM 0x0100 /* rx early */ #define FET_IMR_ETM 0x0200 /* MII status change */ #define FET_ISR_UDFM 0x0200 /* Tx fifo underflow event, for 3065 */ #define FET_IMR_OVFM 0x0400 /* rx FIFO overflow */ #define FET_IMR_PRAIM 0x0800 #define FET_IMR_NBFM 0x1000 #define FET_IMR_ABTM 0x2000 #define FET_IMR_SRCM 0x4000 #define FET_IMR_KEYIM 0x8000 #define FET_ISR_GENIM 0x8000 /* for 3065 */ #define FET_MIMR_TDWBRAI 0x08 /* define imrshadow */ #define IMRShadow 0x620F #define MIMRShadow 0x08 /* * MII status register. */ #define FET_MIISR_SPEED 0x01 #define FET_MIISR_LNKFL 0x02 #define FET_MIISR_MGTREADERR 0x04 #define FET_MIISR_MIIERR 0x08 #define FET_MIISR_PHYOPT 0x10 #define FET_MIISR_MDC_SPEED 0x20 #define FET_MIISR_RSVD 0x40 #define FET_MIISR_GPIO1POLL 0x80 /* * MII CSR offset (0x71) register bits. */ #define FET_MIIADDR_MIDLE 0x80 #define FET_MIIADDR_MSRCEN 0x40 #define FET_MIIADDR_MDONE 0x20 #define FET_MIIADDR_MAD4 0x10 #define FET_MIIADDR_MAD3 0x08 #define FET_MIIADDR_MAD2 0x04 #define FET_MIIADDR_MAD1 0x02 #define FET_MIIADDR_MAD0 0x01 /* * MII command register bits. */ #define FET_MIICR_CLK 0x01 #define FET_MIICR_DATAOUT 0x02 #define FET_MIICR_DATAIN 0x04 #define FET_MIICR_DIR 0x08 #define FET_MIICR_DIRECTPGM 0x10 #define FET_MIICR_WCMD 0x20 #define FET_MIICR_RCMD 0x40 #define FET_MIICR_MAUTO 0x80 /* * EEPROM control bits. */ #define FET_EECSR_DATAIN 0x01 /* data out */ #define FET_EECSR_DATAOUT 0x02 /* data in */ #define FET_EECSR_CLK 0x04 /* clock */ #define FET_EECSR_CS 0x08 /* chip select */ #define FET_EECSR_DPM 0x10 #define FET_EECSR_LOAD 0x20 #define FET_EECSR_EMBP 0x40 #define FET_EECSR_EEPR 0x80 #define FET_EECMD_WRITE 0x140 #define FET_EECMD_READ 0x180 #define FET_EECMD_ERASE 0x1c0 /* * Bits in the BCR0 register */ #define FET_BCR0_MED2 0x80 #define FET_BCR0_LED100M 0x40 #define FET_BCR0_CRFT2 0x20 #define FET_BCR0_CRFT1 0x10 #define FET_BCR0_CRFT0 0x08 #define FET_BCR0_DMAL2 0x04 #define FET_BCR0_DMAL1 0x02 #define FET_BCR0_DMAL0 0x01 /* * Bits in the BCR1 register */ #define FET_BCR1_MED1 0x80 #define FET_BCR1_MED0 0x40 #define FET_BCR1_CTSF 0x20 #define FET_BCR1_CTFT1 0x10 #define FET_BCR1_CTFT0 0x08 #define FET_BCR1_POT2 0x04 #define FET_BCR1_POT1 0x02 #define FET_BCR1_POT0 0x01 /* * Bits in the CFGB register */ #define FET_CFGB_QPKTDIS 0x80 #define FET_CFGB_MRLDIS 0x20 /* * CFGC control bits. */ #define FET_CFGC_MEDEN 0x80 #define FET_CFGC_BROPT 0x40 #define FET_CFGC_DLYEN 0x20 #define FET_CFGC_DTSEL 0x10 #define FET_CFGC_BTSEL 0x08 #define FET_CFGC_BPS2 0x04 #define FET_CFGC_BPS1 0x02 #define FET_CFGC_BPS0 0x01 /* * CFGD control bits. */ #define FET_CFGD_GPIOEN 0x80 #define FET_CFGD_DIAG 0x40 #define FET_CFGD_MRDLEN 0x20 #define FET_CFGD_MAGIC 0x10 #define FET_CFGD_CRADOM 0x08 #define FET_CFGD_CAP 0x04 #define FET_CFGD_MBA 0x02 #define FET_CFGD_BAKOPT 0x01 /* * Test register bits. */ #define FET_TEST_TEST0 0x01 #define FET_TEST_TEST1 0x02 #define FET_TEST_TEST2 0x04 #define FET_TEST_TSTUD 0x08 #define FET_TEST_TSTOV 0x10 #define FET_TEST_BKOFF 0x20 #define FET_TEST_FCOL 0x40 #define FET_TEST_HBDES 0x80 /* * Config register bits. */ #define FET_CFG_GPIO2OUTENB 0x00000001 #define FET_CFG_GPIO2OUT 0x00000002 /* gen. purp. pin */ #define FET_CFG_GPIO2IN 0x00000004 /* gen. purp. pin */ #define FET_CFG_AUTOOPT 0x00000008 /* enable rx/tx autopoll */ #define FET_CFG_MIIOPT 0x00000010 #define FET_CFG_MMIENB 0x00000020 /* memory mapped mode enb */ #define FET_CFG_JUMPER 0x00000040 /* PHY and oper. mode select */ #define FET_CFG_EELOAD 0x00000080 /* enable EEPROM programming */ #define FET_CFG_LATMENB 0x00000100 /* larency timer effect enb. */ #define FET_CFG_MRREADWAIT 0x00000200 #define FET_CFG_MRWRITEWAIT 0x00000400 #define FET_CFG_RX_ARB 0x00000800 #define FET_CFG_TX_ARB 0x00001000 #define FET_CFG_READMULTI 0x00002000 #define FET_CFG_TX_PACE 0x00004000 #define FET_CFG_TX_QDIS 0x00008000 #define FET_CFG_ROMSEL0 0x00010000 #define FET_CFG_ROMSEL1 0x00020000 #define FET_CFG_ROMSEL2 0x00040000 #define FET_CFG_ROMTIMESEL 0x00080000 #define FET_CFG_RSVD0 0x00100000 #define FET_CFG_ROMDLY 0x00200000 #define FET_CFG_ROMOPT 0x00400000 #define FET_CFG_RSVD1 0x00800000 #define FET_CFG_BACKOFFOPT 0x01000000 #define FET_CFG_BACKOFFMOD 0x02000000 #define FET_CFG_CAPEFFECT 0x04000000 #define FET_CFG_BACKOFFRAND 0x08000000 #define FET_CFG_MAGICKPACKET 0x10000000 #define FET_CFG_PCIREADLINE 0x20000000 #define FET_CFG_DIAG 0x40000000 #define FET_CFG_GPIOEN 0x80000000 /* MISC.CR1 register bits */ #define FET_MISCCR1_FORSRST 0x40 #define FET_MISCCR1_VAUXJMP 0x20 #define FET_MISCCR1_PHYINT 0x02 #define FET_MISCCR1_TIMER1_EN 0x01 /* MISC definitions */ #define W_MAX_TIMEOUT 0x0FFFU #define FET_TIMEOUT 1000 #define ETHER_ALIGN 2 /* * Rhine TX/RX list structure. */ struct fet_desc { u_int32_t fet_status; u_int32_t fet_ctl; u_int32_t fet_ptr1; u_int32_t fet_ptr2; }; #define fet_data fet_ptr1 #define fet_next fet_ptr2 #define FET_RXSTAT_RXERR 0x00000001 #define FET_RXSTAT_CRCERR 0x00000002 #define FET_RXSTAT_FRAMEALIGNERR 0x00000004 #define FET_RXSTAT_FIFOOFLOW 0x00000008 #define FET_RXSTAT_GIANT 0x00000010 #define FET_RXSTAT_RUNT 0x00000020 #define FET_RXSTAT_BUSERR 0x00000040 #define FET_RXSTAT_BUFFERR 0x00000080 #define FET_RXSTAT_LASTFRAG 0x00000100 #define FET_RXSTAT_FIRSTFRAG 0x00000200 #define FET_RXSTAT_RLINK 0x00000400 #define FET_RXSTAT_RX_PHYS 0x00000800 #define FET_RXSTAT_RX_BROAD 0x00001000 #define FET_RXSTAT_RX_MULTI 0x00002000 #define FET_RXSTAT_RX_OK 0x00004000 #define FET_RXSTAT_RXLEN 0x07FF0000 #define FET_RXSTAT_RXLEN_EXT 0x78000000 #define FET_RXSTAT_OWN 0x80000000 #define FET_RXBYTES(x) ((x & FET_RXSTAT_RXLEN) >> 16) #define FET_RXSTAT (FET_RXSTAT_FIRSTFRAG|FET_RXSTAT_LASTFRAG|FET_RXSTAT_OWN) #define FET_RXCTL_BUFLEN 0x00000800 #define FET_RXCTL_BUFLEN_EXT 0x00007800 #define FET_RXCTL_CHAIN 0x00008000 #define FET_RXCTL_RX_INTR 0x00800000 #define FET_RXCTL (FET_RXCTL_CHAIN|FET_RXCTL_BUFLEN) #define FET_RXCTL_TAG 0x00010000 #define FET_TXSTAT_DEFER 0x00000001 #define FET_TXSTAT_COLLCNT 0x0000000F #define FET_TXSTAT_AQE 0x00000080 #define FET_TXSTAT_ABT 0x00000100 #define FET_TXSTAT_LATECOLL 0x00000200 #define FET_TXSTAT_CRS 0x00000400 #define FET_TXSTAT_UDF 0x00000800 #define FET_TXSTAT_TBUFF 0x00001000 #define FET_TXSTAT_SERR 0x00002000 #define FET_TXSTAT_JABTIMEO 0x00004000 #define FET_TXSTAT_ERRSUM 0x00008000 #define FET_TXSTAT_OWN 0x80000000 #define FET_TXCTL_BUFLEN 0x00000800 #define FET_TXCTL_BUFLEN_EXT 0x00007800 #define FET_TXCTL_TLINK 0x00008000 #define FET_TXCTL_FIRSTFRAG 0x00200000 #define FET_TXCTL_LASTFRAG 0x00400000 #define FET_TXCTL_FINT 0x00800000 #define FET_MAXFRAGS 16 #define FET_RX_LIST_CNT 64 #define FET_TX_LIST_CNT 128 #define FET_MIN_FRAMELEN 60 #define FET_FRAMELEN 1536 #define FET_RXLEN 1520 #define MAX_PACKET_LEN 1514 #define U_CRC_LEN 4 #define U_HEADER_LEN 14 #define FET_TXOWN(x) x->fet_ptr->fet_status struct fet_list_data { struct fet_desc fet_rx_list[FET_RX_LIST_CNT]; struct fet_desc fet_tx_list[FET_TX_LIST_CNT]; }; struct fet_chain { struct fet_desc *fet_ptr; struct mbuf *fet_mbuf; struct fet_chain *fet_nextdesc; }; struct fet_chain_onefrag { struct fet_desc *fet_ptr; struct mbuf *fet_mbuf; struct fet_chain_onefrag *fet_nextdesc; }; struct fet_chain_data { struct fet_chain_onefrag fet_rx_chain[FET_RX_LIST_CNT]; struct fet_chain fet_tx_chain[FET_TX_LIST_CNT]; struct fet_chain_onefrag *fet_rx_head; struct fet_chain *fet_tx_head; struct fet_chain *fet_tx_tail; struct fet_chain *fet_tx_free; u_int16_t fet_free_tx_count; }; struct fet_type { u_int16_t fet_vid; u_int16_t fet_did; char *fet_name; }; struct fet_mii_frame { u_int8_t mii_stdelim; u_int8_t mii_opcode; u_int8_t mii_phyaddr; u_int8_t mii_regaddr; u_int8_t mii_turnaround; u_int16_t mii_data; }; /* * MII constants */ #define FET_MII_STARTDELIM 0x01 #define FET_MII_READOP 0x02 #define FET_MII_WRITEOP 0x01 #define FET_MII_TURNAROUND 0x02 #define FET_FLAG_FORCEDELAY 1 #define FET_FLAG_SCHEDDELAY 2 #define FET_FLAG_DELAYTIMEO 3 /* mode supported */ typedef enum { FET_AUTO, FET_100_FDX, FET_100_HDX, FET_10_FDX, FET_10_HDX } fet_modeinfo_t; /* Supported media types. */ const int fet_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, }; /* * revision id */ #define REV_ID_VT3043_E 0x04 #define REV_ID_VT3071_A 0x20 #define REV_ID_VT3071_B 0x21 #define REV_ID_VT3065_A 0x40 #define REV_ID_VT3065_B 0x41 #define REV_ID_VT3065_C 0x42 #define REV_ID_VT3106 0x80 #define REV_ID_VT3106_J 0x80 /* 0x80-0x8F */ #define REV_ID_VT3106_S 0x90 /* 0x90-0xA0 */ #if __FreeBSD_version >= 400000 struct fet_softc { struct arpcom arpcom; /* interface info */ bus_space_handle_t fet_bhandle; /* bus space handle */ bus_space_tag_t fet_btag; /* bus space tag */ struct resource *fet_res1; struct resource *fet_res2; struct resource *fet_irq; void *fet_intrhand; struct fet_type *fet_info; /* Rhine adapter info */ u_int8_t fet_unit; /* interface number */ u_int8_t fet_type; u_int8_t fet_autoneg; /* media configuration 1:auto, 0:force*/ u_int8_t fet_full_duplex; /* 1: full duplex, 0:half duplex*/ u_int8_t fet_speed; u_int8_t fet_NWAY_Force; /* 1: do nway_force , 0: not nway_force*/ u_int8_t fet_FlowControl;/* 1: hardware default, 2: disable PAUSE in ANAR, 3: enable PAUSE in ANAR.*/ u_int8_t fet_chip_revid; /* revision of chip */ u_int8_t fet_set_meden; /* set MEDEN bit in CFGC */ fet_modeinfo_t fet_modeinfo; /* type of mode */ struct ifmedia ifmedia; /* media info */ struct fet_list_data *fet_ldata; struct fet_chain_data fet_cdata; struct callout_handle fet_stat_ch; int tx_thresh; int rx_thresh; }; #elif __FreeBSD_version < 400000 struct fet_softc { struct arpcom arpcom; /* interface info */ struct ifmedia ifmedia; /* media info */ bus_space_handle_t fet_bhandle; /* bus space handle */ bus_space_tag_t fet_btag; /* bus space tag */ struct fet_type *fet_info; /* Rhine adapter info */ struct fet_type *fet_pinfo; /* phy info */ u_int8_t fet_unit; /* interface number */ u_int8_t fet_type; u_int8_t fet_phy_addr; /* PHY address */ u_int8_t fet_tx_pend; /* TX pending */ u_int8_t fet_want_auto; u_int8_t fet_autoneg; /* media configuration 1:auto 0:force*/ u_int8_t fet_full_duplex; u_int8_t fet_speed; u_int8_t fet_NWAY_Force; /* 1: do nway_force , 0: not nway_force*/ u_int8_t fet_FlowControl;/* 1: hardware default. 2: disable PAUSE in ANAR. 3: enable PAUSE in ANAR.*/ u_int8_t fet_chip_revid; /* revision of chip */ u_int8_t fet_set_meden; /* set MEDEN bit in CFGC */ fet_modeinfo_t fet_modeinfo; /* type of mode */ caddr_t fet_ldata_ptr; struct fet_list_data *fet_ldata; struct fet_chain_data fet_cdata; int tx_thresh; int rx_thresh; }; #endif /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->fet_btag, sc->fet_bhandle, reg, val) #define CSR_WRITE_2(sc, reg, val) \ bus_space_write_2(sc->fet_btag, sc->fet_bhandle, reg, val) #define CSR_WRITE_1(sc, reg, val) \ bus_space_write_1(sc->fet_btag, sc->fet_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->fet_btag, sc->fet_bhandle, reg) #define CSR_READ_2(sc, reg) \ bus_space_read_2(sc->fet_btag, sc->fet_bhandle, reg) #define CSR_READ_1(sc, reg) \ bus_space_read_1(sc->fet_btag, sc->fet_bhandle, reg) /* * General constants that are fun to know. * * vendor ID */ #define VENDORID 0x1106 /* * device IDs. */ #define DEVICEID_3043 0x3043 #define DEVICEID_3065 0x3065 #define DEVICEID_3106 0x3106 #define DEVICEID_3053 0x3053 /* * PCI low memory base and low I/O base register, and * other PCI registers. */ #define FET_PCI_VENDOR_ID 0x00 #define FET_PCI_DEVICE_ID 0x02 #define FET_PCI_COMMAND 0x04 #define FET_PCI_STATUS 0x06 #define FET_PCI_REVID 0x08 #define FET_PCI_CLASSCODE 0x09 #define FET_PCI_LATENCY_TIMER 0x0D #define FET_PCI_HEADER_TYPE 0x0E #define FET_PCI_LOIO 0x10 #define FET_PCI_LOMEM 0x14 #define FET_PCI_BIOSROM 0x30 #define FET_PCI_INTLINE 0x3C #define FET_PCI_INTPIN 0x3D #define FET_PCI_MINGNT 0x3E #define FET_PCI_MINLAT 0x0F #define FET_PCI_RESETOPT 0x48 #define FET_PCI_EEPROM_DATA 0x4C #define FET_PCI_MODE 0x50 #define PCI_VENDORID(x) ((x) & 0xFFFF) #define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF) #define FET_MODE3_MIION 0x04 /* power management registers */ #define FET_PCI_CAPID 0xDC /* 8 bits */ #define FET_PCI_NEXTPTR 0xDD /* 8 bits */ #define FET_PCI_PWRMGMTCAP 0xDE /* 16 bits */ #define FET_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */ #define FET_PSTATE_MASK 0x0003 #define FET_PSTATE_D0 0x0000 #define FET_PSTATE_D1 0x0002 #define FET_PSTATE_D2 0x0002 #define FET_PSTATE_D3 0x0003 #define FET_PME_EN 0x0010 #define FET_PME_STATUS 0x8000 #define PHY_UNKNOWN 6 #define FET_PHYADDR_MIN 0x00 #define FET_PHYADDR_MAX 0x1F #define PHY_BMCR 0x00 #define PHY_BMSR 0x01 #define PHY_PHYID1 0x02 #define PHY_PHYID2 0x03 #define PHY_ANAR 0x04 #define PHY_LPAR 0x05 #define PHY_ANEXP 0x06 #define PHY_ANAR_NEXTPAGE 0x8000 #define PHY_ANAR_RSVD0 0x4000 #define PHY_ANAR_TLRFLT 0x2000 #define PHY_ANAR_RSVD1 0x1000 #define PHY_ANAR_RSVD2 0x0800 #define PHY_ANAR_RSVD3 0x0400 #define PHY_ANAR_100BT4 0x0200 #define PHY_ANAR_100BTXFULL 0x0100 #define PHY_ANAR_100BTXHALF 0x0080 #define PHY_ANAR_10BTFULL 0x0040 #define PHY_ANAR_10BTHALF 0x0020 #define PHY_ANAR_PROTO4 0x0010 #define PHY_ANAR_PROTO3 0x0008 #define PHY_ANAR_PROTO2 0x0004 #define PHY_ANAR_PROTO1 0x0002 #define PHY_ANAR_PROTO0 0x0001 #define PHY_LPAR_NEXTPAGE 0x8000 #define PHY_LPAR_RSVD0 0x4000 #define PHY_LPAR_TLRFLT 0x2000 #define PHY_LPAR_RSVD1 0x1000 #define PHY_LPAR_RSVD2 0x0800 #define PHY_LPAR_RSVD3 0x0400 #define PHY_LPAR_100BT4 0x0200 #define PHY_LPAR_100BTXFULL 0x0100 #define PHY_LPAR_100BTXHALF 0x0080 #define PHY_LPAR_10BTFULL 0x0040 #define PHY_LPAR_10BTHALF 0x0020 #define PHY_LPAR_PROTO4 0x0010 #define PHY_LPAR_PROTO3 0x0008 #define PHY_LPAR_PROTO2 0x0004 #define PHY_LPAR_PROTO1 0x0002 #define PHY_LPAR_PROTO0 0x0001 #define PHY_ANEXP_LPAUTOABLE 0x0001 /* * These are the register definitions for the PHY (physical layer * interface chip). */ /* * PHY BMCR Basic Mode Control Register */ #define PHY_BMCR_RESET 0x8000 #define PHY_BMCR_LOOPBK 0x4000 #define PHY_BMCR_SPEEDSEL 0x2000 #define PHY_BMCR_AUTONEGENBL 0x1000 #define PHY_BMCR_RSVD0 0x0800 /* write as zero */ #define PHY_BMCR_ISOLATE 0x0400 #define PHY_BMCR_AUTONEGRSTR 0x0200 #define PHY_BMCR_DUPLEX 0x0100 #define PHY_BMCR_COLLTEST 0x0080 #define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ #define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ #define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ #define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ #define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ #define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ #define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ /* * RESET: 1 == software reset, 0 == normal operation * Resets status and control registers to default values. * Relatches all hardware config values. * * LOOPBK: 1 == loopback operation enabled, 0 == normal operation * * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s * Link speed is selected byt his bit or if auto-negotiation if bit * 12 (AUTONEGENBL) is set (in which case the value of this register * is ignored). * * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 * determine speed and mode. Should be cleared and then set if PHY configured * for no autoneg on startup. * * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation * * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation * * DUPLEX: 1 == full duplex mode, 0 == half duplex mode * * COLLTEST: 1 == collision test enabled, 0 == normal operation */ /* * PHY, BMSR Basic Mode Status Register */ #define PHY_BMSR_100BT4 0x8000 #define PHY_BMSR_100BTXFULL 0x4000 #define PHY_BMSR_100BTXHALF 0x2000 #define PHY_BMSR_10BTFULL 0x1000 #define PHY_BMSR_10BTHALF 0x0800 #define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ #define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ #define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ #define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ #define PHY_BMSR_MFPRESUP 0x0040 #define PHY_BMSR_AUTONEGCOMP 0x0020 #define PHY_BMSR_REMFAULT 0x0010 #define PHY_BMSR_CANAUTONEG 0x0008 #define PHY_BMSR_LINKSTAT 0x0004 #define PHY_BMSR_JABBER 0x0002 #define PHY_BMSR_EXTENDED 0x0001 #ifdef __alpha__ #undef vtophys #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va) #endif /* for CAM Controller */ #define CAMC_CAMEN 0x01 #define CAMC_VCAMSL 0x02 #define CAMC_SELECT_MCAM 0x00 #define CAMC_SELECT_VCAM 0x01 #define CAMC_CAMRD 0x08 #define CAMC_CAMWR 0x04 /* for VLAN tagging */ #define BCR1_VIDFR_DIS 0x7F /* Bits in the MIISR register */ #define MIISR_MIIERR 0x08 #define MIISR_MRERR 0x04 #define MIISR_LNKFL 0x02 #define MIISR_SPEED 0x01 /* define 3106J and 3106S Adapter Name*/ #define DeviceName3106J "EtherFast 10/100 Managed Network Adapter" #define DeviceName3106S "EtherFast 10/100 Managed Network Adapter" #endif
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6580000.1060789830>
