1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file is based on code from OCTEON SDK by Cavium Networks.
4  *
5  * Copyright (c) 2003-2007 Cavium Networks
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/netdevice.h>
10 #include <linux/interrupt.h>
11 #include <linux/phy.h>
12 #include <linux/ratelimit.h>
13 #include <net/dst.h>
14 
15 #include <asm/octeon/octeon.h>
16 
17 #include "ethernet-defines.h"
18 #include "octeon-ethernet.h"
19 #include "ethernet-util.h"
20 #include "ethernet-mdio.h"
21 
22 #include <asm/octeon/cvmx-helper.h>
23 
24 #include <asm/octeon/cvmx-ipd-defs.h>
25 #include <asm/octeon/cvmx-npi-defs.h>
26 #include <asm/octeon/cvmx-gmxx-defs.h>
27 
28 static DEFINE_SPINLOCK(global_register_lock);
29 
30 static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
31 {
32 	union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
33 	union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
34 	union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
35 	int interface = INTERFACE(priv->port);
36 	int index = INDEX(priv->port);
37 
38 	/* Set preamble checking. */
39 	gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
40 								   interface));
41 	gmxx_rxx_frm_ctl.s.pre_chk = enable;
42 	cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
43 		       gmxx_rxx_frm_ctl.u64);
44 
45 	/* Set FCS stripping. */
46 	ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
47 	if (enable)
48 		ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
49 	else
50 		ipd_sub_port_fcs.s.port_bit &=
51 					0xffffffffull ^ (1ull << priv->port);
52 	cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
53 
54 	/* Clear any error bits. */
55 	gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
56 								   interface));
57 	cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
58 		       gmxx_rxx_int_reg.u64);
59 }
60 
61 static void cvm_oct_check_preamble_errors(struct net_device *dev)
62 {
63 	struct octeon_ethernet *priv = netdev_priv(dev);
64 	cvmx_helper_link_info_t link_info;
65 	unsigned long flags;
66 
67 	link_info.u64 = priv->link_info;
68 
69 	/*
70 	 * Take the global register lock since we are going to
71 	 * touch registers that affect more than one port.
72 	 */
73 	spin_lock_irqsave(&global_register_lock, flags);
74 
75 	if (link_info.s.speed == 10 && priv->last_speed == 10) {
76 		/*
77 		 * Read the GMXX_RXX_INT_REG[PCTERR] bit and see if we are
78 		 * getting preamble errors.
79 		 */
80 		int interface = INTERFACE(priv->port);
81 		int index = INDEX(priv->port);
82 		union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
83 
84 		gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
85 							(index, interface));
86 		if (gmxx_rxx_int_reg.s.pcterr) {
87 			/*
88 			 * We are getting preamble errors at 10Mbps. Most
89 			 * likely the PHY is giving us packets with misaligned
90 			 * preambles. In order to get these packets we need to
91 			 * disable preamble checking and do it in software.
92 			 */
93 			cvm_oct_set_hw_preamble(priv, false);
94 			printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
95 					   dev->name);
96 		}
97 	} else {
98 		/*
99 		 * Since the 10Mbps preamble workaround is allowed we need to
100 		 * enable preamble checking, FCS stripping, and clear error
101 		 * bits on every speed change. If errors occur during 10Mbps
102 		 * operation the above code will change this stuff
103 		 */
104 		if (priv->last_speed != link_info.s.speed)
105 			cvm_oct_set_hw_preamble(priv, true);
106 		priv->last_speed = link_info.s.speed;
107 	}
108 	spin_unlock_irqrestore(&global_register_lock, flags);
109 }
110 
111 static void cvm_oct_rgmii_poll(struct net_device *dev)
112 {
113 	struct octeon_ethernet *priv = netdev_priv(dev);
114 	cvmx_helper_link_info_t link_info;
115 	bool status_change;
116 
117 	link_info = cvmx_helper_link_get(priv->port);
118 	if (priv->link_info != link_info.u64 &&
119 	    cvmx_helper_link_set(priv->port, link_info))
120 		link_info.u64 = priv->link_info;
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 (dev->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