Blame view

drivers/net/stmmac/dwmac_lib.c 7.07 KB
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
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
  /*******************************************************************************
    Copyright (C) 2007-2009  STMicroelectronics Ltd
  
    This program is free software; you can redistribute it and/or modify it
    under the terms and conditions of the GNU General Public License,
    version 2, as published by the Free Software Foundation.
  
    This program is distributed in the hope it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    more details.
  
    You should have received a copy of the GNU General Public License along with
    this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  
    The full GNU General Public License is included in this distribution in
    the file called "COPYING".
  
    Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
  *******************************************************************************/
  
  #include <linux/io.h>
  #include "common.h"
  #include "dwmac_dma.h"
  
  #undef DWMAC_DMA_DEBUG
  #ifdef DWMAC_DMA_DEBUG
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
29
  #define DWMAC_LIB_DBG(fmt, args...)  printk(fmt, ## args)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
30
  #else
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
31
  #define DWMAC_LIB_DBG(fmt, args...)  do { } while (0)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
32
33
34
  #endif
  
  /* CSR1 enables the transmit DMA to check for new descriptor */
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
35
  void dwmac_enable_dma_transmission(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
36
37
38
  {
  	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
39
  void dwmac_enable_dma_irq(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
40
41
42
  {
  	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
43
  void dwmac_disable_dma_irq(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
44
45
46
  {
  	writel(0, ioaddr + DMA_INTR_ENA);
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
47
  void dwmac_dma_start_tx(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
48
49
50
51
  {
  	u32 value = readl(ioaddr + DMA_CONTROL);
  	value |= DMA_CONTROL_ST;
  	writel(value, ioaddr + DMA_CONTROL);
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
52
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
53
  void dwmac_dma_stop_tx(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
54
55
56
57
  {
  	u32 value = readl(ioaddr + DMA_CONTROL);
  	value &= ~DMA_CONTROL_ST;
  	writel(value, ioaddr + DMA_CONTROL);
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
58
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
59
  void dwmac_dma_start_rx(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
60
61
62
63
  {
  	u32 value = readl(ioaddr + DMA_CONTROL);
  	value |= DMA_CONTROL_SR;
  	writel(value, ioaddr + DMA_CONTROL);
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
64
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
65
  void dwmac_dma_stop_rx(void __iomem *ioaddr)
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
66
67
68
69
  {
  	u32 value = readl(ioaddr + DMA_CONTROL);
  	value &= ~DMA_CONTROL_SR;
  	writel(value, ioaddr + DMA_CONTROL);
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
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
  }
  
  #ifdef DWMAC_DMA_DEBUG
  static void show_tx_process_state(unsigned int status)
  {
  	unsigned int state;
  	state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
  
  	switch (state) {
  	case 0:
  		pr_info("- TX (Stopped): Reset or Stop command
  ");
  		break;
  	case 1:
  		pr_info("- TX (Running):Fetching the Tx desc
  ");
  		break;
  	case 2:
  		pr_info("- TX (Running): Waiting for end of tx
  ");
  		break;
  	case 3:
  		pr_info("- TX (Running): Reading the data "
  		       "and queuing the data into the Tx buf
  ");
  		break;
  	case 6:
  		pr_info("- TX (Suspended): Tx Buff Underflow "
  		       "or an unavailable Transmit descriptor
  ");
  		break;
  	case 7:
  		pr_info("- TX (Running): Closing Tx descriptor
  ");
  		break;
  	default:
  		break;
  	}
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
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
  }
  
  static void show_rx_process_state(unsigned int status)
  {
  	unsigned int state;
  	state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
  
  	switch (state) {
  	case 0:
  		pr_info("- RX (Stopped): Reset or Stop command
  ");
  		break;
  	case 1:
  		pr_info("- RX (Running): Fetching the Rx desc
  ");
  		break;
  	case 2:
  		pr_info("- RX (Running):Checking for end of pkt
  ");
  		break;
  	case 3:
  		pr_info("- RX (Running): Waiting for Rx pkt
  ");
  		break;
  	case 4:
  		pr_info("- RX (Suspended): Unavailable Rx buf
  ");
  		break;
  	case 5:
  		pr_info("- RX (Running): Closing Rx descriptor
  ");
  		break;
  	case 6:
  		pr_info("- RX(Running): Flushing the current frame"
  		       " from the Rx buf
  ");
  		break;
  	case 7:
  		pr_info("- RX (Running): Queuing the Rx frame"
  		       " from the Rx buf into memory
  ");
  		break;
  	default:
  		break;
  	}
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
153
154
  }
  #endif
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
155
  int dwmac_dma_interrupt(void __iomem *ioaddr,
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
156
157
158
159
160
  			struct stmmac_extra_stats *x)
  {
  	int ret = 0;
  	/* read the status register (CSR5) */
  	u32 intr_status = readl(ioaddr + DMA_STATUS);
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
161
162
  	DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]
  ", __func__, intr_status);
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
163
164
165
166
167
168
169
  #ifdef DWMAC_DMA_DEBUG
  	/* It displays the DMA process states (CSR5 register) */
  	show_tx_process_state(intr_status);
  	show_rx_process_state(intr_status);
  #endif
  	/* ABNORMAL interrupts */
  	if (unlikely(intr_status & DMA_STATUS_AIS)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
170
  		DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
171
  		if (unlikely(intr_status & DMA_STATUS_UNF)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
172
173
  			DWMAC_LIB_DBG(KERN_INFO "transmit underflow
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
174
175
176
177
  			ret = tx_hard_error_bump_tc;
  			x->tx_undeflow_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_TJT)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
178
179
  			DWMAC_LIB_DBG(KERN_INFO "transmit jabber
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
180
181
182
  			x->tx_jabber_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_OVF)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
183
184
  			DWMAC_LIB_DBG(KERN_INFO "recv overflow
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
185
186
187
  			x->rx_overflow_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_RU)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
188
189
  			DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
190
191
192
  			x->rx_buf_unav_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_RPS)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
193
194
  			DWMAC_LIB_DBG(KERN_INFO "receive process stopped
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
195
196
197
  			x->rx_process_stopped_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_RWT)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
198
199
  			DWMAC_LIB_DBG(KERN_INFO "receive watchdog
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
200
201
202
  			x->rx_watchdog_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_ETI)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
203
204
  			DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
205
206
207
  			x->tx_early_irq++;
  		}
  		if (unlikely(intr_status & DMA_STATUS_TPS)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
208
209
  			DWMAC_LIB_DBG(KERN_INFO "transmit process stopped
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
210
211
212
213
  			x->tx_process_stopped_irq++;
  			ret = tx_hard_error;
  		}
  		if (unlikely(intr_status & DMA_STATUS_FBI)) {
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
214
215
  			DWMAC_LIB_DBG(KERN_INFO "fatal bus error
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  			x->fatal_bus_error_irq++;
  			ret = tx_hard_error;
  		}
  	}
  	/* TX/RX NORMAL interrupts */
  	if (intr_status & DMA_STATUS_NIS) {
  		x->normal_irq_n++;
  		if (likely((intr_status & DMA_STATUS_RI) ||
  			 (intr_status & (DMA_STATUS_TI))))
  				ret = handle_tx_rx;
  	}
  	/* Optional hardware blocks, interrupts should be disabled */
  	if (unlikely(intr_status &
  		     (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
  		pr_info("%s: unexpected status %08x
  ", __func__, intr_status);
  	/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
  	writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
bded18c2d   Giuseppe CAVALLARO   stmmac: fixed dma...
234
235
236
  	DWMAC_LIB_DBG(KERN_INFO "
  
  ");
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
237
238
  	return ret;
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
239
  void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
688911c2f   Giuseppe CAVALLARO   stmmac: fix Trans...
240
241
242
243
244
245
  {
  	u32 csr6 = readl(ioaddr + DMA_CONTROL);
  	writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
  
  	do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
  }
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
246

ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
247
  void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
248
249
250
251
252
253
254
255
  			 unsigned int high, unsigned int low)
  {
  	unsigned long data;
  
  	data = (addr[5] << 8) | addr[4];
  	writel(data, ioaddr + high);
  	data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
  	writel(data, ioaddr + low);
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
256
  }
ad01b7d48   Giuseppe CAVALLARO   stmmac: make ioad...
257
  void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  			 unsigned int high, unsigned int low)
  {
  	unsigned int hi_addr, lo_addr;
  
  	/* Read the MAC address from the hardware */
  	hi_addr = readl(ioaddr + high);
  	lo_addr = readl(ioaddr + low);
  
  	/* Extract the MAC address from the high and low words */
  	addr[0] = lo_addr & 0xff;
  	addr[1] = (lo_addr >> 8) & 0xff;
  	addr[2] = (lo_addr >> 16) & 0xff;
  	addr[3] = (lo_addr >> 24) & 0xff;
  	addr[4] = hi_addr & 0xff;
  	addr[5] = (hi_addr >> 8) & 0xff;
aec7ff278   Giuseppe CAVALLARO   stmmac: move the ...
273
  }