summaryrefslogtreecommitdiff
path: root/packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch
diff options
context:
space:
mode:
authorSergey Lapin <slapin@ossfans.org>2008-12-04 01:28:47 +0300
committerSergey Lapin <slapin@ossfans.org>2008-12-04 01:36:42 +0300
commitdde71280ca0a91bd8393590f1fa07251645dc21b (patch)
treeec9d96b0b0e750453ad344f7db798d068bbb7ed2 /packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch
parent6ae987b688c82aa1852b5a7bb691b7138c3ebd51 (diff)
linux_2.6.28: made source fetchable after Koen's fix
Diffstat (limited to 'packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch')
-rw-r--r--packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch310
1 files changed, 310 insertions, 0 deletions
diff --git a/packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch b/packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch
new file mode 100644
index 0000000000..9a280d666a
--- /dev/null
+++ b/packages/linux/linux-2.6.27+2.6.28-rc6/afeb9260/0002-SRAM-TX-buffers-implementation-from-atmel-to-fix-TX.patch
@@ -0,0 +1,310 @@
+From 856f17b89eb0e943d36f36d0c760e1226db9d716 Mon Sep 17 00:00:00 2001
+From: Sergey Lapin <slapin@ossfans.org>
+Date: Fri, 4 Jul 2008 01:52:39 +0400
+Subject: [PATCH] SRAM TX buffers implementation from atmel to fix TX underrun errors
+
+Signed-off-by: Sergey Lapin <slapin@ossfans.org>
+---
+ arch/arm/mach-at91/at91sam9260_devices.c | 7 ++
+ drivers/net/Kconfig | 6 ++
+ drivers/net/macb.c | 108 ++++++++++++++++++++++--------
+ drivers/net/macb.h | 7 ++-
+ 4 files changed, 99 insertions(+), 29 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index f5fec0a..681cd40 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -141,6 +141,13 @@ static struct resource eth_resources[] = {
+ .end = AT91SAM9260_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
++#if defined(CONFIG_MACB_TX_SRAM)
++ [2] = {
++ .start = AT91SAM9260_SRAM1_BASE,
++ .end = AT91SAM9260_SRAM1_BASE + AT91SAM9260_SRAM1_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++#endif
+ };
+
+ static struct platform_device at91sam9260_eth_device = {
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 8a03875..a9a46a8 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -218,6 +218,12 @@ config MACB
+ To compile this driver as a module, choose M here: the module
+ will be called macb.
+
++config MACB_TX_SRAM
++ bool "Use internal SRAM for EMAC (Ethernet) transmit buffers"
++ depends on (ARCH_AT91SAM9263 || ARCH_AT91SAM9260) && MACB
++ help
++ Select this if you are using internal SRAM for EMAC transmit buffers.
++
+ source "drivers/net/arm/Kconfig"
+
+ config AX88796
+diff --git a/drivers/net/macb.c b/drivers/net/macb.c
+index daba82b..55063dc 100644
+--- a/drivers/net/macb.c
++++ b/drivers/net/macb.c
+@@ -33,22 +33,27 @@
+ /* 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_MAX_PKT_SIZE 1536
++#define TX_DEFAULT_RING_SIZE 128
++#define DEF_TX_RING_PENDING(bp) ((bp)->tx_ring_size - 1)
++
++#define TX_RING_BYTES(bp) (sizeof(struct dma_desc) * \
++ (bp)->tx_ring_size)
+
+ #define TX_RING_GAP(bp) \
+- (TX_RING_SIZE - (bp)->tx_pending)
++ ((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 NEXT_TX(bp, n) (((n) + 1) % ((bp)->tx_ring_size))
++#define NEXT_RX(n) (((n) + 1) % (RX_RING_SIZE))
++
+
+ /* 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(bp) ((bp)->tx_ring_size / 4)
+
+ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
+ | MACB_BIT(ISR_ROVR))
+@@ -316,11 +321,11 @@ static void macb_tx(struct macb *bp)
+ head = bp->tx_head;
+
+ /*Mark all the buffer as used to avoid sending a lost buffer*/
+- for (i = 0; i < TX_RING_SIZE; i++)
++ for (i = 0; i < bp->tx_ring_size; i++)
+ bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+
+ /* 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 = NEXT_TX(bp, tail)) {
+ struct ring_info *rp = &bp->tx_skb[tail];
+ struct sk_buff *skb = rp->skb;
+
+@@ -346,7 +351,7 @@ static void macb_tx(struct macb *bp)
+ return;
+
+ head = bp->tx_head;
+- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
++ for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(bp, tail)) {
+ struct ring_info *rp = &bp->tx_skb[tail];
+ struct sk_buff *skb = rp->skb;
+ u32 bufstat;
+@@ -371,7 +376,7 @@ static void macb_tx(struct macb *bp)
+
+ bp->tx_tail = tail;
+ if (netif_queue_stopped(bp->dev) &&
+- TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH)
++ TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH(bp))
+ netif_wake_queue(bp->dev);
+ }
+
+@@ -401,6 +406,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ }
+
+ skb_reserve(skb, RX_OFFSET);
++ skb->dev = bp->dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb_put(skb, len);
+
+@@ -637,8 +643,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+ entry = bp->tx_head;
+ dev_dbg(&bp->pdev->dev, "Allocated ring entry %u\n", entry);
+- mapping = dma_map_single(&bp->pdev->dev, skb->data,
++ if (bp->smem_start) {
++ mapping = bp->tx_ring[entry].addr;
++ memcpy(bp->tx_buffers + entry * TX_MAX_PKT_SIZE,
++ skb->data, len);
++ } else {
++ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ len, DMA_TO_DEVICE);
++ bp->tx_ring[entry].addr = mapping;
++ }
+ bp->tx_skb[entry].skb = skb;
+ bp->tx_skb[entry].mapping = mapping;
+ dev_dbg(&bp->pdev->dev, "Mapped skb data %p to DMA addr %08lx\n",
+@@ -646,14 +659,13 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+ ctrl = MACB_BF(TX_FRMLEN, len);
+ ctrl |= MACB_BIT(TX_LAST);
+- if (entry == (TX_RING_SIZE - 1))
++ if (entry == (bp->tx_ring_size - 1))
+ ctrl |= MACB_BIT(TX_WRAP);
+
+- bp->tx_ring[entry].addr = mapping;
+ bp->tx_ring[entry].ctrl = ctrl;
+ wmb();
+
+- entry = NEXT_TX(entry);
++ entry = NEXT_TX(bp, entry);
+ bp->tx_head = entry;
+
+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
+@@ -680,7 +692,8 @@ static void macb_free_consistent(struct macb *bp)
+ bp->rx_ring = NULL;
+ }
+ if (bp->tx_ring) {
+- dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES,
++ if (!bp->smem_start)
++ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES(bp),
+ bp->tx_ring, bp->tx_ring_dma);
+ bp->tx_ring = NULL;
+ }
+@@ -690,13 +703,16 @@ static void macb_free_consistent(struct macb *bp)
+ bp->rx_buffers, bp->rx_buffers_dma);
+ bp->rx_buffers = NULL;
+ }
++
++ if (bp->smem_start && bp->tx_ring_dma)
++ release_mem_region(bp->tx_ring_dma, bp->smem_size);
+ }
+
+ static int macb_alloc_consistent(struct macb *bp)
+ {
+ int size;
+
+- size = TX_RING_SIZE * sizeof(struct ring_info);
++ size = bp->tx_ring_size * sizeof(struct ring_info);
+ bp->tx_skb = kmalloc(size, GFP_KERNEL);
+ if (!bp->tx_skb)
+ goto out_err;
+@@ -710,14 +726,30 @@ static int macb_alloc_consistent(struct macb *bp)
+ "Allocated RX ring of %d bytes at %08lx (mapped %p)\n",
+ size, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
+
+- size = TX_RING_BYTES;
+- bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
++ if (bp->smem_start) {
++ if (request_mem_region(bp->smem_start,
++ bp->smem_size, "macb")) {
++ bp->tx_ring_dma = bp->smem_start;
++ }
++ bp->tx_ring = ioremap(bp->tx_ring_dma, bp->smem_size);
++ if (bp->tx_ring) {
++ bp->tx_buffers_dma = bp->tx_ring_dma +
++ TX_RING_BYTES(bp);
++ bp->tx_buffers = (char *) bp->tx_ring +
++ TX_RING_BYTES(bp);
++ }
++ }
++
++ if (!bp->tx_ring) {
++ size = TX_RING_BYTES(bp);
++ bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
+ &bp->tx_ring_dma, GFP_KERNEL);
+- if (!bp->tx_ring)
+- goto out_err;
+- dev_dbg(&bp->pdev->dev,
+- "Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
++ if (!bp->tx_ring)
++ goto out_err;
++ dev_dbg(&bp->pdev->dev,
++ "Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
++ size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
++ }
+
+ size = RX_RING_SIZE * RX_BUFFER_SIZE;
+ bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
+@@ -748,11 +780,14 @@ static void macb_init_rings(struct macb *bp)
+ }
+ bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
+
+- for (i = 0; i < TX_RING_SIZE; i++) {
+- bp->tx_ring[i].addr = 0;
++ for (i = 0; i < bp->tx_ring_size; i++) {
++ bp->tx_ring[i].addr = (bp->smem_start) ?
++ bp->tx_buffers_dma + i * TX_MAX_PKT_SIZE : 0;
+ bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
++ bp->tx_ring[i].addr = (u32) (bp->tx_buffers_dma +
++ (i * TX_MAX_PKT_SIZE));
+ }
+- bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
++ bp->tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP);
+
+ bp->rx_tail = bp->tx_head = bp->tx_tail = 0;
+ }
+@@ -1090,6 +1125,7 @@ static int __init macb_probe(struct platform_device *pdev)
+ {
+ struct eth_platform_data *pdata;
+ struct resource *regs;
++ struct resource *smem;
+ struct net_device *dev;
+ struct macb *bp;
+ struct phy_device *phydev;
+@@ -1201,7 +1237,23 @@ static int __init macb_probe(struct platform_device *pdev)
+ macb_writel(bp, USRIO, MACB_BIT(MII));
+ #endif
+
+- bp->tx_pending = DEF_TX_RING_PENDING;
++ /* Check mem region for TX buffers */
++ smem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (smem) {
++ bp->smem_start = smem->start;
++ bp->smem_size = smem->end - smem->start + 1;
++ bp->tx_ring_size = bp->smem_size / (TX_MAX_PKT_SIZE +
++ sizeof(struct dma_desc));
++ }
++
++ /* if ring_size == 0 then mem is too
++ small and use standard memory */
++ if (!bp->tx_ring_size) {
++ bp->smem_start = 0;
++ bp->tx_ring_size = TX_DEFAULT_RING_SIZE;
++ }
++
++ bp->tx_pending = DEF_TX_RING_PENDING(bp);
+
+ err = register_netdev(dev);
+ if (err) {
+diff --git a/drivers/net/macb.h b/drivers/net/macb.h
+index 57b85ac..faa5a9d 100644
+--- a/drivers/net/macb.h
++++ b/drivers/net/macb.h
+@@ -364,11 +364,15 @@ struct macb {
+ unsigned int rx_tail;
+ struct dma_desc *rx_ring;
+ void *rx_buffers;
+-
++ void *tx_buffers;
++ unsigned int tx_ring_size;
+ unsigned int tx_head, tx_tail;
+ struct dma_desc *tx_ring;
+ struct ring_info *tx_skb;
+
++ unsigned int smem_start;
++ unsigned int smem_size;
++
+ spinlock_t lock;
+ struct platform_device *pdev;
+ struct clk *pclk;
+@@ -381,6 +385,7 @@ struct macb {
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+ dma_addr_t rx_buffers_dma;
++ dma_addr_t tx_buffers_dma;
+
+ unsigned int rx_pending, tx_pending;
+
+--
+1.5.4.1
+