To send a frame, controller requires a prepended TX header and

the length of frame should be treated as multiple of 4. Actual
frame length is set in the TX header. The TX header position
should be aligned on 4 byte boundary and actual frame start
position should be aligned on 4 byte boundary as well. This means
we need 4(TX header length) + 3(frame length fixup) additional free
space in TX buffer in addition to actual frame length.
Make sure TX handler check these additional bytes.
ae_tx_avail_size() returns actual free space in TX buffer to ease
the calculation of available TX buffer space in caller. While I'm
here, replace magic number to appropriate sizeof operator to
enhance readability.

This change should fix controller lockup issue happened under
certain conditions but it still does not fix watchdog timeout. It
seems the watchdog timeout is side-effect of TxS and TxD
mismatches. The root cause of TxD/TxD mismatch is not known yet but
it looks like silicon bug. I guess driver may have to reinitialize
controller whenever it sees TxS and TxD mismatches but leave it as
it was at this moment.

PR:	kern/145918
This commit is contained in:
yongari 2011-11-11 19:15:32 +00:00
parent e290adc1a6
commit 1ba5a93307

View File

@ -1431,7 +1431,7 @@ ae_tx_avail_size(ae_softc_t *sc)
else
avail = sc->txd_ack - sc->txd_cur;
return (avail - 4); /* 4-byte header. */
return (avail);
}
static int
@ -1448,7 +1448,7 @@ ae_encap(ae_softc_t *sc, struct mbuf **m_head)
len = m0->m_pkthdr.len;
if ((sc->flags & AE_FLAG_TXAVAIL) == 0 ||
ae_tx_avail_size(sc) < len) {
len + sizeof(ae_txd_t) + 3 > ae_tx_avail_size(sc)) {
#ifdef AE_DEBUG
if_printf(sc->ifp, "No free Tx available.\n");
#endif
@ -1457,11 +1457,10 @@ ae_encap(ae_softc_t *sc, struct mbuf **m_head)
hdr = (ae_txd_t *)(sc->txd_base + sc->txd_cur);
bzero(hdr, sizeof(*hdr));
sc->txd_cur = (sc->txd_cur + 4) % AE_TXD_BUFSIZE_DEFAULT; /* Header
size. */
to_end = AE_TXD_BUFSIZE_DEFAULT - sc->txd_cur; /* Space available to
* the end of the ring
*/
/* Skip header size. */
sc->txd_cur = (sc->txd_cur + sizeof(ae_txd_t)) % AE_TXD_BUFSIZE_DEFAULT;
/* Space available to the end of the ring */
to_end = AE_TXD_BUFSIZE_DEFAULT - sc->txd_cur;
if (to_end >= len) {
m_copydata(m0, 0, len, (caddr_t)(sc->txd_base + sc->txd_cur));
} else {
@ -1840,8 +1839,8 @@ ae_tx_intr(ae_softc_t *sc)
/*
* Move txd ack and align on 4-byte boundary.
*/
sc->txd_ack = ((sc->txd_ack + le16toh(txd->len) + 4 + 3) & ~3) %
AE_TXD_BUFSIZE_DEFAULT;
sc->txd_ack = ((sc->txd_ack + le16toh(txd->len) +
sizeof(ae_txs_t) + 3) & ~3) % AE_TXD_BUFSIZE_DEFAULT;
if ((flags & AE_TXS_SUCCESS) != 0)
ifp->if_opackets++;