Skip site navigation (1)Skip section navigation (2)
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>