Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / staging / octeon / ethernet-rgmii.c
1 /*********************************************************************
2  * Author: Cavium Networks
3  *
4  * Contact: support@caviumnetworks.com
5  * This file is part of the OCTEON SDK
6  *
7  * Copyright (c) 2003-2007 Cavium Networks
8  *
9  * This file is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License, Version 2, as
11  * published by the Free Software Foundation.
12  *
13  * This file is distributed in the hope that it will be useful, but
14  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16  * NONINFRINGEMENT.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this file; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  * or visit http://www.gnu.org/licenses/.
23  *
24  * This file may also be available under a different license from Cavium.
25  * Contact Cavium Networks for more information
26 **********************************************************************/
27 #include <linux/kernel.h>
28 #include <linux/netdevice.h>
29 #include <linux/mii.h>
30 #include <net/dst.h>
31
32 #include <asm/octeon/octeon.h>
33
34 #include "ethernet-defines.h"
35 #include "octeon-ethernet.h"
36 #include "ethernet-util.h"
37
38 #include "cvmx-helper.h"
39
40 #include <asm/octeon/cvmx-ipd-defs.h>
41 #include <asm/octeon/cvmx-npi-defs.h>
42 #include "cvmx-gmxx-defs.h"
43
44 DEFINE_SPINLOCK(global_register_lock);
45
46 static int number_rgmii_ports;
47
48 static void cvm_oct_rgmii_poll(struct net_device *dev)
49 {
50         struct octeon_ethernet *priv = netdev_priv(dev);
51         unsigned long flags;
52         cvmx_helper_link_info_t link_info;
53
54         /*
55          * Take the global register lock since we are going to touch
56          * registers that affect more than one port.
57          */
58         spin_lock_irqsave(&global_register_lock, flags);
59
60         link_info = cvmx_helper_link_get(priv->port);
61         if (link_info.u64 == priv->link_info) {
62
63                 /*
64                  * If the 10Mbps preamble workaround is supported and we're
65                  * at 10Mbps we may need to do some special checking.
66                  */
67                 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
68
69                         /*
70                          * Read the GMXX_RXX_INT_REG[PCTERR] bit and
71                          * see if we are getting preamble errors.
72                          */
73                         int interface = INTERFACE(priv->port);
74                         int index = INDEX(priv->port);
75                         union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
76                         gmxx_rxx_int_reg.u64 =
77                             cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
78                                           (index, interface));
79                         if (gmxx_rxx_int_reg.s.pcterr) {
80
81                                 /*
82                                  * We are getting preamble errors at
83                                  * 10Mbps.  Most likely the PHY is
84                                  * giving us packets with mis aligned
85                                  * preambles. In order to get these
86                                  * packets we need to disable preamble
87                                  * checking and do it in software.
88                                  */
89                                 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
90                                 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
91
92                                 /* Disable preamble checking */
93                                 gmxx_rxx_frm_ctl.u64 =
94                                     cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
95                                                   (index, interface));
96                                 gmxx_rxx_frm_ctl.s.pre_chk = 0;
97                                 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
98                                                (index, interface),
99                                                gmxx_rxx_frm_ctl.u64);
100
101                                 /* Disable FCS stripping */
102                                 ipd_sub_port_fcs.u64 =
103                                     cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
104                                 ipd_sub_port_fcs.s.port_bit &=
105                                     0xffffffffull ^ (1ull << priv->port);
106                                 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
107                                                ipd_sub_port_fcs.u64);
108
109                                 /* Clear any error bits */
110                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
111                                                (index, interface),
112                                                gmxx_rxx_int_reg.u64);
113                                 DEBUGPRINT("%s: Using 10Mbps with software "
114                                            "preamble removal\n",
115                                      dev->name);
116                         }
117                 }
118                 spin_unlock_irqrestore(&global_register_lock, flags);
119                 return;
120         }
121
122         /* If the 10Mbps preamble workaround is allowed we need to on
123            preamble checking, FCS stripping, and clear error bits on
124            every speed change. If errors occur during 10Mbps operation
125            the above code will change this stuff */
126         if (USE_10MBPS_PREAMBLE_WORKAROUND) {
127
128                 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
129                 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
130                 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
131                 int interface = INTERFACE(priv->port);
132                 int index = INDEX(priv->port);
133
134                 /* Enable preamble checking */
135                 gmxx_rxx_frm_ctl.u64 =
136                     cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
137                 gmxx_rxx_frm_ctl.s.pre_chk = 1;
138                 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
139                                gmxx_rxx_frm_ctl.u64);
140                 /* Enable FCS stripping */
141                 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
142                 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
143                 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
144                 /* Clear any error bits */
145                 gmxx_rxx_int_reg.u64 =
146                     cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
147                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
148                                gmxx_rxx_int_reg.u64);
149         }
150
151         link_info = cvmx_helper_link_autoconf(priv->port);
152         priv->link_info = link_info.u64;
153         spin_unlock_irqrestore(&global_register_lock, flags);
154
155         /* Tell Linux */
156         if (link_info.s.link_up) {
157
158                 if (!netif_carrier_ok(dev))
159                         netif_carrier_on(dev);
160                 if (priv->queue != -1)
161                         DEBUGPRINT
162                             ("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
163                              dev->name, link_info.s.speed,
164                              (link_info.s.full_duplex) ? "Full" : "Half",
165                              priv->port, priv->queue);
166                 else
167                         DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n",
168                                    dev->name, link_info.s.speed,
169                                    (link_info.s.full_duplex) ? "Full" : "Half",
170                                    priv->port);
171         } else {
172
173                 if (netif_carrier_ok(dev))
174                         netif_carrier_off(dev);
175                 DEBUGPRINT("%s: Link down\n", dev->name);
176         }
177 }
178
179 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
180 {
181         union cvmx_npi_rsl_int_blocks rsl_int_blocks;
182         int index;
183         irqreturn_t return_status = IRQ_NONE;
184
185         rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
186
187         /* Check and see if this interrupt was caused by the GMX0 block */
188         if (rsl_int_blocks.s.gmx0) {
189
190                 int interface = 0;
191                 /* Loop through every port of this interface */
192                 for (index = 0;
193                      index < cvmx_helper_ports_on_interface(interface);
194                      index++) {
195
196                         /* Read the GMX interrupt status bits */
197                         union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
198                         gmx_rx_int_reg.u64 =
199                             cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
200                                           (index, interface));
201                         gmx_rx_int_reg.u64 &=
202                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
203                                           (index, interface));
204                         /* Poll the port if inband status changed */
205                         if (gmx_rx_int_reg.s.phy_dupx
206                             || gmx_rx_int_reg.s.phy_link
207                             || gmx_rx_int_reg.s.phy_spd) {
208
209                                 struct net_device *dev =
210                                     cvm_oct_device[cvmx_helper_get_ipd_port
211                                                    (interface, index)];
212                                 if (dev)
213                                         cvm_oct_rgmii_poll(dev);
214                                 gmx_rx_int_reg.u64 = 0;
215                                 gmx_rx_int_reg.s.phy_dupx = 1;
216                                 gmx_rx_int_reg.s.phy_link = 1;
217                                 gmx_rx_int_reg.s.phy_spd = 1;
218                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
219                                                (index, interface),
220                                                gmx_rx_int_reg.u64);
221                                 return_status = IRQ_HANDLED;
222                         }
223                 }
224         }
225
226         /* Check and see if this interrupt was caused by the GMX1 block */
227         if (rsl_int_blocks.s.gmx1) {
228
229                 int interface = 1;
230                 /* Loop through every port of this interface */
231                 for (index = 0;
232                      index < cvmx_helper_ports_on_interface(interface);
233                      index++) {
234
235                         /* Read the GMX interrupt status bits */
236                         union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
237                         gmx_rx_int_reg.u64 =
238                             cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
239                                           (index, interface));
240                         gmx_rx_int_reg.u64 &=
241                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
242                                           (index, interface));
243                         /* Poll the port if inband status changed */
244                         if (gmx_rx_int_reg.s.phy_dupx
245                             || gmx_rx_int_reg.s.phy_link
246                             || gmx_rx_int_reg.s.phy_spd) {
247
248                                 struct net_device *dev =
249                                     cvm_oct_device[cvmx_helper_get_ipd_port
250                                                    (interface, index)];
251                                 if (dev)
252                                         cvm_oct_rgmii_poll(dev);
253                                 gmx_rx_int_reg.u64 = 0;
254                                 gmx_rx_int_reg.s.phy_dupx = 1;
255                                 gmx_rx_int_reg.s.phy_link = 1;
256                                 gmx_rx_int_reg.s.phy_spd = 1;
257                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
258                                                (index, interface),
259                                                gmx_rx_int_reg.u64);
260                                 return_status = IRQ_HANDLED;
261                         }
262                 }
263         }
264         return return_status;
265 }
266
267 int cvm_oct_rgmii_open(struct net_device *dev)
268 {
269         union cvmx_gmxx_prtx_cfg gmx_cfg;
270         struct octeon_ethernet *priv = netdev_priv(dev);
271         int interface = INTERFACE(priv->port);
272         int index = INDEX(priv->port);
273         cvmx_helper_link_info_t link_info;
274
275         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
276         gmx_cfg.s.en = 1;
277         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
278
279         if (!octeon_is_simulation()) {
280                 link_info = cvmx_helper_link_get(priv->port);
281                 if (!link_info.s.link_up)
282                         netif_carrier_off(dev);
283         }
284
285         return 0;
286 }
287
288 int cvm_oct_rgmii_stop(struct net_device *dev)
289 {
290         union cvmx_gmxx_prtx_cfg gmx_cfg;
291         struct octeon_ethernet *priv = netdev_priv(dev);
292         int interface = INTERFACE(priv->port);
293         int index = INDEX(priv->port);
294
295         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
296         gmx_cfg.s.en = 0;
297         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
298         return 0;
299 }
300
301 int cvm_oct_rgmii_init(struct net_device *dev)
302 {
303         struct octeon_ethernet *priv = netdev_priv(dev);
304         int r;
305
306         cvm_oct_common_init(dev);
307         dev->netdev_ops->ndo_stop(dev);
308
309         /*
310          * Due to GMX errata in CN3XXX series chips, it is necessary
311          * to take the link down immediately whne the PHY changes
312          * state. In order to do this we call the poll function every
313          * time the RGMII inband status changes.  This may cause
314          * problems if the PHY doesn't implement inband status
315          * properly.
316          */
317         if (number_rgmii_ports == 0) {
318                 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
319                                 IRQF_SHARED, "RGMII", &number_rgmii_ports);
320         }
321         number_rgmii_ports++;
322
323         /*
324          * Only true RGMII ports need to be polled. In GMII mode, port
325          * 0 is really a RGMII port.
326          */
327         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
328              && (priv->port == 0))
329             || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
330
331                 if (!octeon_is_simulation()) {
332
333                         union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
334                         int interface = INTERFACE(priv->port);
335                         int index = INDEX(priv->port);
336
337                         /*
338                          * Enable interrupts on inband status changes
339                          * for this port.
340                          */
341                         gmx_rx_int_en.u64 =
342                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
343                                           (index, interface));
344                         gmx_rx_int_en.s.phy_dupx = 1;
345                         gmx_rx_int_en.s.phy_link = 1;
346                         gmx_rx_int_en.s.phy_spd = 1;
347                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
348                                        gmx_rx_int_en.u64);
349                         priv->poll = cvm_oct_rgmii_poll;
350                 }
351         }
352
353         return 0;
354 }
355
356 void cvm_oct_rgmii_uninit(struct net_device *dev)
357 {
358         struct octeon_ethernet *priv = netdev_priv(dev);
359         cvm_oct_common_uninit(dev);
360
361         /*
362          * Only true RGMII ports need to be polled. In GMII mode, port
363          * 0 is really a RGMII port.
364          */
365         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
366              && (priv->port == 0))
367             || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
368
369                 if (!octeon_is_simulation()) {
370
371                         union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
372                         int interface = INTERFACE(priv->port);
373                         int index = INDEX(priv->port);
374
375                         /*
376                          * Disable interrupts on inband status changes
377                          * for this port.
378                          */
379                         gmx_rx_int_en.u64 =
380                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
381                                           (index, interface));
382                         gmx_rx_int_en.s.phy_dupx = 0;
383                         gmx_rx_int_en.s.phy_link = 0;
384                         gmx_rx_int_en.s.phy_spd = 0;
385                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
386                                        gmx_rx_int_en.u64);
387                 }
388         }
389
390         /* Remove the interrupt handler when the last port is removed. */
391         number_rgmii_ports--;
392         if (number_rgmii_ports == 0)
393                 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
394 }