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
47static DEFINE_SPINLOCK(global_register_lock);
48
49static int number_rgmii_ports;
50
51static 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
199static 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
299int 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
334int 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
347static 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
354int 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
408void 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