Hi,

kind of embarassing, but i guess i originally went w/what was enough to
get booting/building over eth, and i blindly followed freebsd driver
more than i should of - as it is clearly nothing but copypaste with
even comments included from linux.. yep.

so sxie has these bugs like trying to flush via rx filter control register
etc., just like every other driver(free,net,linux) i've seen for allwinner
emac still do.
mostly fixed in the diff below, that is huge, i know, but anyone is free
to pick what they want, if anything. :)

i used UM10326.pdf by NXP for ie. the _softreset() below, more specifically
"Chapter 14: LPC32x0 Ethernet Media Access Controller (MAC)".
freebsd has driver for it too, but the "scatter gather dma engines" in it
were different enough to what exists for sun4i emac, so i gave up trying to
fit the pieces before getting hands dirty.

-Artturi


diff --git a/sys/arch/armv7/sunxi/sxie.c b/sys/arch/armv7/sunxi/sxie.c
index 116fda5f8d7..e428425d7f8 100644
--- a/sys/arch/armv7/sunxi/sxie.c
+++ b/sys/arch/armv7/sunxi/sxie.c
@@ -51,105 +51,182 @@
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_clock.h>
 #include <dev/ofw/ofw_pinctrl.h>
+#include <dev/ofw/ofw_regulator.h>
+#include <dev/ofw/ofw_misc.h>
 #include <dev/ofw/fdt.h>
 
-/* configuration registers */
-#define        SXIE_CR                 0x0000
+#if defined(DEBUG) || defined(DIAGNOSTIC)
+#define        SXIE_CD         (ifp->if_flags & IFF_DEBUG)
+#define        SXIEDBG(x)      do { if (SXIE_CD) printf((x)); } while (0)
+#else
+#define        SXIE_CD         (0)
+#define        SXIEDBG(x)      do { } while (0)
+#endif
+
+/* control registers */
+#define        SXIE_CMDR               0x0000
 #define        SXIE_TXMODE             0x0004
-#define        SXIE_TXFLOW             0x0008
+#define        SXIE_TXFLOW             0x0008  /* unused */
 #define        SXIE_TXCR0              0x000c
 #define        SXIE_TXCR1              0x0010
 #define        SXIE_TXINS              0x0014
+/*
+ * XXX was wondering, what if these TXPKTLEN registers
+ * are actually part of memory mapped tx 'fake' descriptors,
+ * something like w/DMA but only via register map or something?
+ * should add some dbg and try to figure out:)
+ */
 #define        SXIE_TXPKTLEN0          0x0018
 #define        SXIE_TXPKTLEN1          0x001c
-#define        SXIE_TXSR               0x0020
+#define        SXIE_TXSR               0x0020  /* unused */
 #define        SXIE_TXIO0              0x0024
-#define        SXIE_TXIO1              0x0028
-#define        SXIE_TXTSVL0            0x002c
-#define        SXIE_TXTSVH0            0x0030
-#define        SXIE_TXTSVL1            0x0034
-#define        SXIE_TXTSVH1            0x0038
-#define        SXIE_RXCR               0x003c
+#define        SXIE_TXIO1              0x0028  /* unused */
+#define        SXIE_TXTSVL0            0x002c  /* unused */
+#define        SXIE_TXTSVH0            0x0030  /* unused */
+#define        SXIE_TXTSVL1            0x0034  /* unused */
+#define        SXIE_TXTSVH1            0x0038  /* unused */
+
+/* receive filter registers */
+#define        SXIE_RXFILTER_CTRL      0x003c
 #define        SXIE_RXHASH0            0x0040
 #define        SXIE_RXHASH1            0x0044
-#define        SXIE_RXSR               0x0048
-#define        SXIE_RXIO               0x004C
+
+/* dunno.. */
+#define        SXIE_RXSR               0x0048  /* unused */
+#define        SXIE_RXIO               0x004c
 #define        SXIE_RXFBC              0x0050
+
+/* module control registers */
 #define        SXIE_INTCR              0x0054
 #define        SXIE_INTSR              0x0058
-#define        SXIE_MACCR0             0x005C
-#define        SXIE_MACCR1             0x0060
-#define        SXIE_MACIPGT            0x0064
-#define        SXIE_MACIPGR            0x0068
-#define        SXIE_MACCLRT            0x006C
-#define        SXIE_MACMFL             0x0070
-#define        SXIE_MACSUPP            0x0074
-#define        SXIE_MACTEST            0x0078
-#define        SXIE_MACMCFG            0x007C
-#define        SXIE_MACMCMD            0x0080
-#define        SXIE_MACMADR            0x0084
-#define        SXIE_MACMWTD            0x0088
-#define        SXIE_MACMRDD            0x008C
-#define        SXIE_MACMIND            0x0090
-#define        SXIE_MACSSRR            0x0094
-#define        SXIE_MACA0              0x0098
-#define        SXIE_MACA1              0x009c
-#define        SXIE_MACA2              0x00a0
+
+/* ethernet MAC registers */
+#define        SXIE_MAC0               0x005c
+#define        SXIE_MAC1               0x0060
+#define        SXIE_MAC_IPGT           0x0064
+#define        SXIE_MAC_IPGR           0x0068
+#define        SXIE_MAC_CLRT           0x006c
+#define        SXIE_MAC_MAXF           0x0070
+#define        SXIE_MAC_SUPP           0x0074
+#define        SXIE_MAC_TEST           0x0078  /* unused */
+#define        SXIE_MAC_MCFG           0x007c
+#define        SXIE_MAC_MCMD           0x0080
+#define        SXIE_MAC_MADR           0x0084
+#define        SXIE_MAC_MWTD           0x0088
+#define        SXIE_MAC_MRDD           0x008c
+#define        SXIE_MAC_MIND           0x0090
+#define        SXIE_MACSSRR            0x0094  /* unused */
+#define        SXIE_MAC_SA0            0x0098
+#define        SXIE_MAC_SA1            0x009c
+#define        SXIE_MACA2              0x00a0  /* unused */
 
 /* i once spent hours on pretty defines, cvs up ate 'em. these shall do */
-#define SXIE_INTR_ENABLE               0x010f
+#define SXIE_INTR_ENABLE       0x010f
 #define SXIE_INTR_DISABLE      0x0000
 #define SXIE_INTR_CLEAR                0x0000
 
-#define SXIE_TX_FIFO0          0x0001
-#define SXIE_TX_FIFO1          0x0002
-
 #define        SXIE_RX_ENABLE          0x0004
 #define        SXIE_TX_ENABLE          0x0003
-#define        SXIE_RXTX_ENABLE                0x0007
+#define        SXIE_RXTX_ENABLE        0x0007
 
 #define        SXIE_RXDRQM             0x0002
 #define        SXIE_RXTM               0x0004
-#define        SXIE_RXFLUSH            0x0008
-#define        SXIE_RXPA               0x0010
-#define        SXIE_RXPCF              0x0020
-#define        SXIE_RXPCRCE            0x0040
-#define        SXIE_RXPLE              0x0080
-#define        SXIE_RXPOR              0x0100
-#define        SXIE_RXUCAD             0x10000
-#define        SXIE_RXDAF              0x20000
-#define        SXIE_RXMCO              0x100000
-#define        SXIE_RXMHF              0x200000
-#define        SXIE_RXBCO              0x400000
-#define        SXIE_RXSAF              0x1000000
-#define        SXIE_RXSAIF             0x2000000
-
-#define        SXIE_MACRXFC            0x0004
-#define        SXIE_MACTXFC            0x0008
-#define SXIE_MACSOFTRESET      0x8000
-
-#define        SXIE_MACDUPLEX          0x0001  /* full = 1 */
-#define        SXIE_MACFLC             0x0002
-#define        SXIE_MACHF              0x0004
-#define        SXIE_MACDCRC            0x0008
-#define        SXIE_MACCRC             0x0010
-#define        SXIE_MACPC              0x0020
-#define        SXIE_MACVC              0x0040
-#define        SXIE_MACADP             0x0080
-#define        SXIE_MACPRE             0x0100
-#define        SXIE_MACLPE             0x0200
-#define        SXIE_MACNB              0x1000
-#define        SXIE_MACBNB             0x2000
-#define        SXIE_MACED              0x4000
-
-#define        SXIE_RX_ERRLENOOR       0x0040
-#define        SXIE_RX_ERRLENCHK       0x0020
-#define        SXIE_RX_ERRCRC          0x0010
-#define        SXIE_RX_ERRRCV          0x0008 /* XXX receive code violation ? 
*/
+
+                                       /* 0x00 */
+#define        SXIE_CMDR_RXENABLE              (1 << 0)
+#define        SXIE_CMDR_TXENABLE              (1 << 1)
+#define        SXIE_CMDR_REGRESET              (1 << 3)
+#define        SXIE_CMDR_TXRESET               (1 << 4)
+#define        SXIE_CMDR_RXRESET               (1 << 5)
+#define        SXIE_CMDR_PASSRUNTFRAME         (1 << 6)
+#define        SXIE_CMDR_PASSRXFILTER          (1 << 7)
+#define        SXIE_CMDR_TXFLOWCTL             (1 << 8)
+#define        SXIE_CMDR_RMII                  (1 << 9)
+#define        SXIE_CMDR_FULLDUPLEX            (1 << 10)
+
+                                       /* 0x3c */
+#define        SXIE_RXFILTER_PROMISC           (1 << 4)
+#define        SXIE_RXFILTER_CONTROLFRAMES     (1 << 5)
+#define        SXIE_RXFILTER_FRAMECRCERR       (1 << 6)
+#define        SXIE_RXFILTER_FRAMELENERR       (1 << 7)
+#define        SXIE_RXFILTER_FRAMELENOOR       (1 << 8)
+#define        SXIE_RXFILTER_UNICAST           (1 << 16)
+#define        SXIE_RXFILTER_DAFILTER          (1 << 17)
+#define SXIE_RXFILTER_MULTICAST                (1 << 20)
+#define        SXIE_RXFILTER_MHASHFILTER       (1 << 21)
+#define        SXIE_RXFILTER_BROADCAST         (1 << 22)
+#define        SXIE_RXFILTER_SAFILTER          (1 << 24)
+#define        SXIE_RXFILTER_SAINVFILTER       (1 << 25)
+
+                                       /* 0x5c */
+#define        SXIE_MAC0_RXENABLE              (1 << 0)
+#define        SXIE_MAC0_PASSALL               (1 << 1)
+#define        SXIE_MAC0_RXFLOWCTRL            (1 << 2)
+#define        SXIE_MAC0_TXFLOWCTRL            (1 << 3)
+#define        SXIE_MAC0_LOOPBACK              (1 << 4)
+#define        SXIE_MAC0_RESETTX               (1 << 8)
+#define        SXIE_MAC0_RESETMCSTX            (1 << 9)
+#define        SXIE_MAC0_RESETRX               (1 << 10)
+#define        SXIE_MAC0_RESETMCSRX            (1 << 11)
+#define        SXIE_MAC0_SOFTRESET             (1 << 15)
+                                       /* 0x60 */
+#define        SXIE_MAC1_FULLDUPLEX            (1 << 0)
+#define        SXIE_MAC1_FRAMELENCHECK         (1 << 1)
+#define        SXIE_MAC1_HUGEFRAME             (1 << 2)
+#define        SXIE_MAC1_DELAYEDCRC            (1 << 3)
+#define        SXIE_MAC1_CRC                   (1 << 4)
+#define        SXIE_MAC1_PADCRC                (1 << 5)
+#define        SXIE_MAC1_VLANPAD               (1 << 6)
+#define        SXIE_MAC1_AUTOPAD               (1 << 7)
+#define        SXIE_MAC1_PUREPREAMBLE          (1 << 8)
+#define        SXIE_MAC1_LONGPREAMBLE          (1 << 9)
+#define        SXIE_MAC1_NOBACKOFF             (1 << 12)
+#define        SXIE_MAC1_BACKPRESSURE          (1 << 13)
+#define        SXIE_MAC1_EXCESSDEFER           (1 << 14)
+                                       /* 0x64 */
+#define        SXIE_MAC_BTB_IPG(x)             ((x) & 0x7f)
+                                       /* 0x68 */
+#define        SXIE_MAC_NBTB_IGP_P2(x)         ((x) & 0x7f)
+#define        SXIE_MAC_NBTB_IGP_P1(x)         (((x) & 0x7f) << 8)
+                                       /* 0x6c */
+#define        SXIE_MAC_CLRT_RETRANSMAX        0x0f
+#define        SXIE_MAC_CLRT_COLLWIND(x)       (((x) & 0x3f) << 8)
+                                       /* 0x70 */
+#define        SXIE_MAC_MAXF_MAXFRAMELENMASK   0xffff
+                                       /* 0x74 */
+#define        SXIE_MAC_SUPP_SPEED             (1 << 8)
+                                       /* 0x78 */
+#define        SXIE_MAC_TEST_SHORTCPAUSEQUANTA (1 << 0)
+#define        SXIE_MAC_TEST_TESTPAUSE         (1 << 1)
+#define        SXIE_MAC_TEST_TESTBACKPRESSURE  (1 << 2)
+                                       /* 0x7c */
+#define        SXIE_MAC_MCFG_SCANINCR          (1 << 0)
+#define        SXIE_MAC_MCFG_SUPPREAMBLE       (1 << 1)
+#define        SXIE_MAC_MCFG_CLKSEL(_n)        (((_n) & 0xf) << 2)
+#define        SXIE_MAC_MCFG_RESET_MII         (1 << 15)
+                                       /* 0x80 */
+#define        SXIE_MAC_MCMD_READ              (1 << 0)
+#define        SXIE_MAC_MCMD_WRITE             (0 << 0)
+#define        SXIE_MAC_MCMD_SCAN              (1 << 1)
+                                       /* 0x90 */
+#define        SXIE_MAC_MIND_BUSY              (1 << 0)
+#define        SXIE_MAC_MIND_SCANNING          (1 << 1)
+#define        SXIE_MAC_MIND_INVALID           (1 << 2)
+#define        SXIE_MAC_MIND_MIIFAIL           (1 << 3)
+
+#define        SXIE_TX_FIFO0           0x0001
+#define        SXIE_TX_FIFO1           0x0002
+#define        SXIE_TX_FIFOS           (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)
+
+#define        SXIE_SRST_RX    (1 << 0)
+#define        SXIE_SRST_TX    (1 << 1)
+#define        SXIE_SRST_FULL  (1 << 2)
+
 #define        SXIE_RX_ERRMASK         0x0070
 
 #define        SXIE_MII_TIMEOUT        100
 #define SXIE_MAX_RXD           8
+#define SXIE_MAX_TXD           2
 #define SXIE_MAX_PKT_SIZE      ETHER_MAX_DIX_LEN
 
 #define SXIE_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
@@ -158,20 +235,26 @@ struct sxie_softc {
        struct device                   sc_dev;
        struct arpcom                   sc_ac;
        struct mii_data                 sc_mii;
+       int                             sc_node;
        int                             sc_phyno;
+       int                             sc_dmanode;
        bus_space_tag_t                 sc_iot;
        bus_space_handle_t              sc_ioh;
-       bus_space_handle_t              sc_sid_ioh;
+       bus_dma_tag_t                   sc_dmat;
        void                            *sc_ih; /* Interrupt handler */
-       uint32_t                        intr_status; /* soft interrupt status */
-       uint32_t                        pauseframe;
-       uint32_t                        txf_inuse;
-};
 
-struct sxie_softc *sxie_sc;
+       struct mutex                    sc_miibus_lock;
+       struct timeout                  sc_tick;
+
+       uint32_t                        sc_pauseframe;
+       uint32_t                        sc_tx_timer;
+       uint32_t                        sc_tx_inuse;
+};
 
 int    sxie_match(struct device *, void *, void *);
 void   sxie_attach(struct device *, struct device *, void *);
+void   sxie_get_lladdr(struct sxie_softc *);
+void   sxie_set_lladdr(struct sxie_softc *);
 void   sxie_setup_interface(struct sxie_softc *, struct device *);
 void   sxie_socware_init(struct sxie_softc *);
 int    sxie_ioctl(struct ifnet *, u_long, caddr_t);
@@ -180,7 +263,7 @@ void        sxie_watchdog(struct ifnet *);
 void   sxie_init(struct sxie_softc *);
 void   sxie_stop(struct sxie_softc *);
 void   sxie_reset(struct sxie_softc *);
-void   sxie_iff(struct sxie_softc *, struct ifnet *);
+void   sxie_iff(struct sxie_softc *);
 int    sxie_intr(void *);
 void   sxie_recv(struct sxie_softc *);
 int    sxie_miibus_readreg(struct device *, int, int);
@@ -188,6 +271,10 @@ void       sxie_miibus_writereg(struct device *, int, int, 
int);
 void   sxie_miibus_statchg(struct device *);
 int    sxie_ifm_change(struct ifnet *);
 void   sxie_ifm_status(struct ifnet *, struct ifmediareq *);
+void   sxie_tick(void *);
+
+static inline void
+       sxie_softreset(struct sxie_softc *, uint32_t);
 
 struct cfattach sxie_ca = {
        sizeof (struct sxie_softc), sxie_match, sxie_attach
@@ -210,57 +297,81 @@ sxie_attach(struct device *parent, struct device *self, 
void *aux)
 {
        struct sxie_softc *sc = (struct sxie_softc *) self;
        struct fdt_attach_args *faa = aux;
-       struct mii_data *mii;
-       struct ifnet *ifp;
+       struct mii_data *mii = &sc->sc_mii;
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+       int phynode, physupply;
        int s;
 
        if (faa->fa_nreg < 1)
                return;
 
-       pinctrl_byname(faa->fa_node, "default");
-
        sc->sc_iot = faa->fa_iot;
+       sc->sc_dmat = faa->fa_dmat;
+       sc->sc_node = faa->fa_node;
 
        if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
-           faa->fa_reg[0].size, 0, &sc->sc_ioh))
-               panic("sxie_attach: bus_space_map ioh failed!");
+           faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
+               printf("%s: bus_space_map ioh failed!\n",
+                   sc->sc_dev.dv_xname);
+               return;
+       }
+
+       mtx_init(&sc->sc_miibus_lock, IPL_NET);
+       timeout_set(&sc->sc_tick, sxie_tick, sc);
 
-       if (bus_space_map(sc->sc_iot, SID_ADDR, SID_SIZE, 0, &sc->sc_sid_ioh))
-               panic("sxie_attach: bus_space_map sid_ioh failed!");
+       pinctrl_byname(faa->fa_node, "default");
 
        clock_enable_all(faa->fa_node);
 
-       sxie_socware_init(sc);
-       sc->txf_inuse = 0;
+       /* Power up PHY. */
+       physupply = OF_getpropint(faa->fa_node, "phy-supply", 0);
+       if (physupply)
+               regulator_enable(physupply);
 
        sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_NET,
            sxie_intr, sc, sc->sc_dev.dv_xname);
+       if (sc->sc_ih == NULL)
+               goto failout;
 
-       s = splnet();
+       /* Lookup PHY. */
+       phynode = OF_getnodebyphandle(OF_getpropint(sc->sc_node, "phy", 0));
+       if (phynode)
+               sc->sc_phyno = OF_getpropint(phynode, "reg", MII_PHY_ANY);
+       else
+               sc->sc_phyno = MII_PHY_ANY;
+
+       /*
+        * try to get&set lladdr in order:
+        * a) devicetree
+        * b) current
+        * c) better than random (from SID rootkey registers)
+        * d) ether_fakeaddr
+        */
+       sxie_get_lladdr(sc);
 
        printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
 
-       /* XXX verify flags & capabilities */
-       ifp = &sc->sc_ac.ac_if;
+       s = splnet();
        ifp->if_softc = sc;
        strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        ifp->if_ioctl = sxie_ioctl;
        ifp->if_start = sxie_start;
        ifp->if_watchdog = sxie_watchdog;
+                       /* XXX can do CRC too */
        ifp->if_capabilities = IFCAP_VLAN_MTU; /* XXX status check in recv? */
 
        IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
 
        /* Initialize MII/media info. */
-       mii = &sc->sc_mii;
        mii->mii_ifp = ifp;
        mii->mii_readreg = sxie_miibus_readreg;
        mii->mii_writereg = sxie_miibus_writereg;
        mii->mii_statchg = sxie_miibus_statchg;
 
        ifmedia_init(&mii->mii_media, 0, sxie_ifm_change, sxie_ifm_status);
-       mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+       mii_attach(self, mii, 0xffffffff, sc->sc_phyno, MII_OFFSET_ANY,
+           MIIF_DOPAUSE);
 
        if (LIST_FIRST(&mii->mii_phys) == NULL) {
                ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
@@ -272,56 +383,125 @@ sxie_attach(struct device *parent, struct device *self, 
void *aux)
        ether_ifattach(ifp);
        splx(s);
 
-       sxie_sc = sc;
+       return;
+failout:
+       if (physupply)
+               regulator_disable(physupply);
+       clock_disable_all(faa->fa_node);
+       bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
 }
 
 void
-sxie_socware_init(struct sxie_softc *sc)
+sxie_softreset(struct sxie_softc *sc, uint32_t rx_tx_full)
 {
-       int have_mac = 0;
-       uint32_t reg;
+       uint32_t mac0_clr, mac0_set;
+       uint32_t cmdr_clr, cmdr_set;
 
-       /* MII clock cfg */
-       SXICMS4(sc, SXIE_MACMCFG, 15 << 2, 13 << 2);
+       rx_tx_full &= 0x07;
 
-       SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE);
-       SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR);
+       switch (rx_tx_full) {
+       case SXIE_SRST_RX:
+               mac0_clr = SXIE_MAC0_RXENABLE;
+               mac0_set = SXIE_MAC0_RESETMCSRX;
+               cmdr_clr = SXIE_CMDR_RXENABLE;
+               cmdr_set = SXIE_CMDR_RXRESET;
+               break;
 
-       /*
-        * If u-boot doesn't set emac, use the Security ID area
-        * to generate a consistent MAC address of.
-        */
-       reg = SXIREAD4(sc, SXIE_MACA0);
-       if (reg != 0) {
-               sc->sc_ac.ac_enaddr[3] = reg >> 16 & 0xff;
-               sc->sc_ac.ac_enaddr[4] = reg >> 8 & 0xff;
-               sc->sc_ac.ac_enaddr[5] = reg & 0xff;
-               reg = SXIREAD4(sc, SXIE_MACA1);
-               sc->sc_ac.ac_enaddr[0] = reg >> 16 & 0xff;
-               sc->sc_ac.ac_enaddr[1] = reg >> 8 & 0xff;
-               sc->sc_ac.ac_enaddr[2] = reg & 0xff;
-
-               have_mac = 1;
+       case SXIE_SRST_TX:
+               mac0_clr = /* XXX txflowcontrol? */0;
+               mac0_set = SXIE_MAC0_RESETMCSTX;
+               cmdr_clr = SXIE_CMDR_TXENABLE;
+               cmdr_set = SXIE_CMDR_TXRESET;
+               break;
+
+       default:
+       case SXIE_SRST_FULL:
+               mac0_clr = SXIE_MAC0_RXENABLE;
+               mac0_set = SXIE_MAC0_SOFTRESET;
+               cmdr_clr = SXIE_CMDR_RXENABLE|SXIE_CMDR_TXENABLE;
+               cmdr_set = SXIE_CMDR_REGRESET;
+               break;
        }
 
-       reg = bus_space_read_4(sc->sc_iot, sc->sc_sid_ioh, 0x0);
+       /* disable, flush(reset), enable */
+       SXICLR4(sc, SXIE_MAC0, mac0_clr);
+       SXICLR4(sc, SXIE_CMDR, cmdr_clr);
 
-       if (!have_mac && reg != 0) {
-               sc->sc_ac.ac_enaddr[0] = 0x02;
-               sc->sc_ac.ac_enaddr[1] = reg & 0xff;
-               reg = bus_space_read_4(sc->sc_iot, sc->sc_sid_ioh, 0x0c);
-               sc->sc_ac.ac_enaddr[2] = reg >> 24 & 0xff;
-               sc->sc_ac.ac_enaddr[3] = reg >> 16 & 0xff;
-               sc->sc_ac.ac_enaddr[4] = reg >> 8 & 0xff;
-               sc->sc_ac.ac_enaddr[5] = reg & 0xff;
+       SXISET4(sc, SXIE_MAC0, mac0_set);
+       SXISET4(sc, SXIE_CMDR, cmdr_set);
+       while (SXIREAD4(sc, SXIE_CMDR) & cmdr_set)
+               delay(10);
 
-               have_mac = 1;
+       if (rx_tx_full != SXIE_SRST_FULL) {
+               SXICLR4(sc, SXIE_MAC0, mac0_set);
+
+               SXISET4(sc, SXIE_CMDR, cmdr_clr);
+               SXISET4(sc, SXIE_MAC0, mac0_clr);
+       } else {
+#if 0
+               sxie_setup_interface(sc);
+               SXICLR4(sc, SXIE_MAC0, mac0_set);
+#else
+               return;
+#endif
        }
+}
 
-       if (!have_mac)
-               ether_fakeaddr(&sc->sc_ac.ac_if);
+void
+sxie_get_lladdr(struct sxie_softc *sc)
+{
+       uint8_t *enaddr = &sc->sc_ac.ac_enaddr[0];
+       bus_space_handle_t sid_ioh;
+       uint32_t reg;
+       int eaplen;
 
-       sc->sc_phyno = 1;
+       eaplen = OF_getproplen(sc->sc_node, "local-mac-address");
+       if (eaplen == ETHER_ADDR_LEN) {
+               OF_getprop(sc->sc_node, "local-mac-address", enaddr, eaplen);
+               return;
+       } else if ((reg = SXIREAD4(sc, SXIE_MAC_SA0)) != 0) {
+               enaddr[3] = reg >> 16 & 0xff;
+               enaddr[4] = reg >> 8 & 0xff;
+               enaddr[5] = reg & 0xff;
+               reg = SXIREAD4(sc, SXIE_MAC_SA1);
+               enaddr[0] = reg >> 16 & 0xff;
+               enaddr[1] = reg >> 8 & 0xff;
+               enaddr[2] = reg & 0xff;
+               return;
+       } else
+       if (bus_space_map(sc->sc_iot, SID_ADDR, SID_SIZE, 0, &sid_ioh) != 0) {
+               if ((reg = bus_space_read_4(sc->sc_iot, sid_ioh, 0x0)) != 0) {
+                       /*
+                        * If U-Boot doesn't set MAC, use the Security ID
+                        * area to generate a consistent MAC address of.
+                        */
+                       enaddr[0] = 0x02;
+                       enaddr[1] = reg & 0xff;
+                       reg = bus_space_read_4(sc->sc_iot, sid_ioh, 0x0c);
+                       enaddr[2] = reg >> 24 & 0xff;
+                       enaddr[3] = reg >> 16 & 0xff;
+                       enaddr[4] = reg >> 8 & 0xff;
+                       enaddr[5] = reg & 0xff;
+               }
+               bus_space_unmap(sc->sc_iot, sid_ioh, SID_SIZE);
+               if (reg != 0)
+                       return;
+       }
+       ether_fakeaddr(&sc->sc_ac.ac_if);
+}
+
+void
+sxie_set_lladdr(struct sxie_softc *sc)
+{
+       /* set lladdr */
+       SXIWRITE4(sc, SXIE_MAC_SA0,
+           sc->sc_ac.ac_enaddr[3] << 16 |
+           sc->sc_ac.ac_enaddr[4] << 8 |
+           sc->sc_ac.ac_enaddr[5]);
+       SXIWRITE4(sc, SXIE_MAC_SA1,
+           sc->sc_ac.ac_enaddr[0] << 16 |
+           sc->sc_ac.ac_enaddr[1] << 8 |
+           sc->sc_ac.ac_enaddr[2]);
 }
 
 void
@@ -329,47 +509,46 @@ sxie_setup_interface(struct sxie_softc *sc, struct device 
*dev)
 {
        uint32_t clr_m, set_m;
 
+       /* MII host clock div */
+       SXICMS4(sc, SXIE_MAC_MCFG,
+           SXIE_MAC_MCFG_CLKSEL(15), SXIE_MAC_MCFG_CLKSEL(13));
+
        /* configure TX */
        SXICMS4(sc, SXIE_TXMODE, 3, 1); /* cpu mode */
 
-       /* configure RX */
-       clr_m = SXIE_RXDRQM | SXIE_RXTM | SXIE_RXPA | SXIE_RXPCF |
-           SXIE_RXPCRCE | SXIE_RXPLE | SXIE_RXMHF | SXIE_RXSAF |
-           SXIE_RXSAIF;
-       set_m = SXIE_RXPOR | SXIE_RXUCAD | SXIE_RXDAF | SXIE_RXBCO;
-       SXICMS4(sc, SXIE_RXCR, clr_m, set_m);
+       /* configure RX filtering */
+       clr_m = SXIE_RXDRQM | SXIE_RXTM |
+           SXIE_RXFILTER_PROMISC | SXIE_RXFILTER_CONTROLFRAMES |
+           SXIE_RXFILTER_FRAMECRCERR | SXIE_RXFILTER_FRAMELENERR |
+           SXIE_RXFILTER_MHASHFILTER | SXIE_RXFILTER_SAFILTER |
+           SXIE_RXFILTER_SAINVFILTER;
+       set_m = SXIE_RXFILTER_FRAMELENOOR | SXIE_RXFILTER_DAFILTER |
+           SXIE_RXFILTER_BROADCAST;
+       SXICMS4(sc, SXIE_RXFILTER_CTRL, clr_m, set_m);
 
        /* configure MAC */
-       SXISET4(sc, SXIE_MACCR0, SXIE_MACTXFC | SXIE_MACRXFC);
-       clr_m = SXIE_MACHF | SXIE_MACDCRC | SXIE_MACVC | SXIE_MACADP |
-           SXIE_MACPRE | SXIE_MACLPE | SXIE_MACNB | SXIE_MACBNB |
-           SXIE_MACED;
-       set_m = SXIE_MACFLC | SXIE_MACCRC | SXIE_MACPC;
+       SXISET4(sc, SXIE_MAC0, SXIE_MAC0_RXFLOWCTRL | SXIE_MAC0_TXFLOWCTRL);
+       clr_m = SXIE_MAC0_LOOPBACK | SXIE_MAC1_DELAYEDCRC |
+           SXIE_MAC1_VLANPAD | SXIE_MAC1_AUTOPAD |
+           SXIE_MAC1_PUREPREAMBLE | SXIE_MAC1_LONGPREAMBLE |
+           SXIE_MAC1_NOBACKOFF | SXIE_MAC1_BACKPRESSURE |
+           SXIE_MAC1_EXCESSDEFER;
+       set_m = SXIE_MAC1_FRAMELENCHECK | SXIE_MAC1_CRC | SXIE_MAC1_PADCRC;
        set_m |= sxie_miibus_readreg(dev, sc->sc_phyno, 0) >> 8 & 1;
-       SXICMS4(sc, SXIE_MACCR1, clr_m, set_m);
+       SXICMS4(sc, SXIE_MAC1, clr_m, set_m);
 
        /* XXX */
-       SXIWRITE4(sc, SXIE_MACIPGT, 0x0015);
-       SXIWRITE4(sc, SXIE_MACIPGR, 0x0c12);
+       SXIWRITE4(sc, SXIE_MAC_IPGT, 0x0015);
+       SXIWRITE4(sc, SXIE_MAC_IPGR, 0x0c12);
 
        /* XXX set collision window */
-       SXIWRITE4(sc, SXIE_MACCLRT, 0x370f);
+       SXIWRITE4(sc, SXIE_MAC_CLRT, 0x370f);
 
        /* set max frame length */
-       SXIWRITE4(sc, SXIE_MACMFL, SXIE_MAX_PKT_SIZE);
+       SXIWRITE4(sc, SXIE_MAC_MAXF, SXIE_MAX_PKT_SIZE);
 
        /* set lladdr */
-       SXIWRITE4(sc, SXIE_MACA0,
-           sc->sc_ac.ac_enaddr[3] << 16 |
-           sc->sc_ac.ac_enaddr[4] << 8 |
-           sc->sc_ac.ac_enaddr[5]);
-       SXIWRITE4(sc, SXIE_MACA1,
-           sc->sc_ac.ac_enaddr[0] << 16 |
-           sc->sc_ac.ac_enaddr[1] << 8 |
-           sc->sc_ac.ac_enaddr[2]);
-
-       sxie_reset(sc);
-       /* XXX possibly missing delay in here. */
+       sxie_set_lladdr(sc);
 }
 
 void
@@ -379,43 +558,47 @@ sxie_init(struct sxie_softc *sc)
        struct device *dev = (struct device *)sc;
        int phyreg;
        
-       sxie_reset(sc);
+       sxie_softreset(sc, SXIE_SRST_FULL);
 
        SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE);
-
        SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR);
 
-       SXISET4(sc, SXIE_RXCR, SXIE_RXFLUSH);
-
-       /* soft reset */
-       SXICLR4(sc, SXIE_MACCR0, SXIE_MACSOFTRESET);
-
-       /* zero rx counter */
-       SXIWRITE4(sc, SXIE_RXFBC, 0);
-
        sxie_setup_interface(sc, dev);
 
+       /* release from softreset */
+       SXICLR4(sc, SXIE_MAC0, SXIE_MAC0_SOFTRESET);
+
        /* power up PHY */
        sxie_miibus_writereg(dev, sc->sc_phyno, 0,
            sxie_miibus_readreg(dev, sc->sc_phyno, 0) & ~(1 << 11));
        delay(1000);
        phyreg = sxie_miibus_readreg(dev, sc->sc_phyno, 0);
 
+       sxie_iff(sc);
+
        /* set duplex */
-       SXICMS4(sc, SXIE_MACCR1, 1, phyreg >> 8 & 1);
+       SXICMS4(sc, SXIE_MAC1, 1, phyreg >> 8 & 1);
 
        /* set speed */
-       SXICMS4(sc, SXIE_MACSUPP, 1 << 8, (phyreg >> 13 & 1) << 8);
+       SXICMS4(sc, SXIE_MAC_SUPP, 1 << 8, (phyreg >> 13 & 1) << 8);
+
+       sc->sc_tx_timer = 0;
+       sc->sc_tx_inuse = 0;
 
-       SXISET4(sc, SXIE_CR, SXIE_RXTX_ENABLE);
+       SXISET4(sc, SXIE_CMDR, SXIE_RXTX_ENABLE);
 
        /* Indicate we are up and running. */
        ifp->if_flags |= IFF_RUNNING;
        ifq_clr_oactive(&ifp->if_snd);
 
+       SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE);
+       SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR);
+
        SXISET4(sc, SXIE_INTCR, SXIE_INTR_ENABLE);
 
        sxie_start(ifp);
+
+       timeout_add_sec(&sc->sc_tick, 1);
 }
 
 int
@@ -439,11 +622,9 @@ sxie_intr(void *arg)
        }
 
        if (pending & (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) {
-               sc->txf_inuse &= ~pending;
-               if (sc->txf_inuse == 0)
-                       ifp->if_timer = 0;
-               else
-                       ifp->if_timer = 5;
+               sc->sc_tx_inuse &= ~(pending & SXIE_TX_FIFOS);
+               ifp->if_timer = (sc->sc_tx_inuse == 0) ? 0 : 1;
+               sc->sc_tx_timer = ifp->if_timer ? 5 : 0;
 
                if (ifq_is_oactive(&ifp->if_snd))
                        ifq_restart(&ifp->if_snd);
@@ -454,6 +635,49 @@ sxie_intr(void *arg)
        return 1;
 }
 
+void
+sxie_tx_mbuf_cpu(struct sxie_softc *sc, uint32_t fifo, struct mbuf *m)
+{
+       uint32_t txbuf[SXIE_MAX_PKT_SIZE / sizeof(uint32_t)];
+
+       /* copy the actual packet to fifo XXX through 'align buffer' */
+       m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txbuf[0]);
+       bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh,
+           SXIE_TXIO0, (uint32_t *)&txbuf[0],
+           SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2);
+
+       /* transmit to PHY from fifo */
+       SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1);
+}
+
+void
+sxie_tx_mbuf_dma(struct sxie_softc *sc, uint32_t fifo, struct mbuf *m)
+{
+       /* XXX not yet */
+       sxie_tx_mbuf_cpu(sc, fifo, m);
+}
+
+void
+sxie_tx_mbuf(struct sxie_softc *sc, struct mbuf *m)
+{
+       uint32_t fifo = 1;
+
+       /* select fifo */
+       fifo <<= sc->sc_tx_inuse & SXIE_TX_FIFO0 ? 1 : 0;
+       sc->sc_tx_inuse |= fifo--;
+       SXIWRITE4(sc, SXIE_TXINS, fifo);
+
+       /* set packet length */
+       SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len);
+
+       /* transfer to fifo */
+       if (sc->sc_dmanode)
+               sxie_tx_mbuf_dma(sc, fifo, m);
+       else
+               sxie_tx_mbuf_cpu(sc, fifo, m);
+}
+
+
 /*
  * XXX there's secondary tx fifo to be used.
  */
@@ -462,30 +686,16 @@ sxie_start(struct ifnet *ifp)
 {
        struct sxie_softc *sc = ifp->if_softc;
        struct mbuf *m;
-       struct mbuf *head;
-       uint8_t *td;
-       uint32_t fifo;
-       uint32_t txbuf[SXIE_MAX_PKT_SIZE / sizeof(uint32_t)]; /* XXX !!! */
 
        if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
                return;
 
-
-       td = (uint8_t *)&txbuf[0];
-       m = NULL;
-       head = NULL;
-
-       for (;;) {
-               if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) {
-                       ifq_set_oactive(&ifp->if_snd);
-                       break;
-               }
-
-               m = ifq_dequeue(&ifp->if_snd);
-               if (m == NULL)
-                       break;
+       for (; sc->sc_tx_inuse < SXIE_MAX_TXD; m_freem(m)) {
+               if ((m = ifq_dequeue(&ifp->if_snd)) == NULL)
+                       return;
 
                if (m->m_pkthdr.len > SXIE_MAX_PKT_SIZE) {
+                       SXIEDBG(("sxie_start: packet too big\n"));
                        m_freem(m);
                        continue;
                }
@@ -494,32 +704,12 @@ sxie_start(struct ifnet *ifp)
                if (ifp->if_bpf)
                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
 #endif
-
-               /* select fifo */
-               if (sc->txf_inuse & SXIE_TX_FIFO0) {
-                       sc->txf_inuse |= SXIE_TX_FIFO1;
-                       fifo = 1;
-               } else {
-                       sc->txf_inuse |= SXIE_TX_FIFO0;
-                       fifo = 0;
-               }
-               SXIWRITE4(sc, SXIE_TXINS, fifo);
-
-               /* set packet length */
-               SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len);
-
-               /* copy the actual packet to fifo XXX through 'align buffer' */
-               m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)td);
-               bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh,
-                   SXIE_TXIO0,
-                   (uint32_t *)td, SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2);
-
-               /* transmit to PHY from fifo */
-               SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1);
-               ifp->if_timer = 5;
-
-               m_freem(m);
+               sxie_tx_mbuf(sc, m);
+               sc->sc_tx_timer = 5;
+               ifp->if_timer = 1;
        }
+
+       ifq_set_oactive(&ifp->if_snd);
 }
 
 void
@@ -527,35 +717,54 @@ sxie_stop(struct sxie_softc *sc)
 {
        struct ifnet *ifp = &sc->sc_ac.ac_if;
 
-       sxie_reset(sc);
+       timeout_del(&sc->sc_tick);
+
+       SXICLR4(sc, SXIE_CMDR, SXIE_CMDR_RXENABLE | SXIE_CMDR_TXENABLE);
+
+       sc->sc_pauseframe = 0;
+       sc->sc_tx_timer = 0;
+       sc->sc_tx_inuse = 0;
 
        ifp->if_flags &= ~IFF_RUNNING;
        ifp->if_timer = 0;
        ifq_clr_oactive(&ifp->if_snd);
+
+       mii_down(&sc->sc_mii);
 }
 
 void
 sxie_reset(struct sxie_softc *sc)
 {
+#if 0
        /* reset the controller */
-       SXIWRITE4(sc, SXIE_CR, 0);
+       SXIWRITE4(sc, SXIE_CMDR, 0);
        delay(200);
-       SXIWRITE4(sc, SXIE_CR, 1);
+       SXIWRITE4(sc, SXIE_CMDR, 1);
        delay(200);
+#endif
 }
 
 void
 sxie_watchdog(struct ifnet *ifp)
 {
        struct sxie_softc *sc = ifp->if_softc;
-       if (sc->pauseframe) {
-               ifp->if_timer = 5;
+
+       if (sc->sc_pauseframe) {
+               ifp->if_timer = 1;
                return;
        }
-       printf("%s: watchdog tx timeout\n", sc->sc_dev.dv_xname);
-       ifp->if_oerrors++;
-       sxie_init(sc);
-       sxie_start(ifp);
+       if (sc->sc_tx_timer > 0) {
+               if (--sc->sc_tx_timer == 0) {
+                       if (ifp->if_flags & IFF_DEBUG)
+                               printf("%s: watchdog tx timeout\n",
+                                   sc->sc_dev.dv_xname);
+                       ifp->if_oerrors++;
+                       sxie_init(sc);
+                       sxie_start(ifp);
+                       return;
+               }
+               ifp->if_timer = 1;
+       }
 }
 
 /*
@@ -570,8 +779,7 @@ sxie_recv(struct sxie_softc *sc)
        struct mbuf *m;
        uint16_t pktstat;
        int16_t pktlen;
-       int rlen;
-       char rxbuf[SXIE_MAX_PKT_SIZE]; /* XXX !!! */
+       char rxbuf[SXIE_MAX_PKT_SIZE];
 trynext:
        fbc = SXIREAD4(sc, SXIE_RXFBC);
        if (!fbc)
@@ -583,44 +791,34 @@ trynext:
         */
        reg = SXIREAD4(sc, SXIE_RXIO);
        if (reg != 0x0143414d) {        /* invalid packet */
-               /* disable, flush, enable */
-               SXICLR4(sc, SXIE_CR, SXIE_RX_ENABLE);
-               SXISET4(sc, SXIE_RXCR, SXIE_RXFLUSH);
-               while (SXIREAD4(sc, SXIE_RXCR) & SXIE_RXFLUSH);
-               SXISET4(sc, SXIE_CR, SXIE_RX_ENABLE);
-
-               goto err_out;
+               sxie_softreset(sc, SXIE_SRST_RX);
+               ifp->if_ierrors++;
+               goto done;
        }
        
        reg = SXIREAD4(sc, SXIE_RXIO);
        pktstat = (uint16_t)reg >> 16;
        pktlen = (int16_t)reg; /* length of useful data */
 
-       if (pktstat & SXIE_RX_ERRMASK || pktlen < ETHER_MIN_LEN) {
+       if (pktstat & SXIE_RX_ERRMASK || pktlen < ETHER_MIN_LEN ||
+           pktlen > SXIE_MAX_PKT_SIZE) {
                ifp->if_ierrors++;
                goto trynext;
        }
-       if (pktlen > SXIE_MAX_PKT_SIZE)
-               pktlen = SXIE_MAX_PKT_SIZE; /* XXX is truncating ok? */
 
        /* read the actual packet from fifo XXX through 'align buffer'.. */
-       if (pktlen & 3)
-               rlen = SXIE_ROUNDUP(pktlen, 4);
-       else
-               rlen = pktlen;
        bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh,
-           SXIE_RXIO, (uint32_t *)&rxbuf[0], rlen >> 2);
+           SXIE_RXIO, (uint32_t *)&rxbuf[0],
+           (pktlen & 3 ? SXIE_ROUNDUP(pktlen, 4) : pktlen) >> 2);
 
        m = m_devget(&rxbuf[0], pktlen, ETHER_ALIGN);
        if (m == NULL) {
                ifp->if_ierrors++;
-               goto err_out;
+               goto done;
        }
 
        ml_enqueue(&ml, m);
        goto trynext;
-err_out:
-       ifp->if_ierrors++;
 done:
        if_input(ifp, &ml);
 }
@@ -659,7 +857,7 @@ sxie_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        }
        if (error == ENETRESET) {
                if (ifp->if_flags & IFF_RUNNING)
-                       sxie_iff(sc, ifp);
+                       sxie_iff(sc);
                error = 0;
        }
 
@@ -668,9 +866,49 @@ sxie_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 }
 
 void
-sxie_iff(struct sxie_softc *sc, struct ifnet *ifp)
+sxie_iff(struct sxie_softc *sc)
 {
-       /* XXX set interface features */
+       struct arpcom *ac = &sc->sc_ac;
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+       struct ether_multi *enm;
+       struct ether_multistep step;
+       uint64_t rxfhash = 0;
+       uint32_t h;
+       uint32_t rxfilt;
+
+       rxfilt = SXIREAD4(sc, SXIE_RXFILTER_CTRL);
+
+       ifp->if_flags &= ~IFF_ALLMULTI;
+       if ((ifp->if_flags & IFF_PROMISC) || ac->ac_multirangecnt > 0) {
+               ifp->if_flags |= IFF_ALLMULTI;
+               rxfhash = 0xffffffffffffffffLLU;
+       } else {
+               ETHER_FIRST_MULTI(step, ac, enm);
+               while (enm != NULL) {
+                       h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
+
+                       rxfhash |= 1LLU << (((uint8_t *)&h)[3] >> 2);
+
+                       ETHER_NEXT_MULTI(step, enm);
+               }
+       }
+
+       rxfilt |= SXIE_RXFILTER_UNICAST | SXIE_RXFILTER_DAFILTER |
+            SXIE_RXFILTER_MULTICAST;
+
+       if (ifp->if_flags & IFF_ALLMULTI)
+               rxfilt |= SXIE_RXFILTER_MHASHFILTER;
+
+       if (ifp->if_flags & IFF_BROADCAST)
+               rxfilt |= SXIE_RXFILTER_BROADCAST;
+
+       if (ifp->if_flags & IFF_PROMISC)
+               rxfilt |= SXIE_RXFILTER_PROMISC;
+
+       SXIWRITE4(sc, SXIE_RXHASH0, (uint32_t)rxfhash);
+       SXIWRITE4(sc, SXIE_RXHASH1, (uint32_t)(rxfhash >> 32));
+
+       SXIWRITE4(sc, SXIE_RXFILTER_CTRL, rxfilt);
 }
 
 /*
@@ -681,11 +919,13 @@ sxie_miibus_readreg(struct device *dev, int phy, int reg)
 {
        struct sxie_softc *sc = (struct sxie_softc *)dev;
        int timo = SXIE_MII_TIMEOUT;
+       int rv;
 
-       SXIWRITE4(sc, SXIE_MACMADR, phy << 8 | reg);
+       mtx_enter(&sc->sc_miibus_lock);
 
-       SXIWRITE4(sc, SXIE_MACMCMD, 1);
-       while (SXIREAD4(sc, SXIE_MACMIND) & 1 && --timo)
+       SXIWRITE4(sc, SXIE_MAC_MADR, phy << 8 | reg);
+       SXIWRITE4(sc, SXIE_MAC_MCMD, 1);
+       while (SXIREAD4(sc, SXIE_MAC_MIND) & 1 && --timo)
                delay(10);
 #ifdef DIAGNOSTIC
        if (!timo)
@@ -693,9 +933,11 @@ sxie_miibus_readreg(struct device *dev, int phy, int reg)
                    sc->sc_dev.dv_xname);
 #endif
 
-       SXIWRITE4(sc, SXIE_MACMCMD, 0);
-       
-       return SXIREAD4(sc, SXIE_MACMRDD) & 0xffff;
+       SXIWRITE4(sc, SXIE_MAC_MCMD, 0);
+       rv = SXIREAD4(sc, SXIE_MAC_MRDD) & 0xffff;
+       mtx_leave(&sc->sc_miibus_lock);
+
+       return rv;
 }
 
 void
@@ -704,38 +946,55 @@ sxie_miibus_writereg(struct device *dev, int phy, int 
reg, int val)
        struct sxie_softc *sc = (struct sxie_softc *)dev;
        int timo = SXIE_MII_TIMEOUT;
 
-       SXIWRITE4(sc, SXIE_MACMADR, phy << 8 | reg);
+       mtx_enter(&sc->sc_miibus_lock);
 
-       SXIWRITE4(sc, SXIE_MACMCMD, 1);
-       while (SXIREAD4(sc, SXIE_MACMIND) & 1 && --timo)
+       SXIWRITE4(sc, SXIE_MAC_MADR, phy << 8 | reg);
+       SXIWRITE4(sc, SXIE_MAC_MCMD, 1);
+       while (SXIREAD4(sc, SXIE_MAC_MIND) & 1 && --timo)
                delay(10);
 #ifdef DIAGNOSTIC
        if (!timo)
-               printf("%s: sxie_miibus_readreg timeout.\n",
+               printf("%s: sxie_miibus_writereg timeout.\n",
                    sc->sc_dev.dv_xname);
 #endif
 
-       SXIWRITE4(sc, SXIE_MACMCMD, 0);
+       SXIWRITE4(sc, SXIE_MAC_MCMD, 0);
+       SXIWRITE4(sc, SXIE_MAC_MWTD, val);
 
-       SXIWRITE4(sc, SXIE_MACMWTD, val);
+       mtx_leave(&sc->sc_miibus_lock);
 }
 
 void
 sxie_miibus_statchg(struct device *dev)
 {
-       /* XXX */
-#if 0
        struct sxie_softc *sc = (struct sxie_softc *)dev;
+       uint64_t mma = sc->sc_mii.mii_media_active;
+       uint64_t _valid = IFM_ACTIVE | IFM_AVALID;
 
-       switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
+       if ((mma & _valid) != _valid)
+               return;         /* no link */
+
+       switch (IFM_SUBTYPE(mma)) {
        case IFM_10_T:
+               SXICLR4(sc, SXIE_MAC_SUPP, SXIE_MAC_SUPP_SPEED);
+               break;
        case IFM_100_TX:
-       /*case IFM_1000_T: only on GMAC */
+               SXISET4(sc, SXIE_MAC_SUPP, SXIE_MAC_SUPP_SPEED);
                break;
        default:
                break;
        }
-#endif
+
+       if (mma & IFM_FLOW) {
+               SXICMS4(sc, SXIE_MAC0,
+                   SXIE_MAC0_TXFLOWCTRL | SXIE_MAC0_RXFLOWCTRL,
+                   (mma & IFM_ETH_TXPAUSE ? SXIE_MAC0_TXFLOWCTRL : 0) |
+                   (mma & IFM_ETH_RXPAUSE ? SXIE_MAC0_RXFLOWCTRL : 0));
+       } else {
+               SXICLR4(sc, SXIE_MAC0, SXIE_MAC0_TXFLOWCTRL | 
SXIE_MAC0_RXFLOWCTRL);
+       }
+
+       SXICMS4(sc, SXIE_MAC1, 1, mma & IFM_FDX ? 1 : 0);
 }
 
 int
@@ -762,3 +1021,16 @@ sxie_ifm_status(struct ifnet *ifp, struct ifmediareq 
*ifmr)
        ifmr->ifm_active = sc->sc_mii.mii_media_active;
        ifmr->ifm_status = sc->sc_mii.mii_media_status;
 }
+
+void
+sxie_tick(void *arg)
+{
+       struct sxie_softc *sc = arg;
+       int s;
+
+       s = splnet();
+       mii_tick(&sc->sc_mii);
+       splx(s);
+
+       timeout_add_sec(&sc->sc_tick, 1);
+}


Reply via email to