diff options
-rw-r--r-- | sys/arm/allwinner/if_emac.c | 37 | ||||
-rw-r--r-- | sys/arm/allwinner/if_emacreg.h | 4 |
2 files changed, 29 insertions, 12 deletions
diff --git a/sys/arm/allwinner/if_emac.c b/sys/arm/allwinner/if_emac.c index ec3c323..af09ec5 100644 --- a/sys/arm/allwinner/if_emac.c +++ b/sys/arm/allwinner/if_emac.c @@ -101,6 +101,7 @@ struct emac_softc { int emac_watchdog_timer; int emac_rx_process_limit; int emac_link; + uint32_t emac_fifo_mask; }; static int emac_probe(device_t); @@ -121,7 +122,7 @@ static void emac_intr(void *); static int emac_ioctl(struct ifnet *, u_long, caddr_t); static void emac_rxeof(struct emac_softc *, int); -static void emac_txeof(struct emac_softc *); +static void emac_txeof(struct emac_softc *, uint32_t); static int emac_miibus_readreg(device_t, int, int); static int emac_miibus_writereg(device_t, int, int, int); @@ -253,14 +254,19 @@ emac_reset(struct emac_softc *sc) } static void -emac_txeof(struct emac_softc *sc) +emac_txeof(struct emac_softc *sc, uint32_t status) { struct ifnet *ifp; EMAC_ASSERT_LOCKED(sc); ifp = sc->emac_ifp; - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + status &= (EMAC_TX_FIFO0 | EMAC_TX_FIFO1); + sc->emac_fifo_mask &= ~status; + if (status == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1)) + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 2); + else + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; /* Unarm watchdog timer if no TX */ @@ -580,11 +586,13 @@ emac_start_locked(struct ifnet *ifp) { struct emac_softc *sc; struct mbuf *m, *m0; - uint32_t reg_val; + uint32_t fifo, reg; sc = ifp->if_softc; if (ifp->if_drv_flags & IFF_DRV_OACTIVE) return; + if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1)) + return; if (sc->emac_link == 0) return; IFQ_DRV_DEQUEUE(&ifp->if_snd, m); @@ -592,7 +600,14 @@ emac_start_locked(struct ifnet *ifp) return; /* Select channel */ - EMAC_WRITE_REG(sc, EMAC_TX_INS, 0); + if (sc->emac_fifo_mask & EMAC_TX_FIFO0) + fifo = 1; + else + fifo = 0; + sc->emac_fifo_mask |= (1 << fifo); + if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1)) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + EMAC_WRITE_REG(sc, EMAC_TX_INS, fifo); /* * Emac controller wants 4 byte aligned TX buffers. @@ -613,17 +628,17 @@ emac_start_locked(struct ifnet *ifp) roundup2(m->m_len, 4) / 4); /* Send the data lengh. */ - EMAC_WRITE_REG(sc, EMAC_TX_PL0, m->m_len); + reg = (fifo == 0) ? EMAC_TX_PL0 : EMAC_TX_PL1; + EMAC_WRITE_REG(sc, reg, m->m_len); /* Start translate from fifo to phy. */ - reg_val = EMAC_READ_REG(sc, EMAC_TX_CTL0); - reg_val |= 1; - EMAC_WRITE_REG(sc, EMAC_TX_CTL0, reg_val); + reg = (fifo == 0) ? EMAC_TX_CTL0 : EMAC_TX_CTL1; + EMAC_WRITE_REG(sc, reg, EMAC_READ_REG(sc, reg) | 1); /* Set timeout */ sc->emac_watchdog_timer = 5; - ifp->if_drv_flags |= IFF_DRV_OACTIVE; + /* Data have been sent to hardware, it is okay to free the mbuf now. */ BPF_MTAP(ifp, m); m_freem(m); } @@ -676,7 +691,7 @@ emac_intr(void *arg) /* Transmit Interrupt check */ if (reg_val & EMAC_INT_STA_TX) { - emac_txeof(sc); + emac_txeof(sc, reg_val); ifp = sc->emac_ifp; if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) emac_start_locked(ifp); diff --git a/sys/arm/allwinner/if_emacreg.h b/sys/arm/allwinner/if_emacreg.h index ee79c30..d276c5d 100644 --- a/sys/arm/allwinner/if_emacreg.h +++ b/sys/arm/allwinner/if_emacreg.h @@ -51,6 +51,8 @@ #define EMAC_TX_TSVH0 0x30 #define EMAC_TX_TSVL1 0x34 #define EMAC_TX_TSVH1 0x38 +#define EMAC_TX_FIFO0 (1 << 0) +#define EMAC_TX_FIFO1 (1 << 1) #define EMAC_RX_CTL 0x3C #define EMAC_RX_HASH0 0x40 @@ -61,7 +63,7 @@ #define EMAC_INT_CTL 0x54 #define EMAC_INT_STA 0x58 -#define EMAC_INT_STA_TX (0x01 | 0x02) +#define EMAC_INT_STA_TX (EMAC_TX_FIFO0 | EMAC_TX_FIFO1) #define EMAC_INT_STA_RX 0x100 #define EMAC_INT_EN (0xf << 0) | (1 << 8) |