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