Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[sfrench/cifs-2.6.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         if (priv->phydev == NULL) {
151                 link_info = cvmx_helper_link_autoconf(priv->port);
152                 priv->link_info = link_info.u64;
153         }
154         spin_unlock_irqrestore(&global_register_lock, flags);
155
156         if (priv->phydev == NULL) {
157                 /* Tell core. */
158                 if (link_info.s.link_up) {
159                         if (!netif_carrier_ok(dev))
160                                 netif_carrier_on(dev);
161                         if (priv->queue != -1)
162                                 DEBUGPRINT("%s: %u Mbps %s duplex, "
163                                            "port %2d, queue %2d\n",
164                                            dev->name, link_info.s.speed,
165                                            (link_info.s.full_duplex) ?
166                                                 "Full" : "Half",
167                                            priv->port, priv->queue);
168                         else
169                                 DEBUGPRINT("%s: %u Mbps %s duplex, "
170                                            "port %2d, POW\n",
171                                            dev->name, link_info.s.speed,
172                                            (link_info.s.full_duplex) ?
173                                                 "Full" : "Half",
174                                            priv->port);
175                 } else {
176                         if (netif_carrier_ok(dev))
177                                 netif_carrier_off(dev);
178                         DEBUGPRINT("%s: Link down\n", dev->name);
179                 }
180         }
181 }
182
183 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
184 {
185         union cvmx_npi_rsl_int_blocks rsl_int_blocks;
186         int index;
187         irqreturn_t return_status = IRQ_NONE;
188
189         rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
190
191         /* Check and see if this interrupt was caused by the GMX0 block */
192         if (rsl_int_blocks.s.gmx0) {
193
194                 int interface = 0;
195                 /* Loop through every port of this interface */
196                 for (index = 0;
197                      index < cvmx_helper_ports_on_interface(interface);
198                      index++) {
199
200                         /* Read the GMX interrupt status bits */
201                         union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
202                         gmx_rx_int_reg.u64 =
203                             cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
204                                           (index, interface));
205                         gmx_rx_int_reg.u64 &=
206                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
207                                           (index, interface));
208                         /* Poll the port if inband status changed */
209                         if (gmx_rx_int_reg.s.phy_dupx
210                             || gmx_rx_int_reg.s.phy_link
211                             || gmx_rx_int_reg.s.phy_spd) {
212
213                                 struct net_device *dev =
214                                     cvm_oct_device[cvmx_helper_get_ipd_port
215                                                    (interface, index)];
216                                 if (dev)
217                                         cvm_oct_rgmii_poll(dev);
218                                 gmx_rx_int_reg.u64 = 0;
219                                 gmx_rx_int_reg.s.phy_dupx = 1;
220                                 gmx_rx_int_reg.s.phy_link = 1;
221                                 gmx_rx_int_reg.s.phy_spd = 1;
222                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
223                                                (index, interface),
224                                                gmx_rx_int_reg.u64);
225                                 return_status = IRQ_HANDLED;
226                         }
227                 }
228         }
229
230         /* Check and see if this interrupt was caused by the GMX1 block */
231         if (rsl_int_blocks.s.gmx1) {
232
233                 int interface = 1;
234                 /* Loop through every port of this interface */
235                 for (index = 0;
236                      index < cvmx_helper_ports_on_interface(interface);
237                      index++) {
238
239                         /* Read the GMX interrupt status bits */
240                         union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
241                         gmx_rx_int_reg.u64 =
242                             cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
243                                           (index, interface));
244                         gmx_rx_int_reg.u64 &=
245                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
246                                           (index, interface));
247                         /* Poll the port if inband status changed */
248                         if (gmx_rx_int_reg.s.phy_dupx
249                             || gmx_rx_int_reg.s.phy_link
250                             || gmx_rx_int_reg.s.phy_spd) {
251
252                                 struct net_device *dev =
253                                     cvm_oct_device[cvmx_helper_get_ipd_port
254                                                    (interface, index)];
255                                 if (dev)
256                                         cvm_oct_rgmii_poll(dev);
257                                 gmx_rx_int_reg.u64 = 0;
258                                 gmx_rx_int_reg.s.phy_dupx = 1;
259                                 gmx_rx_int_reg.s.phy_link = 1;
260                                 gmx_rx_int_reg.s.phy_spd = 1;
261                                 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
262                                                (index, interface),
263                                                gmx_rx_int_reg.u64);
264                                 return_status = IRQ_HANDLED;
265                         }
266                 }
267         }
268         return return_status;
269 }
270
271 int cvm_oct_rgmii_open(struct net_device *dev)
272 {
273         union cvmx_gmxx_prtx_cfg gmx_cfg;
274         struct octeon_ethernet *priv = netdev_priv(dev);
275         int interface = INTERFACE(priv->port);
276         int index = INDEX(priv->port);
277         cvmx_helper_link_info_t link_info;
278
279         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
280         gmx_cfg.s.en = 1;
281         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
282
283         if (!octeon_is_simulation()) {
284                 link_info = cvmx_helper_link_get(priv->port);
285                 if (!link_info.s.link_up)
286                         netif_carrier_off(dev);
287         }
288
289         return 0;
290 }
291
292 int cvm_oct_rgmii_stop(struct net_device *dev)
293 {
294         union cvmx_gmxx_prtx_cfg gmx_cfg;
295         struct octeon_ethernet *priv = netdev_priv(dev);
296         int interface = INTERFACE(priv->port);
297         int index = INDEX(priv->port);
298
299         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
300         gmx_cfg.s.en = 0;
301         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
302         return 0;
303 }
304
305 int cvm_oct_rgmii_init(struct net_device *dev)
306 {
307         struct octeon_ethernet *priv = netdev_priv(dev);
308         int r;
309
310         cvm_oct_common_init(dev);
311         dev->netdev_ops->ndo_stop(dev);
312
313         /*
314          * Due to GMX errata in CN3XXX series chips, it is necessary
315          * to take the link down immediately when the PHY changes
316          * state. In order to do this we call the poll function every
317          * time the RGMII inband status changes.  This may cause
318          * problems if the PHY doesn't implement inband status
319          * properly.
320          */
321         if (number_rgmii_ports == 0) {
322                 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
323                                 IRQF_SHARED, "RGMII", &number_rgmii_ports);
324                 if (r != 0)
325                         return r;
326         }
327         number_rgmii_ports++;
328
329         /*
330          * Only true RGMII ports need to be polled. In GMII mode, port
331          * 0 is really a RGMII port.
332          */
333         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
334              && (priv->port == 0))
335             || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
336
337                 if (!octeon_is_simulation()) {
338
339                         union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
340                         int interface = INTERFACE(priv->port);
341                         int index = INDEX(priv->port);
342
343                         /*
344                          * Enable interrupts on inband status changes
345                          * for this port.
346                          */
347                         gmx_rx_int_en.u64 =
348                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
349                                           (index, interface));
350                         gmx_rx_int_en.s.phy_dupx = 1;
351                         gmx_rx_int_en.s.phy_link = 1;
352                         gmx_rx_int_en.s.phy_spd = 1;
353                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
354                                        gmx_rx_int_en.u64);
355                         priv->poll = cvm_oct_rgmii_poll;
356                 }
357         }
358
359         return 0;
360 }
361
362 void cvm_oct_rgmii_uninit(struct net_device *dev)
363 {
364         struct octeon_ethernet *priv = netdev_priv(dev);
365         cvm_oct_common_uninit(dev);
366
367         /*
368          * Only true RGMII ports need to be polled. In GMII mode, port
369          * 0 is really a RGMII port.
370          */
371         if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
372              && (priv->port == 0))
373             || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
374
375                 if (!octeon_is_simulation()) {
376
377                         union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
378                         int interface = INTERFACE(priv->port);
379                         int index = INDEX(priv->port);
380
381                         /*
382                          * Disable interrupts on inband status changes
383                          * for this port.
384                          */
385                         gmx_rx_int_en.u64 =
386                             cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
387                                           (index, interface));
388                         gmx_rx_int_en.s.phy_dupx = 0;
389                         gmx_rx_int_en.s.phy_link = 0;
390                         gmx_rx_int_en.s.phy_spd = 0;
391                         cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
392                                        gmx_rx_int_en.u64);
393                 }
394         }
395
396         /* Remove the interrupt handler when the last port is removed. */
397         number_rgmii_ports--;
398         if (number_rgmii_ports == 0)
399                 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
400 }