9d6f5c52dc62ad43c9e97310e5d0e204d071117c
[openwrt/staging/ldir.git] /
1 From 80d12452a5f160c39d63efc1be07df36f9d07133 Mon Sep 17 00:00:00 2001
2 From: Vladimir Oltean <vladimir.oltean@nxp.com>
3 Date: Tue, 29 Nov 2022 16:12:20 +0200
4 Subject: [PATCH 13/14] net: dpaa2-switch: serialize changes to priv->mac with
5 a mutex
6
7 The dpaa2-switch driver uses a DPMAC in the same way as the dpaa2-eth
8 driver, so we need to duplicate the locking solution established by the
9 previous change to the switch driver as well.
10
11 Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
12 Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
13 Tested-by: Ioana Ciornei <ioana.ciornei@nxp.com>
14 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
15 ---
16 .../freescale/dpaa2/dpaa2-switch-ethtool.c | 32 +++++++++++++++----
17 .../ethernet/freescale/dpaa2/dpaa2-switch.c | 31 ++++++++++++++++--
18 .../ethernet/freescale/dpaa2/dpaa2-switch.h | 2 ++
19 3 files changed, 55 insertions(+), 10 deletions(-)
20
21 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c
22 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c
23 @@ -60,11 +60,18 @@ dpaa2_switch_get_link_ksettings(struct n
24 {
25 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
26 struct dpsw_link_state state = {0};
27 - int err = 0;
28 + int err;
29
30 - if (dpaa2_switch_port_is_type_phy(port_priv))
31 - return phylink_ethtool_ksettings_get(port_priv->mac->phylink,
32 - link_ksettings);
33 + mutex_lock(&port_priv->mac_lock);
34 +
35 + if (dpaa2_switch_port_is_type_phy(port_priv)) {
36 + err = phylink_ethtool_ksettings_get(port_priv->mac->phylink,
37 + link_ksettings);
38 + mutex_unlock(&port_priv->mac_lock);
39 + return err;
40 + }
41 +
42 + mutex_unlock(&port_priv->mac_lock);
43
44 err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
45 port_priv->ethsw_data->dpsw_handle,
46 @@ -99,9 +106,16 @@ dpaa2_switch_set_link_ksettings(struct n
47 bool if_running;
48 int err = 0, ret;
49
50 - if (dpaa2_switch_port_is_type_phy(port_priv))
51 - return phylink_ethtool_ksettings_set(port_priv->mac->phylink,
52 - link_ksettings);
53 + mutex_lock(&port_priv->mac_lock);
54 +
55 + if (dpaa2_switch_port_is_type_phy(port_priv)) {
56 + err = phylink_ethtool_ksettings_set(port_priv->mac->phylink,
57 + link_ksettings);
58 + mutex_unlock(&port_priv->mac_lock);
59 + return err;
60 + }
61 +
62 + mutex_unlock(&port_priv->mac_lock);
63
64 /* Interface needs to be down to change link settings */
65 if_running = netif_running(netdev);
66 @@ -189,8 +203,12 @@ static void dpaa2_switch_ethtool_get_sta
67 dpaa2_switch_ethtool_counters[i].name, err);
68 }
69
70 + mutex_lock(&port_priv->mac_lock);
71 +
72 if (dpaa2_switch_port_has_mac(port_priv))
73 dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i);
74 +
75 + mutex_unlock(&port_priv->mac_lock);
76 }
77
78 const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
79 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
80 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
81 @@ -603,8 +603,11 @@ static int dpaa2_switch_port_link_state_
82
83 /* When we manage the MAC/PHY using phylink there is no need
84 * to manually update the netif_carrier.
85 + * We can avoid locking because we are called from the "link changed"
86 + * IRQ handler, which is the same as the "endpoint changed" IRQ handler
87 + * (the writer to port_priv->mac), so we cannot race with it.
88 */
89 - if (dpaa2_switch_port_is_type_phy(port_priv))
90 + if (dpaa2_mac_is_type_phy(port_priv->mac))
91 return 0;
92
93 /* Interrupts are received even though no one issued an 'ifconfig up'
94 @@ -684,6 +687,8 @@ static int dpaa2_switch_port_open(struct
95 struct ethsw_core *ethsw = port_priv->ethsw_data;
96 int err;
97
98 + mutex_lock(&port_priv->mac_lock);
99 +
100 if (!dpaa2_switch_port_is_type_phy(port_priv)) {
101 /* Explicitly set carrier off, otherwise
102 * netif_carrier_ok() will return true and cause 'ip link show'
103 @@ -697,6 +702,7 @@ static int dpaa2_switch_port_open(struct
104 port_priv->ethsw_data->dpsw_handle,
105 port_priv->idx);
106 if (err) {
107 + mutex_unlock(&port_priv->mac_lock);
108 netdev_err(netdev, "dpsw_if_enable err %d\n", err);
109 return err;
110 }
111 @@ -706,6 +712,8 @@ static int dpaa2_switch_port_open(struct
112 if (dpaa2_switch_port_is_type_phy(port_priv))
113 dpaa2_mac_start(port_priv->mac);
114
115 + mutex_unlock(&port_priv->mac_lock);
116 +
117 return 0;
118 }
119
120 @@ -715,6 +723,8 @@ static int dpaa2_switch_port_stop(struct
121 struct ethsw_core *ethsw = port_priv->ethsw_data;
122 int err;
123
124 + mutex_lock(&port_priv->mac_lock);
125 +
126 if (dpaa2_switch_port_is_type_phy(port_priv)) {
127 dpaa2_mac_stop(port_priv->mac);
128 } else {
129 @@ -722,6 +732,8 @@ static int dpaa2_switch_port_stop(struct
130 netif_carrier_off(netdev);
131 }
132
133 + mutex_unlock(&port_priv->mac_lock);
134 +
135 err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
136 port_priv->ethsw_data->dpsw_handle,
137 port_priv->idx);
138 @@ -1461,7 +1473,9 @@ static int dpaa2_switch_port_connect_mac
139 }
140 }
141
142 + mutex_lock(&port_priv->mac_lock);
143 port_priv->mac = mac;
144 + mutex_unlock(&port_priv->mac_lock);
145
146 return 0;
147
148 @@ -1474,9 +1488,12 @@ err_free_mac:
149
150 static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv)
151 {
152 - struct dpaa2_mac *mac = port_priv->mac;
153 + struct dpaa2_mac *mac;
154
155 + mutex_lock(&port_priv->mac_lock);
156 + mac = port_priv->mac;
157 port_priv->mac = NULL;
158 + mutex_unlock(&port_priv->mac_lock);
159
160 if (!mac)
161 return;
162 @@ -1495,6 +1512,7 @@ static irqreturn_t dpaa2_switch_irq0_han
163 struct ethsw_port_priv *port_priv;
164 u32 status = ~0;
165 int err, if_id;
166 + bool had_mac;
167
168 err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
169 DPSW_IRQ_INDEX_IF, &status);
170 @@ -1513,7 +1531,12 @@ static irqreturn_t dpaa2_switch_irq0_han
171
172 if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED) {
173 rtnl_lock();
174 - if (dpaa2_switch_port_has_mac(port_priv))
175 + /* We can avoid locking because the "endpoint changed" IRQ
176 + * handler is the only one who changes priv->mac at runtime,
177 + * so we are not racing with anyone.
178 + */
179 + had_mac = !!port_priv->mac;
180 + if (had_mac)
181 dpaa2_switch_port_disconnect_mac(port_priv);
182 else
183 dpaa2_switch_port_connect_mac(port_priv);
184 @@ -3249,6 +3272,8 @@ static int dpaa2_switch_probe_port(struc
185 port_priv->netdev = port_netdev;
186 port_priv->ethsw_data = ethsw;
187
188 + mutex_init(&port_priv->mac_lock);
189 +
190 port_priv->idx = port_idx;
191 port_priv->stp_state = BR_STATE_FORWARDING;
192
193 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
194 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
195 @@ -161,6 +161,8 @@ struct ethsw_port_priv {
196
197 struct dpaa2_switch_filter_block *filter_block;
198 struct dpaa2_mac *mac;
199 + /* Protects against changes to port_priv->mac */
200 + struct mutex mac_lock;
201 };
202
203 /* Switch data */