Linux 2.6.33-rc6
[cris-mirror.git] / drivers / staging / octeon / ethernet-rgmii.c
blob3820f1ec11d16a98dd24357f4c32e5036178b1ac
1 /*********************************************************************
2 * Author: Cavium Networks
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
7 * Copyright (c) 2003-2007 Cavium Networks
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.
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.
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/.
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>
32 #include <asm/octeon/octeon.h>
34 #include "ethernet-defines.h"
35 #include "octeon-ethernet.h"
36 #include "ethernet-util.h"
38 #include "cvmx-helper.h"
40 #include <asm/octeon/cvmx-ipd-defs.h>
41 #include <asm/octeon/cvmx-npi-defs.h>
42 #include "cvmx-gmxx-defs.h"
44 DEFINE_SPINLOCK(global_register_lock);
46 static int number_rgmii_ports;
48 static void cvm_oct_rgmii_poll(struct net_device *dev)
50 struct octeon_ethernet *priv = netdev_priv(dev);
51 unsigned long flags;
52 cvmx_helper_link_info_t link_info;
55 * Take the global register lock since we are going to touch
56 * registers that affect more than one port.
58 spin_lock_irqsave(&global_register_lock, flags);
60 link_info = cvmx_helper_link_get(priv->port);
61 if (link_info.u64 == priv->link_info) {
64 * If the 10Mbps preamble workaround is supported and we're
65 * at 10Mbps we may need to do some special checking.
67 if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
70 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
71 * see if we are getting preamble errors.
73 int interface = INTERFACE(priv->port);
74 int index = INDEX(priv->port);
75 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
76 gmxx_rxx_int_reg.u64 =
77 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
78 (index, interface));
79 if (gmxx_rxx_int_reg.s.pcterr) {
82 * We are getting preamble errors at
83 * 10Mbps. Most likely the PHY is
84 * giving us packets with mis aligned
85 * preambles. In order to get these
86 * packets we need to disable preamble
87 * checking and do it in software.
89 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
90 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
92 /* Disable preamble checking */
93 gmxx_rxx_frm_ctl.u64 =
94 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
95 (index, interface));
96 gmxx_rxx_frm_ctl.s.pre_chk = 0;
97 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
98 (index, interface),
99 gmxx_rxx_frm_ctl.u64);
101 /* Disable FCS stripping */
102 ipd_sub_port_fcs.u64 =
103 cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
104 ipd_sub_port_fcs.s.port_bit &=
105 0xffffffffull ^ (1ull << priv->port);
106 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
107 ipd_sub_port_fcs.u64);
109 /* Clear any error bits */
110 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
111 (index, interface),
112 gmxx_rxx_int_reg.u64);
113 DEBUGPRINT("%s: Using 10Mbps with software "
114 "preamble removal\n",
115 dev->name);
118 spin_unlock_irqrestore(&global_register_lock, flags);
119 return;
122 /* If the 10Mbps preamble workaround is allowed we need to on
123 preamble checking, FCS stripping, and clear error bits on
124 every speed change. If errors occur during 10Mbps operation
125 the above code will change this stuff */
126 if (USE_10MBPS_PREAMBLE_WORKAROUND) {
128 union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
129 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
130 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
131 int interface = INTERFACE(priv->port);
132 int index = INDEX(priv->port);
134 /* Enable preamble checking */
135 gmxx_rxx_frm_ctl.u64 =
136 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
137 gmxx_rxx_frm_ctl.s.pre_chk = 1;
138 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
139 gmxx_rxx_frm_ctl.u64);
140 /* Enable FCS stripping */
141 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
142 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
143 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
144 /* Clear any error bits */
145 gmxx_rxx_int_reg.u64 =
146 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
147 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
148 gmxx_rxx_int_reg.u64);
150 if (priv->phydev == NULL) {
151 link_info = cvmx_helper_link_autoconf(priv->port);
152 priv->link_info = link_info.u64;
154 spin_unlock_irqrestore(&global_register_lock, flags);
156 if (priv->phydev == NULL) {
157 /* Tell core. */
158 if (link_info.s.link_up) {
159 if (!netif_carrier_ok(dev))
160 netif_carrier_on(dev);
161 if (priv->queue != -1)
162 DEBUGPRINT("%s: %u Mbps %s duplex, "
163 "port %2d, queue %2d\n",
164 dev->name, link_info.s.speed,
165 (link_info.s.full_duplex) ?
166 "Full" : "Half",
167 priv->port, priv->queue);
168 else
169 DEBUGPRINT("%s: %u Mbps %s duplex, "
170 "port %2d, POW\n",
171 dev->name, link_info.s.speed,
172 (link_info.s.full_duplex) ?
173 "Full" : "Half",
174 priv->port);
175 } else {
176 if (netif_carrier_ok(dev))
177 netif_carrier_off(dev);
178 DEBUGPRINT("%s: Link down\n", dev->name);
183 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
185 union cvmx_npi_rsl_int_blocks rsl_int_blocks;
186 int index;
187 irqreturn_t return_status = IRQ_NONE;
189 rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
191 /* Check and see if this interrupt was caused by the GMX0 block */
192 if (rsl_int_blocks.s.gmx0) {
194 int interface = 0;
195 /* Loop through every port of this interface */
196 for (index = 0;
197 index < cvmx_helper_ports_on_interface(interface);
198 index++) {
200 /* Read the GMX interrupt status bits */
201 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
202 gmx_rx_int_reg.u64 =
203 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
204 (index, interface));
205 gmx_rx_int_reg.u64 &=
206 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
207 (index, interface));
208 /* Poll the port if inband status changed */
209 if (gmx_rx_int_reg.s.phy_dupx
210 || gmx_rx_int_reg.s.phy_link
211 || gmx_rx_int_reg.s.phy_spd) {
213 struct net_device *dev =
214 cvm_oct_device[cvmx_helper_get_ipd_port
215 (interface, index)];
216 if (dev)
217 cvm_oct_rgmii_poll(dev);
218 gmx_rx_int_reg.u64 = 0;
219 gmx_rx_int_reg.s.phy_dupx = 1;
220 gmx_rx_int_reg.s.phy_link = 1;
221 gmx_rx_int_reg.s.phy_spd = 1;
222 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
223 (index, interface),
224 gmx_rx_int_reg.u64);
225 return_status = IRQ_HANDLED;
230 /* Check and see if this interrupt was caused by the GMX1 block */
231 if (rsl_int_blocks.s.gmx1) {
233 int interface = 1;
234 /* Loop through every port of this interface */
235 for (index = 0;
236 index < cvmx_helper_ports_on_interface(interface);
237 index++) {
239 /* Read the GMX interrupt status bits */
240 union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
241 gmx_rx_int_reg.u64 =
242 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
243 (index, interface));
244 gmx_rx_int_reg.u64 &=
245 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
246 (index, interface));
247 /* Poll the port if inband status changed */
248 if (gmx_rx_int_reg.s.phy_dupx
249 || gmx_rx_int_reg.s.phy_link
250 || gmx_rx_int_reg.s.phy_spd) {
252 struct net_device *dev =
253 cvm_oct_device[cvmx_helper_get_ipd_port
254 (interface, index)];
255 if (dev)
256 cvm_oct_rgmii_poll(dev);
257 gmx_rx_int_reg.u64 = 0;
258 gmx_rx_int_reg.s.phy_dupx = 1;
259 gmx_rx_int_reg.s.phy_link = 1;
260 gmx_rx_int_reg.s.phy_spd = 1;
261 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
262 (index, interface),
263 gmx_rx_int_reg.u64);
264 return_status = IRQ_HANDLED;
268 return return_status;
271 int cvm_oct_rgmii_open(struct net_device *dev)
273 union cvmx_gmxx_prtx_cfg gmx_cfg;
274 struct octeon_ethernet *priv = netdev_priv(dev);
275 int interface = INTERFACE(priv->port);
276 int index = INDEX(priv->port);
277 cvmx_helper_link_info_t link_info;
279 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
280 gmx_cfg.s.en = 1;
281 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
283 if (!octeon_is_simulation()) {
284 link_info = cvmx_helper_link_get(priv->port);
285 if (!link_info.s.link_up)
286 netif_carrier_off(dev);
289 return 0;
292 int cvm_oct_rgmii_stop(struct net_device *dev)
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);
299 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
300 gmx_cfg.s.en = 0;
301 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
302 return 0;
305 int cvm_oct_rgmii_init(struct net_device *dev)
307 struct octeon_ethernet *priv = netdev_priv(dev);
308 int r;
310 cvm_oct_common_init(dev);
311 dev->netdev_ops->ndo_stop(dev);
314 * Due to GMX errata in CN3XXX series chips, it is necessary
315 * to take the link down immediately when the PHY changes
316 * state. In order to do this we call the poll function every
317 * time the RGMII inband status changes. This may cause
318 * problems if the PHY doesn't implement inband status
319 * properly.
321 if (number_rgmii_ports == 0) {
322 r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
323 IRQF_SHARED, "RGMII", &number_rgmii_ports);
324 if (r != 0)
325 return r;
327 number_rgmii_ports++;
330 * Only true RGMII ports need to be polled. In GMII mode, port
331 * 0 is really a RGMII port.
333 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
334 && (priv->port == 0))
335 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
337 if (!octeon_is_simulation()) {
339 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
340 int interface = INTERFACE(priv->port);
341 int index = INDEX(priv->port);
344 * Enable interrupts on inband status changes
345 * for this port.
347 gmx_rx_int_en.u64 =
348 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
349 (index, interface));
350 gmx_rx_int_en.s.phy_dupx = 1;
351 gmx_rx_int_en.s.phy_link = 1;
352 gmx_rx_int_en.s.phy_spd = 1;
353 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
354 gmx_rx_int_en.u64);
355 priv->poll = cvm_oct_rgmii_poll;
359 return 0;
362 void cvm_oct_rgmii_uninit(struct net_device *dev)
364 struct octeon_ethernet *priv = netdev_priv(dev);
365 cvm_oct_common_uninit(dev);
368 * Only true RGMII ports need to be polled. In GMII mode, port
369 * 0 is really a RGMII port.
371 if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
372 && (priv->port == 0))
373 || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
375 if (!octeon_is_simulation()) {
377 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
378 int interface = INTERFACE(priv->port);
379 int index = INDEX(priv->port);
382 * Disable interrupts on inband status changes
383 * for this port.
385 gmx_rx_int_en.u64 =
386 cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
387 (index, interface));
388 gmx_rx_int_en.s.phy_dupx = 0;
389 gmx_rx_int_en.s.phy_link = 0;
390 gmx_rx_int_en.s.phy_spd = 0;
391 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
392 gmx_rx_int_en.u64);
396 /* Remove the interrupt handler when the last port is removed. */
397 number_rgmii_ports--;
398 if (number_rgmii_ports == 0)
399 free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);