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