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