aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch')
-rw-r--r--target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch180
1 files changed, 180 insertions, 0 deletions
diff --git a/target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch b/target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch
new file mode 100644
index 0000000000..e7696e29d7
--- /dev/null
+++ b/target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch
@@ -0,0 +1,180 @@
+From 92b8d976e58fe5e6eb97aedcaa46e80c924fbc04 Mon Sep 17 00:00:00 2001
+From: Wang Huan <wanghuan@zch06.freescale.net>
+Date: Mon, 5 Sep 2011 08:59:46 +0800
+Subject: [PATCH] Fix FEC driver bugs for MCF547x/MCF548x
+
+This patch fixed kernel panic during flood ping with huge packets.
+It also fixed the data integrity errors when running iozone on an
+NFSv3-mounted file system.
+
+Signed-off-by: Jason Jin <jason.jin@freescale.com>
+---
+ arch/m68k/include/asm/cf_548x_cacheflush.h | 45 ++++++++++++++++++++++++---
+ drivers/net/fec_m547x.c | 18 +++++-----
+ 2 files changed, 49 insertions(+), 14 deletions(-)
+
+--- a/arch/m68k/include/asm/cf_548x_cacheflush.h
++++ b/arch/m68k/include/asm/cf_548x_cacheflush.h
+@@ -27,8 +27,8 @@
+ unsigned long end_set; \
+ \
+ start_set = 0; \
+- end_set = (unsigned long)LAST_DCACHE_ADDR; \
+- \
++ end_set = (unsigned long)LAST_ICACHE_ADDR; \
++ asm("nop"); \
+ for (set = start_set; set <= end_set; set += (0x10 - 3)) {\
+ asm volatile("cpushl %%ic,(%0)\n" \
+ "\taddq%.l #1,%0\n" \
+@@ -48,7 +48,7 @@
+ \
+ start_set = 0; \
+ end_set = (unsigned long)LAST_DCACHE_ADDR; \
+- \
++ asm("nop"); \
+ for (set = start_set; set <= end_set; set += (0x10 - 3)) { \
+ asm volatile("cpushl %%dc,(%0)\n" \
+ "\taddq%.l #1,%0\n" \
+@@ -68,7 +68,7 @@
+ \
+ start_set = 0; \
+ end_set = (unsigned long)LAST_DCACHE_ADDR; \
+- \
++ asm("nop"); \
+ for (set = start_set; set <= end_set; set += (0x10 - 3)) { \
+ asm volatile("cpushl %%bc,(%0)\n" \
+ "\taddq%.l #1,%0\n" \
+@@ -240,12 +240,47 @@ extern inline void flush_icache_range(un
+ }
+ }
+
++static inline void flush_dcache_range(unsigned long address,
++ unsigned long endaddr)
++{
++ unsigned long set;
++ unsigned long start_set;
++ unsigned long end_set;
++
++ start_set = address & _DCACHE_SET_MASK;
++ end_set = endaddr & _DCACHE_SET_MASK;
++
++ if (start_set > end_set) {
++ /* from the begining to the lowest address */
++ for (set = 0; set <= end_set; set += (0x10 - 3)) {
++ asm volatile("cpushl %%dc,(%0)\n"
++ "\taddq%.l #1,%0\n"
++ "\tcpushl %%dc,(%0)\n"
++ "\taddq%.l #1,%0\n"
++ "\tcpushl %%dc,(%0)\n"
++ "\taddq%.l #1,%0\n"
++ "\tcpushl %%dc,(%0)" : "=a" (set) : "a" (set));
++ }
++ /* next loop will finish the cache ie pass the hole */
++ end_set = LAST_ICACHE_ADDR;
++ }
++ for (set = start_set; set <= end_set; set += (0x10 - 3)) {
++ asm volatile("cpushl %%dc,(%0)\n"
++ "\taddq%.l #1,%0\n"
++ "\tcpushl %%dc,(%0)\n"
++ "\taddq%.l #1,%0\n"
++ "\tcpushl %%dc,(%0)\n"
++ "\taddq%.l #1,%0\n"
++ "\tcpushl %%dc,(%0)" : "=a" (set) : "a" (set));
++ }
++}
++
+ static inline void copy_to_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr,
+ void *dst, void *src, int len)
+ {
+ memcpy(dst, src, len);
+- flush_icache_user_page(vma, page, vaddr, len);
++ flush_dcache();
+ }
+ static inline void copy_from_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr,
+--- a/drivers/net/fec_m547x.c
++++ b/drivers/net/fec_m547x.c
+@@ -34,7 +34,7 @@
+ #include <asm/m5485sram.h>
+ #include <asm/virtconvert.h>
+ #include <asm/irq.h>
+-
++#include <asm/cf_cacheflush.h>
+ #include "fec_m547x.h"
+
+ #ifdef CONFIG_FEC_548x_ENABLE_FEC2
+@@ -97,7 +97,7 @@ static void fec_interrupt_fec_rx_handler
+ static irqreturn_t fec_interrupt_handler(int irq, void *dev_id);
+ static void fec_interrupt_fec_tx_handler_fec0(void);
+ static void fec_interrupt_fec_rx_handler_fec0(void);
+-static void fec_interrupt_fec_reinit(unsigned long data);
++static void fec_interrupt_fec_reinit(struct net_device *dev);
+
+ /* default fec0 address */
+ unsigned char fec_mac_addr_fec0[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 };
+@@ -145,6 +145,7 @@ static int coldfire_fec_mdio_read(struct
+ #ifdef CONFIG_FEC_548x_SHARED_PHY
+ unsigned long base_addr = (unsigned long)FEC_BASE_ADDR_FEC0;
+ #else
++ struct net_device *dev = bus->priv;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ #endif
+ int tries = 100;
+@@ -179,6 +180,7 @@ static int coldfire_fec_mdio_write(struc
+ #ifdef CONFIG_FEC_548x_SHARED_PHY
+ unsigned long base_addr = (unsigned long)FEC_BASE_ADDR_FEC0;
+ #else
++ struct net_device *dev = bus->priv;
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+ #endif
+ int tries = 100;
+@@ -394,9 +396,6 @@ static int mcf547x_fec_open(struct net_d
+
+ dma_connect(channel, (int) fp->fecpriv_interrupt_fec_tx_handler);
+
+- /* init tasklet for controller reinitialization */
+- tasklet_init(&fp->fecpriv_tasklet_reinit,
+- fec_interrupt_fec_reinit, (unsigned long) dev);
+
+ /* Reset FIFOs */
+ FEC_FECFRST(base_addr) |= FEC_SW_RST | FEC_RST_CTL;
+@@ -790,6 +789,8 @@ static int mcf547x_fec_start_xmit(struct
+
+ /* flush data cache before initializing
+ * the descriptor and starting DMA */
++ flush_dcache_range(virt_to_phys(data_aligned),
++ virt_to_phys(data_aligned) + skb->len);
+
+ spin_lock_irq(&fp->fecpriv_lock);
+
+@@ -1308,7 +1309,7 @@ irqreturn_t fec_interrupt_handler(int ir
+ netif_stop_queue(dev);
+
+ /* execute reinitialization as tasklet */
+- tasklet_schedule(&fp->fecpriv_tasklet_reinit);
++ fec_interrupt_fec_reinit(dev);
+
+ fp->fecpriv_stat.rx_dropped++;
+ }
+@@ -1343,10 +1344,9 @@ irqreturn_t fec_interrupt_handler(int ir
+ * when controller must be reinitialized.
+ *
+ *************************************************************************/
+-void fec_interrupt_fec_reinit(unsigned long data)
++void fec_interrupt_fec_reinit(struct net_device *dev)
+ {
+ int i;
+- struct net_device *dev = (struct net_device *)data;
+ struct fec_priv *fp = netdev_priv(dev);
+ unsigned long base_addr = (unsigned long) dev->base_addr;
+
+@@ -1385,7 +1385,7 @@ void fec_interrupt_fec_reinit(unsigned l
+ fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+ /* flush entire data cache before restarting the DMA */
+-
++ flush_dcache();
+ /* restart DMA from beginning */
+ MCD_startDma(fp->fecpriv_fec_rx_channel,
+ (char *) fp->fecpriv_rxdesc, 0,