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 
31 static DEFINE_SPINLOCK(global_register_lock);
32 
33 static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
34 {
35 	union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
36 	union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
37 	union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
38 	int interface = INTERFACE(priv->port);
39 	int index = INDEX(priv->port);
40 
41 	/* Set preamble checking. */
42 	gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
43 								   interface));
44 	gmxx_rxx_frm_ctl.s.pre_chk = enable;
45 	cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
46 		       gmxx_rxx_frm_ctl.u64);
47 
48 	/* Set FCS stripping. */
49 	ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
50 	if (enable)
51 		ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
52 	else
53 		ipd_sub_port_fcs.s.port_bit &=
54 					0xffffffffull ^ (1ull << priv->port);
55 	cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
56 
57 	/* Clear any error bits. */
58 	gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
59 								   interface));
60 	cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
61 		       gmxx_rxx_int_reg.u64);
62 }
63 
64 static void cvm_oct_check_preamble_errors(struct net_device *dev)
65 {
66 	struct octeon_ethernet *priv = netdev_priv(dev);
67 	cvmx_helper_link_info_t link_info;
68 	unsigned long flags;
69 
70 	link_info.u64 = priv->link_info;
71 
72 	/*
73 	 * Take the global register lock since we are going to
74 	 * touch registers that affect more than one port.
75 	 */
76 	spin_lock_irqsave(&global_register_lock, flags);
77 
78 	if (link_info.s.speed == 10 && priv->last_speed == 10) {
79 		/*
80 		 * Read the GMXX_RXX_INT_REG[PCTERR] bit and see if we are
81 		 * 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 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
88 							(index, interface));
89 		if (gmxx_rxx_int_reg.s.pcterr) {
90 			/*
91 			 * We are getting preamble errors at 10Mbps. Most
92 			 * likely the PHY is giving us packets with misaligned
93 			 * preambles. In order to get these packets we need to
94 			 * disable preamble checking and do it in software.
95 			 */
96 			cvm_oct_set_hw_preamble(priv, false);
97 			printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
98 					   dev->name);
99 		}
100 	} else {
101 		/*
102 		 * Since the 10Mbps preamble workaround is allowed we need to
103 		 * enable preamble checking, FCS stripping, and clear error
104 		 * bits on every speed change. If errors occur during 10Mbps
105 		 * operation the above code will change this stuff
106 		 */
107 		if (priv->last_speed != link_info.s.speed)
108 			cvm_oct_set_hw_preamble(priv, true);
109 		priv->last_speed = link_info.s.speed;
110 	}
111 	spin_unlock_irqrestore(&global_register_lock, flags);
112 }
113 
114 static void cvm_oct_rgmii_poll(struct net_device *dev)
115 {
116 	struct octeon_ethernet *priv = netdev_priv(dev);
117 	cvmx_helper_link_info_t link_info;
118 	bool status_change;
119 
120 	link_info = cvmx_helper_link_autoconf(priv->port);
121 	status_change = priv->link_info != link_info.u64;
122 	priv->link_info = link_info.u64;
123 
124 	cvm_oct_check_preamble_errors(dev);
125 
126 	if (likely(!status_change))
127 		return;
128 
129 	/* Tell core. */
130 	if (link_info.s.link_up) {
131 		if (!netif_carrier_ok(dev))
132 			netif_carrier_on(dev);
133 	} else if (netif_carrier_ok(dev)) {
134 		netif_carrier_off(dev);
135 	}
136 	cvm_oct_note_carrier(priv, link_info);
137 }
138 
139 int cvm_oct_rgmii_open(struct net_device *dev)
140 {
141 	struct octeon_ethernet *priv = netdev_priv(dev);
142 	int ret;
143 
144 	ret = cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
145 	if (ret)
146 		return ret;
147 
148 	if (priv->phydev) {
149 		/*
150 		 * In phydev mode, we need still periodic polling for the
151 		 * preamble error checking, and we also need to call this
152 		 * function on every link state change.
153 		 *
154 		 * Only true RGMII ports need to be polled. In GMII mode, port
155 		 * 0 is really a RGMII port.
156 		 */
157 		if ((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII &&
158 		     priv->port  == 0) ||
159 		    (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
160 			priv->poll = cvm_oct_check_preamble_errors;
161 			cvm_oct_check_preamble_errors(dev);
162 		}
163 	}
164 
165 	return 0;
166 }
167