aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/stmmac/dwmac1000_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/stmmac/dwmac1000_dma.c')
-rw-r--r--drivers/net/stmmac/dwmac1000_dma.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/drivers/net/stmmac/dwmac1000_dma.c b/drivers/net/stmmac/dwmac1000_dma.c
new file mode 100644
index 000000000000..68245508e2de
--- /dev/null
+++ b/drivers/net/stmmac/dwmac1000_dma.c
@@ -0,0 +1,474 @@
1/*******************************************************************************
2 This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
3 DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
4 developing this code.
5
6 This contains the functions to handle the dma and descriptors.
7
8 Copyright (C) 2007-2009 STMicroelectronics Ltd
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms and conditions of the GNU General Public License,
12 version 2, as published by the Free Software Foundation.
13
14 This program is distributed in the hope it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
18
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
22
23 The full GNU General Public License is included in this distribution in
24 the file called "COPYING".
25
26 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
27*******************************************************************************/
28
29#include "dwmac1000.h"
30#include "dwmac_dma.h"
31
32static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
33 u32 dma_rx)
34{
35 u32 value = readl(ioaddr + DMA_BUS_MODE);
36 /* DMA SW reset */
37 value |= DMA_BUS_MODE_SFT_RESET;
38 writel(value, ioaddr + DMA_BUS_MODE);
39 do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
40
41 value = /* DMA_BUS_MODE_FB | */ DMA_BUS_MODE_4PBL |
42 ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
43 (pbl << DMA_BUS_MODE_RPBL_SHIFT));
44
45#ifdef CONFIG_STMMAC_DA
46 value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
47#endif
48 writel(value, ioaddr + DMA_BUS_MODE);
49
50 /* Mask interrupts by writing to CSR7 */
51 writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
52
53 /* The base address of the RX/TX descriptor lists must be written into
54 * DMA CSR3 and CSR4, respectively. */
55 writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
56 writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
57
58 return 0;
59}
60
61/* Transmit FIFO flush operation */
62static void dwmac1000_flush_tx_fifo(unsigned long ioaddr)
63{
64 u32 csr6 = readl(ioaddr + DMA_CONTROL);
65 writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
66
67 do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
68}
69
70static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
71 int rxmode)
72{
73 u32 csr6 = readl(ioaddr + DMA_CONTROL);
74
75 if (txmode == SF_DMA_MODE) {
76 DBG(KERN_DEBUG "GMAC: enabling TX store and forward mode\n");
77 /* Transmit COE type 2 cannot be done in cut-through mode. */
78 csr6 |= DMA_CONTROL_TSF;
79 /* Operating on second frame increase the performance
80 * especially when transmit store-and-forward is used.*/
81 csr6 |= DMA_CONTROL_OSF;
82 } else {
83 DBG(KERN_DEBUG "GMAC: disabling TX store and forward mode"
84 " (threshold = %d)\n", txmode);
85 csr6 &= ~DMA_CONTROL_TSF;
86 csr6 &= DMA_CONTROL_TC_TX_MASK;
87 /* Set the transmit threshold */
88 if (txmode <= 32)
89 csr6 |= DMA_CONTROL_TTC_32;
90 else if (txmode <= 64)
91 csr6 |= DMA_CONTROL_TTC_64;
92 else if (txmode <= 128)
93 csr6 |= DMA_CONTROL_TTC_128;
94 else if (txmode <= 192)
95 csr6 |= DMA_CONTROL_TTC_192;
96 else
97 csr6 |= DMA_CONTROL_TTC_256;
98 }
99
100 if (rxmode == SF_DMA_MODE) {
101 DBG(KERN_DEBUG "GMAC: enabling RX store and forward mode\n");
102 csr6 |= DMA_CONTROL_RSF;
103 } else {
104 DBG(KERN_DEBUG "GMAC: disabling RX store and forward mode"
105 " (threshold = %d)\n", rxmode);
106 csr6 &= ~DMA_CONTROL_RSF;
107 csr6 &= DMA_CONTROL_TC_RX_MASK;
108 if (rxmode <= 32)
109 csr6 |= DMA_CONTROL_RTC_32;
110 else if (rxmode <= 64)
111 csr6 |= DMA_CONTROL_RTC_64;
112 else if (rxmode <= 96)
113 csr6 |= DMA_CONTROL_RTC_96;
114 else
115 csr6 |= DMA_CONTROL_RTC_128;
116 }
117
118 writel(csr6, ioaddr + DMA_CONTROL);
119 return;
120}
121
122/* Not yet implemented --- no RMON module */
123static void dwmac1000_dma_diagnostic_fr(void *data,
124 struct stmmac_extra_stats *x, unsigned long ioaddr)
125{
126 return;
127}
128
129static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
130{
131 int i;
132 pr_info(" DMA registers\n");
133 for (i = 0; i < 22; i++) {
134 if ((i < 9) || (i > 17)) {
135 int offset = i * 4;
136 pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i,
137 (DMA_BUS_MODE + offset),
138 readl(ioaddr + DMA_BUS_MODE + offset));
139 }
140 }
141 return;
142}
143
144static int dwmac1000_get_tx_frame_status(void *data,
145 struct stmmac_extra_stats *x,
146 struct dma_desc *p, unsigned long ioaddr)
147{
148 int ret = 0;
149 struct net_device_stats *stats = (struct net_device_stats *)data;
150
151 if (unlikely(p->des01.etx.error_summary)) {
152 DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
153 if (unlikely(p->des01.etx.jabber_timeout)) {
154 DBG(KERN_ERR "\tjabber_timeout error\n");
155 x->tx_jabber++;
156 }
157
158 if (unlikely(p->des01.etx.frame_flushed)) {
159 DBG(KERN_ERR "\tframe_flushed error\n");
160 x->tx_frame_flushed++;
161 dwmac1000_flush_tx_fifo(ioaddr);
162 }
163
164 if (unlikely(p->des01.etx.loss_carrier)) {
165 DBG(KERN_ERR "\tloss_carrier error\n");
166 x->tx_losscarrier++;
167 stats->tx_carrier_errors++;
168 }
169 if (unlikely(p->des01.etx.no_carrier)) {
170 DBG(KERN_ERR "\tno_carrier error\n");
171 x->tx_carrier++;
172 stats->tx_carrier_errors++;
173 }
174 if (unlikely(p->des01.etx.late_collision)) {
175 DBG(KERN_ERR "\tlate_collision error\n");
176 stats->collisions += p->des01.etx.collision_count;
177 }
178 if (unlikely(p->des01.etx.excessive_collisions)) {
179 DBG(KERN_ERR "\texcessive_collisions\n");
180 stats->collisions += p->des01.etx.collision_count;
181 }
182 if (unlikely(p->des01.etx.excessive_deferral)) {
183 DBG(KERN_INFO "\texcessive tx_deferral\n");
184 x->tx_deferred++;
185 }
186
187 if (unlikely(p->des01.etx.underflow_error)) {
188 DBG(KERN_ERR "\tunderflow error\n");
189 dwmac1000_flush_tx_fifo(ioaddr);
190 x->tx_underflow++;
191 }
192
193 if (unlikely(p->des01.etx.ip_header_error)) {
194 DBG(KERN_ERR "\tTX IP header csum error\n");
195 x->tx_ip_header_error++;
196 }
197
198 if (unlikely(p->des01.etx.payload_error)) {
199 DBG(KERN_ERR "\tAddr/Payload csum error\n");
200 x->tx_payload_error++;
201 dwmac1000_flush_tx_fifo(ioaddr);
202 }
203
204 ret = -1;
205 }
206
207 if (unlikely(p->des01.etx.deferred)) {
208 DBG(KERN_INFO "GMAC TX status: tx deferred\n");
209 x->tx_deferred++;
210 }
211#ifdef STMMAC_VLAN_TAG_USED
212 if (p->des01.etx.vlan_frame) {
213 DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
214 x->tx_vlan++;
215 }
216#endif
217
218 return ret;
219}
220
221static int dwmac1000_get_tx_len(struct dma_desc *p)
222{
223 return p->des01.etx.buffer1_size;
224}
225
226static int dwmac1000_coe_rdes0(int ipc_err, int type, int payload_err)
227{
228 int ret = good_frame;
229 u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
230
231 /* bits 5 7 0 | Frame status
232 * ----------------------------------------------------------
233 * 0 0 0 | IEEE 802.3 Type frame (lenght < 1536 octects)
234 * 1 0 0 | IPv4/6 No CSUM errorS.
235 * 1 0 1 | IPv4/6 CSUM PAYLOAD error
236 * 1 1 0 | IPv4/6 CSUM IP HR error
237 * 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
238 * 0 0 1 | IPv4/6 unsupported IP PAYLOAD
239 * 0 1 1 | COE bypassed.. no IPv4/6 frame
240 * 0 1 0 | Reserved.
241 */
242 if (status == 0x0) {
243 DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
244 ret = good_frame;
245 } else if (status == 0x4) {
246 DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
247 ret = good_frame;
248 } else if (status == 0x5) {
249 DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
250 ret = csum_none;
251 } else if (status == 0x6) {
252 DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
253 ret = csum_none;
254 } else if (status == 0x7) {
255 DBG(KERN_ERR
256 "RX Des0 status: IPv4/6 Header and Payload Error.\n");
257 ret = csum_none;
258 } else if (status == 0x1) {
259 DBG(KERN_ERR
260 "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
261 ret = discard_frame;
262 } else if (status == 0x3) {
263 DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
264 ret = discard_frame;
265 }
266 return ret;
267}
268
269static int dwmac1000_get_rx_frame_status(void *data,
270 struct stmmac_extra_stats *x, struct dma_desc *p)
271{
272 int ret = good_frame;
273 struct net_device_stats *stats = (struct net_device_stats *)data;
274
275 if (unlikely(p->des01.erx.error_summary)) {
276 DBG(KERN_ERR "GMAC RX Error Summary... 0x%08x\n", p->des01.erx);
277 if (unlikely(p->des01.erx.descriptor_error)) {
278 DBG(KERN_ERR "\tdescriptor error\n");
279 x->rx_desc++;
280 stats->rx_length_errors++;
281 }
282 if (unlikely(p->des01.erx.overflow_error)) {
283 DBG(KERN_ERR "\toverflow error\n");
284 x->rx_gmac_overflow++;
285 }
286
287 if (unlikely(p->des01.erx.ipc_csum_error))
288 DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
289
290 if (unlikely(p->des01.erx.late_collision)) {
291 DBG(KERN_ERR "\tlate_collision error\n");
292 stats->collisions++;
293 stats->collisions++;
294 }
295 if (unlikely(p->des01.erx.receive_watchdog)) {
296 DBG(KERN_ERR "\treceive_watchdog error\n");
297 x->rx_watchdog++;
298 }
299 if (unlikely(p->des01.erx.error_gmii)) {
300 DBG(KERN_ERR "\tReceive Error\n");
301 x->rx_mii++;
302 }
303 if (unlikely(p->des01.erx.crc_error)) {
304 DBG(KERN_ERR "\tCRC error\n");
305 x->rx_crc++;
306 stats->rx_crc_errors++;
307 }
308 ret = discard_frame;
309 }
310
311 /* After a payload csum error, the ES bit is set.
312 * It doesn't match with the information reported into the databook.
313 * At any rate, we need to understand if the CSUM hw computation is ok
314 * and report this info to the upper layers. */
315 ret = dwmac1000_coe_rdes0(p->des01.erx.ipc_csum_error,
316 p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
317
318 if (unlikely(p->des01.erx.dribbling)) {
319 DBG(KERN_ERR "GMAC RX: dribbling error\n");
320 ret = discard_frame;
321 }
322 if (unlikely(p->des01.erx.sa_filter_fail)) {
323 DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
324 x->sa_rx_filter_fail++;
325 ret = discard_frame;
326 }
327 if (unlikely(p->des01.erx.da_filter_fail)) {
328 DBG(KERN_ERR "GMAC RX : Destination Address filter fail\n");
329 x->da_rx_filter_fail++;
330 ret = discard_frame;
331 }
332 if (unlikely(p->des01.erx.length_error)) {
333 DBG(KERN_ERR "GMAC RX: length_error error\n");
334 x->rx_lenght++;
335 ret = discard_frame;
336 }
337#ifdef STMMAC_VLAN_TAG_USED
338 if (p->des01.erx.vlan_tag) {
339 DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
340 x->rx_vlan++;
341 }
342#endif
343 return ret;
344}
345
346static void dwmac1000_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
347 int disable_rx_ic)
348{
349 int i;
350 for (i = 0; i < ring_size; i++) {
351 p->des01.erx.own = 1;
352 p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
353 /* To support jumbo frames */
354 p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
355 if (i == ring_size - 1)
356 p->des01.erx.end_ring = 1;
357 if (disable_rx_ic)
358 p->des01.erx.disable_ic = 1;
359 p++;
360 }
361 return;
362}
363
364static void dwmac1000_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
365{
366 int i;
367
368 for (i = 0; i < ring_size; i++) {
369 p->des01.etx.own = 0;
370 if (i == ring_size - 1)
371 p->des01.etx.end_ring = 1;
372 p++;
373 }
374
375 return;
376}
377
378static int dwmac1000_get_tx_owner(struct dma_desc *p)
379{
380 return p->des01.etx.own;
381}
382
383static int dwmac1000_get_rx_owner(struct dma_desc *p)
384{
385 return p->des01.erx.own;
386}
387
388static void dwmac1000_set_tx_owner(struct dma_desc *p)
389{
390 p->des01.etx.own = 1;
391}
392
393static void dwmac1000_set_rx_owner(struct dma_desc *p)
394{
395 p->des01.erx.own = 1;
396}
397
398static int dwmac1000_get_tx_ls(struct dma_desc *p)
399{
400 return p->des01.etx.last_segment;
401}
402
403static void dwmac1000_release_tx_desc(struct dma_desc *p)
404{
405 int ter = p->des01.etx.end_ring;
406
407 memset(p, 0, sizeof(struct dma_desc));
408 p->des01.etx.end_ring = ter;
409
410 return;
411}
412
413static void dwmac1000_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
414 int csum_flag)
415{
416 p->des01.etx.first_segment = is_fs;
417 if (unlikely(len > BUF_SIZE_4KiB)) {
418 p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
419 p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
420 } else {
421 p->des01.etx.buffer1_size = len;
422 }
423 if (likely(csum_flag))
424 p->des01.etx.checksum_insertion = cic_full;
425}
426
427static void dwmac1000_clear_tx_ic(struct dma_desc *p)
428{
429 p->des01.etx.interrupt = 0;
430}
431
432static void dwmac1000_close_tx_desc(struct dma_desc *p)
433{
434 p->des01.etx.last_segment = 1;
435 p->des01.etx.interrupt = 1;
436}
437
438static int dwmac1000_get_rx_frame_len(struct dma_desc *p)
439{
440 return p->des01.erx.frame_length;
441}
442
443struct stmmac_dma_ops dwmac1000_dma_ops = {
444 .init = dwmac1000_dma_init,
445 .dump_regs = dwmac1000_dump_dma_regs,
446 .dma_mode = dwmac1000_dma_operation_mode,
447 .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr,
448 .enable_dma_transmission = dwmac_enable_dma_transmission,
449 .enable_dma_irq = dwmac_enable_dma_irq,
450 .disable_dma_irq = dwmac_disable_dma_irq,
451 .start_tx = dwmac_dma_start_tx,
452 .stop_tx = dwmac_dma_stop_tx,
453 .start_rx = dwmac_dma_start_rx,
454 .stop_rx = dwmac_dma_stop_rx,
455 .dma_interrupt = dwmac_dma_interrupt,
456};
457
458struct stmmac_desc_ops dwmac1000_desc_ops = {
459 .tx_status = dwmac1000_get_tx_frame_status,
460 .rx_status = dwmac1000_get_rx_frame_status,
461 .get_tx_len = dwmac1000_get_tx_len,
462 .init_rx_desc = dwmac1000_init_rx_desc,
463 .init_tx_desc = dwmac1000_init_tx_desc,
464 .get_tx_owner = dwmac1000_get_tx_owner,
465 .get_rx_owner = dwmac1000_get_rx_owner,
466 .release_tx_desc = dwmac1000_release_tx_desc,
467 .prepare_tx_desc = dwmac1000_prepare_tx_desc,
468 .clear_tx_ic = dwmac1000_clear_tx_ic,
469 .close_tx_desc = dwmac1000_close_tx_desc,
470 .get_tx_ls = dwmac1000_get_tx_ls,
471 .set_tx_owner = dwmac1000_set_tx_owner,
472 .set_rx_owner = dwmac1000_set_rx_owner,
473 .get_rx_frame_len = dwmac1000_get_rx_frame_len,
474};