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 <net/dst.h>
30 
31 #include <asm/octeon/octeon.h>
32 
33 #include "ethernet-defines.h"
34 #include "octeon-ethernet.h"
35 #include "ethernet-util.h"
36 
37 #include "cvmx-helper.h"
38 
39 #include <asm/octeon/cvmx-ipd-defs.h>
40 #include <asm/octeon/cvmx-npi-defs.h>
41 #include "cvmx-gmxx-defs.h"
42 
43 DEFINE_SPINLOCK(global_register_lock);
44 
45 static int number_rgmii_ports;
46 
47 static void cvm_oct_rgmii_poll(struct net_device *dev)
48 {
49 	struct octeon_ethernet *priv = netdev_priv(dev);
50 	unsigned long flags;
51 	cvmx_helper_link_info_t link_info;
52 
53 	/*
54 	 * Take the global register lock since we are going to touch
55 	 * registers that affect more than one port.
56 	 */
57 	spin_lock_irqsave(&global_register_lock, flags);
58 
59 	link_info = cvmx_helper_link_get(priv->port);
60 	if (link_info.u64 == priv->link_info) {
61 
62 		/*
63 		 * If the 10Mbps preamble workaround is supported and we're
64 		 * at 10Mbps we may need to do some special checking.
65 		 */
66 		if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
67 
68 			/*
69 			 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
70 			 * see if we are getting preamble errors.
71 			 */
72 			int interface = INTERFACE(priv->port);
73 			int index = INDEX(priv->port);
74 			union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
75 			gmxx_rxx_int_reg.u64 =
76 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
77 					  (index, interface));
78 			if (gmxx_rxx_int_reg.s.pcterr) {
79 
80 				/*
81 				 * We are getting preamble errors at
82 				 * 10Mbps.  Most likely the PHY is
83 				 * giving us packets with mis aligned
84 				 * preambles. In order to get these
85 				 * packets we need to disable preamble
86 				 * checking and do it in software.
87 				 */
88 				union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
89 				union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
90 
91 				/* Disable preamble checking */
92 				gmxx_rxx_frm_ctl.u64 =
93 				    cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
94 						  (index, interface));
95 				gmxx_rxx_frm_ctl.s.pre_chk = 0;
96 				cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
97 					       (index, interface),
98 					       gmxx_rxx_frm_ctl.u64);
99 
100 				/* Disable FCS stripping */
101 				ipd_sub_port_fcs.u64 =
102 				    cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
103 				ipd_sub_port_fcs.s.port_bit &=
104 				    0xffffffffull ^ (1ull << priv->port);
105 				cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
106 					       ipd_sub_port_fcs.u64);
107 
108 				/* Clear any error bits */
109 				cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
110 					       (index, interface),
111 					       gmxx_rxx_int_reg.u64);
112 				DEBUGPRINT("%s: Using 10Mbps with software "
113 					   "preamble removal\n",
114 				     dev->name);
115 			}
116 		}
117 		spin_unlock_irqrestore(&global_register_lock, flags);
118 		return;
119 	}
120 
121 	/* If the 10Mbps preamble workaround is allowed we need to on
122 	   preamble checking, FCS stripping, and clear error bits on
123 	   every speed change. If errors occur during 10Mbps operation
124 	   the above code will change this stuff */
125 	if (USE_10MBPS_PREAMBLE_WORKAROUND) {
126 
127 		union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
128 		union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
129 		union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
130 		int interface = INTERFACE(priv->port);
131 		int index = INDEX(priv->port);
132 
133 		/* Enable preamble checking */
134 		gmxx_rxx_frm_ctl.u64 =
135 		    cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
136 		gmxx_rxx_frm_ctl.s.pre_chk = 1;
137 		cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
138 			       gmxx_rxx_frm_ctl.u64);
139 		/* Enable FCS stripping */
140 		ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
141 		ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
142 		cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
143 		/* Clear any error bits */
144 		gmxx_rxx_int_reg.u64 =
145 		    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
146 		cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
147 			       gmxx_rxx_int_reg.u64);
148 	}
149 	if (priv->phydev == NULL) {
150 		link_info = cvmx_helper_link_autoconf(priv->port);
151 		priv->link_info = link_info.u64;
152 	}
153 	spin_unlock_irqrestore(&global_register_lock, flags);
154 
155 	if (priv->phydev == NULL) {
156 		/* Tell core. */
157 		if (link_info.s.link_up) {
158 			if (!netif_carrier_ok(dev))
159 				netif_carrier_on(dev);
160 			if (priv->queue != -1)
161 				DEBUGPRINT("%s: %u Mbps %s duplex, "
162 					   "port %2d, queue %2d\n",
163 					   dev->name, link_info.s.speed,
164 					   (link_info.s.full_duplex) ?
165 						"Full" : "Half",
166 					   priv->port, priv->queue);
167 			else
168 				DEBUGPRINT("%s: %u Mbps %s duplex, "
169 					   "port %2d, POW\n",
170 					   dev->name, link_info.s.speed,
171 					   (link_info.s.full_duplex) ?
172 						"Full" : "Half",
173 					   priv->port);
174 		} else {
175 			if (netif_carrier_ok(dev))
176 				netif_carrier_off(dev);
177 			DEBUGPRINT("%s: Link down\n", dev->name);
178 		}
179 	}
180 }
181 
182 static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
183 {
184 	union cvmx_npi_rsl_int_blocks rsl_int_blocks;
185 	int index;
186 	irqreturn_t return_status = IRQ_NONE;
187 
188 	rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
189 
190 	/* Check and see if this interrupt was caused by the GMX0 block */
191 	if (rsl_int_blocks.s.gmx0) {
192 
193 		int interface = 0;
194 		/* Loop through every port of this interface */
195 		for (index = 0;
196 		     index < cvmx_helper_ports_on_interface(interface);
197 		     index++) {
198 
199 			/* Read the GMX interrupt status bits */
200 			union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
201 			gmx_rx_int_reg.u64 =
202 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
203 					  (index, interface));
204 			gmx_rx_int_reg.u64 &=
205 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
206 					  (index, interface));
207 			/* Poll the port if inband status changed */
208 			if (gmx_rx_int_reg.s.phy_dupx
209 			    || gmx_rx_int_reg.s.phy_link
210 			    || gmx_rx_int_reg.s.phy_spd) {
211 
212 				struct net_device *dev =
213 				    cvm_oct_device[cvmx_helper_get_ipd_port
214 						   (interface, index)];
215 				if (dev)
216 					cvm_oct_rgmii_poll(dev);
217 				gmx_rx_int_reg.u64 = 0;
218 				gmx_rx_int_reg.s.phy_dupx = 1;
219 				gmx_rx_int_reg.s.phy_link = 1;
220 				gmx_rx_int_reg.s.phy_spd = 1;
221 				cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
222 					       (index, interface),
223 					       gmx_rx_int_reg.u64);
224 				return_status = IRQ_HANDLED;
225 			}
226 		}
227 	}
228 
229 	/* Check and see if this interrupt was caused by the GMX1 block */
230 	if (rsl_int_blocks.s.gmx1) {
231 
232 		int interface = 1;
233 		/* Loop through every port of this interface */
234 		for (index = 0;
235 		     index < cvmx_helper_ports_on_interface(interface);
236 		     index++) {
237 
238 			/* Read the GMX interrupt status bits */
239 			union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
240 			gmx_rx_int_reg.u64 =
241 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
242 					  (index, interface));
243 			gmx_rx_int_reg.u64 &=
244 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
245 					  (index, interface));
246 			/* Poll the port if inband status changed */
247 			if (gmx_rx_int_reg.s.phy_dupx
248 			    || gmx_rx_int_reg.s.phy_link
249 			    || gmx_rx_int_reg.s.phy_spd) {
250 
251 				struct net_device *dev =
252 				    cvm_oct_device[cvmx_helper_get_ipd_port
253 						   (interface, index)];
254 				if (dev)
255 					cvm_oct_rgmii_poll(dev);
256 				gmx_rx_int_reg.u64 = 0;
257 				gmx_rx_int_reg.s.phy_dupx = 1;
258 				gmx_rx_int_reg.s.phy_link = 1;
259 				gmx_rx_int_reg.s.phy_spd = 1;
260 				cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
261 					       (index, interface),
262 					       gmx_rx_int_reg.u64);
263 				return_status = IRQ_HANDLED;
264 			}
265 		}
266 	}
267 	return return_status;
268 }
269 
270 int cvm_oct_rgmii_open(struct net_device *dev)
271 {
272 	union cvmx_gmxx_prtx_cfg gmx_cfg;
273 	struct octeon_ethernet *priv = netdev_priv(dev);
274 	int interface = INTERFACE(priv->port);
275 	int index = INDEX(priv->port);
276 	cvmx_helper_link_info_t link_info;
277 
278 	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
279 	gmx_cfg.s.en = 1;
280 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
281 
282 	if (!octeon_is_simulation()) {
283 		link_info = cvmx_helper_link_get(priv->port);
284 		if (!link_info.s.link_up)
285 			netif_carrier_off(dev);
286 	}
287 
288 	return 0;
289 }
290 
291 int cvm_oct_rgmii_stop(struct net_device *dev)
292 {
293 	union cvmx_gmxx_prtx_cfg gmx_cfg;
294 	struct octeon_ethernet *priv = netdev_priv(dev);
295 	int interface = INTERFACE(priv->port);
296 	int index = INDEX(priv->port);
297 
298 	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
299 	gmx_cfg.s.en = 0;
300 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
301 	return 0;
302 }
303 
304 int cvm_oct_rgmii_init(struct net_device *dev)
305 {
306 	struct octeon_ethernet *priv = netdev_priv(dev);
307 	int r;
308 
309 	cvm_oct_common_init(dev);
310 	dev->netdev_ops->ndo_stop(dev);
311 
312 	/*
313 	 * Due to GMX errata in CN3XXX series chips, it is necessary
314 	 * to take the link down immediately when 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 		if (r != 0)
324 			return r;
325 	}
326 	number_rgmii_ports++;
327 
328 	/*
329 	 * Only true RGMII ports need to be polled. In GMII mode, port
330 	 * 0 is really a RGMII port.
331 	 */
332 	if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
333 	     && (priv->port == 0))
334 	    || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
335 
336 		if (!octeon_is_simulation()) {
337 
338 			union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
339 			int interface = INTERFACE(priv->port);
340 			int index = INDEX(priv->port);
341 
342 			/*
343 			 * Enable interrupts on inband status changes
344 			 * for this port.
345 			 */
346 			gmx_rx_int_en.u64 =
347 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
348 					  (index, interface));
349 			gmx_rx_int_en.s.phy_dupx = 1;
350 			gmx_rx_int_en.s.phy_link = 1;
351 			gmx_rx_int_en.s.phy_spd = 1;
352 			cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
353 				       gmx_rx_int_en.u64);
354 			priv->poll = cvm_oct_rgmii_poll;
355 		}
356 	}
357 
358 	return 0;
359 }
360 
361 void cvm_oct_rgmii_uninit(struct net_device *dev)
362 {
363 	struct octeon_ethernet *priv = netdev_priv(dev);
364 	cvm_oct_common_uninit(dev);
365 
366 	/*
367 	 * Only true RGMII ports need to be polled. In GMII mode, port
368 	 * 0 is really a RGMII port.
369 	 */
370 	if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
371 	     && (priv->port == 0))
372 	    || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
373 
374 		if (!octeon_is_simulation()) {
375 
376 			union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
377 			int interface = INTERFACE(priv->port);
378 			int index = INDEX(priv->port);
379 
380 			/*
381 			 * Disable interrupts on inband status changes
382 			 * for this port.
383 			 */
384 			gmx_rx_int_en.u64 =
385 			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
386 					  (index, interface));
387 			gmx_rx_int_en.s.phy_dupx = 0;
388 			gmx_rx_int_en.s.phy_link = 0;
389 			gmx_rx_int_en.s.phy_spd = 0;
390 			cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
391 				       gmx_rx_int_en.u64);
392 		}
393 	}
394 
395 	/* Remove the interrupt handler when the last port is removed. */
396 	number_rgmii_ports--;
397 	if (number_rgmii_ports == 0)
398 		free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
399 }
400