1
2
3
4
5
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
28static DEFINE_SPINLOCK(global_register_lock);
29
30static 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
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
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
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
61static 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
71
72
73 spin_lock_irqsave(&global_register_lock, flags);
74
75 if (link_info.s.speed == 10 && priv->last_speed == 10) {
76
77
78
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
89
90
91
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
100
101
102
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
111static 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
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
139int 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
151
152
153
154
155
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