Module Name: src Committed By: hsuenaga Date: Wed Jun 3 03:55:47 UTC 2015
Modified Files: src/sys/arch/arm/marvell: files.marvell mvsoc.c src/sys/dev/marvell: files.armada if_mvxpe.c if_mvxpereg.h if_mvxpevar.h Added Files: src/sys/dev/marvell: mvxpbm.c mvxpbmvar.h Log Message: separate buffer management codes 'mvxpbm.c' from if_mvxpe.c. the buffer management(ex. fill the rx descriptors/buffers) is done by H/W in ARMADA XP/380, and is done by S/W in ARMADA 370. the H/W BM support is not yet implemented, so all devices use the S/W management mode at this time. To generate a diff of this commit: cvs rdiff -u -r1.15 -r1.16 src/sys/arch/arm/marvell/files.marvell cvs rdiff -u -r1.21 -r1.22 src/sys/arch/arm/marvell/mvsoc.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/marvell/files.armada \ src/sys/dev/marvell/if_mvxpe.c src/sys/dev/marvell/if_mvxpereg.h \ src/sys/dev/marvell/if_mvxpevar.h cvs rdiff -u -r0 -r1.1 src/sys/dev/marvell/mvxpbm.c \ src/sys/dev/marvell/mvxpbmvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/marvell/files.marvell diff -u src/sys/arch/arm/marvell/files.marvell:1.15 src/sys/arch/arm/marvell/files.marvell:1.16 --- src/sys/arch/arm/marvell/files.marvell:1.15 Wed Jun 3 03:34:38 2015 +++ src/sys/arch/arm/marvell/files.marvell Wed Jun 3 03:55:47 2015 @@ -1,4 +1,4 @@ -# $NetBSD: files.marvell,v 1.15 2015/06/03 03:34:38 hsuenaga Exp $ +# $NetBSD: files.marvell,v 1.16 2015/06/03 03:55:47 hsuenaga Exp $ # # Configuration info for Marvell System on Chip support # @@ -58,6 +58,9 @@ attach mvsata at mvsoc with mvsata_mbus # Gigabit Ethernet Controller Interface attach mvgbec at mvsoc with mvgbec_mbus +# ARMADA XP Buffer Manager +attach mvxpbm at mvsoc with mvxpbm_mbus + # ARMADA XP Gigabit Ethernet Controller Interface attach mvxpe at mvsoc with mvxpe_mbus Index: src/sys/arch/arm/marvell/mvsoc.c diff -u src/sys/arch/arm/marvell/mvsoc.c:1.21 src/sys/arch/arm/marvell/mvsoc.c:1.22 --- src/sys/arch/arm/marvell/mvsoc.c:1.21 Wed Jun 3 03:04:21 2015 +++ src/sys/arch/arm/marvell/mvsoc.c Wed Jun 3 03:55:47 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsoc.c,v 1.21 2015/06/03 03:04:21 hsuenaga Exp $ */ +/* $NetBSD: mvsoc.c,v 1.22 2015/06/03 03:55:47 hsuenaga Exp $ */ /* * Copyright (c) 2007, 2008, 2013, 2014 KIYOHARA Takashi * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mvsoc.c,v 1.21 2015/06/03 03:04:21 hsuenaga Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsoc.c,v 1.22 2015/06/03 03:55:47 hsuenaga Exp $"); #include "opt_cputypes.h" #include "opt_mvsoc.h" @@ -685,6 +685,7 @@ static const struct mvsoc_periph { { ARMADAXP(MV78130), "mvsdio", 0, ARMADAXP_SDIO_BASE,ARMADAXP_IRQ_SDIO }, { ARMADAXP(MV78130), "mvxpe", 0, ARMADAXP_GBE0_BASE,ARMADAXP_IRQ_GBE0_TH_RXTX }, #if NMVXPE > 0 + { ARMADAXP(MV78130), "mvxpbm", 0, MVA_OFFSET_DEFAULT,IRQ_DEFAULT }, { ARMADAXP(MV78130), "mvxpe", 1, ARMADAXP_GBE1_BASE,ARMADAXP_IRQ_GBE1_TH_RXTX }, { ARMADAXP(MV78130), "mvxpe", 2, ARMADAXP_GBE2_BASE,ARMADAXP_IRQ_GBE2_TH_RXTX }, #else @@ -716,6 +717,7 @@ static const struct mvsoc_periph { { ARMADAXP(MV78160), "mvspi", 0, ARMADAXP_SPI_BASE,ARMADAXP_IRQ_SPI }, { ARMADAXP(MV78160), "mvsdio", 0, ARMADAXP_SDIO_BASE,ARMADAXP_IRQ_SDIO }, #if NMVXPE > 0 + { ARMADAXP(MV78160), "mvxpbm", 0, MVA_OFFSET_DEFAULT,IRQ_DEFAULT }, { ARMADAXP(MV78160), "mvxpe", 0, ARMADAXP_GBE0_BASE,ARMADAXP_IRQ_GBE0_TH_RXTX }, { ARMADAXP(MV78160), "mvxpe", 1, ARMADAXP_GBE1_BASE,ARMADAXP_IRQ_GBE1_TH_RXTX }, { ARMADAXP(MV78160), "mvxpe", 2, ARMADAXP_GBE2_BASE,ARMADAXP_IRQ_GBE2_TH_RXTX }, @@ -751,6 +753,7 @@ static const struct mvsoc_periph { { ARMADAXP(MV78230), "mvspi", 0, ARMADAXP_SPI_BASE,ARMADAXP_IRQ_SPI }, { ARMADAXP(MV78230), "mvsdio", 0, ARMADAXP_SDIO_BASE,ARMADAXP_IRQ_SDIO }, #if NMVXPE > 0 + { ARMADAXP(MV78230), "mvxpbm", 0, MVA_OFFSET_DEFAULT,IRQ_DEFAULT }, { ARMADAXP(MV78230), "mvxpe", 0, ARMADAXP_GBE0_BASE,ARMADAXP_IRQ_GBE0_TH_RXTX }, { ARMADAXP(MV78230), "mvxpe", 1, ARMADAXP_GBE1_BASE,ARMADAXP_IRQ_GBE1_TH_RXTX }, { ARMADAXP(MV78230), "mvxpe", 2, ARMADAXP_GBE2_BASE,ARMADAXP_IRQ_GBE2_TH_RXTX }, @@ -784,6 +787,7 @@ static const struct mvsoc_periph { { ARMADAXP(MV78260), "mvspi", 0, ARMADAXP_SPI_BASE,ARMADAXP_IRQ_SPI }, { ARMADAXP(MV78260), "mvsdio", 0, ARMADAXP_SDIO_BASE,ARMADAXP_IRQ_SDIO }, #if NMVXPE > 0 + { ARMADAXP(MV78260), "mvxpbm", 0, MVA_OFFSET_DEFAULT,IRQ_DEFAULT }, { ARMADAXP(MV78260), "mvxpe", 0, ARMADAXP_GBE0_BASE,ARMADAXP_IRQ_GBE0_TH_RXTX }, { ARMADAXP(MV78260), "mvxpe", 1, ARMADAXP_GBE1_BASE,ARMADAXP_IRQ_GBE1_TH_RXTX }, { ARMADAXP(MV78260), "mvxpe", 2, ARMADAXP_GBE2_BASE,ARMADAXP_IRQ_GBE2_TH_RXTX }, @@ -820,6 +824,7 @@ static const struct mvsoc_periph { { ARMADAXP(MV78460), "mvspi", 0, ARMADAXP_SPI_BASE,ARMADAXP_IRQ_SPI }, { ARMADAXP(MV78460), "mvsdio", 0, ARMADAXP_SDIO_BASE,ARMADAXP_IRQ_SDIO }, #if NMVXPE > 0 + { ARMADAXP(MV78460), "mvxpbm", 0, MVA_OFFSET_DEFAULT,IRQ_DEFAULT }, { ARMADAXP(MV78460), "mvxpe", 0, ARMADAXP_GBE0_BASE,ARMADAXP_IRQ_GBE0_TH_RXTX }, { ARMADAXP(MV78460), "mvxpe", 1, ARMADAXP_GBE1_BASE,ARMADAXP_IRQ_GBE1_TH_RXTX }, { ARMADAXP(MV78460), "mvxpe", 2, ARMADAXP_GBE2_BASE,ARMADAXP_IRQ_GBE2_TH_RXTX }, @@ -849,6 +854,7 @@ static const struct mvsoc_periph { { ARMADA370(MV6710), "mvspi", 1, ARMADAXP_SPI_BASE,ARMADAXP_IRQ_SPI }, { ARMADA370(MV6710), "mvsdio", 0, ARMADAXP_SDIO_BASE,ARMADAXP_IRQ_SDIO }, #if NMVXPE > 0 + { ARMADA370(MV6710), "mvxpbm", 0, MVA_OFFSET_DEFAULT,IRQ_DEFAULT }, { ARMADA370(MV6710), "mvxpe", 0, ARMADAXP_GBE0_BASE,ARMADAXP_IRQ_GBE0_TH_RXTX }, { ARMADA370(MV6710), "mvxpe", 1, ARMADAXP_GBE1_BASE,ARMADAXP_IRQ_GBE1_TH_RXTX }, #else Index: src/sys/dev/marvell/files.armada diff -u src/sys/dev/marvell/files.armada:1.1 src/sys/dev/marvell/files.armada:1.2 --- src/sys/dev/marvell/files.armada:1.1 Wed Jun 3 03:34:38 2015 +++ src/sys/dev/marvell/files.armada Wed Jun 3 03:55:47 2015 @@ -1,7 +1,11 @@ -# $NetBSD: files.armada,v 1.1 2015/06/03 03:34:38 hsuenaga Exp $ +# $NetBSD: files.armada,v 1.2 2015/06/03 03:55:47 hsuenaga Exp $ # Configuration info for Marvell ARMADA integrated peripherals +# ARMADA XP Buffer Manger +device mvxpbm { [port = -1 ], [irq = -1] } +file dev/marvell/mvxpbm.c + # ARMADA XP Gigabit Ethernet Controller Interface define mvxpe { [port = -1 ], [irq = -1] } -device mvxpe: ether, ifnet, arp, mii +device mvxpe: mvxpbm, ether, ifnet, arp, mii file dev/marvell/if_mvxpe.c mvxpe needs-flag Index: src/sys/dev/marvell/if_mvxpe.c diff -u src/sys/dev/marvell/if_mvxpe.c:1.1 src/sys/dev/marvell/if_mvxpe.c:1.2 --- src/sys/dev/marvell/if_mvxpe.c:1.1 Sun May 3 14:38:10 2015 +++ src/sys/dev/marvell/if_mvxpe.c Wed Jun 3 03:55:47 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_mvxpe.c,v 1.1 2015/05/03 14:38:10 hsuenaga Exp $ */ +/* $NetBSD: if_mvxpe.c,v 1.2 2015/06/03 03:55:47 hsuenaga Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. * All rights reserved. @@ -25,7 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_mvxpe.c,v 1.1 2015/05/03 14:38:10 hsuenaga Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_mvxpe.c,v 1.2 2015/06/03 03:55:47 hsuenaga Exp $"); #include "opt_multiprocessor.h" @@ -58,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_mvxpe.c,v #include <dev/marvell/marvellreg.h> #include <dev/marvell/marvellvar.h> +#include <dev/marvell/mvxpbmvar.h> #include <dev/marvell/if_mvxpereg.h> #include <dev/marvell/if_mvxpevar.h> @@ -136,30 +137,20 @@ STATIC void mvxpe_linkup(struct mvxpe_so STATIC void mvxpe_linkdown(struct mvxpe_softc *); STATIC void mvxpe_linkreset(struct mvxpe_softc *); -/* Packet Buffer Manager(BM) */ -STATIC int mvxpe_bm_init(struct mvxpe_softc *); -STATIC int mvxpe_bm_init_mbuf_hdr(struct mvxpe_bm_chunk *); -STATIC struct mvxpe_bm_chunk *mvxpe_bm_alloc(struct mvxpe_softc *); -STATIC void mvxpe_bm_free_mbuf(struct mbuf *, void *, size_t, void *); -STATIC void mvxpe_bm_free_chunk(struct mvxpe_bm_chunk *); -STATIC void mvxpe_bm_sync(struct mvxpe_bm_chunk *, size_t, int); -STATIC void mvxpe_bm_lock(struct mvxpe_softc *); -STATIC void mvxpe_bm_unlock(struct mvxpe_softc *); - /* Tx Subroutines */ STATIC int mvxpe_tx_queue_select(struct mvxpe_softc *, struct mbuf *); STATIC int mvxpe_tx_queue(struct mvxpe_softc *, struct mbuf *, int); STATIC void mvxpe_tx_set_csumflag(struct ifnet *, struct mvxpe_tx_desc *, struct mbuf *); -STATIC void mvxpe_tx_complete(struct mvxpe_softc *); -STATIC void mvxpe_tx_queue_del(struct mvxpe_softc *, int); +STATIC void mvxpe_tx_complete(struct mvxpe_softc *, uint32_t); +STATIC void mvxpe_tx_queue_complete(struct mvxpe_softc *, int); /* Rx Subroutines */ -STATIC void mvxpe_rx(struct mvxpe_softc *); +STATIC void mvxpe_rx(struct mvxpe_softc *, uint32_t); STATIC void mvxpe_rx_queue(struct mvxpe_softc *, int, int); -STATIC int mvxpe_rx_queue_select(struct mvxpe_softc *, int *); -STATIC void mvxpe_rx_reload(struct mvxpe_softc *); -STATIC void mvxpe_rx_queue_reload(struct mvxpe_softc *, int); +STATIC int mvxpe_rx_queue_select(struct mvxpe_softc *, uint32_t, int *); +STATIC void mvxpe_rx_refill(struct mvxpe_softc *, uint32_t); +STATIC void mvxpe_rx_queue_refill(struct mvxpe_softc *, int); STATIC int mvxpe_rx_queue_add(struct mvxpe_softc *, int); STATIC void mvxpe_rx_set_csumflag(struct ifnet *, struct mvxpe_rx_desc *, struct mbuf *); @@ -330,14 +321,19 @@ mvxpe_attach(device_t parent, device_t s aprint_normal_dev(self, "Port Version %#x\n", sc->sc_version); /* - * Software based Buffer Manager(BM) subsystem. - * Try to allocate special memory chunks for Rx packets. - * Some version of SoC has hardware based BM(not supported yet) + * Buffer Manager(BM) subsystem. */ - if (mvxpe_bm_init(sc) != 0) { - aprint_error_dev(self, "BM pool allocation failure\n"); + sc->sc_bm = mvxpbm_device(mva); + if (sc->sc_bm == NULL) { + aprint_error_dev(self, "no Buffer Manager.\n"); goto fail; } + aprint_normal_dev(self, + "Using Buffer Manager: %s\n", mvxpbm_xname(sc->sc_bm)); + aprint_normal_dev(sc->sc_dev, + "%zu kbytes managed buffer, %zu bytes * %u entries allocated.\n", + mvxpbm_buf_size(sc->sc_bm) / 1024, + mvxpbm_chunk_size(sc->sc_bm), mvxpbm_chunk_count(sc->sc_bm)); /* * make sure DMA engines are in reset state @@ -526,9 +522,9 @@ fail: STATIC int mvxpe_evcnt_attach(struct mvxpe_softc *sc) { +#ifdef MVXPE_EVENT_COUNTERS int q; -#ifdef MVXPE_EVENT_COUNTERS /* Master Interrupt Handler */ evcnt_attach_dynamic(&sc->sc_ev.ev_i_rxtxth, EVCNT_TYPE_INTR, NULL, device_xname(sc->sc_dev), "RxTxTH Intr."); @@ -1103,8 +1099,8 @@ mvxpe_ring_init_queue(struct mvxpe_softc rx->rx_queue_len = rx_default_queue_len[q]; if (rx->rx_queue_len > MVXPE_RX_RING_CNT) rx->rx_queue_len = MVXPE_RX_RING_CNT; - rx->rx_queue_th_received = rx->rx_queue_len / 4; - rx->rx_queue_th_free = rx->rx_queue_len / 2; + rx->rx_queue_th_received = rx->rx_queue_len / MVXPE_RXTH_RATIO; + rx->rx_queue_th_free = rx->rx_queue_len / MVXPE_RXTH_REFILL_RATIO; rx->rx_queue_th_time = (mvTclk / 1000) / 2; /* 0.5 [ms] */ /* Tx handle */ @@ -1113,8 +1109,9 @@ mvxpe_ring_init_queue(struct mvxpe_softc MVXPE_TX_DESC_OFF(sc, q, i) = sizeof(struct mvxpe_tx_desc) * i; MVXPE_TX_MBUF(sc, q, i) = NULL; /* Tx handle needs DMA map for busdma_load_mbuf() */ - if (bus_dmamap_create(sc->sc_dmat, sc->sc_bm.bm_chunk_size, - MVXPE_TX_SEGLIMIT, sc->sc_bm.bm_chunk_size, 0, + if (bus_dmamap_create(sc->sc_dmat, + mvxpbm_chunk_size(sc->sc_bm), + MVXPE_TX_SEGLIMIT, mvxpbm_chunk_size(sc->sc_bm), 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &MVXPE_TX_MAP(sc, q, i))) { aprint_error_dev(sc->sc_dev, @@ -1126,8 +1123,8 @@ mvxpe_ring_init_queue(struct mvxpe_softc tx->tx_queue_len = tx_default_queue_len[q]; if (tx->tx_queue_len > MVXPE_TX_RING_CNT) tx->tx_queue_len = MVXPE_TX_RING_CNT; - tx->tx_free_cnt = tx->tx_queue_len; - tx->tx_queue_th_free = tx->tx_queue_len / 2; + tx->tx_used = 0; + tx->tx_queue_th_free = tx->tx_queue_len / MVXPE_TXTH_RATIO; } STATIC void @@ -1144,7 +1141,7 @@ mvxpe_ring_flush_queue(struct mvxpe_soft for (i = 0; i < MVXPE_RX_RING_CNT; i++) { if (MVXPE_RX_PKTBUF(sc, q, i) == NULL) continue; - mvxpe_bm_free_chunk(MVXPE_RX_PKTBUF(sc, q, i)); + mvxpbm_free_chunk(MVXPE_RX_PKTBUF(sc, q, i)); MVXPE_RX_PKTBUF(sc, q, i) = NULL; } rx->rx_dma = rx->rx_cpu = 0; @@ -1158,7 +1155,7 @@ mvxpe_ring_flush_queue(struct mvxpe_soft MVXPE_TX_MBUF(sc, q, i) = NULL; } tx->tx_dma = tx->tx_cpu = 0; - tx->tx_free_cnt = tx->tx_queue_len; + tx->tx_used = 0; } STATIC void @@ -1218,18 +1215,23 @@ mvxpe_rx_queue_init(struct ifnet *ifp, i MVXPE_WRITE(sc, MVXPE_PRXDQA(q), MVXPE_RX_RING_MEM_PA(sc, q)); /* Rx buffer size and descriptor ring size */ - reg = MVXPE_PRXDQS_BUFFERSIZE(sc->sc_bm.bm_chunk_size >> 3); + reg = MVXPE_PRXDQS_BUFFERSIZE(mvxpbm_chunk_size(sc->sc_bm) >> 3); reg |= MVXPE_PRXDQS_DESCRIPTORSQUEUESIZE(MVXPE_RX_RING_CNT); MVXPE_WRITE(sc, MVXPE_PRXDQS(q), reg); DPRINTIFNET(ifp, 1, "PRXDQS(%d): %#x\n", q, MVXPE_READ(sc, MVXPE_PRXDQS(q))); /* Rx packet offset address */ - reg = MVXPE_PRXC_PACKETOFFSET(sc->sc_bm.bm_chunk_packet_offset >> 3); + reg = MVXPE_PRXC_PACKETOFFSET(mvxpbm_packet_offset(sc->sc_bm) >> 3); MVXPE_WRITE(sc, MVXPE_PRXC(q), reg); DPRINTIFNET(ifp, 1, "PRXC(%d): %#x\n", q, MVXPE_READ(sc, MVXPE_PRXC(q))); + /* Rx DMA SNOOP */ + reg = MVXPE_PRXSNP_SNOOPNOOFBYTES(MVXPE_MRU); + reg |= MVXPE_PRXSNP_L2DEPOSITNOOFBYTES(MVXPE_MRU); + MVXPE_WRITE(sc, MVXPE_PRXSNP(q), reg); + /* if DMA is not working, register is not updated */ KASSERT(MVXPE_READ(sc, MVXPE_PRXDQA(q)) == MVXPE_RX_RING_MEM_PA(sc, q)); return 0; @@ -1412,58 +1414,51 @@ mvxpe_rxtxth_intr(void *arg) { struct mvxpe_softc *sc = arg; struct ifnet *ifp = &sc->sc_ethercom.ec_if; - uint32_t ic, datum = 0; - int claimed = 0; - + uint32_t ic, queues, datum = 0; DPRINTSC(sc, 2, "got RXTX_TH_Intr\n"); MVXPE_EVCNT_INCR(&sc->sc_ev.ev_i_rxtxth); mvxpe_sc_lock(sc); - for (;;) { - ic = MVXPE_READ(sc, MVXPE_PRXTXTIC); - if (ic == 0) - break; - MVXPE_WRITE(sc, MVXPE_PRXTXTIC, ~ic); - datum = datum ^ ic; - claimed = 1; - - DPRINTIFNET(ifp, 2, "PRXTXTIC: %#x\n", ic); - - /* route maintance interrupt first */ - if (ic & MVXPE_PRXTXTI_PTXERRORSUMMARY) { - DPRINTIFNET(ifp, 1, "PRXTXTIC: +PTXERRORSUMMARY\n"); - MVXPE_EVCNT_INCR(&sc->sc_ev.ev_rxtxth_txerr); - } - if ((ic & MVXPE_PRXTXTI_PMISCICSUMMARY)) { - DPRINTIFNET(ifp, 2, "PTXTXTIC: +PMISCICSUMMARY\n"); - mvxpe_misc_intr(sc); - } - if (ic & MVXPE_PRXTXTI_PRXTXICSUMMARY) { - DPRINTIFNET(ifp, 2, "PTXTXTIC: +PRXTXICSUMMARY\n"); - mvxpe_rxtx_intr(sc); - } - if (!(ifp->if_flags & IFF_RUNNING)) - break; - - /* RxTx interrupt */ - if (ic & (MVXPE_PRXTXTI_RBICTAPQ_MASK)) { - DPRINTIFNET(ifp, 2, "PRXTXTIC: +RXEOF\n"); - mvxpe_rx(sc); - } + ic = MVXPE_READ(sc, MVXPE_PRXTXTIC); + if (ic == 0) + return 0; + MVXPE_WRITE(sc, MVXPE_PRXTXTIC, ~ic); + datum = datum ^ ic; - if (ic & MVXPE_PRXTXTI_TBTCQ_MASK) { - DPRINTIFNET(ifp, 2, "PRXTXTIC: +TBTCQ\n"); - mvxpe_tx_complete(sc); - } + DPRINTIFNET(ifp, 2, "PRXTXTIC: %#x\n", ic); - if (ic & MVXPE_PRXTXTI_RDTAQ_MASK) { - DPRINTIFNET(ifp, 2, "PRXTXTIC: +RDTAQ\n"); - mvxpe_rx_reload(sc); - } - - /* don' loop here. we are using interrupt coalescing */ - break; + /* ack maintance interrupt first */ + if (ic & MVXPE_PRXTXTI_PTXERRORSUMMARY) { + DPRINTIFNET(ifp, 1, "PRXTXTIC: +PTXERRORSUMMARY\n"); + MVXPE_EVCNT_INCR(&sc->sc_ev.ev_rxtxth_txerr); + } + if ((ic & MVXPE_PRXTXTI_PMISCICSUMMARY)) { + DPRINTIFNET(ifp, 2, "PTXTXTIC: +PMISCICSUMMARY\n"); + mvxpe_misc_intr(sc); + } + if (ic & MVXPE_PRXTXTI_PRXTXICSUMMARY) { + DPRINTIFNET(ifp, 2, "PTXTXTIC: +PRXTXICSUMMARY\n"); + mvxpe_rxtx_intr(sc); + } + if (!(ifp->if_flags & IFF_RUNNING)) + return 1; + + /* RxTxTH interrupt */ + queues = MVXPE_PRXTXTI_GET_RBICTAPQ(ic); + if (queues) { + DPRINTIFNET(ifp, 2, "PRXTXTIC: +RXEOF\n"); + mvxpe_rx(sc, queues); + } + queues = MVXPE_PRXTXTI_GET_TBTCQ(ic); + if (queues) { + DPRINTIFNET(ifp, 2, "PRXTXTIC: +TBTCQ\n"); + mvxpe_tx_complete(sc, queues); + } + queues = MVXPE_PRXTXTI_GET_RDTAQ(ic); + if (queues) { + DPRINTIFNET(ifp, 2, "PRXTXTIC: +RDTAQ\n"); + mvxpe_rx_refill(sc, queues); } mvxpe_sc_unlock(sc); @@ -1472,7 +1467,7 @@ mvxpe_rxtxth_intr(void *arg) rnd_add_uint32(&sc->sc_rnd_source, datum); - return claimed; + return 1; } STATIC int @@ -1689,8 +1684,8 @@ mvxpe_start(struct ifnet *ifp) break; } mvxpe_tx_unlockq(sc, q); - KASSERT(sc->sc_tx_ring[q].tx_free_cnt >= 0); - KASSERT(sc->sc_tx_ring[q].tx_free_cnt <= + KASSERT(sc->sc_tx_ring[q].tx_used >= 0); + KASSERT(sc->sc_tx_ring[q].tx_used <= sc->sc_tx_ring[q].tx_queue_len); DPRINTIFNET(ifp, 1, "a packet is added to tx ring\n"); sc->sc_tx_pending++; @@ -1763,7 +1758,7 @@ mvxpe_init(struct ifnet *ifp) for (q = 0; q < MVXPE_QUEUE_SIZE; q++) { mvxpe_rx_lockq(sc, q); mvxpe_rx_queue_enable(ifp, q); - mvxpe_rx_queue_reload(sc, q); + mvxpe_rx_queue_refill(sc, q); mvxpe_rx_unlockq(sc, q); mvxpe_tx_lockq(sc, q); @@ -1876,7 +1871,7 @@ mvxpe_stop(struct ifnet *ifp, int disabl mvxpe_rx_lockq(sc, q); mvxpe_tx_lockq(sc, q); - /* Disable Rx packet buffer reloading */ + /* Disable Rx packet buffer refill request */ reg = MVXPE_PRXDQTH_ODT(rx->rx_queue_th_received); reg |= MVXPE_PRXDQTH_NODT(0); MVXPE_WRITE(sc, MVXPE_PRXITTH(q), reg); @@ -1912,7 +1907,7 @@ mvxpe_watchdog(struct ifnet *ifp) * Reclaim first as there is a possibility of losing Tx completion * interrupts. */ - mvxpe_tx_complete(sc); + mvxpe_tx_complete(sc, 0xff); for (q = 0; q < MVXPE_QUEUE_SIZE; q++) { struct mvxpe_tx_ring *tx = MVXPE_TX_RING(sc, q); @@ -1989,7 +1984,6 @@ mvxpe_mediastatus(struct ifnet *ifp, str */ STATIC void mvxpe_linkupdate(struct mvxpe_softc *sc) { - struct ifnet *ifp = &sc->sc_ethercom.ec_if; int linkup; /* bool */ KASSERT_SC_MTX(sc); @@ -2002,7 +1996,10 @@ STATIC void mvxpe_linkupdate(struct mvxp if (sc->sc_linkstate == linkup) return; - log(LOG_CRIT, "%s: link %s\n", ifp->if_xname, linkup ? "up" : "down"); +#ifdef DEBUG + log(LOG_DEBUG, + "%s: link %s\n", device_xname(sc->sc_dev), linkup ? "up" : "down"); +#endif if (linkup) MVXPE_EVCNT_INCR(&sc->sc_ev.ev_link_up); else @@ -2082,264 +2079,6 @@ mvxpe_linkreset(struct mvxpe_softc *sc) } /* - * Packet Buffer Manager(BM) - */ -STATIC int -mvxpe_bm_init(struct mvxpe_softc *sc) -{ - struct mvxpe_bm_softc *bm = &sc->sc_bm; - bus_dma_segment_t segs; - char *kva, *ptr, *ptr_next, *ptr_data; - char *bm_buf_end; - paddr_t bm_buf_pa; - uint32_t align, pad; - size_t bm_buf_size; - int nsegs, error; - - error = 0; - - memset(bm, 0, sizeof(*bm)); - bm->bm_dmat = sc->sc_dmat; - bm->bm_chunk_count = 0; - bm->bm_chunk_size = MVXPE_BM_SIZE; - bm->bm_chunk_header_size = sizeof(struct mvxpe_bm_chunk); - bm->bm_chunk_packet_offset = 0; - mutex_init(&bm->bm_mtx, MUTEX_DEFAULT, IPL_NET); - LIST_INIT(&bm->bm_free); - LIST_INIT(&bm->bm_inuse); - - /* - * adjust bm_chunk_size, bm_chunk_header_size, bm_slotsize - * to satisfy alignemnt restrictions. - * - * <---------------- bm_slotsize [oct.] ------------------> - * <--- bm_chunk_size[oct.] ----> - * <--- header_size[oct] ---> <-- MBXPE_BM_SIZE[oct.] -----> - * +-----------------+--------+---------+-----------------+--+ - * | bm_chunk hdr |pad |pkt_off | packet data | | - * +-----------------+--------+---------+-----------------+--+ - * ^ ^ ^ ^ - * | | | | - * ptr ptr_data DMA here ptr_next - * - * Restrictions: - * - ptr must be aligned to MVXPE_BM_ADDR_ALIGN - * - data must be aligned to MVXPE_RXBUF_ALIGN - * - data size X must be multiple of 8. - */ - /* assume start of buffer at 0x0000.0000 */ - ptr = (char *)0; - /* align start of packet data */ - ptr_data = ptr + bm->bm_chunk_header_size; - align = (unsigned long)ptr_data & MVXPE_RXBUF_MASK; - if (align != 0) { - pad = MVXPE_RXBUF_ALIGN - align; - bm->bm_chunk_header_size += pad; - DPRINTSC(sc, 1, "added padding to BM header, %u bytes\n", pad); - } - /* align size of packet data */ - ptr_data = ptr + bm->bm_chunk_header_size; - ptr_next = ptr_data + MVXPE_BM_SIZE; - align = (unsigned long)ptr_next & MVXPE_BM_ADDR_MASK; - if (align != 0) { - pad = MVXPE_BM_ADDR_ALIGN - align; - ptr_next += pad; - DPRINTSC(sc, 1, "added padding to BM pktbuf, %u bytes\n", pad); - } - bm->bm_slotsize = ptr_next - ptr; - bm->bm_chunk_size = ptr_next - ptr_data; - KASSERT((bm->bm_chunk_size % 8) == 0); - /* align total buffer size to page boundary */ - bm_buf_size = bm->bm_slotsize * MVXPE_BM_SLOTS; - align = (unsigned long)bm_buf_size & (PAGE_SIZE - 1); - if (align != 0) { - pad = PAGE_SIZE - align; - bm_buf_size += pad; - DPRINTSC(sc, 1, - "expand buffer to fit page boundary, %u bytes\n", pad); - } - - /* - * get the aligned buffer from busdma(9) framework - */ - if (bus_dmamem_alloc(bm->bm_dmat, bm_buf_size, PAGE_SIZE, 0, - &segs, 1, &nsegs, BUS_DMA_NOWAIT)) { - aprint_error_dev(sc->sc_dev, "can't alloc BM buffers\n"); - return ENOBUFS; - } - if (bus_dmamem_map(bm->bm_dmat, &segs, nsegs, bm_buf_size, - (void **)&kva, BUS_DMA_NOWAIT)) { - aprint_error_dev(sc->sc_dev, - "can't map dma buffers (%zu bytes)\n", bm_buf_size); - error = ENOBUFS; - goto fail1; - } - KASSERT(((unsigned long)kva & MVXPE_BM_ADDR_MASK) == 0); - if (bus_dmamap_create(bm->bm_dmat, bm_buf_size, 1, bm_buf_size, 0, - BUS_DMA_NOWAIT, &bm->bm_map)) { - aprint_error_dev(sc->sc_dev, "can't create dma map\n"); - error = ENOBUFS; - goto fail2; - } - if (bus_dmamap_load(bm->bm_dmat, bm->bm_map, - kva, bm_buf_size, NULL, BUS_DMA_NOWAIT)) { - aprint_error_dev(sc->sc_dev, "can't load dma map\n"); - error = ENOBUFS; - goto fail3; - } - bm->bm_buf = (void *)kva; - bm_buf_end = (void *)(kva + bm_buf_size); - bm_buf_pa = segs.ds_addr; - DPRINTSC(sc, 1, "memory pool at %p\n", bm->bm_buf); - - /* slice the buffer */ - mvxpe_bm_lock(sc); - for (ptr = bm->bm_buf; ptr + bm->bm_slotsize <= bm_buf_end; - ptr += bm->bm_slotsize) { - struct mvxpe_bm_chunk *chunk; - - /* initialzie chunk */ - ptr_data = ptr + bm->bm_chunk_header_size; - chunk = (struct mvxpe_bm_chunk *)ptr; - chunk->m = NULL; - chunk->sc = sc; - chunk->off = (ptr - bm->bm_buf); - chunk->pa = (paddr_t)(bm_buf_pa + chunk->off); - chunk->buf_off = (ptr_data - bm->bm_buf); - chunk->buf_pa = (paddr_t)(bm_buf_pa + chunk->buf_off); - chunk->buf_va = (vaddr_t)(bm->bm_buf + chunk->buf_off); - chunk->buf_size = bm->bm_chunk_size; - - /* add to array */ - bm->bm_slots[bm->bm_chunk_count++] = chunk; - - /* add to free list (for software management) */ - LIST_INSERT_HEAD(&bm->bm_free, chunk, link); - mvxpe_bm_sync(chunk, BM_SYNC_ALL, BUS_DMASYNC_PREREAD); - - DPRINTSC(sc, 9, "new chunk %p\n", (void *)chunk->buf_va); - } - mvxpe_bm_unlock(sc); - aprint_normal_dev(sc->sc_dev, - "%zu bytes packet buffer, %zu bytes * %zu entries allocated.\n", - bm_buf_size, bm->bm_chunk_size, bm->bm_chunk_count); - return 0; - -fail3: - bus_dmamap_destroy(bm->bm_dmat, bm->bm_map); -fail2: - bus_dmamem_unmap(bm->bm_dmat, kva, bm_buf_size); -fail1: - bus_dmamem_free(bm->bm_dmat, &segs, nsegs); - - return error; -} - -STATIC int -mvxpe_bm_init_mbuf_hdr(struct mvxpe_bm_chunk *chunk) -{ - struct mvxpe_softc *sc = chunk->sc; - - KASSERT(chunk->m == NULL); - - /* add mbuf header */ - MGETHDR(chunk->m, M_DONTWAIT, MT_DATA); - if (chunk->m == NULL) { - aprint_error_dev(sc->sc_dev, "cannot get mbuf\n"); - return ENOBUFS; - } - MEXTADD(chunk->m, chunk->buf_va, chunk->buf_size, 0, - mvxpe_bm_free_mbuf, chunk); - chunk->m->m_flags |= M_EXT_RW; - chunk->m->m_len = chunk->m->m_pkthdr.len = chunk->buf_size; - if (sc->sc_bm.bm_chunk_packet_offset) - m_adj(chunk->m, sc->sc_bm.bm_chunk_packet_offset); - - return 0; -} - -STATIC struct mvxpe_bm_chunk * -mvxpe_bm_alloc(struct mvxpe_softc *sc) -{ - struct mvxpe_bm_chunk *chunk; - struct mvxpe_bm_softc *bm = &sc->sc_bm; - - mvxpe_bm_lock(sc); - - chunk = LIST_FIRST(&bm->bm_free); - if (chunk == NULL) { - mvxpe_bm_unlock(sc); - return NULL; - } - - LIST_REMOVE(chunk, link); - LIST_INSERT_HEAD(&bm->bm_inuse, chunk, link); - - mvxpe_bm_unlock(sc); - return chunk; -} - -STATIC void -mvxpe_bm_free_mbuf(struct mbuf *m, void *buf, size_t size, void *arg) -{ - struct mvxpe_bm_chunk *chunk = (struct mvxpe_bm_chunk *)arg; - int s; - - KASSERT(m != NULL); - KASSERT(arg != NULL); - - DPRINTFN(3, "free packet %p\n", m); - if (m->m_flags & M_PKTHDR) - m_tag_delete_chain((m), NULL); - chunk->m = NULL; - s = splvm(); - pool_cache_put(mb_cache, m); - splx(s); - return mvxpe_bm_free_chunk(chunk); -} - -STATIC void -mvxpe_bm_free_chunk(struct mvxpe_bm_chunk *chunk) -{ - struct mvxpe_softc *sc = chunk->sc; - struct mvxpe_bm_softc *bm = &sc->sc_bm; - - DPRINTFN(3, "bm chunk free\n"); - - mvxpe_bm_lock(sc); - - LIST_REMOVE(chunk, link); - LIST_INSERT_HEAD(&bm->bm_free, chunk, link); - - mvxpe_bm_unlock(sc); -} - -STATIC void -mvxpe_bm_sync(struct mvxpe_bm_chunk *chunk, size_t size, int ops) -{ - struct mvxpe_softc *sc = (struct mvxpe_softc *)chunk->sc; - struct mvxpe_bm_softc *bm = &sc->sc_bm; - - KASSERT(size <= chunk->buf_size); - if (size == 0) - size = chunk->buf_size; - - bus_dmamap_sync(bm->bm_dmat, bm->bm_map, chunk->buf_off, size, ops); -} - -STATIC void -mvxpe_bm_lock(struct mvxpe_softc *sc) -{ - mutex_enter(&sc->sc_bm.bm_mtx); -} - -STATIC void -mvxpe_bm_unlock(struct mvxpe_softc *sc) -{ - mutex_exit(&sc->sc_bm.bm_mtx); -} - -/* * Tx Subroutines */ STATIC int @@ -2364,9 +2103,9 @@ mvxpe_tx_queue(struct mvxpe_softc *sc, s int start, used; int i; - KASSERT(mutex_owned(&tx->tx_ring_mtx)); - KASSERT(tx->tx_free_cnt >= 0); - KASSERT(tx->tx_free_cnt <= tx->tx_queue_len); + KASSERT_TX_MTX(sc, q); + KASSERT(tx->tx_used >= 0); + KASSERT(tx->tx_used <= tx->tx_queue_len); /* load mbuf using dmamap of 1st descriptor */ if (bus_dmamap_load_mbuf(sc->sc_dmat, @@ -2376,7 +2115,7 @@ mvxpe_tx_queue(struct mvxpe_softc *sc, s } txsegs = MVXPE_TX_MAP(sc, q, tx->tx_cpu)->dm_segs; txnsegs = MVXPE_TX_MAP(sc, q, tx->tx_cpu)->dm_nsegs; - if (txnsegs <= 0 || txnsegs > tx->tx_free_cnt) { + if (txnsegs <= 0 || (txnsegs + tx->tx_used) > tx->tx_queue_len) { /* we have no enough descriptors or mbuf is broken */ bus_dmamap_unload(sc->sc_dmat, MVXPE_TX_MAP(sc, q, tx->tx_cpu)); m_freem(m); @@ -2411,7 +2150,7 @@ mvxpe_tx_queue(struct mvxpe_softc *sc, s t->bufptr = txsegs[i].ds_addr; t->bytecnt = txsegs[i].ds_len; tx->tx_cpu = tx_counter_adv(tx->tx_cpu, 1); - tx->tx_free_cnt--; + tx->tx_used++; used++; } /* t is last descriptor here */ @@ -2450,8 +2189,8 @@ mvxpe_tx_queue(struct mvxpe_softc *sc, s "PTXDI: queue %d, %d\n", q, MVXPE_READ(sc, MVXPE_PTXDI(q))); DPRINTSC(sc, 2, "TQC: %#x\n", MVXPE_READ(sc, MVXPE_TQC)); DPRINTIFNET(ifp, 2, - "Tx: tx_cpu = %d, tx_dma = %d, tx_free_cnt = %d\n", - tx->tx_cpu, tx->tx_dma, tx->tx_free_cnt); + "Tx: tx_cpu = %d, tx_dma = %d, tx_used = %d\n", + tx->tx_cpu, tx->tx_dma, tx->tx_used); return 0; } @@ -2459,61 +2198,72 @@ STATIC void mvxpe_tx_set_csumflag(struct ifnet *ifp, struct mvxpe_tx_desc *t, struct mbuf *m) { + struct ether_header *eh; int csum_flags; uint32_t iphl = 0, ipoff = 0; csum_flags = ifp->if_csum_flags_tx & m->m_pkthdr.csum_flags; - if (csum_flags & (M_CSUM_IPv4| M_CSUM_TCPv4|M_CSUM_UDPv4)) { + eh = mtod(m, struct ether_header *); + switch (htons(eh->ether_type)) { + case ETHERTYPE_IP: + case ETHERTYPE_IPV6: + ipoff = ETHER_HDR_LEN; + break; + case ETHERTYPE_VLAN: + ipoff = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + break; + } + + if (csum_flags & (M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4)) { iphl = M_CSUM_DATA_IPv4_IPHL(m->m_pkthdr.csum_data); - ipoff = M_CSUM_DATA_IPv4_OFFSET(m->m_pkthdr.csum_data); + t->command |= MVXPE_TX_CMD_L3_IP4; } else if (csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) { iphl = M_CSUM_DATA_IPv6_HL(m->m_pkthdr.csum_data); - ipoff = M_CSUM_DATA_IPv6_OFFSET(m->m_pkthdr.csum_data); + t->command |= MVXPE_TX_CMD_L3_IP6; } else { t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NONE; return; } + /* L3 */ if (csum_flags & M_CSUM_IPv4) { - t->command |= MVXPE_TX_CMD_L3_IP4; t->command |= MVXPE_TX_CMD_IP4_CHECKSUM; } /* L4 */ - if (csum_flags & M_CSUM_TCPv4) { - t->command |= MVXPE_TX_CMD_L3_IP4; + if ((csum_flags & + (M_CSUM_TCPv4|M_CSUM_UDPv4|M_CSUM_TCPv6|M_CSUM_UDPv6)) == 0) { + t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NONE; + } + else if (csum_flags & M_CSUM_TCPv4) { + t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NOFRAG; t->command |= MVXPE_TX_CMD_L4_TCP; } else if (csum_flags & M_CSUM_UDPv4) { - t->command |= MVXPE_TX_CMD_L3_IP4; + t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NOFRAG; t->command |= MVXPE_TX_CMD_L4_UDP; } else if (csum_flags & M_CSUM_TCPv6) { - t->command |= MVXPE_TX_CMD_L3_IP6; + t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NOFRAG; t->command |= MVXPE_TX_CMD_L4_TCP; } else if (csum_flags & M_CSUM_UDPv6) { - t->command |= MVXPE_TX_CMD_L3_IP6; + t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NOFRAG; t->command |= MVXPE_TX_CMD_L4_UDP; } - /* - * NetBSD's networking stack is not request H/W csum on fragmented - * packets. - */ t->l4ichk = 0; - t->command |= MVXPE_TX_CMD_L4_CHECKSUM_NOFRAG; - t->command |= MVXPE_TX_CMD_W_IP_HEADER_LEN(iphl >> 2); - t->command |= MVXPE_TX_CMD_W_L3_OFFSET(ipoff); + t->command |= MVXPE_TX_CMD_IP_HEADER_LEN(iphl >> 2); + t->command |= MVXPE_TX_CMD_L3_OFFSET(ipoff); } STATIC void -mvxpe_tx_complete(struct mvxpe_softc *sc) +mvxpe_tx_complete(struct mvxpe_softc *sc, uint32_t queues) { struct ifnet *ifp = &sc->sc_ethercom.ec_if; int q; @@ -2522,10 +2272,11 @@ mvxpe_tx_complete(struct mvxpe_softc *sc KASSERT_SC_MTX(sc); - /* XXX: check queue bit array */ for (q = 0; q < MVXPE_QUEUE_SIZE; q++) { + if (!MVXPE_IS_QUEUE_BUSY(queues, q)) + continue; mvxpe_tx_lockq(sc, q); - mvxpe_tx_queue_del(sc, q); + mvxpe_tx_queue_complete(sc, q); mvxpe_tx_unlockq(sc, q); } KASSERT(sc->sc_tx_pending >= 0); @@ -2534,7 +2285,7 @@ mvxpe_tx_complete(struct mvxpe_softc *sc } STATIC void -mvxpe_tx_queue_del(struct mvxpe_softc *sc, int q) +mvxpe_tx_queue_complete(struct mvxpe_softc *sc, int q) { struct mvxpe_tx_ring *tx = MVXPE_TX_RING(sc, q); struct mvxpe_tx_desc *t; @@ -2585,14 +2336,14 @@ mvxpe_tx_queue_del(struct mvxpe_softc *s else KASSERT((t->flags & MVXPE_TX_CMD_F) == 0); tx->tx_dma = tx_counter_adv(tx->tx_dma, 1); - tx->tx_free_cnt++; + tx->tx_used--; if (error) MVXPE_EVCNT_INCR(&sc->sc_ev.ev_drv_txqe[q]); else MVXPE_EVCNT_INCR(&sc->sc_ev.ev_drv_txq[q]); } - KASSERT(tx->tx_free_cnt >= 0); - KASSERT(tx->tx_free_cnt <= tx->tx_queue_len); + KASSERT(tx->tx_used >= 0); + KASSERT(tx->tx_used <= tx->tx_queue_len); while (ndesc > 255) { ptxsu = MVXPE_PTXSU_NORB(255); MVXPE_WRITE(sc, MVXPE_PTXSU(q), ptxsu); @@ -2603,22 +2354,22 @@ mvxpe_tx_queue_del(struct mvxpe_softc *s MVXPE_WRITE(sc, MVXPE_PTXSU(q), ptxsu); } DPRINTSC(sc, 2, - "Tx complete q %d, tx_cpu = %d, tx_dma = %d, tx_free_cnt = %d\n", - q, tx->tx_cpu, tx->tx_dma, tx->tx_free_cnt); + "Tx complete q %d, tx_cpu = %d, tx_dma = %d, tx_used = %d\n", + q, tx->tx_cpu, tx->tx_dma, tx->tx_used); } /* * Rx Subroutines */ STATIC void -mvxpe_rx(struct mvxpe_softc *sc) +mvxpe_rx(struct mvxpe_softc *sc, uint32_t queues) { int q, npkt; KASSERT_SC_MTX(sc); - while ( (npkt = mvxpe_rx_queue_select(sc, &q))) { - /* mutex is held by rx_queue_sel */ + while ( (npkt = mvxpe_rx_queue_select(sc, queues, &q))) { + /* mutex is held by rx_queue_select */ mvxpe_rx_queue(sc, q, npkt); mvxpe_rx_unlockq(sc, q); } @@ -2630,7 +2381,7 @@ mvxpe_rx_queue(struct mvxpe_softc *sc, i struct ifnet *ifp = &sc->sc_ethercom.ec_if; struct mvxpe_rx_ring *rx = MVXPE_RX_RING(sc, q); struct mvxpe_rx_desc *r; - struct mvxpe_bm_chunk *chunk; + struct mvxpbm_chunk *chunk; struct mbuf *m; uint32_t prxsu; int error = 0; @@ -2646,7 +2397,7 @@ mvxpe_rx_queue(struct mvxpe_softc *sc, i chunk = MVXPE_RX_PKTBUF(sc, q, rx->rx_dma); MVXPE_RX_PKTBUF(sc, q, rx->rx_dma) = NULL; r = MVXPE_RX_DESC(sc, q, rx->rx_dma); - mvxpe_bm_sync(chunk, r->bytecnt, BUS_DMASYNC_POSTREAD); + mvxpbm_dmamap_sync(chunk, r->bytecnt, BUS_DMASYNC_POSTREAD); /* check errors */ if (r->status & MVXPE_RX_ES) { @@ -2686,7 +2437,10 @@ mvxpe_rx_queue(struct mvxpe_softc *sc, i } /* extract packet buffer */ - mvxpe_bm_init_mbuf_hdr(chunk); + if (mvxpbm_init_mbuf_hdr(chunk) != 0) { + error = 1; + goto rx_done; + } m = chunk->m; m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = r->bytecnt - ETHER_CRC_LEN; @@ -2699,7 +2453,7 @@ mvxpe_rx_queue(struct mvxpe_softc *sc, i rx_done: if (chunk) { /* rx error. just return the chunk to BM. */ - mvxpe_bm_free_chunk(chunk); + mvxpbm_free_chunk(chunk); } if (error) MVXPE_EVCNT_INCR(&sc->sc_ev.ev_drv_rxqe[q]); @@ -2733,7 +2487,7 @@ rx_done: } STATIC int -mvxpe_rx_queue_select(struct mvxpe_softc *sc, int *queue) +mvxpe_rx_queue_select(struct mvxpe_softc *sc, uint32_t queues, int *queue) { uint32_t prxs, npkt; int q; @@ -2743,6 +2497,9 @@ mvxpe_rx_queue_select(struct mvxpe_softc DPRINTSC(sc, 2, "selecting rx queue\n"); for (q = MVXPE_QUEUE_SIZE - 1; q >= 0; q--) { + if (!MVXPE_IS_QUEUE_BUSY(queues, q)) + continue; + prxs = MVXPE_READ(sc, MVXPE_PRXS(q)); npkt = MVXPE_PRXS_GET_ODC(prxs); if (npkt == 0) @@ -2760,7 +2517,7 @@ mvxpe_rx_queue_select(struct mvxpe_softc } STATIC void -mvxpe_rx_reload(struct mvxpe_softc *sc) +mvxpe_rx_refill(struct mvxpe_softc *sc, uint32_t queues) { int q; @@ -2768,37 +2525,38 @@ mvxpe_rx_reload(struct mvxpe_softc *sc) /* XXX: check rx bit array */ for (q = 0; q < MVXPE_QUEUE_SIZE; q++) { - mvxpe_rx_lockq(sc, q); - - mvxpe_rx_queue_reload(sc, q); + if (!MVXPE_IS_QUEUE_BUSY(queues, q)) + continue; + mvxpe_rx_lockq(sc, q); + mvxpe_rx_queue_refill(sc, q); mvxpe_rx_unlockq(sc, q); } } STATIC void -mvxpe_rx_queue_reload(struct mvxpe_softc *sc, int q) +mvxpe_rx_queue_refill(struct mvxpe_softc *sc, int q) { struct mvxpe_rx_ring *rx = MVXPE_RX_RING(sc, q); uint32_t prxs, prxsu, ndesc; - int idx, reload = 0; + int idx, refill = 0; int npkt; KASSERT_RX_MTX(sc, q); prxs = MVXPE_READ(sc, MVXPE_PRXS(q)); ndesc = MVXPE_PRXS_GET_NODC(prxs) + MVXPE_PRXS_GET_ODC(prxs); - reload = rx->rx_queue_len - ndesc; - if (reload <= 0) + refill = rx->rx_queue_len - ndesc; + if (refill <= 0) return; DPRINTPRXS(2, q); - DPRINTSC(sc, 2, "%d buffers to reload.\n", reload); + DPRINTSC(sc, 2, "%d buffers to refill.\n", refill); idx = rx->rx_cpu; - for (npkt = 0; npkt < reload; npkt++) + for (npkt = 0; npkt < refill; npkt++) if (mvxpe_rx_queue_add(sc, q) != 0) break; - DPRINTSC(sc, 2, "queue %d, %d buffer reloaded.\n", q, npkt); + DPRINTSC(sc, 2, "queue %d, %d buffer refilled.\n", q, npkt); if (npkt == 0) return; @@ -2823,12 +2581,12 @@ mvxpe_rx_queue_add(struct mvxpe_softc *s { struct mvxpe_rx_ring *rx = MVXPE_RX_RING(sc, q); struct mvxpe_rx_desc *r; - struct mvxpe_bm_chunk *chunk = NULL; + struct mvxpbm_chunk *chunk = NULL; KASSERT_RX_MTX(sc, q); /* Allocate the packet buffer */ - chunk = mvxpe_bm_alloc(sc); + chunk = mvxpbm_alloc(sc->sc_bm); if (chunk == NULL) { DPRINTSC(sc, 1, "BM chunk allocation failed.\n"); return ENOBUFS; @@ -2837,7 +2595,7 @@ mvxpe_rx_queue_add(struct mvxpe_softc *s /* Add the packet to descritor */ KASSERT(MVXPE_RX_PKTBUF(sc, q, rx->rx_cpu) == NULL); MVXPE_RX_PKTBUF(sc, q, rx->rx_cpu) = chunk; - mvxpe_bm_sync(chunk, BM_SYNC_ALL, BUS_DMASYNC_PREREAD); + mvxpbm_dmamap_sync(chunk, BM_SYNC_ALL, BUS_DMASYNC_PREREAD); r = MVXPE_RX_DESC(sc, q, rx->rx_cpu); r->bufptr = chunk->buf_pa; @@ -3139,8 +2897,10 @@ sysctl_set_queue_length(SYSCTLFN_ARGS) case MVXPE_SYSCTL_RX: mvxpe_rx_lockq(sc, arg->queue); rx->rx_queue_len = val; - rx->rx_queue_th_received = rx->rx_queue_len / 4; - rx->rx_queue_th_free = rx->rx_queue_len / 2; + rx->rx_queue_th_received = + rx->rx_queue_len / MVXPE_RXTH_RATIO; + rx->rx_queue_th_free = + rx->rx_queue_len / MVXPE_RXTH_REFILL_RATIO; reg = MVXPE_PRXDQTH_ODT(rx->rx_queue_th_received); reg |= MVXPE_PRXDQTH_NODT(rx->rx_queue_th_free); @@ -3151,7 +2911,8 @@ sysctl_set_queue_length(SYSCTLFN_ARGS) case MVXPE_SYSCTL_TX: mvxpe_tx_lockq(sc, arg->queue); tx->tx_queue_len = val; - tx->tx_queue_th_free = tx->tx_queue_len / 2; + tx->tx_queue_th_free = + tx->tx_queue_len / MVXPE_TXTH_RATIO; reg = MVXPE_PTXDQS_TBT(tx->tx_queue_th_free); reg |= MVXPE_PTXDQS_DQS(MVXPE_TX_RING_CNT); Index: src/sys/dev/marvell/if_mvxpereg.h diff -u src/sys/dev/marvell/if_mvxpereg.h:1.1 src/sys/dev/marvell/if_mvxpereg.h:1.2 --- src/sys/dev/marvell/if_mvxpereg.h:1.1 Sun May 3 14:38:10 2015 +++ src/sys/dev/marvell/if_mvxpereg.h Wed Jun 3 03:55:47 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_mvxpereg.h,v 1.1 2015/05/03 14:38:10 hsuenaga Exp $ */ +/* $NetBSD: if_mvxpereg.h,v 1.2 2015/06/03 03:55:47 hsuenaga Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. * All rights reserved. @@ -705,12 +705,15 @@ /* Port RX_TX Threshold Interrupt Cause/Mask (MVXPE_PRXTXTIC/MVXPE_PRXTXTIM) */ #define MVXPE_PRXTXTI_TBTCQ(q) (1 << ((q) + 0)) #define MVXPE_PRXTXTI_TBTCQ_MASK (0xff << 0) +#define MVXPE_PRXTXTI_GET_TBTCQ(reg) (((reg) >> 0) & 0xff) /* Tx Buffer Threshold Cross Queue*/ #define MVXPE_PRXTXTI_RBICTAPQ(q) (1 << ((q) + 8)) #define MVXPE_PRXTXTI_RBICTAPQ_MASK (0xff << 8) +#define MVXPE_PRXTXTI_GET_RBICTAPQ(reg) (((reg) >> 8) & 0xff) /* Rx Buffer Int. Coaleasing Th. Pri. Alrt Q */ #define MVXPE_PRXTXTI_RDTAQ(q) (1 << ((q) + 16)) #define MVXPE_PRXTXTI_RDTAQ_MASK (0xff << 16) +#define MVXPE_PRXTXTI_GET_RDTAQ(reg) (((reg) >> 16) & 0xff) /* Rx Descriptor Threshold Alert Queue*/ #define MVXPE_PRXTXTI_PRXTXICSUMMARY (1 << 29) /* PRXTXI summary */ #define MVXPE_PRXTXTI_PTXERRORSUMMARY (1 << 30) /* PTEXERROR summary */ @@ -719,10 +722,13 @@ /* Port RX_TX Interrupt Cause/Mask (MVXPE_PRXTXIC/MVXPE_PRXTXIM) */ #define MVXPE_PRXTXI_TBRQ(q) (1 << ((q) + 0)) #define MVXPE_PRXTXI_TBRQ_MASK (0xff << 0) +#define MVXPE_PRXTXI_GET_TBRQ(reg) (((reg) >> 0) & 0xff) #define MVXPE_PRXTXI_RPQ(q) (1 << ((q) + 8)) #define MVXPE_PRXTXI_RPQ_MASK (0xff << 8) +#define MVXPE_PRXTXI_GET_RPQ(reg) (((reg) >> 8) & 0xff) #define MVXPE_PRXTXI_RREQ(q) (1 << ((q) + 16)) #define MVXPE_PRXTXI_RREQ_MASK (0xff << 16) +#define MVXPE_PRXTXI_GET_RREQ(reg) (((reg) >> 16) & 0xff) #define MVXPE_PRXTXI_PRXTXTHICSUMMARY (1 << 29) #define MVXPE_PRXTXI_PTXERRORSUMMARY (1 << 30) #define MVXPE_PRXTXI_PMISCICSUMMARY (1 << 31) @@ -854,18 +860,16 @@ struct mvxpe_rx_desc { #define MVXPE_TX_CMD_L (1 << 20) /* Last buffer */ #define MVXPE_TX_CMD_PADDING (1 << 19) /* Pad short frame */ #define MVXPE_TX_CMD_IP4_CHECKSUM (1 << 18) /* Do IPv4 Checksum */ -#define MVXPE_TX_CMD_L3_TYPE (1 << 17) /* L3 Type 0:IP4, 1:IP6 */ #define MVXPE_TX_CMD_L3_IP4 (0 << 17) -#define MVXPE_TX_CMD_L3_IP6 (0 << 17) -#define MVXPE_TX_CMD_L4_TYPE (1 << 16) /* L4 Type 0:TCP, 1:UDP */ +#define MVXPE_TX_CMD_L3_IP6 (1 << 17) #define MVXPE_TX_CMD_L4_TCP (0 << 16) #define MVXPE_TX_CMD_L4_UDP (1 << 16) /* bit 15:13 reserved */ #define MVXPE_TX_CMD_IP_HEADER_LEN_MASK (0x1f << 8) /* IP header len >> 2 */ -#define MVXPE_TX_CMD_W_IP_HEADER_LEN(v) (((v) & 0x1f) << 8) +#define MVXPE_TX_CMD_IP_HEADER_LEN(v) (((v) & 0x1f) << 8) /* bit 7 reserved */ #define MVXPE_TX_CMD_L3_OFFSET_MASK (0x7f << 0) /* offset of L3 hdr. */ -#define MVXPE_TX_CMD_W_L3_OFFSET(v) (((v) & 0x7f) << 0) +#define MVXPE_TX_CMD_L3_OFFSET(v) (((v) & 0x7f) << 0) /* * Transmit pakcet extra attributes Index: src/sys/dev/marvell/if_mvxpevar.h diff -u src/sys/dev/marvell/if_mvxpevar.h:1.1 src/sys/dev/marvell/if_mvxpevar.h:1.2 --- src/sys/dev/marvell/if_mvxpevar.h:1.1 Sun May 3 14:38:10 2015 +++ src/sys/dev/marvell/if_mvxpevar.h Wed Jun 3 03:55:47 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_mvxpevar.h,v 1.1 2015/05/03 14:38:10 hsuenaga Exp $ */ +/* $NetBSD: if_mvxpevar.h,v 1.2 2015/06/03 03:55:47 hsuenaga Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. * All rights reserved. @@ -26,12 +26,8 @@ */ #ifndef _IF_MVXPEVAR_H_ #define _IF_MVXPEVAR_H_ -/* - * Comple options - * XXX: use kernel config - */ -#define MVXPE_DEBUG 0 -#define MVXPE_EVENT_COUNTERS +#include <net/if.h> +#include <dev/marvell/mvxpbmvar.h> /* * Limit of packet sizes. @@ -48,23 +44,28 @@ * * XXX: packet classifier is not implement yet */ -#define MVXPE_RX_QUEUE_LIMIT_0 8 -#define MVXPE_RX_QUEUE_LIMIT_1 8 -#define MVXPE_RX_QUEUE_LIMIT_2 8 -#define MVXPE_RX_QUEUE_LIMIT_3 8 -#define MVXPE_RX_QUEUE_LIMIT_4 8 -#define MVXPE_RX_QUEUE_LIMIT_5 8 -#define MVXPE_RX_QUEUE_LIMIT_6 8 -#define MVXPE_RX_QUEUE_LIMIT_7 256 - -#define MVXPE_TX_QUEUE_LIMIT_0 256 -#define MVXPE_TX_QUEUE_LIMIT_1 8 -#define MVXPE_TX_QUEUE_LIMIT_2 8 -#define MVXPE_TX_QUEUE_LIMIT_3 8 -#define MVXPE_TX_QUEUE_LIMIT_4 8 -#define MVXPE_TX_QUEUE_LIMIT_5 8 -#define MVXPE_TX_QUEUE_LIMIT_6 8 -#define MVXPE_TX_QUEUE_LIMIT_7 8 +#define MVXPE_RX_QUEUE_LIMIT_0 8 +#define MVXPE_RX_QUEUE_LIMIT_1 8 +#define MVXPE_RX_QUEUE_LIMIT_2 8 +#define MVXPE_RX_QUEUE_LIMIT_3 8 +#define MVXPE_RX_QUEUE_LIMIT_4 8 +#define MVXPE_RX_QUEUE_LIMIT_5 8 +#define MVXPE_RX_QUEUE_LIMIT_6 8 +#define MVXPE_RX_QUEUE_LIMIT_7 IFQ_MAXLEN + +#define MVXPE_TX_QUEUE_LIMIT_0 IFQ_MAXLEN +#define MVXPE_TX_QUEUE_LIMIT_1 8 +#define MVXPE_TX_QUEUE_LIMIT_2 8 +#define MVXPE_TX_QUEUE_LIMIT_3 8 +#define MVXPE_TX_QUEUE_LIMIT_4 8 +#define MVXPE_TX_QUEUE_LIMIT_5 8 +#define MVXPE_TX_QUEUE_LIMIT_6 8 +#define MVXPE_TX_QUEUE_LIMIT_7 8 + +/* interrupt is triggered when corossing (queuelen / RATIO) */ +#define MVXPE_RXTH_RATIO 8 +#define MVXPE_RXTH_REFILL_RATIO 2 +#define MVXPE_TXTH_RATIO 8 /* * Device Register access @@ -85,6 +86,9 @@ #define MVXPE_IS_LINKUP(sc) \ (MVXPE_READ((sc), MVXPE_PSR) & MVXPE_PSR_LINKUP) +#define MVXPE_IS_QUEUE_BUSY(queues, q) \ + ((((queues) >> (q)) & 0x1)) + /* * EEE: Lower Power Idle config * Default timer is duration of MTU sized frame transmission. @@ -101,10 +105,10 @@ * the ethernet device has 8 rx/tx DMA queues. each of queue has its own * decriptor list. descriptors are simply index by counter inside the device. */ -#define MVXPE_TX_RING_CNT 256 +#define MVXPE_TX_RING_CNT IFQ_MAXLEN #define MVXPE_TX_RING_MSK (MVXPE_TX_RING_CNT - 1) #define MVXPE_TX_RING_NEXT(x) (((x) + 1) & MVXPE_TX_RING_MSK) -#define MVXPE_RX_RING_CNT 256 +#define MVXPE_RX_RING_CNT IFQ_MAXLEN #define MVXPE_RX_RING_MSK (MVXPE_RX_RING_CNT - 1) #define MVXPE_RX_RING_NEXT(x) (((x) + 1) & MVXPE_RX_RING_MSK) #define MVXPE_TX_SEGLIMIT 32 @@ -118,7 +122,7 @@ struct mvxpe_rx_ring { struct mvxpe_rx_handle { struct mvxpe_rx_desc *rxdesc_va; off_t rxdesc_off; /* from rx_descriptors[0] */ - struct mvxpe_bm_chunk *chunk; + struct mvxpbm_chunk *chunk; } rx_handle[MVXPE_RX_RING_CNT]; /* locks */ @@ -152,7 +156,7 @@ struct mvxpe_tx_ring { kmutex_t tx_ring_mtx; /* Index */ - int tx_free_cnt; + int tx_used; int tx_dma; int tx_cpu; @@ -184,14 +188,6 @@ rx_counter_adv(int ctr, int n) } /* - * Buffer alignement - */ -#define MVXPE_RXBUF_ALIGN 32 /* Cache line size */ -#define MVXPE_RXBUF_MASK (MVXPE_RXBUF_ALIGN - 1) -#define MVXPE_BM_ADDR_ALIGN 32 -#define MVXPE_BM_ADDR_MASK (MVXPE_BM_ADDR_ALIGN - 1) - -/* * Timeout control */ #define MVXPE_PHY_TIMEOUT 10000 /* msec */ @@ -389,67 +385,6 @@ struct mvxpe_sysctl_mib { }; /* - * Packet Buffer Header - * - * this chunks may be managed by H/W Buffer Manger(BM) device, - * but there is no device driver yet. - * - * +----------------+ bm_buf - * |chunk header | | - * +----------------+ | | |chunk->buf_off - * |mbuf (M_EXT set)|<--------|struct mbuf *m | V - * +----------------+ +----------------+ chunk->buf_va/buf_pa - * | m_ext.ext_buf|-------->|packet buffer | | - * +----------------+ | | |chunk->buf_size - * | | V - * +----------------+ - * |chunk header | - * |.... | - */ -#define MVXPE_BM_SLOTS \ - (MVXPE_RX_RING_CNT * (MVXPE_QUEUE_SIZE + 1)) -#define MVXPE_BM_SIZE \ - (MVXPE_MRU + MVXPE_HWHEADER_SIZE) - -struct mvxpe_bm_chunk { - struct mbuf *m; /* back pointer to mbuf header */ - void *sc; /* back pointer to softc */ - off_t off; /* offset of chunk */ - paddr_t pa; /* physical address of chunk */ - - off_t buf_off; /* offset of packet from sc_bm_buf */ - paddr_t buf_pa; /* physical address of packet */ - vaddr_t buf_va; /* virtual addres of packet */ - size_t buf_size; /* size of buffer (exclude hdr) */ - - LIST_ENTRY(mvxpe_bm_chunk) link; - /* followed by packet buffer */ -}; - -struct mvxpe_bm_softc { - bus_dma_tag_t bm_dmat; - bus_dmamap_t bm_map; - kmutex_t bm_mtx; - - /* DMA MAP for entire buffer */ - char *bm_buf; - - /* memory chunk properties */ - size_t bm_slotsize; /* size of bm_slots include header */ - size_t bm_chunk_count; /* number of chunks */ - size_t bm_chunk_size; /* size of packet buffer */ - off_t bm_chunk_header_size; /* size of hader + padding */ - off_t bm_chunk_packet_offset; /* allocate m_leading_space */ - struct mvxpe_bm_chunk *bm_slots[MVXPE_BM_SLOTS]; - - /* for software based management */ - LIST_HEAD(__mvxpe_bm_freehead, mvxpe_bm_chunk) bm_free; - LIST_HEAD(__mvxpe_bm_inusehead, mvxpe_bm_chunk) bm_inuse; -} sc_bm; - -#define BM_SYNC_ALL 0 - -/* * Ethernet Device main context */ struct mvxpe_softc { @@ -495,9 +430,8 @@ struct mvxpe_softc { /* * Software Buffer Manager - * XXX: to be writtten the independent device driver. */ - struct mvxpe_bm_softc sc_bm; + struct mvxpbm_softc *sc_bm; /* * Maintance clock Added files: Index: src/sys/dev/marvell/mvxpbm.c diff -u /dev/null src/sys/dev/marvell/mvxpbm.c:1.1 --- /dev/null Wed Jun 3 03:55:47 2015 +++ src/sys/dev/marvell/mvxpbm.c Wed Jun 3 03:55:47 2015 @@ -0,0 +1,492 @@ +/* $NetBSD: mvxpbm.c,v 1.1 2015/06/03 03:55:47 hsuenaga Exp $ */ +/* + * Copyright (c) 2015 Internet Initiative Japan Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: mvxpbm.c,v 1.1 2015/06/03 03:55:47 hsuenaga Exp $"); + +#include "opt_multiprocessor.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/mbuf.h> + +#include <dev/marvell/marvellreg.h> +#include <dev/marvell/marvellvar.h> + +#include "mvxpbmvar.h" + +#ifdef DEBUG +#define STATIC /* nothing */ +#define DPRINTF(fmt, ...) \ + do { \ + if (mvxpbm_debug >= 1) { \ + printf("%s: ", __func__); \ + printf((fmt), ##__VA_ARGS__); \ + } \ + } while (/*CONSTCOND*/0) +#define DPRINTFN(level , fmt, ...) \ + do { \ + if (mvxpbm_debug >= (level)) { \ + printf("%s: ", __func__); \ + printf((fmt), ##__VA_ARGS__); \ + } \ + } while (/*CONSTCOND*/0) +#define DPRINTDEV(dev, level, fmt, ...) \ + do { \ + if (mvxpbm_debug >= (level)) { \ + device_printf((dev), \ + "%s: "fmt , __func__, ##__VA_ARGS__); \ + } \ + } while (/*CONSTCOND*/0) +#define DPRINTSC(sc, level, fmt, ...) \ + do { \ + device_t dev = (sc)->sc_dev; \ + if (mvxpbm_debug >= (level)) { \ + device_printf(dev, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } \ + } while (/*CONSTCOND*/0) +#else +#define STATIC static +#define DPRINTF(fmt, ...) +#define DPRINTFN(level, fmt, ...) +#define DPRINTDEV(dev, level, fmt, ...) +#define DPRINTSC(sc, level, fmt, ...) +#endif + +/* autoconf(9) */ +STATIC int mvxpbm_match(device_t, cfdata_t, void *); +STATIC void mvxpbm_attach(device_t, device_t, void *); +STATIC int mvxpbm_evcnt_attach(struct mvxpbm_softc *); +CFATTACH_DECL_NEW(mvxpbm_mbus, sizeof(struct mvxpbm_softc), + mvxpbm_match, mvxpbm_attach, NULL, NULL); + +/* DMA buffers */ +STATIC int mvxpbm_alloc_buffer(struct mvxpbm_softc *); + +/* mbuf subroutines */ +STATIC void mvxpbm_free_mbuf(struct mbuf *, void *, size_t, void *); + +/* singleton device instance */ +static struct mvxpbm_softc sc_emul; +static struct mvxpbm_softc *sc0; + +/* debug level */ +#ifdef DEBUG +static int mvxpbm_debug = 0; +#endif + +/* + * autoconf(9) + */ +STATIC int +mvxpbm_match(device_t parent, cfdata_t match, void *aux) +{ + struct marvell_attach_args *mva = aux; + + if (strcmp(mva->mva_name, match->cf_name) != 0) + return 0; + if (mva->mva_unit > MVXPBM_UNIT_MAX) + return 0; + if (sc0 != NULL) + return 0; + if (mva->mva_offset != MVA_OFFSET_DEFAULT) { + /* Hardware BM is not supported yet. */ + return 0; + } + + return 1; +} + +STATIC void +mvxpbm_attach(device_t parnet, device_t self, void *aux) +{ + struct marvell_attach_args *mva = aux; + struct mvxpbm_softc *sc = device_private(self); + + aprint_naive("\n"); + aprint_normal(": Marvell ARMADA Buffer Manager\n"); + memset(sc, 0, sizeof(*sc)); + sc->sc_dev = self; + sc->sc_iot = mva->mva_iot; + sc->sc_dmat = mva->mva_dmat; + + if (mva->mva_offset == MVA_OFFSET_DEFAULT) { + aprint_normal_dev(sc->sc_dev, "Software emulation.\n"); + sc->sc_emul = 1; + } + + mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NET); + LIST_INIT(&sc->sc_free); + LIST_INIT(&sc->sc_inuse); + + /* DMA buffers */ + if (mvxpbm_alloc_buffer(sc) != 0) + return; + + /* event counters */ + mvxpbm_evcnt_attach(sc); + + sc0 = sc; + return; + +} + +STATIC int +mvxpbm_evcnt_attach(struct mvxpbm_softc *sc) +{ + return 0; +} + +/* + * DMA buffers + */ +STATIC int +mvxpbm_alloc_buffer(struct mvxpbm_softc *sc) +{ + bus_dma_segment_t segs; + char *kva, *ptr, *ptr_next, *ptr_data; + char *bm_buf_end; + uint32_t align, pad; + int nsegs; + int error; + + /* + * set default buffer sizes. this will changed to satisfy + * alignment restrictions. + */ + sc->sc_chunk_count = 0; + sc->sc_chunk_size = MVXPBM_PACKET_SIZE; + sc->sc_chunk_header_size = sizeof(struct mvxpbm_chunk); + sc->sc_chunk_packet_offset = 64; + + /* + * adjust bm_chunk_size, bm_chunk_header_size, bm_slotsize + * to satisfy alignemnt restrictions. + * + * <---------------- bm_slotsize [oct.] ------------------> + * <--- bm_chunk_size[oct.] ----> + * <--- header_size[oct] ---> <-- MBXPE_BM_SIZE[oct.] ---> + * +-----------------+--------+---------+-----------------+--+ + * | bm_chunk hdr |pad |pkt_off | packet data | | + * +-----------------+--------+---------+-----------------+--+ + * ^ ^ ^ ^ + * | | | | + * ptr ptr_data DMA here ptr_next + * + * Restrictions: + * - total buffer size must be multiple of MVXPBM_BUF_ALIGN + * - ptr must be aligned to MVXPBM_CHUNK_ALIGN + * - ptr_data must be aligned to MVXPEBM_DATA_ALIGN + * - bm_chunk_size must be multiple of 8[bytes]. + */ + /* start calclation from 0x0000.0000 */ + ptr = (char *)0; + + /* align start of packet data */ + ptr_data = ptr + sc->sc_chunk_header_size; + align = (unsigned long)ptr_data & MVXPBM_DATA_MASK; + if (align != 0) { + pad = MVXPBM_DATA_ALIGN - align; + sc->sc_chunk_header_size += pad; + DPRINTSC(sc, 1, "added padding to BM header, %u bytes\n", pad); + } + + /* align size of packet data */ + ptr_data = ptr + sc->sc_chunk_header_size; + ptr_next = ptr_data + MVXPBM_PACKET_SIZE; + align = (unsigned long)ptr_next & MVXPBM_CHUNK_MASK; + if (align != 0) { + pad = MVXPBM_CHUNK_ALIGN - align; + ptr_next += pad; + DPRINTSC(sc, 1, "added padding to BM pktbuf, %u bytes\n", pad); + } + sc->sc_slotsize = ptr_next - ptr; + sc->sc_chunk_size = ptr_next - ptr_data; + KASSERT((sc->sc_chunk_size % MVXPBM_DATA_UNIT) == 0); + + /* align total buffer size to Mbus window boundary */ + sc->sc_buf_size = sc->sc_slotsize * MVXPBM_NUM_SLOTS; + align = (unsigned long)sc->sc_buf_size & MVXPBM_BUF_MASK; + if (align != 0) { + pad = MVXPBM_BUF_ALIGN - align; + sc->sc_buf_size += pad; + DPRINTSC(sc, 1, + "expand buffer to fit page boundary, %u bytes\n", pad); + } + + /* + * get the aligned buffer from busdma(9) framework + */ + if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_buf_size, MVXPBM_BUF_ALIGN, 0, + &segs, 1, &nsegs, BUS_DMA_NOWAIT)) { + aprint_error_dev(sc->sc_dev, "can't alloc BM buffers\n"); + return ENOBUFS; + } + if (bus_dmamem_map(sc->sc_dmat, &segs, nsegs, sc->sc_buf_size, + (void **)&kva, BUS_DMA_NOWAIT)) { + aprint_error_dev(sc->sc_dev, + "can't map dma buffers (%zu bytes)\n", sc->sc_buf_size); + error = ENOBUFS; + goto fail1; + } + if (bus_dmamap_create(sc->sc_dmat, sc->sc_buf_size, 1, sc->sc_buf_size, + 0, BUS_DMA_NOWAIT, &sc->sc_buf_map)) { + aprint_error_dev(sc->sc_dev, "can't create dma map\n"); + error = ENOBUFS; + goto fail2; + } + if (bus_dmamap_load(sc->sc_dmat, sc->sc_buf_map, + kva, sc->sc_buf_size, NULL, BUS_DMA_NOWAIT)) { + aprint_error_dev(sc->sc_dev, "can't load dma map\n"); + error = ENOBUFS; + goto fail3; + } + sc->sc_buf = (void *)kva; + sc->sc_buf_pa = segs.ds_addr; + bm_buf_end = (void *)(kva + sc->sc_buf_size); + DPRINTSC(sc, 1, "memory pool at %p\n", sc->sc_buf); + + /* slice the buffer */ + mvxpbm_lock(sc); + for (ptr = sc->sc_buf; ptr + sc->sc_slotsize <= bm_buf_end; + ptr += sc->sc_slotsize) { + struct mvxpbm_chunk *chunk; + + /* initialzie chunk */ + ptr_data = ptr + sc->sc_chunk_header_size; + chunk = (struct mvxpbm_chunk *)ptr; + chunk->m = NULL; + chunk->sc = sc; + chunk->off = (ptr - sc->sc_buf); + chunk->pa = (paddr_t)(sc->sc_buf_pa + chunk->off); + chunk->buf_off = (ptr_data - sc->sc_buf); + chunk->buf_pa = (paddr_t)(sc->sc_buf_pa + chunk->buf_off); + chunk->buf_va = (vaddr_t)(sc->sc_buf + chunk->buf_off); + chunk->buf_size = sc->sc_chunk_size; + + /* add to free list (for software management) */ + LIST_INSERT_HEAD(&sc->sc_free, chunk, link); + mvxpbm_dmamap_sync(chunk, BM_SYNC_ALL, BUS_DMASYNC_PREREAD); + sc->sc_chunk_count++; + + DPRINTSC(sc, 9, "new chunk %p\n", (void *)chunk->buf_va); + } + mvxpbm_unlock(sc); + return 0; + +fail3: + bus_dmamap_destroy(sc->sc_dmat, sc->sc_buf_map); +fail2: + bus_dmamem_unmap(sc->sc_dmat, kva, sc->sc_buf_size); +fail1: + bus_dmamem_free(sc->sc_dmat, &segs, nsegs); + + return error; +} + +/* + * mbuf subroutines + */ +STATIC void +mvxpbm_free_mbuf(struct mbuf *m, void *buf, size_t size, void *arg) +{ + struct mvxpbm_chunk *chunk = (struct mvxpbm_chunk *)arg; + int s; + + KASSERT(m != NULL); + KASSERT(arg != NULL); + + DPRINTFN(3, "free packet %p\n", m); + if (m->m_flags & M_PKTHDR) + m_tag_delete_chain((m), NULL); + chunk->m = NULL; + s = splvm(); + pool_cache_put(mb_cache, m); + splx(s); + return mvxpbm_free_chunk(chunk); +} + +/* + * Exported APIs + */ +/* get mvxpbm device context */ +struct mvxpbm_softc * +mvxpbm_device(struct marvell_attach_args *mva) +{ + struct mvxpbm_softc *sc; + + if (sc0 != NULL) + return sc0; + if (mva == NULL) + return NULL; + + /* allocate software emulation context */ + sc = &sc_emul; + memset(sc, 0, sizeof(*sc)); + sc->sc_emul = 1; + sc->sc_iot = mva->mva_iot; + sc->sc_dmat = mva->mva_dmat; + + mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NET); + LIST_INIT(&sc->sc_free); + LIST_INIT(&sc->sc_inuse); + + if (mvxpbm_alloc_buffer(sc) != 0) + return NULL; + mvxpbm_evcnt_attach(sc); + sc0 = sc; + return sc0; +} + +/* allocate new memory chunk */ +struct mvxpbm_chunk * +mvxpbm_alloc(struct mvxpbm_softc *sc) +{ + struct mvxpbm_chunk *chunk; + + mvxpbm_lock(sc); + + chunk = LIST_FIRST(&sc->sc_free); + if (chunk == NULL) { + mvxpbm_unlock(sc); + return NULL; + } + + LIST_REMOVE(chunk, link); + LIST_INSERT_HEAD(&sc->sc_inuse, chunk, link); + + mvxpbm_unlock(sc); + return chunk; +} + +/* free memory chunk */ +void +mvxpbm_free_chunk(struct mvxpbm_chunk *chunk) +{ + struct mvxpbm_softc *sc = chunk->sc; + + KASSERT(chunk->m == NULL); + DPRINTFN(3, "bm chunk free\n"); + + mvxpbm_lock(sc); + + LIST_REMOVE(chunk, link); + LIST_INSERT_HEAD(&sc->sc_free, chunk, link); + + mvxpbm_unlock(sc); +} + +/* prepare mbuf header after Rx */ +int +mvxpbm_init_mbuf_hdr(struct mvxpbm_chunk *chunk) +{ + struct mvxpbm_softc *sc = chunk->sc; + + KASSERT(chunk->m == NULL); + + /* add new mbuf header */ + MGETHDR(chunk->m, M_DONTWAIT, MT_DATA); + if (chunk->m == NULL) { + aprint_error_dev(sc->sc_dev, "cannot get mbuf\n"); + return ENOBUFS; + } + MEXTADD(chunk->m, chunk->buf_va, chunk->buf_size, 0, + mvxpbm_free_mbuf, chunk); + chunk->m->m_flags |= M_EXT_RW; + chunk->m->m_len = chunk->m->m_pkthdr.len = chunk->buf_size; + if (sc->sc_chunk_packet_offset) + m_adj(chunk->m, sc->sc_chunk_packet_offset); + + return 0; +} + +/* sync DMA seguments */ +void +mvxpbm_dmamap_sync(struct mvxpbm_chunk *chunk, size_t size, int ops) +{ + struct mvxpbm_softc *sc = chunk->sc; + + KASSERT(size <= chunk->buf_size); + if (size == 0) + size = chunk->buf_size; + + bus_dmamap_sync(sc->sc_dmat, sc->sc_buf_map, chunk->buf_off, size, ops); +} + +/* lock */ +void +mvxpbm_lock(struct mvxpbm_softc *sc) +{ + mutex_enter(&sc->sc_mtx); +} + +void +mvxpbm_unlock(struct mvxpbm_softc *sc) +{ + mutex_exit(&sc->sc_mtx); +} + +/* get params */ +const char * +mvxpbm_xname(struct mvxpbm_softc *sc) +{ + if (sc->sc_emul) { + return "software_bm"; + } + return device_xname(sc->sc_dev); +} + +size_t +mvxpbm_chunk_size(struct mvxpbm_softc *sc) +{ + return sc->sc_chunk_size; +} + +uint32_t +mvxpbm_chunk_count(struct mvxpbm_softc *sc) +{ + return sc->sc_chunk_count; +} + +off_t +mvxpbm_packet_offset(struct mvxpbm_softc *sc) +{ + return sc->sc_chunk_packet_offset; +} + +paddr_t +mvxpbm_buf_pbase(struct mvxpbm_softc *sc) +{ + return sc->sc_buf_pa; +} + +size_t +mvxpbm_buf_size(struct mvxpbm_softc *sc) +{ + return sc->sc_buf_size; +} Index: src/sys/dev/marvell/mvxpbmvar.h diff -u /dev/null src/sys/dev/marvell/mvxpbmvar.h:1.1 --- /dev/null Wed Jun 3 03:55:47 2015 +++ src/sys/dev/marvell/mvxpbmvar.h Wed Jun 3 03:55:47 2015 @@ -0,0 +1,139 @@ +/* $NetBSD: mvxpbmvar.h,v 1.1 2015/06/03 03:55:47 hsuenaga Exp $ */ +/* + * Copyright (c) 2015 Internet Initiative Japan Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _MVXPBMVAR_H_ +#define _MVXPBMVAR_H_ +#include <dev/marvell/marvellvar.h> + +/* + * Max number of unit. + */ +#define MVXPBM_UNIT_MAX 1 + +/* + * Buffer alignement + */ +#define MVXPBM_NUM_SLOTS 2048 /* minimum number of slots */ +#define MVXPBM_PACKET_SIZE 2000 /* minimum packet size */ + +#define MVXPBM_BUF_ALIGN 65536 /* Mbus window size granularity */ +#define MVXPBM_BUF_MASK (MVXPBM_BUF_ALIGN - 1) +#define MVXPBM_CHUNK_ALIGN 32 /* Cache line size */ +#define MVXPBM_CHUNK_MASK (MVXPBM_CHUNK_ALIGN - 1) +#define MVXPBM_DATA_ALIGN 32 /* Cache line size */ +#define MVXPBM_DATA_MASK (MVXPBM_DATA_ALIGN - 1) +#define MVXPBM_DATA_UNIT 8 + +/* + * Packet Buffer Header + * + * this chunks may be managed by H/W Buffer Manger(BM) device, + * but there is no device driver yet. + * + * +----------------+ bm_buf + * |chunk header | | + * +----------------+ | | |chunk->buf_off + * |mbuf (M_EXT set)|<--------|struct mbuf *m | V + * +----------------+ +----------------+ chunk->buf_va/buf_pa + * | m_ext.ext_buf|-------->|packet buffer | | + * +----------------+ | | |chunk->buf_size + * | | V + * +----------------+ + * |chunk header | + * |.... | + */ + +struct mvxpbm_chunk { + struct mbuf *m; /* back pointer to mbuf header */ + void *sc; /* back pointer to softc */ + off_t off; /* offset of chunk */ + paddr_t pa; /* physical address of chunk */ + + off_t buf_off; /* offset of packet from sc_bm_buf */ + paddr_t buf_pa; /* physical address of packet */ + vaddr_t buf_va; /* virtual addres of packet */ + size_t buf_size; /* size of buffer (exclude hdr) */ + + LIST_ENTRY(mvxpbm_chunk) link; + /* followed by packet buffer */ +}; + +struct mvxpbm_softc { + device_t sc_dev; + bus_dma_tag_t sc_dmat; + bus_space_tag_t sc_iot; + kmutex_t sc_mtx; + + /* software emulated */ + int sc_emul; + + /* DMA MAP for entire buffer */ + bus_dmamap_t sc_buf_map; + char *sc_buf; + paddr_t sc_buf_pa; + size_t sc_buf_size; + + /* memory chunk properties */ + size_t sc_slotsize; /* size of bm_slots include header */ + uint32_t sc_chunk_count; /* number of chunks */ + size_t sc_chunk_size; /* size of packet buffer */ + size_t sc_chunk_header_size; /* size of hader + padding */ + off_t sc_chunk_packet_offset; /* allocate m_leading_space */ + + /* for software based management */ + LIST_HEAD(__mvxpbm_freehead, mvxpbm_chunk) sc_free; + LIST_HEAD(__mvxpbm_inusehead, mvxpbm_chunk) sc_inuse; +}; + +#define BM_SYNC_ALL 0 + +/* get mvxpbm device context */ +struct mvxpbm_softc *mvxpbm_device(struct marvell_attach_args *); + +/* allocate new memory chunk */ +struct mvxpbm_chunk *mvxpbm_alloc(struct mvxpbm_softc *); + +/* free memory chunk */ +void mvxpbm_free_chunk(struct mvxpbm_chunk *); + +/* prepare mbuf header after Rx */ +int mvxpbm_init_mbuf_hdr(struct mvxpbm_chunk *); + +/* sync DMA seguments */ +void mvxpbm_dmamap_sync(struct mvxpbm_chunk *, size_t, int); + +/* lock */ +void mvxpbm_lock(struct mvxpbm_softc *); +void mvxpbm_unlock(struct mvxpbm_softc *); + +/* get params */ +const char *mvxpbm_xname(struct mvxpbm_softc *); +size_t mvxpbm_chunk_size(struct mvxpbm_softc *); +uint32_t mvxpbm_chunk_count(struct mvxpbm_softc *); +off_t mvxpbm_packet_offset(struct mvxpbm_softc *); +paddr_t mvxpbm_buf_pbase(struct mvxpbm_softc *); +size_t mvxpbm_buf_size(struct mvxpbm_softc *); +#endif /* _MVXPBMVAR_H_ */