Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/broadcom Add some defensive code to deal with "...
details: https://anonhg.NetBSD.org/src/rev/415ee024f1d5
branches: trunk
changeset: 782010:415ee024f1d5
user: matt <matt%NetBSD.org@localhost>
date: Fri Oct 12 23:25:15 2012 +0000
description:
Add some defensive code to deal with "issues" of this interface.
Seems it can't do DMA updates of the rxsts for mbufs with addresses
>= 256MB. It can't also seem to properly read from the descriptor rings
if they are < 256MB. And I have no idea why either should matter.
diffstat:
sys/arch/arm/broadcom/bcm53xx_eth.c | 106 ++++++++++++++++++++++++++++++-----
1 files changed, 89 insertions(+), 17 deletions(-)
diffs (268 lines):
diff -r 67f7a44f47b4 -r 415ee024f1d5 sys/arch/arm/broadcom/bcm53xx_eth.c
--- a/sys/arch/arm/broadcom/bcm53xx_eth.c Fri Oct 12 21:10:55 2012 +0000
+++ b/sys/arch/arm/broadcom/bcm53xx_eth.c Fri Oct 12 23:25:15 2012 +0000
@@ -27,13 +27,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define _ARM32_BUS_DMA_PRIVATE
#define GMAC_PRIVATE
#include "locators.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: bcm53xx_eth.c,v 1.9 2012/10/08 20:54:10 matt Exp $");
+__KERNEL_RCSID(1, "$NetBSD: bcm53xx_eth.c,v 1.10 2012/10/12 23:25:15 matt Exp $");
#include <sys/param.h>
#include <sys/atomic.h>
@@ -61,13 +62,15 @@
#include <arm/broadcom/bcm53xx_var.h>
#define BCMETH_RCVOFFSET 6
-#define BCMETH_MAXTXMBUFS 32
+#define BCMETH_MAXTXMBUFS 128
#define BCMETH_NTXSEGS 30
#define BCMETH_MAXRXMBUFS 255
#define BCMETH_MINRXMBUFS 64
#define BCMETH_NRXSEGS 1
#define BCMETH_RINGSIZE PAGE_SIZE
+#define BCMETH_RCVMAGIC 0xfeedface
+
static int bcmeth_ccb_match(device_t, cfdata_t, void *);
static void bcmeth_ccb_attach(device_t, device_t, void *);
@@ -86,6 +89,7 @@
bus_size_t txq_reg_xmtptr;
bus_size_t txq_reg_xmtctl;
bus_size_t txq_reg_xmtsts0;
+ bus_size_t txq_reg_xmtsts1;
bus_dma_segment_t txq_descmap_seg;
};
@@ -104,6 +108,7 @@
bus_size_t rxq_reg_rcvptr;
bus_size_t rxq_reg_rcvctl;
bus_size_t rxq_reg_rcvsts0;
+ bus_size_t rxq_reg_rcvsts1;
bus_dma_segment_t rxq_descmap_seg;
};
@@ -141,8 +146,10 @@
struct evcnt sc_ev_intr;
struct evcnt sc_ev_soft_intr;
- struct evcnt sc_ev_work;;
+ struct evcnt sc_ev_work;
struct evcnt sc_ev_tx_stall;
+ struct evcnt sc_ev_rx_badmagic_lo;
+ struct evcnt sc_ev_rx_badmagic_hi;
struct ifqueue sc_rx_bufcache;
struct bcmeth_mapcache *sc_rx_mapcache;
@@ -203,6 +210,13 @@
static int bcmeth_mediachange(struct ifnet *);
static void bcmeth_mediastatus(struct ifnet *, struct ifmediareq *);
+static struct arm32_dma_range bcmeth_dma_ranges[2];
+static struct arm32_bus_dma_tag bcmeth_dma_tag = {
+ _BUS_DMAMAP_FUNCS,
+ _BUS_DMAMEM_FUNCS,
+ _BUS_DMATAG_FUNCS,
+};
+
static inline uint32_t
bcmeth_read_4(struct bcmeth_softc *sc, bus_size_t o)
{
@@ -252,6 +266,25 @@
bus_space_subregion(sc->sc_bst, ccbaa->ccbaa_ccb_bsh,
loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+ /*
+ * Initialize a bus_dma_tag to prefer memory over 256MB.
+ */
+ if (bcmeth_dma_tag._nranges != sc->sc_dmat->_nranges) {
+ KASSERT(sc->sc_dmat->_nranges == 2);
+ bcmeth_dma_ranges[0] = sc->sc_dmat->_ranges[1];
+ bcmeth_dma_ranges[1] = sc->sc_dmat->_ranges[0];
+ bcmeth_dma_tag._ranges = bcmeth_dma_ranges;
+ bcmeth_dma_tag._nranges = sc->sc_dmat->_nranges;
+ }
+
+ /*
+ * If we initialized our dma tag, then use it.
+ */
+ if (bcmeth_dma_tag._nranges > 0) {
+ sc->sc_dmat = &bcmeth_dma_tag;
+ KASSERT(sc->sc_dmat->_ranges[0].dr_busbase - sc->sc_dmat->_ranges[1].dr_busbase == 0x10000000);
+ }
+
prop_data_t eaprop = prop_dictionary_get(dict, "mac-address");
if (eaprop == NULL) {
uint32_t mac0 = bcmeth_read_4(sc, UNIMAC_MAC_0);
@@ -372,6 +405,10 @@
NULL, xname, "work items");
evcnt_attach_dynamic(&sc->sc_ev_tx_stall, EVCNT_TYPE_MISC,
NULL, xname, "tx stalls");
+ evcnt_attach_dynamic(&sc->sc_ev_rx_badmagic_lo, EVCNT_TYPE_MISC,
+ NULL, xname, "rx badmagic lo");
+ evcnt_attach_dynamic(&sc->sc_ev_rx_badmagic_hi, EVCNT_TYPE_MISC,
+ NULL, xname, "rx badmagic hi");
}
static int
@@ -763,15 +800,14 @@
*kvap = NULL;
*map = NULL;
- error = bus_dmamem_alloc(dmat, map_size, PAGE_SIZE, 0,
+ error = bus_dmamem_alloc(dmat, map_size, 2*PAGE_SIZE, 0,
seg, 1, &nseg, 0);
if (error)
return error;
KASSERT(nseg == 1);
- error = bus_dmamem_map(dmat, seg, nseg, map_size, (void **)kvap,
- BUS_DMA_COHERENT);
+ error = bus_dmamem_map(dmat, seg, nseg, map_size, (void **)kvap, 0);
if (error == 0) {
error = bus_dmamap_create(dmat, map_size, 1, map_size, 0, 0,
map);
@@ -826,8 +862,12 @@
return NULL;
}
KASSERT(map->dm_mapsize == MCLBYTES);
- bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
- BUS_DMASYNC_PREREAD);
+ *mtod(m, uint32_t *) = BCMETH_RCVMAGIC;
+ bus_dmamap_sync(sc->sc_dmat, map, 0, sizeof(uint32_t),
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ bus_dmamap_sync(sc->sc_dmat, map, sizeof(uint32_t),
+ map->dm_mapsize - sizeof(uint32_t), BUS_DMASYNC_PREREAD);
return m;
}
@@ -977,19 +1017,26 @@
bus_dmamap_sync(sc->sc_dmat, map, 0, arm_dcache_align,
BUS_DMASYNC_POSTREAD);
memcpy(&rxsts, rxq->rxq_mhead->m_data, 4);
+#if 0
+ KASSERTMSG(rxsts != BCMETH_RCVMAGIC, "currdscr=%u consumer=%zd",
+ currdscr, consumer - rxq->rxq_first);
+#endif
/*
* Get the count of descriptors. Fetch the correct number
* of mbufs.
*/
- size_t desc_count = __SHIFTOUT(rxsts, RXSTS_DESC_COUNT) + 1;
+ size_t desc_count = rxsts != BCMETH_RCVMAGIC ? __SHIFTOUT(rxsts, RXSTS_DESC_COUNT) + 1 : 1;
struct mbuf *m = rxq->rxq_mhead;
struct mbuf *m_last = m;
for (size_t i = 1; i < desc_count; i++) {
if (++consumer == rxq->rxq_last) {
consumer = rxq->rxq_first;
}
- KASSERT(consumer != rxq->rxq_first + currdscr);
+ KASSERTMSG(consumer != rxq->rxq_first + currdscr,
+ "i=%zu rxsts=%#x desc_count=%zu currdscr=%u consumer=%zd",
+ i, rxsts, desc_count, currdscr,
+ consumer - rxq->rxq_first);
m_last = m_last->m_next;
}
@@ -1000,7 +1047,15 @@
rxq->rxq_mtail = &rxq->rxq_mhead;
m_last->m_next = NULL;
- if (rxsts & (RXSTS_CRC_ERROR|RXSTS_OVERSIZED|RXSTS_PKT_OVERFLOW)) {
+ if (rxsts == BCMETH_RCVMAGIC) {
+ ifp->if_ierrors++;
+ if ((m->m_ext.ext_paddr >> 28) == 8) {
+ sc->sc_ev_rx_badmagic_lo.ev_count++;
+ } else {
+ sc->sc_ev_rx_badmagic_hi.ev_count++;
+ }
+ IF_ENQUEUE(&sc->sc_rx_bufcache, m);
+ } else if (rxsts & (RXSTS_CRC_ERROR|RXSTS_OVERSIZED|RXSTS_PKT_OVERFLOW)) {
aprint_error_dev(sc->sc_dev, "[%zu]: count=%zu rxsts=%#x\n",
consumer - rxq->rxq_first, desc_count, rxsts);
/*
@@ -1137,6 +1192,7 @@
rxq->rxq_reg_rcvctl = GMAC_RCVCONTROL;
rxq->rxq_reg_rcvptr = GMAC_RCVPTR;
rxq->rxq_reg_rcvsts0 = GMAC_RCVSTATUS0;
+ rxq->rxq_reg_rcvsts1 = GMAC_RCVSTATUS1;
return 0;
}
@@ -1186,6 +1242,7 @@
txq->txq_reg_xmtctl = GMAC_XMTCONTROL;
txq->txq_reg_xmtptr = GMAC_XMTPTR;
txq->txq_reg_xmtsts0 = GMAC_XMTSTATUS0;
+ txq->txq_reg_xmtsts1 = GMAC_XMTSTATUS1;
bcmeth_txq_reset(sc, txq);
@@ -1292,7 +1349,8 @@
producer->txdb_flags, producer->txdb_buflen,
producer->txdb_addrlo, producer->txdb_addrhi);
#endif
- bcmeth_txq_desc_presync(sc, txq, start, count);
+ if (count)
+ bcmeth_txq_desc_presync(sc, txq, start, count);
/*
* Reduce free count by the number of segments we consumed.
@@ -1308,12 +1366,11 @@
txq->txq_producer - txq->txq_first, producer - txq->txq_first);
#endif
- if (++producer == txq->txq_last)
+ if (producer + 1 == txq->txq_last)
txq->txq_producer = txq->txq_first;
else
- txq->txq_producer = producer;
+ txq->txq_producer = producer + 1;
IF_ENQUEUE(&txq->txq_mbufs, m);
- bpf_mtap(&sc->sc_if, m);
/*
* Let the transmitter know there's more to do
@@ -1415,6 +1472,7 @@
printf("%s: mbuf %p: consumed a %u byte packet\n",
__func__, m, m->m_pkthdr.len);
#endif
+ bpf_mtap(ifp, m);
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
if (m->m_flags & M_MCAST)
@@ -1584,8 +1642,22 @@
}
if (intstatus) {
- aprint_error_dev(sc->sc_dev, "intr: intstatus=%#x\n",
- intstatus);
+ aprint_error_dev(sc->sc_dev,
+ "intr: intstatus=%#x\n", intstatus);
+ aprint_error_dev(sc->sc_dev,
+ "rcvbase=%p/%#lx rcvptr=%#x rcvsts=%#x/%#x\n",
+ sc->sc_rxq.rxq_first,
+ sc->sc_rxq.rxq_descmap->dm_segs[0].ds_addr,
+ bcmeth_read_4(sc, sc->sc_rxq.rxq_reg_rcvptr),
+ bcmeth_read_4(sc, sc->sc_rxq.rxq_reg_rcvsts0),
+ bcmeth_read_4(sc, sc->sc_rxq.rxq_reg_rcvsts1));
+ aprint_error_dev(sc->sc_dev,
+ "xmtbase=%p/%#lx xmtptr=%#x xmtsts=%#x/%#x\n",
+ sc->sc_txq.txq_first,
+ sc->sc_txq.txq_descmap->dm_segs[0].ds_addr,
+ bcmeth_read_4(sc, sc->sc_txq.txq_reg_xmtptr),
+ bcmeth_read_4(sc, sc->sc_txq.txq_reg_xmtsts0),
+ bcmeth_read_4(sc, sc->sc_txq.txq_reg_xmtsts1));
Debugger();
sc->sc_intmask &= ~intstatus;
work_flags |= WORK_REINIT;
Home |
Main Index |
Thread Index |
Old Index