Fix pass3 Tx DMA - when an mbuf spans a page boundary, make sure that

it either is sitting in contiguous physical RAM or split the mbuf
 into two Tx descriptors.  Not the prettiest patch, but works well in
 practice - gets about an 8% decrease on CPU time for a simple ttcp TCP
 Tx benchmark.  Thanks to Chris Demetriou for some debugging help.
Add some event counters.
Remove some #if 0'd debug code.
This commit is contained in:
simonb 2004-03-18 05:57:58 +00:00
parent 934c6a9eb2
commit 0c55ae72f4

View File

@ -1,4 +1,4 @@
/* $NetBSD: sbmac.c,v 1.14 2004/03/14 10:55:45 simonb Exp $ */
/* $NetBSD: sbmac.c,v 1.15 2004/03/18 05:57:58 simonb Exp $ */
/*
* Copyright 2000, 2001
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sbmac.c,v 1.14 2004/03/14 10:55:45 simonb Exp $");
__KERNEL_RCSID(0, "$NetBSD: sbmac.c,v 1.15 2004/03/18 05:57:58 simonb Exp $");
#include "bpfilter.h"
#include "opt_inet.h"
@ -83,7 +83,6 @@ __KERNEL_RCSID(0, "$NetBSD: sbmac.c,v 1.14 2004/03/14 10:55:45 simonb Exp $");
#include <mips/sibyte/include/sb1250_dma.h>
#include <mips/sibyte/include/sb1250_scd.h>
/* Simple types */
typedef u_long sbmac_port_t;
@ -105,6 +104,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
/* Macros */
#define SBMAC_EVENT_COUNTERS /* Include counters for various events */
#define SBDMA_NEXTBUF(d, f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \
(d)->sbdma_dscrtable : (d)->f+1)
@ -213,9 +214,25 @@ struct sbmac_softc {
sbmacdma_t sbm_rxdma;
int sbm_pass3_dma; /* chip has pass3 SOC DMA features */
#ifdef SBMAC_EVENT_COUNTERS
struct evcnt sbm_ev_rxintr; /* Rx interrupts */
struct evcnt sbm_ev_txintr; /* Tx interrupts */
struct evcnt sbm_ev_txdrop; /* Tx dropped due to no mbuf alloc failed */
struct evcnt sbm_ev_txstall; /* Tx stalled due to no descriptors free */
struct evcnt sbm_ev_txsplit; /* pass3 Tx split mbuf */
struct evcnt sbm_ev_txkeep; /* pass3 Tx didn't split mbuf */
#endif
};
#ifdef SBMAC_EVENT_COUNTERS
#define SBMAC_EVCNT_INCR(ev) (ev).ev_count++
#else
#define SBMAC_EVCNT_INCR(ev) do { /* nothing */ } while (0)
#endif
/* Externs */
extern paddr_t kvtophys(vaddr_t);
@ -593,22 +610,10 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
* the ring, the ring is full
*/
if (nextdsc == d->sbdma_remptr)
if (nextdsc == d->sbdma_remptr) {
SBMAC_EVCNT_INCR(sc->sbm_ev_txstall);
return ENOSPC;
#if 0
do {
struct mbuf *m0;
printf("mbuf chain: ");
for (m0 = m; m0 != 0; m0 = m0->m_next) {
printf("%d%c/%X ", m0->m_len,
m0->m_flags & M_EXT ? 'X' : 'N',
mtod(m0, u_int));
}
printf("\n");
} while (0);
#endif
/*
* PASS3 parts do not have buffer alignment restriction.
@ -632,7 +637,8 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
*/
dsc->dscr_b =
V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |
V_DMA_DSCRB_A_SIZE((m->m_len + (mtod(m,unsigned int) & 0x0000001F))) |
V_DMA_DSCRB_A_SIZE((m->m_len +
(mtod(m,unsigned int) & 0x0000001F))) |
V_DMA_DSCRB_PKT_SIZE_MSB( (m->m_pkthdr.len & 0xB000) ) |
V_DMA_DSCRB_PKT_SIZE(m->m_pkthdr.len);
@ -643,24 +649,50 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
/* Start with first non-head mbuf */
for(m_temp = m->m_next; m_temp != 0; m_temp = m_temp->m_next) {
int len, next_len;
uint64_t addr;
if (m_temp->m_len == 0)
continue; /* Skip 0-length mbufs */
len = m_temp->m_len;
addr = KVTOPHYS(mtod(m_temp, caddr_t));
/*
* Check to see if the mbuf spans a page boundary. If
* it does, and the physical pages behind the virtual
* pages are not contiguous, split it so that each
* virtual page uses it's own Tx descriptor.
*/
if (trunc_page(addr) != trunc_page(addr + len - 1)) {
next_len = (addr + len) - trunc_page(addr + len);
len -= next_len;
if (addr + len ==
KVTOPHYS(mtod(m_temp, caddr_t) + len)) {
SBMAC_EVCNT_INCR(sc->sbm_ev_txkeep);
len += next_len;
next_len = 0;
} else {
SBMAC_EVCNT_INCR(sc->sbm_ev_txsplit);
}
} else {
next_len = 0;
}
again:
/*
* fill in the descriptor
*/
dsc->dscr_a = KVTOPHYS(mtod(m_temp,caddr_t)) |
M_DMA_DSCRA_INTERRUPT;
dsc->dscr_a = addr | M_DMA_DSCRA_INTERRUPT;
/*
* transmitting: set outbound options,buffer A
* size(+ low 5 bits of start addr)
*/
dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_NOTSOP) |
V_DMA_DSCRB_A_SIZE( (m_temp->m_len +
(mtod(m_temp,unsigned int) & 0x0000001F)) );
V_DMA_DSCRB_A_SIZE((len + (addr & 0x0000001F)));
d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = NULL;
@ -670,6 +702,7 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
if (nextdsc == d->sbdma_remptr) {
d->sbdma_addptr = origdesc;
SBMAC_EVCNT_INCR(sc->sbm_ev_txstall);
return ENOSPC;
}
d->sbdma_addptr = nextdsc;
@ -677,8 +710,16 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
prevdsc = dsc;
dsc = d->sbdma_addptr;
num_mbufs++;
if (next_len != 0) {
addr = KVTOPHYS(mtod(m_temp, caddr_t) + len);
len = next_len;
next_len = 0;
goto again;
}
}
/*Set head mbuf to last context index*/
d->sbdma_ctxtable[prevdsc-d->sbdma_dscrtable] = m;
} else {
@ -694,6 +735,7 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
if (m_new == NULL) {
printf("%s: mbuf allocation failed\n",
d->sbdma_eth->sc_dev.dv_xname);
SBMAC_EVCNT_INCR(sc->sbm_ev_txdrop);
return ENOBUFS;
}
@ -702,6 +744,7 @@ sbdma_add_txbuffer(sbmacdma_t *d, struct mbuf *m)
printf("%s: mbuf cluster allocation failed\n",
d->sbdma_eth->sc_dev.dv_xname);
m_freem(m_new);
SBMAC_EVCNT_INCR(sc->sbm_ev_txdrop);
return ENOBUFS;
}
@ -1077,12 +1120,22 @@ sbmac_initctx(struct sbmac_softc *s)
SYS_SOC_TYPE(sysrev) == K_SYS_SOC_TYPE_BCM1125H ||
(SYS_SOC_TYPE(sysrev) == K_SYS_SOC_TYPE_BCM1250 &&
0));
#ifdef SBMAC_EVENT_COUNTERS
evcnt_attach_dynamic(&s->sbm_ev_rxintr, EVCNT_TYPE_INTR,
NULL, s->sc_dev.dv_xname, "rxintr");
evcnt_attach_dynamic(&s->sbm_ev_txintr, EVCNT_TYPE_INTR,
NULL, s->sc_dev.dv_xname, "txintr");
evcnt_attach_dynamic(&s->sbm_ev_txdrop, EVCNT_TYPE_MISC,
NULL, s->sc_dev.dv_xname, "txdrop");
evcnt_attach_dynamic(&s->sbm_ev_txstall, EVCNT_TYPE_MISC,
NULL, s->sc_dev.dv_xname, "txstall");
if (s->sbm_pass3_dma) {
printf("\n");
printf("%s: disabling unaligned tx DMA\n", s->sc_dev.dv_xname);
printf("%s", s->sc_dev.dv_xname);
s->sbm_pass3_dma = 0;
evcnt_attach_dynamic(&s->sbm_ev_txsplit, EVCNT_TYPE_MISC,
NULL, s->sc_dev.dv_xname, "pass3tx-split");
evcnt_attach_dynamic(&s->sbm_ev_txkeep, EVCNT_TYPE_MISC,
NULL, s->sc_dev.dv_xname, "pass3tx-keep");
}
#endif
}
/*
@ -1706,15 +1759,19 @@ sbmac_intr(void *xsc, uint32_t status, uint32_t pc)
* Transmits on channel 0
*/
if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0))
if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
sbdma_tx_process(sc, &(sc->sbm_txdma));
SBMAC_EVCNT_INCR(sc->sbm_ev_txintr);
}
/*
* Receives on channel 0
*/
if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0))
if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
sbdma_rx_process(sc, &(sc->sbm_rxdma));
SBMAC_EVCNT_INCR(sc->sbm_ev_rxintr);
}
}
/* try to get more packets going */