From patchwork Wed Sep 19 11:55:19 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Ferre X-Patchwork-Id: 1477131 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id C145DDF280 for ; Wed, 19 Sep 2012 12:03:12 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TEIx0-0000RR-6j; Wed, 19 Sep 2012 12:00:18 +0000 Received: from eusmtp01.atmel.com ([212.144.249.243]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TEIuY-0007vz-IO for linux-arm-kernel@lists.infradead.org; Wed, 19 Sep 2012 11:57:53 +0000 Received: from tenerife.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.31) with Microsoft SMTP Server id 14.2.318.1; Wed, 19 Sep 2012 13:56:39 +0200 From: Nicolas Ferre To: , , Subject: [PATCH v2 6/9] net/macb: clean up ring buffer logic Date: Wed, 19 Sep 2012 13:55:19 +0200 Message-ID: <733dedf159c750dff9026441a0c4995b43a536aa.1348055112.git.nicolas.ferre@atmel.com> X-Mailer: git-send-email 1.7.11.3 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.5 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.5 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.6 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Nicolas Ferre , patrice.vilchez@atmel.com, linux-kernel@vger.kernel.org, bhutchings@solarflare.com, plagnioj@jcrosoft.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Havard Skinnemoen Instead of masking head and tail every time we increment them, just let them wrap through UINT_MAX and mask them when subscripting. Add simple accessor functions to do the subscripting properly to minimize the chances of messing this up. This makes the code slightly smaller, and hopefully faster as well. Also, doing the ring buffer management this way will simplify things a lot when making the ring sizes configurable in the future. Signed-off-by: Havard Skinnemoen [nicolas.ferre@atmel.com: split patch in topics, adapt to newer kernel] Signed-off-by: Nicolas Ferre --- drivers/net/ethernet/cadence/macb.c | 168 +++++++++++++++++++++++------------- drivers/net/ethernet/cadence/macb.h | 22 +++-- 2 files changed, 122 insertions(+), 68 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index e98f6fc..5758a1c 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -31,24 +31,13 @@ #define RX_BUFFER_SIZE 128 #define RX_RING_SIZE 512 -#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) +#define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE) /* Make the IP header word-aligned (the ethernet header is 14 bytes) */ #define RX_OFFSET 2 #define TX_RING_SIZE 128 -#define DEF_TX_RING_PENDING (TX_RING_SIZE - 1) -#define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE) - -#define TX_RING_GAP(bp) \ - (TX_RING_SIZE - (bp)->tx_pending) -#define TX_BUFFS_AVAIL(bp) \ - (((bp)->tx_tail <= (bp)->tx_head) ? \ - (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \ - (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp)) -#define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1)) - -#define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1)) +#define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE) /* minimum number of free TX descriptors before waking up TX process */ #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4) @@ -56,6 +45,51 @@ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ | MACB_BIT(ISR_ROVR)) +/* Ring buffer accessors */ +static unsigned int macb_tx_ring_wrap(unsigned int index) +{ + return index & (TX_RING_SIZE - 1); +} + +static unsigned int macb_tx_ring_avail(struct macb *bp) +{ + return TX_RING_SIZE - (bp->tx_head - bp->tx_tail); +} + +static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index) +{ + return &bp->tx_ring[macb_tx_ring_wrap(index)]; +} + +static struct macb_tx_skb *macb_tx_skb(struct macb *bp, unsigned int index) +{ + return &bp->tx_skb[macb_tx_ring_wrap(index)]; +} + +static dma_addr_t macb_tx_dma(struct macb *bp, unsigned int index) +{ + dma_addr_t offset; + + offset = macb_tx_ring_wrap(index) * sizeof(struct macb_dma_desc); + + return bp->tx_ring_dma + offset; +} + +static unsigned int macb_rx_ring_wrap(unsigned int index) +{ + return index & (RX_RING_SIZE - 1); +} + +static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index) +{ + return &bp->rx_ring[macb_rx_ring_wrap(index)]; +} + +static void *macb_rx_buffer(struct macb *bp, unsigned int index) +{ + return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index); +} + static void __macb_set_hwaddr(struct macb *bp) { u32 bottom; @@ -332,17 +366,18 @@ static void macb_tx(struct macb *bp) bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); /* free transmit buffer in upper layer*/ - for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { - struct ring_info *rp = &bp->tx_skb[tail]; - struct sk_buff *skb = rp->skb; - - BUG_ON(skb == NULL); + for (tail = bp->tx_tail; tail != head; tail++) { + struct macb_tx_skb *tx_skb; + struct sk_buff *skb; rmb(); - dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, - DMA_TO_DEVICE); - rp->skb = NULL; + tx_skb = macb_tx_skb(bp, tail); + skb = tx_skb->skb; + + dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, + skb->len, DMA_TO_DEVICE); + tx_skb->skb = NULL; dev_kfree_skb_irq(skb); } @@ -362,34 +397,38 @@ static void macb_tx(struct macb *bp) return; head = bp->tx_head; - for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { - struct ring_info *rp = &bp->tx_skb[tail]; - struct sk_buff *skb = rp->skb; - u32 bufstat; + for (tail = bp->tx_tail; tail != head; tail++) { + struct macb_tx_skb *tx_skb; + struct sk_buff *skb; + struct macb_dma_desc *desc; + u32 ctrl; - BUG_ON(skb == NULL); + desc = macb_tx_desc(bp, tail); /* Make hw descriptor updates visible to CPU */ rmb(); - bufstat = bp->tx_ring[tail].ctrl; + ctrl = desc->ctrl; - if (!(bufstat & MACB_BIT(TX_USED))) + if (!(ctrl & MACB_BIT(TX_USED))) break; + tx_skb = macb_tx_skb(bp, tail); + skb = tx_skb->skb; + netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", - tail, skb->data); - dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, + macb_tx_ring_wrap(tail), skb->data); + dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len, DMA_TO_DEVICE); bp->stats.tx_packets++; bp->stats.tx_bytes += skb->len; - rp->skb = NULL; + tx_skb->skb = NULL; dev_kfree_skb_irq(skb); } bp->tx_tail = tail; - if (netif_queue_stopped(bp->dev) && - TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH) + if (netif_queue_stopped(bp->dev) + && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH) netif_wake_queue(bp->dev); } @@ -400,17 +439,21 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, unsigned int frag; unsigned int offset = 0; struct sk_buff *skb; + struct macb_dma_desc *desc; - len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl); + desc = macb_rx_desc(bp, last_frag); + len = MACB_BFEXT(RX_FRMLEN, desc->ctrl); netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n", - first_frag, last_frag, len); + macb_rx_ring_wrap(first_frag), + macb_rx_ring_wrap(last_frag), len); skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET); if (!skb) { bp->stats.rx_dropped++; - for (frag = first_frag; ; frag = NEXT_RX(frag)) { - bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); + for (frag = first_frag; ; frag++) { + desc = macb_rx_desc(bp, frag); + desc->addr &= ~MACB_BIT(RX_USED); if (frag == last_frag) break; } @@ -425,7 +468,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, skb_checksum_none_assert(skb); skb_put(skb, len); - for (frag = first_frag; ; frag = NEXT_RX(frag)) { + for (frag = first_frag; ; frag++) { unsigned int frag_len = RX_BUFFER_SIZE; if (offset + frag_len > len) { @@ -433,11 +476,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, frag_len = len - offset; } skb_copy_to_linear_data_offset(skb, offset, - (bp->rx_buffers + - (RX_BUFFER_SIZE * frag)), - frag_len); + macb_rx_buffer(bp, frag), frag_len); offset += RX_BUFFER_SIZE; - bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); + desc = macb_rx_desc(bp, frag); + desc->addr &= ~MACB_BIT(RX_USED); if (frag == last_frag) break; @@ -463,8 +505,10 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin, { unsigned int frag; - for (frag = begin; frag != end; frag = NEXT_RX(frag)) - bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); + for (frag = begin; frag != end; frag++) { + struct macb_dma_desc *desc = macb_rx_desc(bp, frag); + desc->addr &= ~MACB_BIT(RX_USED); + } /* Make descriptor updates visible to hardware */ wmb(); @@ -479,17 +523,18 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin, static int macb_rx(struct macb *bp, int budget) { int received = 0; - unsigned int tail = bp->rx_tail; + unsigned int tail; int first_frag = -1; - for (; budget > 0; tail = NEXT_RX(tail)) { + for (tail = bp->rx_tail; budget > 0; tail++) { + struct macb_dma_desc *desc = macb_rx_desc(bp, tail); u32 addr, ctrl; /* Make hw descriptor updates visible to CPU */ rmb(); - addr = bp->rx_ring[tail].addr; - ctrl = bp->rx_ring[tail].ctrl; + addr = desc->addr; + ctrl = desc->ctrl; if (!(addr & MACB_BIT(RX_USED))) break; @@ -643,6 +688,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) struct macb *bp = netdev_priv(dev); dma_addr_t mapping; unsigned int len, entry; + struct macb_dma_desc *desc; + struct macb_tx_skb *tx_skb; u32 ctrl; unsigned long flags; @@ -659,7 +706,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&bp->lock, flags); /* This is a hard error, log it. */ - if (TX_BUFFS_AVAIL(bp) < 1) { + if (macb_tx_ring_avail(bp) < 1) { netif_stop_queue(dev); spin_unlock_irqrestore(&bp->lock, flags); netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n"); @@ -668,12 +715,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - entry = bp->tx_head; + entry = macb_tx_ring_wrap(bp->tx_head); + bp->tx_head++; netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry); mapping = dma_map_single(&bp->pdev->dev, skb->data, len, DMA_TO_DEVICE); - bp->tx_skb[entry].skb = skb; - bp->tx_skb[entry].mapping = mapping; + + tx_skb = &bp->tx_skb[entry]; + tx_skb->skb = skb; + tx_skb->mapping = mapping; netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n", skb->data, (unsigned long)mapping); @@ -682,20 +732,18 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) if (entry == (TX_RING_SIZE - 1)) ctrl |= MACB_BIT(TX_WRAP); - bp->tx_ring[entry].addr = mapping; - bp->tx_ring[entry].ctrl = ctrl; + desc = &bp->tx_ring[entry]; + desc->addr = mapping; + desc->ctrl = ctrl; /* Make newly initialized descriptor visible to hardware */ wmb(); - entry = NEXT_TX(entry); - bp->tx_head = entry; - skb_tx_timestamp(skb); macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); - if (TX_BUFFS_AVAIL(bp) < 1) + if (macb_tx_ring_avail(bp) < 1) netif_stop_queue(dev); spin_unlock_irqrestore(&bp->lock, flags); @@ -731,7 +779,7 @@ static int macb_alloc_consistent(struct macb *bp) { int size; - size = TX_RING_SIZE * sizeof(struct ring_info); + size = TX_RING_SIZE * sizeof(struct macb_tx_skb); bp->tx_skb = kmalloc(size, GFP_KERNEL); if (!bp->tx_skb) goto out_err; @@ -1401,8 +1449,6 @@ static int __init macb_probe(struct platform_device *pdev) macb_or_gem_writel(bp, USRIO, MACB_BIT(MII)); #endif - bp->tx_pending = DEF_TX_RING_PENDING; - err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index f69ceef..8a4ee2f 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -356,7 +356,12 @@ __v; \ }) -struct dma_desc { +/** + * struct macb_dma_desc - Hardware DMA descriptor + * @addr: DMA address of data buffer + * @ctrl: Control and status bits + */ +struct macb_dma_desc { u32 addr; u32 ctrl; }; @@ -421,7 +426,12 @@ struct dma_desc { #define MACB_TX_USED_OFFSET 31 #define MACB_TX_USED_SIZE 1 -struct ring_info { +/** + * struct macb_tx_skb - data about an skb which is being transmitted + * @skb: skb currently being transmitted + * @mapping: DMA address of the skb's data buffer + */ +struct macb_tx_skb { struct sk_buff *skb; dma_addr_t mapping; }; @@ -506,12 +516,12 @@ struct macb { void __iomem *regs; unsigned int rx_tail; - struct dma_desc *rx_ring; + struct macb_dma_desc *rx_ring; void *rx_buffers; unsigned int tx_head, tx_tail; - struct dma_desc *tx_ring; - struct ring_info *tx_skb; + struct macb_dma_desc *tx_ring; + struct macb_tx_skb *tx_skb; spinlock_t lock; struct platform_device *pdev; @@ -529,8 +539,6 @@ struct macb { dma_addr_t tx_ring_dma; dma_addr_t rx_buffers_dma; - unsigned int rx_pending, tx_pending; - struct mii_bus *mii_bus; struct phy_device *phy_dev; unsigned int link;