Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / net / ethernet / stmicro / stmmac / dwmac_lib.c
1 /*******************************************************************************
2   Copyright (C) 2007-2009  STMicroelectronics Ltd
3
4   This program is free software; you can redistribute it and/or modify it
5   under the terms and conditions of the GNU General Public License,
6   version 2, as published by the Free Software Foundation.
7
8   This program is distributed in the hope it will be useful, but WITHOUT
9   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11   more details.
12
13   The full GNU General Public License is included in this distribution in
14   the file called "COPYING".
15
16   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
17 *******************************************************************************/
18
19 #include <linux/io.h>
20 #include <linux/iopoll.h>
21 #include "common.h"
22 #include "dwmac_dma.h"
23
24 #define GMAC_HI_REG_AE          0x80000000
25
26 int dwmac_dma_reset(void __iomem *ioaddr)
27 {
28         u32 value = readl(ioaddr + DMA_BUS_MODE);
29         int err;
30
31         /* DMA SW reset */
32         value |= DMA_BUS_MODE_SFT_RESET;
33         writel(value, ioaddr + DMA_BUS_MODE);
34
35         err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
36                                  !(value & DMA_BUS_MODE_SFT_RESET),
37                                  10000, 100000);
38         if (err)
39                 return -EBUSY;
40
41         return 0;
42 }
43
44 /* CSR1 enables the transmit DMA to check for new descriptor */
45 void dwmac_enable_dma_transmission(void __iomem *ioaddr)
46 {
47         writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
48 }
49
50 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
51 {
52         writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
53 }
54
55 void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
56 {
57         writel(0, ioaddr + DMA_INTR_ENA);
58 }
59
60 void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
61 {
62         u32 value = readl(ioaddr + DMA_CONTROL);
63         value |= DMA_CONTROL_ST;
64         writel(value, ioaddr + DMA_CONTROL);
65 }
66
67 void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
68 {
69         u32 value = readl(ioaddr + DMA_CONTROL);
70         value &= ~DMA_CONTROL_ST;
71         writel(value, ioaddr + DMA_CONTROL);
72 }
73
74 void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
75 {
76         u32 value = readl(ioaddr + DMA_CONTROL);
77         value |= DMA_CONTROL_SR;
78         writel(value, ioaddr + DMA_CONTROL);
79 }
80
81 void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
82 {
83         u32 value = readl(ioaddr + DMA_CONTROL);
84         value &= ~DMA_CONTROL_SR;
85         writel(value, ioaddr + DMA_CONTROL);
86 }
87
88 #ifdef DWMAC_DMA_DEBUG
89 static void show_tx_process_state(unsigned int status)
90 {
91         unsigned int state;
92         state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
93
94         switch (state) {
95         case 0:
96                 pr_debug("- TX (Stopped): Reset or Stop command\n");
97                 break;
98         case 1:
99                 pr_debug("- TX (Running): Fetching the Tx desc\n");
100                 break;
101         case 2:
102                 pr_debug("- TX (Running): Waiting for end of tx\n");
103                 break;
104         case 3:
105                 pr_debug("- TX (Running): Reading the data "
106                        "and queuing the data into the Tx buf\n");
107                 break;
108         case 6:
109                 pr_debug("- TX (Suspended): Tx Buff Underflow "
110                        "or an unavailable Transmit descriptor\n");
111                 break;
112         case 7:
113                 pr_debug("- TX (Running): Closing Tx descriptor\n");
114                 break;
115         default:
116                 break;
117         }
118 }
119
120 static void show_rx_process_state(unsigned int status)
121 {
122         unsigned int state;
123         state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
124
125         switch (state) {
126         case 0:
127                 pr_debug("- RX (Stopped): Reset or Stop command\n");
128                 break;
129         case 1:
130                 pr_debug("- RX (Running): Fetching the Rx desc\n");
131                 break;
132         case 2:
133                 pr_debug("- RX (Running): Checking for end of pkt\n");
134                 break;
135         case 3:
136                 pr_debug("- RX (Running): Waiting for Rx pkt\n");
137                 break;
138         case 4:
139                 pr_debug("- RX (Suspended): Unavailable Rx buf\n");
140                 break;
141         case 5:
142                 pr_debug("- RX (Running): Closing Rx descriptor\n");
143                 break;
144         case 6:
145                 pr_debug("- RX(Running): Flushing the current frame"
146                        " from the Rx buf\n");
147                 break;
148         case 7:
149                 pr_debug("- RX (Running): Queuing the Rx frame"
150                        " from the Rx buf into memory\n");
151                 break;
152         default:
153                 break;
154         }
155 }
156 #endif
157
158 int dwmac_dma_interrupt(void __iomem *ioaddr,
159                         struct stmmac_extra_stats *x, u32 chan)
160 {
161         int ret = 0;
162         /* read the status register (CSR5) */
163         u32 intr_status = readl(ioaddr + DMA_STATUS);
164
165 #ifdef DWMAC_DMA_DEBUG
166         /* Enable it to monitor DMA rx/tx status in case of critical problems */
167         pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);
168         show_tx_process_state(intr_status);
169         show_rx_process_state(intr_status);
170 #endif
171         /* ABNORMAL interrupts */
172         if (unlikely(intr_status & DMA_STATUS_AIS)) {
173                 if (unlikely(intr_status & DMA_STATUS_UNF)) {
174                         ret = tx_hard_error_bump_tc;
175                         x->tx_undeflow_irq++;
176                 }
177                 if (unlikely(intr_status & DMA_STATUS_TJT))
178                         x->tx_jabber_irq++;
179
180                 if (unlikely(intr_status & DMA_STATUS_OVF))
181                         x->rx_overflow_irq++;
182
183                 if (unlikely(intr_status & DMA_STATUS_RU))
184                         x->rx_buf_unav_irq++;
185                 if (unlikely(intr_status & DMA_STATUS_RPS))
186                         x->rx_process_stopped_irq++;
187                 if (unlikely(intr_status & DMA_STATUS_RWT))
188                         x->rx_watchdog_irq++;
189                 if (unlikely(intr_status & DMA_STATUS_ETI))
190                         x->tx_early_irq++;
191                 if (unlikely(intr_status & DMA_STATUS_TPS)) {
192                         x->tx_process_stopped_irq++;
193                         ret = tx_hard_error;
194                 }
195                 if (unlikely(intr_status & DMA_STATUS_FBI)) {
196                         x->fatal_bus_error_irq++;
197                         ret = tx_hard_error;
198                 }
199         }
200         /* TX/RX NORMAL interrupts */
201         if (likely(intr_status & DMA_STATUS_NIS)) {
202                 x->normal_irq_n++;
203                 if (likely(intr_status & DMA_STATUS_RI)) {
204                         u32 value = readl(ioaddr + DMA_INTR_ENA);
205                         /* to schedule NAPI on real RIE event. */
206                         if (likely(value & DMA_INTR_ENA_RIE)) {
207                                 x->rx_normal_irq_n++;
208                                 ret |= handle_rx;
209                         }
210                 }
211                 if (likely(intr_status & DMA_STATUS_TI)) {
212                         x->tx_normal_irq_n++;
213                         ret |= handle_tx;
214                 }
215                 if (unlikely(intr_status & DMA_STATUS_ERI))
216                         x->rx_early_irq++;
217         }
218         /* Optional hardware blocks, interrupts should be disabled */
219         if (unlikely(intr_status &
220                      (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
221                 pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
222
223         /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
224         writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
225
226         return ret;
227 }
228
229 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
230 {
231         u32 csr6 = readl(ioaddr + DMA_CONTROL);
232         writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
233
234         do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
235 }
236
237 void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
238                          unsigned int high, unsigned int low)
239 {
240         unsigned long data;
241
242         data = (addr[5] << 8) | addr[4];
243         /* For MAC Addr registers we have to set the Address Enable (AE)
244          * bit that has no effect on the High Reg 0 where the bit 31 (MO)
245          * is RO.
246          */
247         writel(data | GMAC_HI_REG_AE, ioaddr + high);
248         data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
249         writel(data, ioaddr + low);
250 }
251 EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);
252
253 /* Enable disable MAC RX/TX */
254 void stmmac_set_mac(void __iomem *ioaddr, bool enable)
255 {
256         u32 value = readl(ioaddr + MAC_CTRL_REG);
257
258         if (enable)
259                 value |= MAC_ENABLE_RX | MAC_ENABLE_TX;
260         else
261                 value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);
262
263         writel(value, ioaddr + MAC_CTRL_REG);
264 }
265
266 void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
267                          unsigned int high, unsigned int low)
268 {
269         unsigned int hi_addr, lo_addr;
270
271         /* Read the MAC address from the hardware */
272         hi_addr = readl(ioaddr + high);
273         lo_addr = readl(ioaddr + low);
274
275         /* Extract the MAC address from the high and low words */
276         addr[0] = lo_addr & 0xff;
277         addr[1] = (lo_addr >> 8) & 0xff;
278         addr[2] = (lo_addr >> 16) & 0xff;
279         addr[3] = (lo_addr >> 24) & 0xff;
280         addr[4] = hi_addr & 0xff;
281         addr[5] = (hi_addr >> 8) & 0xff;
282 }
283 EXPORT_SYMBOL_GPL(stmmac_get_mac_addr);