Staging: Add octeon-ethernet driver files.
[linux-2.6-block.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>
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
45DEFINE_SPINLOCK(global_register_lock);
46
47static int number_rgmii_ports;
48
49static 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
180static 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
268static 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
289static 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
302int 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
359void 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}