1/*
2 * This file is based on code from OCTEON SDK by Cavium Networks.
3 *
4 * Copyright (c) 2003-2007 Cavium Networks
5 *
6 * This file is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, Version 2, as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/netdevice.h>
13#include <linux/interrupt.h>
14#include <linux/phy.h>
15#include <linux/ratelimit.h>
16#include <net/dst.h>
17
18#include <asm/octeon/octeon.h>
19
20#include "ethernet-defines.h"
21#include "octeon-ethernet.h"
22#include "ethernet-util.h"
23#include "ethernet-mdio.h"
24
25#include <asm/octeon/cvmx-helper.h>
26
27#include <asm/octeon/cvmx-ipd-defs.h>
28#include <asm/octeon/cvmx-npi-defs.h>
29#include <asm/octeon/cvmx-gmxx-defs.h>
30
31static DEFINE_SPINLOCK(global_register_lock);
32
33static int number_rgmii_ports;
34
35static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
36{
37	union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
38	union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
39	union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
40	int interface = INTERFACE(priv->port);
41	int index = INDEX(priv->port);
42
43	/* Set preamble checking. */
44	gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
45								   interface));
46	gmxx_rxx_frm_ctl.s.pre_chk = enable;
47	cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
48		       gmxx_rxx_frm_ctl.u64);
49
50	/* Set FCS stripping. */
51	ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
52	if (enable)
53		ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
54	else
55		ipd_sub_port_fcs.s.port_bit &=
56					0xffffffffull ^ (1ull << priv->port);
57	cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
58
59	/* Clear any error bits. */
60	gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
61								   interface));
62	cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
63		       gmxx_rxx_int_reg.u64);
64}
65
66static void cvm_oct_rgmii_poll(struct net_device *dev)
67{
68	struct octeon_ethernet *priv = netdev_priv(dev);
69	unsigned long flags = 0;
70	cvmx_helper_link_info_t link_info;
71	int use_global_register_lock = (priv->phydev == NULL);
72
73	BUG_ON(in_interrupt());
74	if (use_global_register_lock) {
75		/*
76		 * Take the global register lock since we are going to
77		 * touch registers that affect more than one port.
78		 */
79		spin_lock_irqsave(&global_register_lock, flags);
80	} else {
81		mutex_lock(&priv->phydev->bus->mdio_lock);
82	}
83
84	link_info = cvmx_helper_link_get(priv->port);
85	if (link_info.u64 == priv->link_info) {
86		if (link_info.s.speed == 10) {
87			/*
88			 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
89			 * see if we are getting preamble errors.
90			 */
91			int interface = INTERFACE(priv->port);
92			int index = INDEX(priv->port);
93			union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
94
95			gmxx_rxx_int_reg.u64 =
96			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
97					  (index, interface));
98			if (gmxx_rxx_int_reg.s.pcterr) {
99				/*
100				 * We are getting preamble errors at
101				 * 10Mbps.  Most likely the PHY is
102				 * giving us packets with mis aligned
103				 * preambles. In order to get these
104				 * packets we need to disable preamble
105				 * checking and do it in software.
106				 */
107				cvm_oct_set_hw_preamble(priv, false);
108				printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
109						   dev->name);
110			}
111		}
112
113		if (use_global_register_lock)
114			spin_unlock_irqrestore(&global_register_lock, flags);
115		else
116			mutex_unlock(&priv->phydev->bus->mdio_lock);
117		return;
118	}
119
120	/* Since the 10Mbps preamble workaround is allowed we need to enable
121	 * preamble checking, FCS stripping, and clear error bits on
122	 * every speed change. If errors occur during 10Mbps operation
123	 * the above code will change this stuff
124	 */
125	cvm_oct_set_hw_preamble(priv, true);
126
127	if (priv->phydev == NULL) {
128		link_info = cvmx_helper_link_autoconf(priv->port);
129		priv->link_info = link_info.u64;
130	}
131
132	if (use_global_register_lock)
133		spin_unlock_irqrestore(&global_register_lock, flags);
134	else
135		mutex_unlock(&priv->phydev->bus->mdio_lock);
136
137	if (priv->phydev == NULL) {
138		/* Tell core. */
139		if (link_info.s.link_up) {
140			if (!netif_carrier_ok(dev))
141				netif_carrier_on(dev);
142		} else if (netif_carrier_ok(dev)) {
143			netif_carrier_off(dev);
144		}
145		cvm_oct_note_carrier(priv, link_info);
146	}
147}
148
149static int cmv_oct_rgmii_gmx_interrupt(int interface)
150{
151	int index;
152	int count = 0;
153
154	/* Loop through every port of this interface */
155	for (index = 0;
156	     index < cvmx_helper_ports_on_interface(interface);
157	     index++) {
158		union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
159
160		/* Read the GMX interrupt status bits */
161		gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
162					  (index, interface));
163		gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
164					  (index, interface));
165
166		/* Poll the port if inband status changed */
167		if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link ||
168		    gmx_rx_int_reg.s.phy_spd) {
169			struct net_device *dev =
170				    cvm_oct_device[cvmx_helper_get_ipd_port
171						   (interface, index)];
172			struct octeon_ethernet *priv = netdev_priv(dev);
173
174			if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
175				queue_work(cvm_oct_poll_queue,
176					   &priv->port_work);
177
178			gmx_rx_int_reg.u64 = 0;
179			gmx_rx_int_reg.s.phy_dupx = 1;
180			gmx_rx_int_reg.s.phy_link = 1;
181			gmx_rx_int_reg.s.phy_spd = 1;
182			cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
183				       gmx_rx_int_reg.u64);
184			count++;
185		}
186	}
187	return count;
188}
189
190static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
191{
192	union cvmx_npi_rsl_int_blocks rsl_int_blocks;
193	int count = 0;
194
195	rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
196
197	/* Check and see if this interrupt was caused by the GMX0 block */
198	if (rsl_int_blocks.s.gmx0)
199		count += cmv_oct_rgmii_gmx_interrupt(0);
200
201	/* Check and see if this interrupt was caused by the GMX1 block */
202	if (rsl_int_blocks.s.gmx1)
203		count += cmv_oct_rgmii_gmx_interrupt(1);
204
205	return count ? IRQ_HANDLED : IRQ_NONE;
206}
207
208int cvm_oct_rgmii_open(struct net_device *dev)
209{
210	return cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
211}
212
213static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
214{
215	struct octeon_ethernet *priv =
216		container_of(work, struct octeon_ethernet, port_work);
217	cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
218}
219
220int cvm_oct_rgmii_init(struct net_device *dev)
221{
222	struct octeon_ethernet *priv = netdev_priv(dev);
223	int r;
224
225	cvm_oct_common_init(dev);
226	INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
227	/*
228	 * Due to GMX errata in CN3XXX series chips, it is necessary
229	 * to take the link down immediately when the PHY changes
230	 * state. In order to do this we call the poll function every
231	 * time the RGMII inband status changes.  This may cause
232	 * problems if the PHY doesn't implement inband status
233	 * properly.
234	 */
235	if (number_rgmii_ports == 0) {
236		r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
237				IRQF_SHARED, "RGMII", &number_rgmii_ports);
238		if (r != 0)
239			return r;
240	}
241	number_rgmii_ports++;
242
243	/*
244	 * Only true RGMII ports need to be polled. In GMII mode, port
245	 * 0 is really a RGMII port.
246	 */
247	if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
248	     && (priv->port == 0))
249	    || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
250
251		if (!octeon_is_simulation()) {
252
253			union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
254			int interface = INTERFACE(priv->port);
255			int index = INDEX(priv->port);
256
257			/*
258			 * Enable interrupts on inband status changes
259			 * for this port.
260			 */
261			gmx_rx_int_en.u64 = 0;
262			gmx_rx_int_en.s.phy_dupx = 1;
263			gmx_rx_int_en.s.phy_link = 1;
264			gmx_rx_int_en.s.phy_spd = 1;
265			cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
266				       gmx_rx_int_en.u64);
267		}
268	}
269
270	return 0;
271}
272
273void cvm_oct_rgmii_uninit(struct net_device *dev)
274{
275	struct octeon_ethernet *priv = netdev_priv(dev);
276
277	cvm_oct_common_uninit(dev);
278
279	/*
280	 * Only true RGMII ports need to be polled. In GMII mode, port
281	 * 0 is really a RGMII port.
282	 */
283	if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
284	     && (priv->port == 0))
285	    || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
286
287		if (!octeon_is_simulation()) {
288
289			union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
290			int interface = INTERFACE(priv->port);
291			int index = INDEX(priv->port);
292
293			/*
294			 * Disable interrupts on inband status changes
295			 * for this port.
296			 */
297			gmx_rx_int_en.u64 =
298			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
299					  (index, interface));
300			gmx_rx_int_en.s.phy_dupx = 0;
301			gmx_rx_int_en.s.phy_link = 0;
302			gmx_rx_int_en.s.phy_spd = 0;
303			cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
304				       gmx_rx_int_en.u64);
305		}
306	}
307
308	/* Remove the interrupt handler when the last port is removed. */
309	number_rgmii_ports--;
310	if (number_rgmii_ports == 0)
311		free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
312	cancel_work_sync(&priv->port_work);
313}
314