@@ -91,6 +91,79 @@ int dsa_8021q_rx_source_port(u16 vid)
91
91
}
92
92
EXPORT_SYMBOL_GPL (dsa_8021q_rx_source_port );
93
93
94
+ static int dsa_8021q_restore_pvid (struct dsa_switch * ds , int port )
95
+ {
96
+ struct bridge_vlan_info vinfo ;
97
+ struct net_device * slave ;
98
+ u16 pvid ;
99
+ int err ;
100
+
101
+ if (!dsa_is_user_port (ds , port ))
102
+ return 0 ;
103
+
104
+ slave = ds -> ports [port ].slave ;
105
+
106
+ err = br_vlan_get_pvid (slave , & pvid );
107
+ if (err < 0 )
108
+ /* There is no pvid on the bridge for this port, which is
109
+ * perfectly valid. Nothing to restore, bye-bye!
110
+ */
111
+ return 0 ;
112
+
113
+ err = br_vlan_get_info (slave , pvid , & vinfo );
114
+ if (err < 0 ) {
115
+ dev_err (ds -> dev , "Couldn't determine PVID attributes\n" );
116
+ return err ;
117
+ }
118
+
119
+ return dsa_port_vid_add (& ds -> ports [port ], pvid , vinfo .flags );
120
+ }
121
+
122
+ /* If @enabled is true, installs @vid with @flags into the switch port's HW
123
+ * filter.
124
+ * If @enabled is false, deletes @vid (ignores @flags) from the port. Had the
125
+ * user explicitly configured this @vid through the bridge core, then the @vid
126
+ * is installed again, but this time with the flags from the bridge layer.
127
+ */
128
+ static int dsa_8021q_vid_apply (struct dsa_switch * ds , int port , u16 vid ,
129
+ u16 flags , bool enabled )
130
+ {
131
+ struct dsa_port * dp = & ds -> ports [port ];
132
+ struct bridge_vlan_info vinfo ;
133
+ int err ;
134
+
135
+ if (enabled )
136
+ return dsa_port_vid_add (dp , vid , flags );
137
+
138
+ err = dsa_port_vid_del (dp , vid );
139
+ if (err < 0 )
140
+ return err ;
141
+
142
+ /* Nothing to restore from the bridge for a non-user port.
143
+ * The CPU port VLANs are restored implicitly with the user ports,
144
+ * similar to how the bridge does in dsa_slave_vlan_add and
145
+ * dsa_slave_vlan_del.
146
+ */
147
+ if (!dsa_is_user_port (ds , port ))
148
+ return 0 ;
149
+
150
+ err = br_vlan_get_info (dp -> slave , vid , & vinfo );
151
+ /* Couldn't determine bridge attributes for this vid,
152
+ * it means the bridge had not configured it.
153
+ */
154
+ if (err < 0 )
155
+ return 0 ;
156
+
157
+ /* Restore the VID from the bridge */
158
+ err = dsa_port_vid_add (dp , vid , vinfo .flags );
159
+ if (err < 0 )
160
+ return err ;
161
+
162
+ vinfo .flags &= ~BRIDGE_VLAN_INFO_PVID ;
163
+
164
+ return dsa_port_vid_add (dp -> cpu_dp , vid , vinfo .flags );
165
+ }
166
+
94
167
/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single
95
168
* front-panel switch port (here swp0).
96
169
*
@@ -146,8 +219,6 @@ EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
146
219
int dsa_port_setup_8021q_tagging (struct dsa_switch * ds , int port , bool enabled )
147
220
{
148
221
int upstream = dsa_upstream_port (ds , port );
149
- struct dsa_port * dp = & ds -> ports [port ];
150
- struct dsa_port * upstream_dp = & ds -> ports [upstream ];
151
222
u16 rx_vid = dsa_8021q_rx_vid (ds , port );
152
223
u16 tx_vid = dsa_8021q_tx_vid (ds , port );
153
224
int i , err ;
@@ -164,7 +235,6 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
164
235
* restrictions, so there are no concerns about leaking traffic.
165
236
*/
166
237
for (i = 0 ; i < ds -> num_ports ; i ++ ) {
167
- struct dsa_port * other_dp = & ds -> ports [i ];
168
238
u16 flags ;
169
239
170
240
if (i == upstream )
@@ -177,10 +247,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
177
247
/* The RX VID is a regular VLAN on all others */
178
248
flags = BRIDGE_VLAN_INFO_UNTAGGED ;
179
249
180
- if (enabled )
181
- err = dsa_port_vid_add (other_dp , rx_vid , flags );
182
- else
183
- err = dsa_port_vid_del (other_dp , rx_vid );
250
+ err = dsa_8021q_vid_apply (ds , i , rx_vid , flags , enabled );
184
251
if (err ) {
185
252
dev_err (ds -> dev , "Failed to apply RX VID %d to port %d: %d\n" ,
186
253
rx_vid , port , err );
@@ -191,37 +258,32 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
191
258
/* CPU port needs to see this port's RX VID
192
259
* as tagged egress.
193
260
*/
194
- if (enabled )
195
- err = dsa_port_vid_add (upstream_dp , rx_vid , 0 );
196
- else
197
- err = dsa_port_vid_del (upstream_dp , rx_vid );
261
+ err = dsa_8021q_vid_apply (ds , upstream , rx_vid , 0 , enabled );
198
262
if (err ) {
199
263
dev_err (ds -> dev , "Failed to apply RX VID %d to port %d: %d\n" ,
200
264
rx_vid , port , err );
201
265
return err ;
202
266
}
203
267
204
268
/* Finally apply the TX VID on this port and on the CPU port */
205
- if (enabled )
206
- err = dsa_port_vid_add (dp , tx_vid , BRIDGE_VLAN_INFO_UNTAGGED );
207
- else
208
- err = dsa_port_vid_del (dp , tx_vid );
269
+ err = dsa_8021q_vid_apply (ds , port , tx_vid , BRIDGE_VLAN_INFO_UNTAGGED ,
270
+ enabled );
209
271
if (err ) {
210
272
dev_err (ds -> dev , "Failed to apply TX VID %d on port %d: %d\n" ,
211
273
tx_vid , port , err );
212
274
return err ;
213
275
}
214
- if (enabled )
215
- err = dsa_port_vid_add (upstream_dp , tx_vid , 0 );
216
- else
217
- err = dsa_port_vid_del (upstream_dp , tx_vid );
276
+ err = dsa_8021q_vid_apply (ds , upstream , tx_vid , 0 , enabled );
218
277
if (err ) {
219
278
dev_err (ds -> dev , "Failed to apply TX VID %d on port %d: %d\n" ,
220
279
tx_vid , upstream , err );
221
280
return err ;
222
281
}
223
282
224
- return 0 ;
283
+ if (!enabled )
284
+ err = dsa_8021q_restore_pvid (ds , port );
285
+
286
+ return err ;
225
287
}
226
288
EXPORT_SYMBOL_GPL (dsa_port_setup_8021q_tagging );
227
289
0 commit comments