staging: octeon-ethernet: eliminate USE_10MBPS_PREAMBLE_WORKAROUND define
[deliverable/linux.git] / drivers / staging / octeon / ethernet-rgmii.c
CommitLineData
80ff0fd3
DD
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>
048316be 29#include <linux/interrupt.h>
f8c26486 30#include <linux/phy.h>
7a2eaf93 31#include <linux/ratelimit.h>
80ff0fd3
DD
32#include <net/dst.h>
33
34#include <asm/octeon/octeon.h>
35
36#include "ethernet-defines.h"
37#include "octeon-ethernet.h"
80ff0fd3 38#include "ethernet-util.h"
ec3a2207 39#include "ethernet-mdio.h"
80ff0fd3 40
af866496 41#include <asm/octeon/cvmx-helper.h>
80ff0fd3
DD
42
43#include <asm/octeon/cvmx-ipd-defs.h>
44#include <asm/octeon/cvmx-npi-defs.h>
af866496 45#include <asm/octeon/cvmx-gmxx-defs.h>
80ff0fd3 46
54bf917e 47static DEFINE_SPINLOCK(global_register_lock);
80ff0fd3
DD
48
49static int number_rgmii_ports;
50
01d3007a
AK
51static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
52{
53 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
54 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
55 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
56 int interface = INTERFACE(priv->port);
57 int index = INDEX(priv->port);
58
59 /* Set preamble checking. */
60 gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
61 interface));
62 gmxx_rxx_frm_ctl.s.pre_chk = enable;
63 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
64 gmxx_rxx_frm_ctl.u64);
65
66 /* Set FCS stripping. */
67 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
68 if (enable)
69 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
70 else
71 ipd_sub_port_fcs.s.port_bit &=
72 0xffffffffull ^ (1ull << priv->port);
73 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
74
75 /* Clear any error bits. */
76 gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
77 interface));
78 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
79 gmxx_rxx_int_reg.u64);
80}
81
80ff0fd3
DD
82static void cvm_oct_rgmii_poll(struct net_device *dev)
83{
84 struct octeon_ethernet *priv = netdev_priv(dev);
f8c26486 85 unsigned long flags = 0;
80ff0fd3 86 cvmx_helper_link_info_t link_info;
f8c26486 87 int use_global_register_lock = (priv->phydev == NULL);
80ff0fd3 88
f8c26486
DD
89 BUG_ON(in_interrupt());
90 if (use_global_register_lock) {
91 /*
92 * Take the global register lock since we are going to
93 * touch registers that affect more than one port.
94 */
95 spin_lock_irqsave(&global_register_lock, flags);
96 } else {
97 mutex_lock(&priv->phydev->bus->mdio_lock);
98 }
80ff0fd3
DD
99
100 link_info = cvmx_helper_link_get(priv->port);
101 if (link_info.u64 == priv->link_info) {
25efe08e 102 if (link_info.s.speed == 10) {
80ff0fd3
DD
103 /*
104 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
105 * see if we are getting preamble errors.
106 */
107 int interface = INTERFACE(priv->port);
108 int index = INDEX(priv->port);
109 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
5a2da4ab 110
80ff0fd3
DD
111 gmxx_rxx_int_reg.u64 =
112 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
113 (index, interface));
114 if (gmxx_rxx_int_reg.s.pcterr) {
80ff0fd3
DD
115 /*
116 * We are getting preamble errors at
117 * 10Mbps. Most likely the PHY is
118 * giving us packets with mis aligned
119 * preambles. In order to get these
120 * packets we need to disable preamble
121 * checking and do it in software.
122 */
01d3007a 123 cvm_oct_set_hw_preamble(priv, false);
42e0e19d 124 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
7a2eaf93 125 dev->name);
80ff0fd3
DD
126 }
127 }
f8c26486
DD
128
129 if (use_global_register_lock)
130 spin_unlock_irqrestore(&global_register_lock, flags);
131 else
132 mutex_unlock(&priv->phydev->bus->mdio_lock);
80ff0fd3
DD
133 return;
134 }
135
25efe08e 136 /* Since the 10Mbps preamble workaround is allowed we need to enable
80ff0fd3
DD
137 preamble checking, FCS stripping, and clear error bits on
138 every speed change. If errors occur during 10Mbps operation
139 the above code will change this stuff */
25efe08e 140 cvm_oct_set_hw_preamble(priv, true);
01d3007a 141
f6ed1b3b
DD
142 if (priv->phydev == NULL) {
143 link_info = cvmx_helper_link_autoconf(priv->port);
144 priv->link_info = link_info.u64;
145 }
f8c26486
DD
146
147 if (use_global_register_lock)
148 spin_unlock_irqrestore(&global_register_lock, flags);
4504b1bc 149 else
f8c26486 150 mutex_unlock(&priv->phydev->bus->mdio_lock);
80ff0fd3 151
f6ed1b3b
DD
152 if (priv->phydev == NULL) {
153 /* Tell core. */
154 if (link_info.s.link_up) {
155 if (!netif_carrier_ok(dev))
156 netif_carrier_on(dev);
2638f713
AK
157 } else if (netif_carrier_ok(dev)) {
158 netif_carrier_off(dev);
f6ed1b3b 159 }
2638f713 160 cvm_oct_note_carrier(priv, link_info);
80ff0fd3
DD
161 }
162}
163
67d2ee25 164static int cmv_oct_rgmii_gmx_interrupt(int interface)
80ff0fd3 165{
80ff0fd3 166 int index;
67d2ee25 167 int count = 0;
80ff0fd3 168
67d2ee25
AK
169 /* Loop through every port of this interface */
170 for (index = 0;
171 index < cvmx_helper_ports_on_interface(interface);
172 index++) {
173 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
80ff0fd3 174
67d2ee25
AK
175 /* Read the GMX interrupt status bits */
176 gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
80ff0fd3 177 (index, interface));
67d2ee25 178 gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
80ff0fd3 179 (index, interface));
80ff0fd3 180
67d2ee25
AK
181 /* Poll the port if inband status changed */
182 if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link ||
183 gmx_rx_int_reg.s.phy_spd) {
184 struct net_device *dev =
80ff0fd3
DD
185 cvm_oct_device[cvmx_helper_get_ipd_port
186 (interface, index)];
67d2ee25
AK
187 struct octeon_ethernet *priv = netdev_priv(dev);
188
189 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
190 queue_work(cvm_oct_poll_queue,
191 &priv->port_work);
192
193 gmx_rx_int_reg.u64 = 0;
194 gmx_rx_int_reg.s.phy_dupx = 1;
195 gmx_rx_int_reg.s.phy_link = 1;
196 gmx_rx_int_reg.s.phy_spd = 1;
197 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
198 gmx_rx_int_reg.u64);
199 count++;
80ff0fd3
DD
200 }
201 }
67d2ee25
AK
202 return count;
203}
80ff0fd3 204
67d2ee25
AK
205static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
206{
207 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
208 int count = 0;
5a2da4ab 209
67d2ee25 210 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
80ff0fd3 211
67d2ee25
AK
212 /* Check and see if this interrupt was caused by the GMX0 block */
213 if (rsl_int_blocks.s.gmx0)
214 count += cmv_oct_rgmii_gmx_interrupt(0);
f8c26486 215
67d2ee25
AK
216 /* Check and see if this interrupt was caused by the GMX1 block */
217 if (rsl_int_blocks.s.gmx1)
218 count += cmv_oct_rgmii_gmx_interrupt(1);
f8c26486 219
67d2ee25 220 return count ? IRQ_HANDLED : IRQ_NONE;
80ff0fd3
DD
221}
222
f696a108 223int cvm_oct_rgmii_open(struct net_device *dev)
80ff0fd3 224{
9e3ae4f9 225 return cvm_oct_common_open(dev, cvm_oct_rgmii_poll, false);
80ff0fd3
DD
226}
227
f8c26486
DD
228static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
229{
f09d1444
AO
230 struct octeon_ethernet *priv =
231 container_of(work, struct octeon_ethernet, port_work);
f8c26486
DD
232 cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
233}
234
80ff0fd3
DD
235int cvm_oct_rgmii_init(struct net_device *dev)
236{
237 struct octeon_ethernet *priv = netdev_priv(dev);
238 int r;
239
240 cvm_oct_common_init(dev);
f8c26486 241 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
80ff0fd3
DD
242 /*
243 * Due to GMX errata in CN3XXX series chips, it is necessary
82c7c11f 244 * to take the link down immediately when the PHY changes
80ff0fd3
DD
245 * state. In order to do this we call the poll function every
246 * time the RGMII inband status changes. This may cause
247 * problems if the PHY doesn't implement inband status
248 * properly.
249 */
250 if (number_rgmii_ports == 0) {
251 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
252 IRQF_SHARED, "RGMII", &number_rgmii_ports);
82c7c11f
RK
253 if (r != 0)
254 return r;
80ff0fd3
DD
255 }
256 number_rgmii_ports++;
257
258 /*
259 * Only true RGMII ports need to be polled. In GMII mode, port
260 * 0 is really a RGMII port.
261 */
262 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
263 && (priv->port == 0))
264 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
265
266 if (!octeon_is_simulation()) {
267
268 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
269 int interface = INTERFACE(priv->port);
270 int index = INDEX(priv->port);
271
272 /*
273 * Enable interrupts on inband status changes
274 * for this port.
275 */
7cc4fa1e 276 gmx_rx_int_en.u64 = 0;
80ff0fd3
DD
277 gmx_rx_int_en.s.phy_dupx = 1;
278 gmx_rx_int_en.s.phy_link = 1;
279 gmx_rx_int_en.s.phy_spd = 1;
280 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
281 gmx_rx_int_en.u64);
80ff0fd3
DD
282 }
283 }
284
285 return 0;
286}
287
288void cvm_oct_rgmii_uninit(struct net_device *dev)
289{
290 struct octeon_ethernet *priv = netdev_priv(dev);
5a2da4ab 291
80ff0fd3
DD
292 cvm_oct_common_uninit(dev);
293
294 /*
295 * Only true RGMII ports need to be polled. In GMII mode, port
296 * 0 is really a RGMII port.
297 */
298 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
299 && (priv->port == 0))
300 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
301
302 if (!octeon_is_simulation()) {
303
304 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
305 int interface = INTERFACE(priv->port);
306 int index = INDEX(priv->port);
307
308 /*
309 * Disable interrupts on inband status changes
310 * for this port.
311 */
312 gmx_rx_int_en.u64 =
313 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
314 (index, interface));
315 gmx_rx_int_en.s.phy_dupx = 0;
316 gmx_rx_int_en.s.phy_link = 0;
317 gmx_rx_int_en.s.phy_spd = 0;
318 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
319 gmx_rx_int_en.u64);
320 }
321 }
322
323 /* Remove the interrupt handler when the last port is removed. */
324 number_rgmii_ports--;
325 if (number_rgmii_ports == 0)
326 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
f8c26486 327 cancel_work_sync(&priv->port_work);
80ff0fd3 328}
This page took 0.569718 seconds and 5 git commands to generate.