aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/patches/100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch
blob: e7696e29d713f87a09590f3719e96cbe108a038f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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,