[ar531x] [if_are] Fix if_are behaviour under high load traffic
* use ifqmaxlen * handle (inefficiently for now) meeting padding and alignment requirements for transmit mbufs. * change how TX ring handling is done Submitted by: Hiroki Mori <yamori813@yahoo.co.jp> Differential Revision: https://reviews.freebsd.org/D10557
This commit is contained in:
parent
013fbe10b5
commit
32e554aed2
@ -302,9 +302,9 @@ are_attach(device_t dev)
|
||||
ifp->if_init = are_init;
|
||||
sc->are_if_flags = ifp->if_flags;
|
||||
|
||||
/* XXX: add real size */
|
||||
IFQ_SET_MAXLEN(&ifp->if_snd, 9);
|
||||
ifp->if_snd.ifq_maxlen = 9;
|
||||
/* ifqmaxlen is sysctl value in net/if.c */
|
||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
IFQ_SET_READY(&ifp->if_snd);
|
||||
|
||||
/* Tell the upper layer(s) we support long frames. */
|
||||
@ -686,19 +686,92 @@ are_encap(struct are_softc *sc, struct mbuf **m_head)
|
||||
{
|
||||
struct are_txdesc *txd;
|
||||
struct are_desc *desc, *prev_desc;
|
||||
struct mbuf *m;
|
||||
bus_dma_segment_t txsegs[ARE_MAXFRAGS];
|
||||
uint32_t link_addr;
|
||||
int error, i, nsegs, prod, si, prev_prod;
|
||||
int txstat;
|
||||
int startcount;
|
||||
int padlen;
|
||||
|
||||
startcount = sc->are_cdata.are_tx_cnt;
|
||||
|
||||
ARE_LOCK_ASSERT(sc);
|
||||
|
||||
/*
|
||||
* Some VIA Rhine wants packet buffers to be longword
|
||||
* aligned, but very often our mbufs aren't. Rather than
|
||||
* waste time trying to decide when to copy and when not
|
||||
* to copy, just do it all the time.
|
||||
*/
|
||||
m = m_defrag(*m_head, M_NOWAIT);
|
||||
if (m == NULL) {
|
||||
device_printf(sc->are_dev, "are_encap m_defrag error\n");
|
||||
m_freem(*m_head);
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
*m_head = m;
|
||||
|
||||
/*
|
||||
* The Rhine chip doesn't auto-pad, so we have to make
|
||||
* sure to pad short frames out to the minimum frame length
|
||||
* ourselves.
|
||||
*/
|
||||
if ((*m_head)->m_pkthdr.len < ARE_MIN_FRAMELEN) {
|
||||
m = *m_head;
|
||||
padlen = ARE_MIN_FRAMELEN - m->m_pkthdr.len;
|
||||
if (M_WRITABLE(m) == 0) {
|
||||
/* Get a writable copy. */
|
||||
m = m_dup(*m_head, M_NOWAIT);
|
||||
m_freem(*m_head);
|
||||
if (m == NULL) {
|
||||
device_printf(sc->are_dev, "are_encap m_dup error\n");
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
*m_head = m;
|
||||
}
|
||||
if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) {
|
||||
m = m_defrag(m, M_NOWAIT);
|
||||
if (m == NULL) {
|
||||
device_printf(sc->are_dev, "are_encap m_defrag error\n");
|
||||
m_freem(*m_head);
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Manually pad short frames, and zero the pad space
|
||||
* to avoid leaking data.
|
||||
*/
|
||||
bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
|
||||
m->m_pkthdr.len += padlen;
|
||||
m->m_len = m->m_pkthdr.len;
|
||||
*m_head = m;
|
||||
}
|
||||
|
||||
prod = sc->are_cdata.are_tx_prod;
|
||||
txd = &sc->are_cdata.are_txdesc[prod];
|
||||
error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, txd->tx_dmamap,
|
||||
*m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
|
||||
error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag,
|
||||
txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
|
||||
if (error == EFBIG) {
|
||||
panic("EFBIG");
|
||||
device_printf(sc->are_dev, "are_encap EFBIG error\n");
|
||||
m = m_defrag(*m_head, M_NOWAIT);
|
||||
if (m == NULL) {
|
||||
m_freem(*m_head);
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
*m_head = m;
|
||||
error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag,
|
||||
txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
|
||||
if (error != 0) {
|
||||
m_freem(*m_head);
|
||||
*m_head = NULL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
} else if (error != 0)
|
||||
return (error);
|
||||
if (nsegs == 0) {
|
||||
@ -729,13 +802,12 @@ are_encap(struct are_softc *sc, struct mbuf **m_head)
|
||||
for (i = 0; i < nsegs; i++) {
|
||||
desc = &sc->are_rdata.are_tx_ring[prod];
|
||||
desc->are_stat = ADSTAT_OWN;
|
||||
desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len) | ADCTL_CH;
|
||||
if (i == 0)
|
||||
desc->are_devcs |= ADCTL_Tx_FS;
|
||||
desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len);
|
||||
desc->are_addr = txsegs[i].ds_addr;
|
||||
/* link with previous descriptor */
|
||||
if (prev_desc)
|
||||
prev_desc->are_link = ARE_TX_RING_ADDR(sc, prod);
|
||||
/* end of descriptor */
|
||||
if (prod == ARE_TX_RING_CNT - 1)
|
||||
desc->are_devcs |= ADCTL_ER;
|
||||
|
||||
sc->are_cdata.are_tx_cnt++;
|
||||
prev_desc = desc;
|
||||
@ -761,16 +833,16 @@ are_encap(struct are_softc *sc, struct mbuf **m_head)
|
||||
/* Start transmitting */
|
||||
/* Check if new list is queued in NDPTR */
|
||||
txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
|
||||
if (txstat == 0 || txstat == 6) {
|
||||
/* Transmit Process Stat is stop or suspended */
|
||||
CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
|
||||
if (startcount == 0 && (txstat == 0 || txstat == 6)) {
|
||||
desc = &sc->are_rdata.are_tx_ring[si];
|
||||
desc->are_devcs |= ADCTL_Tx_FS;
|
||||
}
|
||||
else {
|
||||
link_addr = ARE_TX_RING_ADDR(sc, si);
|
||||
/* Get previous descriptor */
|
||||
si = (si + ARE_TX_RING_CNT - 1) % ARE_TX_RING_CNT;
|
||||
desc = &sc->are_rdata.are_tx_ring[si];
|
||||
desc->are_link = link_addr;
|
||||
desc->are_devcs &= ~(ADCTL_Tx_IC | ADCTL_Tx_LS);
|
||||
}
|
||||
|
||||
return (0);
|
||||
@ -782,6 +854,7 @@ are_start_locked(struct ifnet *ifp)
|
||||
struct are_softc *sc;
|
||||
struct mbuf *m_head;
|
||||
int enq;
|
||||
int txstat;
|
||||
|
||||
sc = ifp->if_softc;
|
||||
|
||||
@ -816,6 +889,14 @@ are_start_locked(struct ifnet *ifp)
|
||||
*/
|
||||
ETHER_BPF_MTAP(ifp, m_head);
|
||||
}
|
||||
|
||||
if (enq > 0) {
|
||||
txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
|
||||
if (txstat == 0 || txstat == 6) {
|
||||
/* Transmit Process Stat is stop or suspended */
|
||||
CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -44,6 +44,8 @@ struct are_desc {
|
||||
#define ARE_TX_RING_CNT 128
|
||||
#define ARE_TX_RING_SIZE sizeof(struct are_desc) * ARE_TX_RING_CNT
|
||||
#define ARE_RX_RING_SIZE sizeof(struct are_desc) * ARE_RX_RING_CNT
|
||||
|
||||
#define ARE_MIN_FRAMELEN 60
|
||||
#define ARE_RING_ALIGN sizeof(struct are_desc)
|
||||
#define ARE_RX_ALIGN sizeof(uint32_t)
|
||||
#define ARE_MAXFRAGS 8
|
||||
|
Loading…
Reference in New Issue
Block a user