mvebu: backport upstream ethernet driver improvements and enable buffer manager support
[openwrt/openwrt.git] / target / linux / mvebu / patches-4.4 / 031-mvneta-implement-ethtool-autonegotiation-control.patch
1 From: Stas Sergeev <stsp@list.ru>
2 Date: Wed, 2 Dec 2015 20:35:11 +0300
3 Subject: [PATCH] mvneta: implement ethtool autonegotiation control
4
5 This patch allows to do
6 ethtool -s eth0 autoneg off
7 ethtool -s eth0 autoneg on
8 to disable or enable autonegotiation at run-time.
9 Without that functionality, the only way to control the autonegotiation
10 is to modify the device tree.
11
12 This is needed if you plan to use the same kernel with
13 different ethernet switches, the ones that support the in-band
14 status and the ones that not.
15
16 CC: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
17 CC: netdev@vger.kernel.org
18 CC: linux-kernel@vger.kernel.org
19
20 Signed-off-by: Stas Sergeev <stsp@users.sourceforge.net>
21 Signed-off-by: David S. Miller <davem@davemloft.net>
22 ---
23
24 --- a/drivers/net/ethernet/marvell/mvneta.c
25 +++ b/drivers/net/ethernet/marvell/mvneta.c
26 @@ -371,7 +371,7 @@ struct mvneta_port {
27 unsigned int duplex;
28 unsigned int speed;
29 unsigned int tx_csum_limit;
30 - int use_inband_status:1;
31 + unsigned int use_inband_status:1;
32
33 u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
34 };
35 @@ -973,6 +973,44 @@ static void mvneta_set_other_mcast_table
36 mvreg_write(pp, MVNETA_DA_FILT_OTH_MCAST + offset, val);
37 }
38
39 +static void mvneta_set_autoneg(struct mvneta_port *pp, int enable)
40 +{
41 + u32 val;
42 +
43 + if (enable) {
44 + val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
45 + val &= ~(MVNETA_GMAC_FORCE_LINK_PASS |
46 + MVNETA_GMAC_FORCE_LINK_DOWN |
47 + MVNETA_GMAC_AN_FLOW_CTRL_EN);
48 + val |= MVNETA_GMAC_INBAND_AN_ENABLE |
49 + MVNETA_GMAC_AN_SPEED_EN |
50 + MVNETA_GMAC_AN_DUPLEX_EN;
51 + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
52 +
53 + val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
54 + val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
55 + mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
56 +
57 + val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
58 + val |= MVNETA_GMAC2_INBAND_AN_ENABLE;
59 + mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
60 + } else {
61 + val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
62 + val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
63 + MVNETA_GMAC_AN_SPEED_EN |
64 + MVNETA_GMAC_AN_DUPLEX_EN);
65 + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
66 +
67 + val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
68 + val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
69 + mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
70 +
71 + val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
72 + val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE;
73 + mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
74 + }
75 +}
76 +
77 /* This method sets defaults to the NETA port:
78 * Clears interrupt Cause and Mask registers.
79 * Clears all MAC tables.
80 @@ -1058,39 +1096,7 @@ static void mvneta_defaults_set(struct m
81 val &= ~MVNETA_PHY_POLLING_ENABLE;
82 mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
83
84 - if (pp->use_inband_status) {
85 - val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
86 - val &= ~(MVNETA_GMAC_FORCE_LINK_PASS |
87 - MVNETA_GMAC_FORCE_LINK_DOWN |
88 - MVNETA_GMAC_AN_FLOW_CTRL_EN);
89 - val |= MVNETA_GMAC_INBAND_AN_ENABLE |
90 - MVNETA_GMAC_AN_SPEED_EN |
91 - MVNETA_GMAC_AN_DUPLEX_EN;
92 - mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
93 -
94 - val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
95 - val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
96 - mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
97 -
98 - val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
99 - val |= MVNETA_GMAC2_INBAND_AN_ENABLE;
100 - mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
101 - } else {
102 - val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
103 - val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
104 - MVNETA_GMAC_AN_SPEED_EN |
105 - MVNETA_GMAC_AN_DUPLEX_EN);
106 - mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
107 -
108 - val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
109 - val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
110 - mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
111 -
112 - val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
113 - val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE;
114 - mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
115 - }
116 -
117 + mvneta_set_autoneg(pp, pp->use_inband_status);
118 mvneta_set_ucast_table(pp, -1);
119 mvneta_set_special_mcast_table(pp, -1);
120 mvneta_set_other_mcast_table(pp, -1);
121 @@ -2956,10 +2962,43 @@ int mvneta_ethtool_get_settings(struct n
122 int mvneta_ethtool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
123 {
124 struct mvneta_port *pp = netdev_priv(dev);
125 + struct phy_device *phydev = pp->phy_dev;
126
127 - if (!pp->phy_dev)
128 + if (!phydev)
129 return -ENODEV;
130
131 + if ((cmd->autoneg == AUTONEG_ENABLE) != pp->use_inband_status) {
132 + u32 val;
133 +
134 + mvneta_set_autoneg(pp, cmd->autoneg == AUTONEG_ENABLE);
135 +
136 + if (cmd->autoneg == AUTONEG_DISABLE) {
137 + val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
138 + val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED |
139 + MVNETA_GMAC_CONFIG_GMII_SPEED |
140 + MVNETA_GMAC_CONFIG_FULL_DUPLEX);
141 +
142 + if (phydev->duplex)
143 + val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
144 +
145 + if (phydev->speed == SPEED_1000)
146 + val |= MVNETA_GMAC_CONFIG_GMII_SPEED;
147 + else if (phydev->speed == SPEED_100)
148 + val |= MVNETA_GMAC_CONFIG_MII_SPEED;
149 +
150 + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
151 + }
152 +
153 + pp->use_inband_status = (cmd->autoneg == AUTONEG_ENABLE);
154 + netdev_info(pp->dev, "autoneg status set to %i\n",
155 + pp->use_inband_status);
156 +
157 + if (netif_running(dev)) {
158 + mvneta_port_down(pp);
159 + mvneta_port_up(pp);
160 + }
161 + }
162 +
163 return phy_ethtool_sset(pp->phy_dev, cmd);
164 }
165