aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/stmmac/enh_desc.c
diff options
context:
space:
mode:
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>2010-04-13 16:21:12 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-14 07:49:50 -0400
commit56b106ae7b1f6b7cef4ef7e79a03b59cfc940923 (patch)
tree3bf4908dd7a31231480f7f7289e6660b49bd41e3 /drivers/net/stmmac/enh_desc.c
parent3c32be635c18ead00d460b7bdad1da52622ff40f (diff)
stmmac: rework normal and enhanced descriptors
Currently the driver assumes that the mac10/100 can only use the normal descriptor structure and the gmac can only use the enhanced structures. This patch removes the descriptor's code from the dma files and adds two new files just for handling the normal and enhanced descriptors. Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/stmmac/enh_desc.c')
-rw-r--r--drivers/net/stmmac/enh_desc.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/stmmac/enh_desc.c
new file mode 100644
index 000000000000..e5ac2593dc68
--- /dev/null
+++ b/drivers/net/stmmac/enh_desc.c
@@ -0,0 +1,342 @@
1/*******************************************************************************
2 This contains the functions to handle the enhanced descriptors.
3
4 Copyright (C) 2007-2009 STMicroelectronics Ltd
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms and conditions of the GNU General Public License,
8 version 2, as published by the Free Software Foundation.
9
10 This program is distributed in the hope it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18
19 The full GNU General Public License is included in this distribution in
20 the file called "COPYING".
21
22 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
23*******************************************************************************/
24
25#include "common.h"
26
27static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
28 struct dma_desc *p, unsigned long ioaddr)
29{
30 int ret = 0;
31 struct net_device_stats *stats = (struct net_device_stats *)data;
32
33 if (unlikely(p->des01.etx.error_summary)) {
34 CHIP_DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
35 if (unlikely(p->des01.etx.jabber_timeout)) {
36 CHIP_DBG(KERN_ERR "\tjabber_timeout error\n");
37 x->tx_jabber++;
38 }
39
40 if (unlikely(p->des01.etx.frame_flushed)) {
41 CHIP_DBG(KERN_ERR "\tframe_flushed error\n");
42 x->tx_frame_flushed++;
43 /*enh_desc_flush_tx_fifo(ioaddr);*/
44 }
45
46 if (unlikely(p->des01.etx.loss_carrier)) {
47 CHIP_DBG(KERN_ERR "\tloss_carrier error\n");
48 x->tx_losscarrier++;
49 stats->tx_carrier_errors++;
50 }
51 if (unlikely(p->des01.etx.no_carrier)) {
52 CHIP_DBG(KERN_ERR "\tno_carrier error\n");
53 x->tx_carrier++;
54 stats->tx_carrier_errors++;
55 }
56 if (unlikely(p->des01.etx.late_collision)) {
57 CHIP_DBG(KERN_ERR "\tlate_collision error\n");
58 stats->collisions += p->des01.etx.collision_count;
59 }
60 if (unlikely(p->des01.etx.excessive_collisions)) {
61 CHIP_DBG(KERN_ERR "\texcessive_collisions\n");
62 stats->collisions += p->des01.etx.collision_count;
63 }
64 if (unlikely(p->des01.etx.excessive_deferral)) {
65 CHIP_DBG(KERN_INFO "\texcessive tx_deferral\n");
66 x->tx_deferred++;
67 }
68
69 if (unlikely(p->des01.etx.underflow_error)) {
70 CHIP_DBG(KERN_ERR "\tunderflow error\n");
71 /*enh_desc_flush_tx_fifo(ioaddr);*/
72 x->tx_underflow++;
73 }
74
75 if (unlikely(p->des01.etx.ip_header_error)) {
76 CHIP_DBG(KERN_ERR "\tTX IP header csum error\n");
77 x->tx_ip_header_error++;
78 }
79
80 if (unlikely(p->des01.etx.payload_error)) {
81 CHIP_DBG(KERN_ERR "\tAddr/Payload csum error\n");
82 x->tx_payload_error++;
83 /*enh_desc_flush_tx_fifo(ioaddr);*/
84 }
85
86 ret = -1;
87 }
88
89 if (unlikely(p->des01.etx.deferred)) {
90 CHIP_DBG(KERN_INFO "GMAC TX status: tx deferred\n");
91 x->tx_deferred++;
92 }
93#ifdef STMMAC_VLAN_TAG_USED
94 if (p->des01.etx.vlan_frame) {
95 CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
96 x->tx_vlan++;
97 }
98#endif
99
100 return ret;
101}
102
103static int enh_desc_get_tx_len(struct dma_desc *p)
104{
105 return p->des01.etx.buffer1_size;
106}
107
108static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
109{
110 int ret = good_frame;
111 u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
112
113 /* bits 5 7 0 | Frame status
114 * ----------------------------------------------------------
115 * 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
116 * 1 0 0 | IPv4/6 No CSUM errorS.
117 * 1 0 1 | IPv4/6 CSUM PAYLOAD error
118 * 1 1 0 | IPv4/6 CSUM IP HR error
119 * 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
120 * 0 0 1 | IPv4/6 unsupported IP PAYLOAD
121 * 0 1 1 | COE bypassed.. no IPv4/6 frame
122 * 0 1 0 | Reserved.
123 */
124 if (status == 0x0) {
125 CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
126 ret = good_frame;
127 } else if (status == 0x4) {
128 CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
129 ret = good_frame;
130 } else if (status == 0x5) {
131 CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
132 ret = csum_none;
133 } else if (status == 0x6) {
134 CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
135 ret = csum_none;
136 } else if (status == 0x7) {
137 CHIP_DBG(KERN_ERR
138 "RX Des0 status: IPv4/6 Header and Payload Error.\n");
139 ret = csum_none;
140 } else if (status == 0x1) {
141 CHIP_DBG(KERN_ERR
142 "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
143 ret = discard_frame;
144 } else if (status == 0x3) {
145 CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
146 ret = discard_frame;
147 }
148 return ret;
149}
150
151static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
152 struct dma_desc *p)
153{
154 int ret = good_frame;
155 struct net_device_stats *stats = (struct net_device_stats *)data;
156
157 if (unlikely(p->des01.erx.error_summary)) {
158 CHIP_DBG(KERN_ERR "GMAC RX Error Summary 0x%08x\n",
159 p->des01.erx);
160 if (unlikely(p->des01.erx.descriptor_error)) {
161 CHIP_DBG(KERN_ERR "\tdescriptor error\n");
162 x->rx_desc++;
163 stats->rx_length_errors++;
164 }
165 if (unlikely(p->des01.erx.overflow_error)) {
166 CHIP_DBG(KERN_ERR "\toverflow error\n");
167 x->rx_gmac_overflow++;
168 }
169
170 if (unlikely(p->des01.erx.ipc_csum_error))
171 CHIP_DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
172
173 if (unlikely(p->des01.erx.late_collision)) {
174 CHIP_DBG(KERN_ERR "\tlate_collision error\n");
175 stats->collisions++;
176 stats->collisions++;
177 }
178 if (unlikely(p->des01.erx.receive_watchdog)) {
179 CHIP_DBG(KERN_ERR "\treceive_watchdog error\n");
180 x->rx_watchdog++;
181 }
182 if (unlikely(p->des01.erx.error_gmii)) {
183 CHIP_DBG(KERN_ERR "\tReceive Error\n");
184 x->rx_mii++;
185 }
186 if (unlikely(p->des01.erx.crc_error)) {
187 CHIP_DBG(KERN_ERR "\tCRC error\n");
188 x->rx_crc++;
189 stats->rx_crc_errors++;
190 }
191 ret = discard_frame;
192 }
193
194 /* After a payload csum error, the ES bit is set.
195 * It doesn't match with the information reported into the databook.
196 * At any rate, we need to understand if the CSUM hw computation is ok
197 * and report this info to the upper layers. */
198 ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
199 p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
200
201 if (unlikely(p->des01.erx.dribbling)) {
202 CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
203 ret = discard_frame;
204 }
205 if (unlikely(p->des01.erx.sa_filter_fail)) {
206 CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
207 x->sa_rx_filter_fail++;
208 ret = discard_frame;
209 }
210 if (unlikely(p->des01.erx.da_filter_fail)) {
211 CHIP_DBG(KERN_ERR "GMAC RX : Dest Address filter fail\n");
212 x->da_rx_filter_fail++;
213 ret = discard_frame;
214 }
215 if (unlikely(p->des01.erx.length_error)) {
216 CHIP_DBG(KERN_ERR "GMAC RX: length_error error\n");
217 x->rx_length++;
218 ret = discard_frame;
219 }
220#ifdef STMMAC_VLAN_TAG_USED
221 if (p->des01.erx.vlan_tag) {
222 CHIP_DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
223 x->rx_vlan++;
224 }
225#endif
226 return ret;
227}
228
229static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
230 int disable_rx_ic)
231{
232 int i;
233 for (i = 0; i < ring_size; i++) {
234 p->des01.erx.own = 1;
235 p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
236 /* To support jumbo frames */
237 p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
238 if (i == ring_size - 1)
239 p->des01.erx.end_ring = 1;
240 if (disable_rx_ic)
241 p->des01.erx.disable_ic = 1;
242 p++;
243 }
244 return;
245}
246
247static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
248{
249 int i;
250
251 for (i = 0; i < ring_size; i++) {
252 p->des01.etx.own = 0;
253 if (i == ring_size - 1)
254 p->des01.etx.end_ring = 1;
255 p++;
256 }
257
258 return;
259}
260
261static int enh_desc_get_tx_owner(struct dma_desc *p)
262{
263 return p->des01.etx.own;
264}
265
266static int enh_desc_get_rx_owner(struct dma_desc *p)
267{
268 return p->des01.erx.own;
269}
270
271static void enh_desc_set_tx_owner(struct dma_desc *p)
272{
273 p->des01.etx.own = 1;
274}
275
276static void enh_desc_set_rx_owner(struct dma_desc *p)
277{
278 p->des01.erx.own = 1;
279}
280
281static int enh_desc_get_tx_ls(struct dma_desc *p)
282{
283 return p->des01.etx.last_segment;
284}
285
286static void enh_desc_release_tx_desc(struct dma_desc *p)
287{
288 int ter = p->des01.etx.end_ring;
289
290 memset(p, 0, sizeof(struct dma_desc));
291 p->des01.etx.end_ring = ter;
292
293 return;
294}
295
296static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
297 int csum_flag)
298{
299 p->des01.etx.first_segment = is_fs;
300 if (unlikely(len > BUF_SIZE_4KiB)) {
301 p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
302 p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
303 } else {
304 p->des01.etx.buffer1_size = len;
305 }
306 if (likely(csum_flag))
307 p->des01.etx.checksum_insertion = cic_full;
308}
309
310static void enh_desc_clear_tx_ic(struct dma_desc *p)
311{
312 p->des01.etx.interrupt = 0;
313}
314
315static void enh_desc_close_tx_desc(struct dma_desc *p)
316{
317 p->des01.etx.last_segment = 1;
318 p->des01.etx.interrupt = 1;
319}
320
321static int enh_desc_get_rx_frame_len(struct dma_desc *p)
322{
323 return p->des01.erx.frame_length;
324}
325
326struct stmmac_desc_ops enh_desc_ops = {
327 .tx_status = enh_desc_get_tx_status,
328 .rx_status = enh_desc_get_rx_status,
329 .get_tx_len = enh_desc_get_tx_len,
330 .init_rx_desc = enh_desc_init_rx_desc,
331 .init_tx_desc = enh_desc_init_tx_desc,
332 .get_tx_owner = enh_desc_get_tx_owner,
333 .get_rx_owner = enh_desc_get_rx_owner,
334 .release_tx_desc = enh_desc_release_tx_desc,
335 .prepare_tx_desc = enh_desc_prepare_tx_desc,
336 .clear_tx_ic = enh_desc_clear_tx_ic,
337 .close_tx_desc = enh_desc_close_tx_desc,
338 .get_tx_ls = enh_desc_get_tx_ls,
339 .set_tx_owner = enh_desc_set_tx_owner,
340 .set_rx_owner = enh_desc_set_rx_owner,
341 .get_rx_frame_len = enh_desc_get_rx_frame_len,
342};