ba2ad2aaca3ebc8f4bc35bfe38a51ecce7cfd770
[deliverable/linux.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/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 #include "ethernet-mdio.h"
40
41 #include <asm/octeon/cvmx-helper.h>
42
43 #include <asm/octeon/cvmx-ipd-defs.h>
44 #include <asm/octeon/cvmx-npi-defs.h>
45 #include <asm/octeon/cvmx-gmxx-defs.h>
46
47 static DEFINE_SPINLOCK(global_register_lock);
48
49 static int number_rgmii_ports;
50
51 static 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
82 static void cvm_oct_rgmii_poll(struct net_device *dev)
83 {
84 struct octeon_ethernet *priv = netdev_priv(dev);
85 unsigned long flags = 0;
86 cvmx_helper_link_info_t link_info;
87 int use_global_register_lock = (priv->phydev == NULL);
88
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 }
99
100 link_info = cvmx_helper_link_get(priv->port);
101 if (link_info.u64 == priv->link_info) {
102
103 /*
104 * If the 10Mbps preamble workaround is supported and we're
105 * at 10Mbps we may need to do some special checking.
106 */
107 if (USE_10MBPS_PREAMBLE_WORKAROUND &&
108 (link_info.s.speed == 10)) {
109
110 /*
111 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
112 * see if we are getting preamble errors.
113 */
114 int interface = INTERFACE(priv->port);
115 int index = INDEX(priv->port);
116 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
117
118 gmxx_rxx_int_reg.u64 =
119 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
120 (index, interface));
121 if (gmxx_rxx_int_reg.s.pcterr) {
122 /*
123 * We are getting preamble errors at
124 * 10Mbps. Most likely the PHY is
125 * giving us packets with mis aligned
126 * preambles. In order to get these
127 * packets we need to disable preamble
128 * checking and do it in software.
129 */
130 cvm_oct_set_hw_preamble(priv, false);
131 printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
132 dev->name);
133 }
134 }
135
136 if (use_global_register_lock)
137 spin_unlock_irqrestore(&global_register_lock, flags);
138 else
139 mutex_unlock(&priv->phydev->bus->mdio_lock);
140 return;
141 }
142
143 /* If the 10Mbps preamble workaround is allowed we need to on
144 preamble checking, FCS stripping, and clear error bits on
145 every speed change. If errors occur during 10Mbps operation
146 the above code will change this stuff */
147 if (USE_10MBPS_PREAMBLE_WORKAROUND)
148 cvm_oct_set_hw_preamble(priv, true);
149
150 if (priv->phydev == NULL) {
151 link_info = cvmx_helper_link_autoconf(priv->port);
152 priv->link_info = link_info.u64;
153 }
154
155 if (use_global_register_lock)
156 spin_unlock_irqrestore(&global_register_lock, flags);
157 else
158 mutex_unlock(&priv->phydev->bus->mdio_lock);
159
160 if (priv->phydev == NULL) {
161 /* Tell core. */
162 if (link_info.s.link_up) {
163 if (!netif_carrier_ok(dev))
164 netif_carrier_on(dev);
165 } else if (netif_carrier_ok(dev)) {
166 netif_carrier_off(dev);
167 }
168 cvm_oct_note_carrier(priv, link_info);
169 }
170 }
171
172 static int cmv_oct_rgmii_gmx_interrupt(int interface)
173 {
174 int index;
175 int count = 0;
176
177 /* Loop through every port of this interface */
178 for (index = 0;
179 index < cvmx_helper_ports_on_interface(interface);
180 index++) {
181 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
182
183 /* Read the GMX interrupt status bits */
184 gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
185 (index, interface));
186 gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
187 (index, interface));
188
189 /* Poll the port if inband status changed */
190 if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link ||
191 gmx_rx_int_reg.s.phy_spd) {
192 struct net_device *dev =
193 cvm_oct_device[cvmx_helper_get_ipd_port
194 (interface, index)];
195 struct octeon_ethernet *priv = netdev_priv(dev);
196
197 if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
198 queue_work(cvm_oct_poll_queue,
199 &priv->port_work);
200
201 gmx_rx_int_reg.u64 = 0;
202 gmx_rx_int_reg.s.phy_dupx = 1;
203 gmx_rx_int_reg.s.phy_link = 1;
204 gmx_rx_int_reg.s.phy_spd = 1;
205 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
206 gmx_rx_int_reg.u64);
207 count++;
208 }
209 }
210 return count;
211 }
212
213 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
214 {
215 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
216 int count = 0;
217
218 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
219
220 /* Check and see if this interrupt was caused by the GMX0 block */
221 if (rsl_int_blocks.s.gmx0)
222 count += cmv_oct_rgmii_gmx_interrupt(0);
223
224 /* Check and see if this interrupt was caused by the GMX1 block */
225 if (rsl_int_blocks.s.gmx1)
226 count += cmv_oct_rgmii_gmx_interrupt(1);
227
228 return count ? IRQ_HANDLED : IRQ_NONE;
229 }
230
231 int cvm_oct_rgmii_open(struct net_device *dev)
232 {
233 return cvm_oct_common_open(dev, cvm_oct_rgmii_poll, false);
234 }
235
236 static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
237 {
238 struct octeon_ethernet *priv =
239 container_of(work, struct octeon_ethernet, port_work);
240 cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
241 }
242
243 int cvm_oct_rgmii_init(struct net_device *dev)
244 {
245 struct octeon_ethernet *priv = netdev_priv(dev);
246 int r;
247
248 cvm_oct_common_init(dev);
249 INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
250 /*
251 * Due to GMX errata in CN3XXX series chips, it is necessary
252 * to take the link down immediately when the PHY changes
253 * state. In order to do this we call the poll function every
254 * time the RGMII inband status changes. This may cause
255 * problems if the PHY doesn't implement inband status
256 * properly.
257 */
258 if (number_rgmii_ports == 0) {
259 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
260 IRQF_SHARED, "RGMII", &number_rgmii_ports);
261 if (r != 0)
262 return r;
263 }
264 number_rgmii_ports++;
265
266 /*
267 * Only true RGMII ports need to be polled. In GMII mode, port
268 * 0 is really a RGMII port.
269 */
270 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
271 && (priv->port == 0))
272 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
273
274 if (!octeon_is_simulation()) {
275
276 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
277 int interface = INTERFACE(priv->port);
278 int index = INDEX(priv->port);
279
280 /*
281 * Enable interrupts on inband status changes
282 * for this port.
283 */
284 gmx_rx_int_en.u64 = 0;
285 gmx_rx_int_en.s.phy_dupx = 1;
286 gmx_rx_int_en.s.phy_link = 1;
287 gmx_rx_int_en.s.phy_spd = 1;
288 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
289 gmx_rx_int_en.u64);
290 }
291 }
292
293 return 0;
294 }
295
296 void cvm_oct_rgmii_uninit(struct net_device *dev)
297 {
298 struct octeon_ethernet *priv = netdev_priv(dev);
299
300 cvm_oct_common_uninit(dev);
301
302 /*
303 * Only true RGMII ports need to be polled. In GMII mode, port
304 * 0 is really a RGMII port.
305 */
306 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
307 && (priv->port == 0))
308 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
309
310 if (!octeon_is_simulation()) {
311
312 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
313 int interface = INTERFACE(priv->port);
314 int index = INDEX(priv->port);
315
316 /*
317 * Disable interrupts on inband status changes
318 * for this port.
319 */
320 gmx_rx_int_en.u64 =
321 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
322 (index, interface));
323 gmx_rx_int_en.s.phy_dupx = 0;
324 gmx_rx_int_en.s.phy_link = 0;
325 gmx_rx_int_en.s.phy_spd = 0;
326 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
327 gmx_rx_int_en.u64);
328 }
329 }
330
331 /* Remove the interrupt handler when the last port is removed. */
332 number_rgmii_ports--;
333 if (number_rgmii_ports == 0)
334 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
335 cancel_work_sync(&priv->port_work);
336 }
This page took 0.053316 seconds and 4 git commands to generate.