~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/staging/octeon/ethernet-rgmii.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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