leon: R.I.P.
[openwrt/staging/dedeckeh.git] / target / linux / coldfire / patches / 100-kernel-2.6.38-Fix-FEC-driver-bugs-for-MCF547x-MCF548x.patch
1 From 92b8d976e58fe5e6eb97aedcaa46e80c924fbc04 Mon Sep 17 00:00:00 2001
2 From: Wang Huan <wanghuan@zch06.freescale.net>
3 Date: Mon, 5 Sep 2011 08:59:46 +0800
4 Subject: [PATCH] Fix FEC driver bugs for MCF547x/MCF548x
5
6 This patch fixed kernel panic during flood ping with huge packets.
7 It also fixed the data integrity errors when running iozone on an
8 NFSv3-mounted file system.
9
10 Signed-off-by: Jason Jin <jason.jin@freescale.com>
11 ---
12 arch/m68k/include/asm/cf_548x_cacheflush.h | 45 ++++++++++++++++++++++++---
13 drivers/net/fec_m547x.c | 18 +++++-----
14 2 files changed, 49 insertions(+), 14 deletions(-)
15
16 --- a/arch/m68k/include/asm/cf_548x_cacheflush.h
17 +++ b/arch/m68k/include/asm/cf_548x_cacheflush.h
18 @@ -27,8 +27,8 @@
19 unsigned long end_set; \
20 \
21 start_set = 0; \
22 - end_set = (unsigned long)LAST_DCACHE_ADDR; \
23 - \
24 + end_set = (unsigned long)LAST_ICACHE_ADDR; \
25 + asm("nop"); \
26 for (set = start_set; set <= end_set; set += (0x10 - 3)) {\
27 asm volatile("cpushl %%ic,(%0)\n" \
28 "\taddq%.l #1,%0\n" \
29 @@ -48,7 +48,7 @@
30 \
31 start_set = 0; \
32 end_set = (unsigned long)LAST_DCACHE_ADDR; \
33 - \
34 + asm("nop"); \
35 for (set = start_set; set <= end_set; set += (0x10 - 3)) { \
36 asm volatile("cpushl %%dc,(%0)\n" \
37 "\taddq%.l #1,%0\n" \
38 @@ -68,7 +68,7 @@
39 \
40 start_set = 0; \
41 end_set = (unsigned long)LAST_DCACHE_ADDR; \
42 - \
43 + asm("nop"); \
44 for (set = start_set; set <= end_set; set += (0x10 - 3)) { \
45 asm volatile("cpushl %%bc,(%0)\n" \
46 "\taddq%.l #1,%0\n" \
47 @@ -240,12 +240,47 @@ extern inline void flush_icache_range(un
48 }
49 }
50
51 +static inline void flush_dcache_range(unsigned long address,
52 + unsigned long endaddr)
53 +{
54 + unsigned long set;
55 + unsigned long start_set;
56 + unsigned long end_set;
57 +
58 + start_set = address & _DCACHE_SET_MASK;
59 + end_set = endaddr & _DCACHE_SET_MASK;
60 +
61 + if (start_set > end_set) {
62 + /* from the begining to the lowest address */
63 + for (set = 0; set <= end_set; set += (0x10 - 3)) {
64 + asm volatile("cpushl %%dc,(%0)\n"
65 + "\taddq%.l #1,%0\n"
66 + "\tcpushl %%dc,(%0)\n"
67 + "\taddq%.l #1,%0\n"
68 + "\tcpushl %%dc,(%0)\n"
69 + "\taddq%.l #1,%0\n"
70 + "\tcpushl %%dc,(%0)" : "=a" (set) : "a" (set));
71 + }
72 + /* next loop will finish the cache ie pass the hole */
73 + end_set = LAST_ICACHE_ADDR;
74 + }
75 + for (set = start_set; set <= end_set; set += (0x10 - 3)) {
76 + asm volatile("cpushl %%dc,(%0)\n"
77 + "\taddq%.l #1,%0\n"
78 + "\tcpushl %%dc,(%0)\n"
79 + "\taddq%.l #1,%0\n"
80 + "\tcpushl %%dc,(%0)\n"
81 + "\taddq%.l #1,%0\n"
82 + "\tcpushl %%dc,(%0)" : "=a" (set) : "a" (set));
83 + }
84 +}
85 +
86 static inline void copy_to_user_page(struct vm_area_struct *vma,
87 struct page *page, unsigned long vaddr,
88 void *dst, void *src, int len)
89 {
90 memcpy(dst, src, len);
91 - flush_icache_user_page(vma, page, vaddr, len);
92 + flush_dcache();
93 }
94 static inline void copy_from_user_page(struct vm_area_struct *vma,
95 struct page *page, unsigned long vaddr,
96 --- a/drivers/net/fec_m547x.c
97 +++ b/drivers/net/fec_m547x.c
98 @@ -34,7 +34,7 @@
99 #include <asm/m5485sram.h>
100 #include <asm/virtconvert.h>
101 #include <asm/irq.h>
102 -
103 +#include <asm/cf_cacheflush.h>
104 #include "fec_m547x.h"
105
106 #ifdef CONFIG_FEC_548x_ENABLE_FEC2
107 @@ -97,7 +97,7 @@ static void fec_interrupt_fec_rx_handler
108 static irqreturn_t fec_interrupt_handler(int irq, void *dev_id);
109 static void fec_interrupt_fec_tx_handler_fec0(void);
110 static void fec_interrupt_fec_rx_handler_fec0(void);
111 -static void fec_interrupt_fec_reinit(unsigned long data);
112 +static void fec_interrupt_fec_reinit(struct net_device *dev);
113
114 /* default fec0 address */
115 unsigned char fec_mac_addr_fec0[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 };
116 @@ -145,6 +145,7 @@ static int coldfire_fec_mdio_read(struct
117 #ifdef CONFIG_FEC_548x_SHARED_PHY
118 unsigned long base_addr = (unsigned long)FEC_BASE_ADDR_FEC0;
119 #else
120 + struct net_device *dev = bus->priv;
121 unsigned long base_addr = (unsigned long) dev->base_addr;
122 #endif
123 int tries = 100;
124 @@ -179,6 +180,7 @@ static int coldfire_fec_mdio_write(struc
125 #ifdef CONFIG_FEC_548x_SHARED_PHY
126 unsigned long base_addr = (unsigned long)FEC_BASE_ADDR_FEC0;
127 #else
128 + struct net_device *dev = bus->priv;
129 unsigned long base_addr = (unsigned long) dev->base_addr;
130 #endif
131 int tries = 100;
132 @@ -394,9 +396,6 @@ static int mcf547x_fec_open(struct net_d
133
134 dma_connect(channel, (int) fp->fecpriv_interrupt_fec_tx_handler);
135
136 - /* init tasklet for controller reinitialization */
137 - tasklet_init(&fp->fecpriv_tasklet_reinit,
138 - fec_interrupt_fec_reinit, (unsigned long) dev);
139
140 /* Reset FIFOs */
141 FEC_FECFRST(base_addr) |= FEC_SW_RST | FEC_RST_CTL;
142 @@ -790,6 +789,8 @@ static int mcf547x_fec_start_xmit(struct
143
144 /* flush data cache before initializing
145 * the descriptor and starting DMA */
146 + flush_dcache_range(virt_to_phys(data_aligned),
147 + virt_to_phys(data_aligned) + skb->len);
148
149 spin_lock_irq(&fp->fecpriv_lock);
150
151 @@ -1308,7 +1309,7 @@ irqreturn_t fec_interrupt_handler(int ir
152 netif_stop_queue(dev);
153
154 /* execute reinitialization as tasklet */
155 - tasklet_schedule(&fp->fecpriv_tasklet_reinit);
156 + fec_interrupt_fec_reinit(dev);
157
158 fp->fecpriv_stat.rx_dropped++;
159 }
160 @@ -1343,10 +1344,9 @@ irqreturn_t fec_interrupt_handler(int ir
161 * when controller must be reinitialized.
162 *
163 *************************************************************************/
164 -void fec_interrupt_fec_reinit(unsigned long data)
165 +void fec_interrupt_fec_reinit(struct net_device *dev)
166 {
167 int i;
168 - struct net_device *dev = (struct net_device *)data;
169 struct fec_priv *fp = netdev_priv(dev);
170 unsigned long base_addr = (unsigned long) dev->base_addr;
171
172 @@ -1385,7 +1385,7 @@ void fec_interrupt_fec_reinit(unsigned l
173 fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
174
175 /* flush entire data cache before restarting the DMA */
176 -
177 + flush_dcache();
178 /* restart DMA from beginning */
179 MCD_startDma(fp->fecpriv_fec_rx_channel,
180 (char *) fp->fecpriv_rxdesc, 0,