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