mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-21 11:13:30 +00:00
MFp4:
o Fix the packet statistics o Make sure we set the FD bit when in full duplex o Improve TX side efficency by eliminating a data copy for unfragmented mbufs (the hardware can't do s/g). o Minor busdma pedantry o better comments in some places, more XXX in others o Minor style nits. This solves a problem I was seeing where I'd get no ethernet when not booting with a NFS root. Well, unless I unplugged the cable and plugged it back in first so I'd get the same up down up messages I get for NFS root... Thanks to sam and scottl for suggestions on making this driver more efficient through better use of approrpiate APIs.
This commit is contained in:
parent
1df1b94714
commit
8cd5dc08c3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=163937
@ -195,7 +195,6 @@ ate_attach(device_t dev)
|
|||||||
ate_get_mac(sc, eaddr);
|
ate_get_mac(sc, eaddr);
|
||||||
ate_set_mac(sc, eaddr);
|
ate_set_mac(sc, eaddr);
|
||||||
|
|
||||||
|
|
||||||
sc->ifp = ifp = if_alloc(IFT_ETHER);
|
sc->ifp = ifp = if_alloc(IFT_ETHER);
|
||||||
if (mii_phy_probe(dev, &sc->miibus, ate_ifmedia_upd, ate_ifmedia_sts)) {
|
if (mii_phy_probe(dev, &sc->miibus, ate_ifmedia_upd, ate_ifmedia_sts)) {
|
||||||
device_printf(dev, "Cannot find my PHY.\n");
|
device_printf(dev, "Cannot find my PHY.\n");
|
||||||
@ -271,10 +270,12 @@ ate_load_rx_buf(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
|||||||
* For the last buffer, set the wrap bit so the controller
|
* For the last buffer, set the wrap bit so the controller
|
||||||
* restarts from the first descriptor.
|
* restarts from the first descriptor.
|
||||||
*/
|
*/
|
||||||
|
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE);
|
||||||
if (i == ATE_MAX_RX_BUFFERS - 1)
|
if (i == ATE_MAX_RX_BUFFERS - 1)
|
||||||
sc->rx_descs[i].addr = segs[0].ds_addr | ETH_WRAP_BIT;
|
sc->rx_descs[i].addr = segs[0].ds_addr | ETH_WRAP_BIT;
|
||||||
else
|
else
|
||||||
sc->rx_descs[i].addr = segs[0].ds_addr;
|
sc->rx_descs[i].addr = segs[0].ds_addr;
|
||||||
|
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_POSTWRITE);
|
||||||
sc->rx_descs[i].status = 0;
|
sc->rx_descs[i].status = 0;
|
||||||
/* Flush the memory in the mbuf */
|
/* Flush the memory in the mbuf */
|
||||||
bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREREAD);
|
bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREREAD);
|
||||||
@ -488,12 +489,31 @@ ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
|
|||||||
ATE_UNLOCK(sc);
|
ATE_UNLOCK(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ate_stat_update(struct ate_softc *sc, int active)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The speed and full/half-duplex state needs to be reflected
|
||||||
|
* in the ETH_CFG register.
|
||||||
|
*/
|
||||||
|
if (IFM_SUBTYPE(active) == IFM_10_T)
|
||||||
|
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_SPD);
|
||||||
|
else
|
||||||
|
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_SPD);
|
||||||
|
if (active & IFM_FDX)
|
||||||
|
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_FD);
|
||||||
|
else
|
||||||
|
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_FD);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ate_tick(void *xsc)
|
ate_tick(void *xsc)
|
||||||
{
|
{
|
||||||
struct ate_softc *sc = xsc;
|
struct ate_softc *sc = xsc;
|
||||||
|
struct ifnet *ifp = sc->ifp;
|
||||||
struct mii_data *mii;
|
struct mii_data *mii;
|
||||||
int active;
|
int active;
|
||||||
|
uint32_t c;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The KB920x boot loader tests ETH_SR & ETH_SR_LINK and will ask
|
* The KB920x boot loader tests ETH_SR & ETH_SR_LINK and will ask
|
||||||
@ -506,25 +526,8 @@ ate_tick(void *xsc)
|
|||||||
active = mii->mii_media_active;
|
active = mii->mii_media_active;
|
||||||
mii_tick(mii);
|
mii_tick(mii);
|
||||||
if (mii->mii_media_status & IFM_ACTIVE &&
|
if (mii->mii_media_status & IFM_ACTIVE &&
|
||||||
active != mii->mii_media_active) {
|
active != mii->mii_media_active)
|
||||||
/*
|
ate_stat_update(sc, mii->mii_media_active);
|
||||||
* The speed and full/half-duplex state needs
|
|
||||||
* to be reflected in the ETH_CFG register, it
|
|
||||||
* seems.
|
|
||||||
*/
|
|
||||||
if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
|
|
||||||
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) &
|
|
||||||
~ETH_CFG_SPD);
|
|
||||||
else
|
|
||||||
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) |
|
|
||||||
ETH_CFG_SPD);
|
|
||||||
if (mii->mii_media_active & IFM_FDX)
|
|
||||||
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) |
|
|
||||||
ETH_CFG_FD);
|
|
||||||
else
|
|
||||||
WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) &
|
|
||||||
~ETH_CFG_FD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -535,16 +538,25 @@ ate_tick(void *xsc)
|
|||||||
* the dot3Stats mib, so for those we just count them as general
|
* the dot3Stats mib, so for those we just count them as general
|
||||||
* errors. Stats for iframes, ibutes, oframes and obytes are
|
* errors. Stats for iframes, ibutes, oframes and obytes are
|
||||||
* collected elsewhere. These registers zero on a read to prevent
|
* collected elsewhere. These registers zero on a read to prevent
|
||||||
* races.
|
* races. For all the collision stats, also update the collision
|
||||||
|
* stats for the interface.
|
||||||
*/
|
*/
|
||||||
sc->mibdata.dot3StatsAlignmentErrors += RD4(sc, ETH_ALE);
|
sc->mibdata.dot3StatsAlignmentErrors += RD4(sc, ETH_ALE);
|
||||||
sc->mibdata.dot3StatsFCSErrors += RD4(sc, ETH_SEQE);
|
sc->mibdata.dot3StatsFCSErrors += RD4(sc, ETH_SEQE);
|
||||||
sc->mibdata.dot3StatsSingleCollisionFrames += RD4(sc, ETH_SCOL);
|
c = RD4(sc, ETH_SCOL);
|
||||||
sc->mibdata.dot3StatsMultipleCollisionFrames += RD4(sc, ETH_MCOL);
|
ifp->if_collisions += c;
|
||||||
|
sc->mibdata.dot3StatsSingleCollisionFrames += c;
|
||||||
|
c = RD4(sc, ETH_MCOL);
|
||||||
|
sc->mibdata.dot3StatsMultipleCollisionFrames += c;
|
||||||
|
ifp->if_collisions += c;
|
||||||
sc->mibdata.dot3StatsSQETestErrors += RD4(sc, ETH_SQEE);
|
sc->mibdata.dot3StatsSQETestErrors += RD4(sc, ETH_SQEE);
|
||||||
sc->mibdata.dot3StatsDeferredTransmissions += RD4(sc, ETH_DTE);
|
sc->mibdata.dot3StatsDeferredTransmissions += RD4(sc, ETH_DTE);
|
||||||
sc->mibdata.dot3StatsLateCollisions += RD4(sc, ETH_LCOL);
|
c = RD4(sc, ETH_LCOL);
|
||||||
sc->mibdata.dot3StatsExcessiveCollisions += RD4(sc, ETH_ECOL);
|
sc->mibdata.dot3StatsLateCollisions += c;
|
||||||
|
ifp->if_collisions += c;
|
||||||
|
c = RD4(sc, ETH_ECOL);
|
||||||
|
sc->mibdata.dot3StatsExcessiveCollisions += c;
|
||||||
|
ifp->if_collisions += c;
|
||||||
sc->mibdata.dot3StatsCarrierSenseErrors += RD4(sc, ETH_CSE);
|
sc->mibdata.dot3StatsCarrierSenseErrors += RD4(sc, ETH_CSE);
|
||||||
sc->mibdata.dot3StatsFrameTooLongs += RD4(sc, ETH_ELR);
|
sc->mibdata.dot3StatsFrameTooLongs += RD4(sc, ETH_ELR);
|
||||||
sc->mibdata.dot3StatsInternalMacReceiveErrors += RD4(sc, ETH_DRFC);
|
sc->mibdata.dot3StatsInternalMacReceiveErrors += RD4(sc, ETH_DRFC);
|
||||||
@ -552,7 +564,7 @@ ate_tick(void *xsc)
|
|||||||
* not sure where to lump these, so count them against the errors
|
* not sure where to lump these, so count them against the errors
|
||||||
* for the interface.
|
* for the interface.
|
||||||
*/
|
*/
|
||||||
sc->ifp->if_oerrors += RD4(sc, ETH_CSE) + RD4(sc, ETH_TUE);
|
sc->ifp->if_oerrors += RD4(sc, ETH_TUE);
|
||||||
sc->ifp->if_ierrors += RD4(sc, ETH_CDE) + RD4(sc, ETH_RJB) +
|
sc->ifp->if_ierrors += RD4(sc, ETH_CDE) + RD4(sc, ETH_RJB) +
|
||||||
RD4(sc, ETH_USF);
|
RD4(sc, ETH_USF);
|
||||||
|
|
||||||
@ -577,9 +589,9 @@ ate_get_mac(struct ate_softc *sc, u_char *eaddr)
|
|||||||
uint32_t low, high;
|
uint32_t low, high;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The KB920x loaders will setup the MAC with an address, if one
|
* The boot loader setup the MAC with an address, if one is set in
|
||||||
* is set in the loader. The TSC loader will also set the MAC address
|
* the loader. The TSC loader will also set the MAC address in a
|
||||||
* in a similar way. Grab the MAC address from the SA1[HL] registers.
|
* similar way. Grab the MAC address from the SA1[HL] registers.
|
||||||
*/
|
*/
|
||||||
low = RD4(sc, ETH_SA1L);
|
low = RD4(sc, ETH_SA1L);
|
||||||
high = RD4(sc, ETH_SA1H);
|
high = RD4(sc, ETH_SA1H);
|
||||||
@ -595,6 +607,7 @@ static void
|
|||||||
ate_intr(void *xsc)
|
ate_intr(void *xsc)
|
||||||
{
|
{
|
||||||
struct ate_softc *sc = xsc;
|
struct ate_softc *sc = xsc;
|
||||||
|
struct ifnet *ifp = sc->ifp;
|
||||||
int status;
|
int status;
|
||||||
int i;
|
int i;
|
||||||
void *bp;
|
void *bp;
|
||||||
@ -614,15 +627,18 @@ ate_intr(void *xsc)
|
|||||||
rx_stat = sc->rx_descs[i].status;
|
rx_stat = sc->rx_descs[i].status;
|
||||||
if ((rx_stat & ETH_LEN_MASK) == 0) {
|
if ((rx_stat & ETH_LEN_MASK) == 0) {
|
||||||
printf("ignoring bogus 0 len packet\n");
|
printf("ignoring bogus 0 len packet\n");
|
||||||
sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
|
|
||||||
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
|
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
|
||||||
BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREWRITE);
|
||||||
|
sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
|
||||||
|
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
|
||||||
|
BUS_DMASYNC_POSTWRITE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Flush memory for mbuf so we don't get stale bytes */
|
/* Flush memory for mbuf so we don't get stale bytes */
|
||||||
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
|
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
|
||||||
BUS_DMASYNC_POSTREAD);
|
BUS_DMASYNC_POSTREAD);
|
||||||
WR4(sc, ETH_RSR, RD4(sc, ETH_RSR)); // XXX WHY? XXX imp
|
WR4(sc, ETH_RSR, RD4(sc, ETH_RSR));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The length returned by the device includes the
|
* The length returned by the device includes the
|
||||||
* ethernet CRC calculation for the packet, but
|
* ethernet CRC calculation for the packet, but
|
||||||
@ -630,25 +646,37 @@ ate_intr(void *xsc)
|
|||||||
*/
|
*/
|
||||||
mb = m_devget(sc->rx_buf[i],
|
mb = m_devget(sc->rx_buf[i],
|
||||||
(rx_stat & ETH_LEN_MASK) - ETHER_CRC_LEN,
|
(rx_stat & ETH_LEN_MASK) - ETHER_CRC_LEN,
|
||||||
ETHER_ALIGN, sc->ifp, NULL);
|
ETHER_ALIGN, ifp, NULL);
|
||||||
sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
|
|
||||||
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
|
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
|
||||||
BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREWRITE);
|
||||||
|
sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
|
||||||
|
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
|
||||||
|
BUS_DMASYNC_POSTWRITE);
|
||||||
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
|
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
|
||||||
BUS_DMASYNC_PREREAD);
|
BUS_DMASYNC_PREREAD);
|
||||||
if (mb != NULL)
|
if (mb != NULL) {
|
||||||
(*sc->ifp->if_input)(sc->ifp, mb);
|
ifp->if_ipackets++;
|
||||||
|
(*ifp->if_input)(ifp, mb);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status & ETH_ISR_TCOM) {
|
if (status & ETH_ISR_TCOM) {
|
||||||
ATE_LOCK(sc);
|
ATE_LOCK(sc);
|
||||||
|
/* XXX TSR register should be cleared */
|
||||||
if (sc->sent_mbuf[0]) {
|
if (sc->sent_mbuf[0]) {
|
||||||
|
bus_dmamap_sync(sc->rxtag, sc->tx_map[0],
|
||||||
|
BUS_DMASYNC_POSTWRITE);
|
||||||
m_freem(sc->sent_mbuf[0]);
|
m_freem(sc->sent_mbuf[0]);
|
||||||
|
ifp->if_opackets++;
|
||||||
sc->sent_mbuf[0] = NULL;
|
sc->sent_mbuf[0] = NULL;
|
||||||
}
|
}
|
||||||
if (sc->sent_mbuf[1]) {
|
if (sc->sent_mbuf[1]) {
|
||||||
if (RD4(sc, ETH_TSR) & ETH_TSR_IDLE) {
|
if (RD4(sc, ETH_TSR) & ETH_TSR_IDLE) {
|
||||||
|
bus_dmamap_sync(sc->rxtag, sc->tx_map[1],
|
||||||
|
BUS_DMASYNC_POSTWRITE);
|
||||||
m_freem(sc->sent_mbuf[1]);
|
m_freem(sc->sent_mbuf[1]);
|
||||||
|
ifp->if_opackets++;
|
||||||
sc->txcur = 0;
|
sc->txcur = 0;
|
||||||
sc->sent_mbuf[0] = sc->sent_mbuf[1] = NULL;
|
sc->sent_mbuf[0] = sc->sent_mbuf[1] = NULL;
|
||||||
} else {
|
} else {
|
||||||
@ -684,6 +712,7 @@ ateinit_locked(void *xsc)
|
|||||||
{
|
{
|
||||||
struct ate_softc *sc = xsc;
|
struct ate_softc *sc = xsc;
|
||||||
struct ifnet *ifp = sc->ifp;
|
struct ifnet *ifp = sc->ifp;
|
||||||
|
struct mii_data *mii;
|
||||||
|
|
||||||
ATE_ASSERT_LOCKED(sc);
|
ATE_ASSERT_LOCKED(sc);
|
||||||
|
|
||||||
@ -731,6 +760,10 @@ ateinit_locked(void *xsc)
|
|||||||
*/
|
*/
|
||||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
||||||
|
|
||||||
|
mii = device_get_softc(sc->miibus);
|
||||||
|
mii_pollstat(mii);
|
||||||
|
ate_stat_update(sc, mii->mii_media_active);
|
||||||
atestart_locked(ifp);
|
atestart_locked(ifp);
|
||||||
|
|
||||||
callout_reset(&sc->tick_ch, hz, ate_tick, sc);
|
callout_reset(&sc->tick_ch, hz, ate_tick, sc);
|
||||||
@ -745,7 +778,7 @@ atestart_locked(struct ifnet *ifp)
|
|||||||
struct ate_softc *sc = ifp->if_softc;
|
struct ate_softc *sc = ifp->if_softc;
|
||||||
struct mbuf *m, *mdefrag;
|
struct mbuf *m, *mdefrag;
|
||||||
bus_dma_segment_t segs[1];
|
bus_dma_segment_t segs[1];
|
||||||
int nseg;
|
int nseg, e;
|
||||||
|
|
||||||
ATE_ASSERT_LOCKED(sc);
|
ATE_ASSERT_LOCKED(sc);
|
||||||
if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
|
if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
|
||||||
@ -767,14 +800,19 @@ atestart_locked(struct ifnet *ifp)
|
|||||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
e = bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txcur], m,
|
||||||
|
segs, &nseg, 0);
|
||||||
|
if (e == EFBIG) {
|
||||||
mdefrag = m_defrag(m, M_DONTWAIT);
|
mdefrag = m_defrag(m, M_DONTWAIT);
|
||||||
if (mdefrag == NULL) {
|
if (mdefrag == NULL) {
|
||||||
IFQ_DRV_PREPEND(&ifp->if_snd, m);
|
IFQ_DRV_PREPEND(&ifp->if_snd, m);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m = mdefrag;
|
m = mdefrag;
|
||||||
if (bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txcur], m,
|
e = bus_dmamap_load_mbuf_sg(sc->mtag,
|
||||||
segs, &nseg, 0) != 0) {
|
sc->tx_map[sc->txcur], m, segs, &nseg, 0);
|
||||||
|
}
|
||||||
|
if (e != 0) {
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user