Commit 55054a16 authored by Havard Skinnemoen's avatar Havard Skinnemoen Committed by David S. Miller

net/macb: clean up ring buffer logic

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.

Available number of descriptors in ring buffer function by David Laight.
Signed-off-by: default avatarHavard Skinnemoen <havard@skinnemoen.net>
[nicolas.ferre@atmel.com: split patch in topics, adapt to newer kernel]
Signed-off-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Tested-by: default avatarJoachim Eastwood <manabian@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cde30a85
...@@ -156,7 +156,7 @@ static int at91ether_start(struct net_device *dev) ...@@ -156,7 +156,7 @@ static int at91ether_start(struct net_device *dev)
int i; int i;
lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev, lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev,
MAX_RX_DESCR * sizeof(struct dma_desc), MAX_RX_DESCR * sizeof(struct macb_dma_desc),
&lp->rx_ring_dma, GFP_KERNEL); &lp->rx_ring_dma, GFP_KERNEL);
if (!lp->rx_ring) { if (!lp->rx_ring) {
netdev_err(lp->dev, "unable to alloc rx ring DMA buffer\n"); netdev_err(lp->dev, "unable to alloc rx ring DMA buffer\n");
...@@ -170,7 +170,7 @@ static int at91ether_start(struct net_device *dev) ...@@ -170,7 +170,7 @@ static int at91ether_start(struct net_device *dev)
netdev_err(lp->dev, "unable to alloc rx data DMA buffer\n"); netdev_err(lp->dev, "unable to alloc rx data DMA buffer\n");
dma_free_coherent(&lp->pdev->dev, dma_free_coherent(&lp->pdev->dev,
MAX_RX_DESCR * sizeof(struct dma_desc), MAX_RX_DESCR * sizeof(struct macb_dma_desc),
lp->rx_ring, lp->rx_ring_dma); lp->rx_ring, lp->rx_ring_dma);
lp->rx_ring = NULL; lp->rx_ring = NULL;
return -ENOMEM; return -ENOMEM;
...@@ -256,7 +256,7 @@ static int at91ether_close(struct net_device *dev) ...@@ -256,7 +256,7 @@ static int at91ether_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
dma_free_coherent(&lp->pdev->dev, dma_free_coherent(&lp->pdev->dev,
MAX_RX_DESCR * sizeof(struct dma_desc), MAX_RX_DESCR * sizeof(struct macb_dma_desc),
lp->rx_ring, lp->rx_ring_dma); lp->rx_ring, lp->rx_ring_dma);
lp->rx_ring = NULL; lp->rx_ring = NULL;
......
...@@ -30,25 +30,14 @@ ...@@ -30,25 +30,14 @@
#include "macb.h" #include "macb.h"
#define RX_BUFFER_SIZE 128 #define RX_BUFFER_SIZE 128
#define RX_RING_SIZE 512 #define RX_RING_SIZE 512 /* must be power of 2 */
#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) */ /* Make the IP header word-aligned (the ethernet header is 14 bytes) */
#define RX_OFFSET 2 #define RX_OFFSET 2
#define TX_RING_SIZE 128 #define TX_RING_SIZE 128 /* must be power of 2 */
#define DEF_TX_RING_PENDING (TX_RING_SIZE - 1) #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
#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))
/* minimum number of free TX descriptors before waking up TX process */ /* minimum number of free TX descriptors before waking up TX process */
#define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4) #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4)
...@@ -56,6 +45,51 @@ ...@@ -56,6 +45,51 @@
#define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
| MACB_BIT(ISR_ROVR)) | 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 (bp->tx_tail - bp->tx_head) & (TX_RING_SIZE - 1);
}
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) static void __macb_set_hwaddr(struct macb *bp)
{ {
u32 bottom; u32 bottom;
...@@ -336,17 +370,18 @@ static void macb_tx(struct macb *bp) ...@@ -336,17 +370,18 @@ static void macb_tx(struct macb *bp)
bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
/* free transmit buffer in upper layer*/ /* free transmit buffer in upper layer*/
for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { for (tail = bp->tx_tail; tail != head; tail++) {
struct ring_info *rp = &bp->tx_skb[tail]; struct macb_tx_skb *tx_skb;
struct sk_buff *skb = rp->skb; struct sk_buff *skb;
BUG_ON(skb == NULL);
rmb(); rmb();
dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, tx_skb = macb_tx_skb(bp, tail);
DMA_TO_DEVICE); skb = tx_skb->skb;
rp->skb = NULL;
dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
skb->len, DMA_TO_DEVICE);
tx_skb->skb = NULL;
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
} }
...@@ -366,34 +401,38 @@ static void macb_tx(struct macb *bp) ...@@ -366,34 +401,38 @@ static void macb_tx(struct macb *bp)
return; return;
head = bp->tx_head; head = bp->tx_head;
for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { for (tail = bp->tx_tail; tail != head; tail++) {
struct ring_info *rp = &bp->tx_skb[tail]; struct macb_tx_skb *tx_skb;
struct sk_buff *skb = rp->skb; struct sk_buff *skb;
u32 bufstat; struct macb_dma_desc *desc;
u32 ctrl;
BUG_ON(skb == NULL); desc = macb_tx_desc(bp, tail);
/* Make hw descriptor updates visible to CPU */ /* Make hw descriptor updates visible to CPU */
rmb(); rmb();
bufstat = bp->tx_ring[tail].ctrl; ctrl = desc->ctrl;
if (!(bufstat & MACB_BIT(TX_USED))) if (!(ctrl & MACB_BIT(TX_USED)))
break; break;
tx_skb = macb_tx_skb(bp, tail);
skb = tx_skb->skb;
netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
tail, skb->data); macb_tx_ring_wrap(tail), skb->data);
dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
bp->stats.tx_packets++; bp->stats.tx_packets++;
bp->stats.tx_bytes += skb->len; bp->stats.tx_bytes += skb->len;
rp->skb = NULL; tx_skb->skb = NULL;
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
} }
bp->tx_tail = tail; bp->tx_tail = tail;
if (netif_queue_stopped(bp->dev) && if (netif_queue_stopped(bp->dev)
TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH) && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH)
netif_wake_queue(bp->dev); netif_wake_queue(bp->dev);
} }
...@@ -404,17 +443,21 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, ...@@ -404,17 +443,21 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
unsigned int frag; unsigned int frag;
unsigned int offset = 0; unsigned int offset = 0;
struct sk_buff *skb; 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", 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); skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
if (!skb) { if (!skb) {
bp->stats.rx_dropped++; bp->stats.rx_dropped++;
for (frag = first_frag; ; frag = NEXT_RX(frag)) { for (frag = first_frag; ; frag++) {
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) if (frag == last_frag)
break; break;
} }
...@@ -429,7 +472,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, ...@@ -429,7 +472,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
skb_checksum_none_assert(skb); skb_checksum_none_assert(skb);
skb_put(skb, len); skb_put(skb, len);
for (frag = first_frag; ; frag = NEXT_RX(frag)) { for (frag = first_frag; ; frag++) {
unsigned int frag_len = RX_BUFFER_SIZE; unsigned int frag_len = RX_BUFFER_SIZE;
if (offset + frag_len > len) { if (offset + frag_len > len) {
...@@ -437,11 +480,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, ...@@ -437,11 +480,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
frag_len = len - offset; frag_len = len - offset;
} }
skb_copy_to_linear_data_offset(skb, offset, skb_copy_to_linear_data_offset(skb, offset,
(bp->rx_buffers + macb_rx_buffer(bp, frag), frag_len);
(RX_BUFFER_SIZE * frag)),
frag_len);
offset += RX_BUFFER_SIZE; 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) if (frag == last_frag)
break; break;
...@@ -467,8 +509,10 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin, ...@@ -467,8 +509,10 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
{ {
unsigned int frag; unsigned int frag;
for (frag = begin; frag != end; frag = NEXT_RX(frag)) for (frag = begin; frag != end; frag++) {
bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); struct macb_dma_desc *desc = macb_rx_desc(bp, frag);
desc->addr &= ~MACB_BIT(RX_USED);
}
/* Make descriptor updates visible to hardware */ /* Make descriptor updates visible to hardware */
wmb(); wmb();
...@@ -483,17 +527,18 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin, ...@@ -483,17 +527,18 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
static int macb_rx(struct macb *bp, int budget) static int macb_rx(struct macb *bp, int budget)
{ {
int received = 0; int received = 0;
unsigned int tail = bp->rx_tail; unsigned int tail;
int first_frag = -1; 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; u32 addr, ctrl;
/* Make hw descriptor updates visible to CPU */ /* Make hw descriptor updates visible to CPU */
rmb(); rmb();
addr = bp->rx_ring[tail].addr; addr = desc->addr;
ctrl = bp->rx_ring[tail].ctrl; ctrl = desc->ctrl;
if (!(addr & MACB_BIT(RX_USED))) if (!(addr & MACB_BIT(RX_USED)))
break; break;
...@@ -647,6 +692,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -647,6 +692,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct macb *bp = netdev_priv(dev); struct macb *bp = netdev_priv(dev);
dma_addr_t mapping; dma_addr_t mapping;
unsigned int len, entry; unsigned int len, entry;
struct macb_dma_desc *desc;
struct macb_tx_skb *tx_skb;
u32 ctrl; u32 ctrl;
unsigned long flags; unsigned long flags;
...@@ -663,7 +710,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -663,7 +710,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&bp->lock, flags); spin_lock_irqsave(&bp->lock, flags);
/* This is a hard error, log it. */ /* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(bp) < 1) { if (macb_tx_ring_avail(bp) < 1) {
netif_stop_queue(dev); netif_stop_queue(dev);
spin_unlock_irqrestore(&bp->lock, flags); spin_unlock_irqrestore(&bp->lock, flags);
netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n"); netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n");
...@@ -672,12 +719,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -672,12 +719,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY; 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); netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
mapping = dma_map_single(&bp->pdev->dev, skb->data, mapping = dma_map_single(&bp->pdev->dev, skb->data,
len, DMA_TO_DEVICE); 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", netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
skb->data, (unsigned long)mapping); skb->data, (unsigned long)mapping);
...@@ -686,20 +736,18 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -686,20 +736,18 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (entry == (TX_RING_SIZE - 1)) if (entry == (TX_RING_SIZE - 1))
ctrl |= MACB_BIT(TX_WRAP); ctrl |= MACB_BIT(TX_WRAP);
bp->tx_ring[entry].addr = mapping; desc = &bp->tx_ring[entry];
bp->tx_ring[entry].ctrl = ctrl; desc->addr = mapping;
desc->ctrl = ctrl;
/* Make newly initialized descriptor visible to hardware */ /* Make newly initialized descriptor visible to hardware */
wmb(); wmb();
entry = NEXT_TX(entry);
bp->tx_head = entry;
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); 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); netif_stop_queue(dev);
spin_unlock_irqrestore(&bp->lock, flags); spin_unlock_irqrestore(&bp->lock, flags);
...@@ -735,7 +783,7 @@ static int macb_alloc_consistent(struct macb *bp) ...@@ -735,7 +783,7 @@ static int macb_alloc_consistent(struct macb *bp)
{ {
int size; 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); bp->tx_skb = kmalloc(size, GFP_KERNEL);
if (!bp->tx_skb) if (!bp->tx_skb)
goto out_err; goto out_err;
...@@ -1412,8 +1460,6 @@ static int __init macb_probe(struct platform_device *pdev) ...@@ -1412,8 +1460,6 @@ static int __init macb_probe(struct platform_device *pdev)
macb_or_gem_writel(bp, USRIO, MACB_BIT(MII)); macb_or_gem_writel(bp, USRIO, MACB_BIT(MII));
#endif #endif
bp->tx_pending = DEF_TX_RING_PENDING;
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
......
...@@ -362,7 +362,12 @@ ...@@ -362,7 +362,12 @@
__v; \ __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 addr;
u32 ctrl; u32 ctrl;
}; };
...@@ -427,7 +432,12 @@ struct dma_desc { ...@@ -427,7 +432,12 @@ struct dma_desc {
#define MACB_TX_USED_OFFSET 31 #define MACB_TX_USED_OFFSET 31
#define MACB_TX_USED_SIZE 1 #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; struct sk_buff *skb;
dma_addr_t mapping; dma_addr_t mapping;
}; };
...@@ -512,12 +522,12 @@ struct macb { ...@@ -512,12 +522,12 @@ struct macb {
void __iomem *regs; void __iomem *regs;
unsigned int rx_tail; unsigned int rx_tail;
struct dma_desc *rx_ring; struct macb_dma_desc *rx_ring;
void *rx_buffers; void *rx_buffers;
unsigned int tx_head, tx_tail; unsigned int tx_head, tx_tail;
struct dma_desc *tx_ring; struct macb_dma_desc *tx_ring;
struct ring_info *tx_skb; struct macb_tx_skb *tx_skb;
spinlock_t lock; spinlock_t lock;
struct platform_device *pdev; struct platform_device *pdev;
...@@ -535,8 +545,6 @@ struct macb { ...@@ -535,8 +545,6 @@ struct macb {
dma_addr_t tx_ring_dma; dma_addr_t tx_ring_dma;
dma_addr_t rx_buffers_dma; dma_addr_t rx_buffers_dma;
unsigned int rx_pending, tx_pending;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
struct phy_device *phy_dev; struct phy_device *phy_dev;
unsigned int link; unsigned int link;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment