Skip to content

Commit 4925930

Browse files
committed
Merge branch 'dsa-core-vlan'
Vladimir Oltean says: ==================== Improvements to DSA core VLAN manipulation In preparation of submitting the NXP SJA1105 driver, the Broadcom b53 and Mediatek mt7530 drivers have been found to apply some VLAN workarounds that are needed in the new driver as well. Therefore this patchset is mostly simply promoting the DSA driver workarounds for VLAN to the generic code. The b53 driver was applying a few workarounds in order to convince DSA that its vlan_filtering setting is not really per-port. This is now simply set by the driver via a DSA variable at probe time. The sja1105 driver will be a second user of this. The mt7530 was also keeping track of when the .port_vlan_filtering callback was being called. Remove the kept state from this driver and simplify dealing with vlan_filtering in the generic case. TODO: Find the best way to deal generically with the situation described below (discussion at https://lkml.org/lkml/2019/4/16/1355): > > +Segregating the switch ports in multiple bridges is supported (e.g. 2 + 2), but > > +all bridges should have the same level of VLAN awareness (either both have > > +``vlan_filtering`` 0, or both 1). Also an inevitable limitation of the fact > > +that VLAN awareness is global at the switch level is that once a bridge with > > +``vlan_filtering`` enslaves at least one switch port, the other un-bridged > > +ports are no longer available for standalone traffic termination. > > That is quite a limitation that I don't think I had fully grasped until > reading your different patches. Since enslaving ports into a bridge > comes after the network device was already made available for use, maybe > you should force the carrier down or something along those lines as soon > as a port is enslaved into a bridge with vlan_filtering=1 to make this > more predictable for the user? ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents a658a3f + 314f76d commit 4925930

File tree

9 files changed

+156
-63
lines changed

9 files changed

+156
-63
lines changed

drivers/net/dsa/b53/b53_common.c

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,6 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable,
428428
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
429429

430430
dev->vlan_enabled = enable;
431-
dev->vlan_filtering_enabled = enable_filtering;
432431
}
433432

434433
static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100)
@@ -665,7 +664,7 @@ int b53_configure_vlan(struct dsa_switch *ds)
665664
b53_do_vlan_op(dev, VTA_CMD_CLEAR);
666665
}
667666

668-
b53_enable_vlan(dev, false, dev->vlan_filtering_enabled);
667+
b53_enable_vlan(dev, false, ds->vlan_filtering);
669668

670669
b53_for_each_port(dev, i)
671670
b53_write16(dev, B53_VLAN_PAGE,
@@ -966,6 +965,13 @@ static int b53_setup(struct dsa_switch *ds)
966965
b53_disable_port(ds, port);
967966
}
968967

968+
/* Let DSA handle the case were multiple bridges span the same switch
969+
* device and different VLAN awareness settings are requested, which
970+
* would be breaking filtering semantics for any of the other bridge
971+
* devices. (not hardware supported)
972+
*/
973+
ds->vlan_filtering_is_global = true;
974+
969975
return ret;
970976
}
971977

@@ -1275,35 +1281,17 @@ EXPORT_SYMBOL(b53_phylink_mac_link_up);
12751281
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
12761282
{
12771283
struct b53_device *dev = ds->priv;
1278-
struct net_device *bridge_dev;
1279-
unsigned int i;
12801284
u16 pvid, new_pvid;
12811285

1282-
/* Handle the case were multiple bridges span the same switch device
1283-
* and one of them has a different setting than what is being requested
1284-
* which would be breaking filtering semantics for any of the other
1285-
* bridge devices.
1286-
*/
1287-
b53_for_each_port(dev, i) {
1288-
bridge_dev = dsa_to_port(ds, i)->bridge_dev;
1289-
if (bridge_dev &&
1290-
bridge_dev != dsa_to_port(ds, port)->bridge_dev &&
1291-
br_vlan_enabled(bridge_dev) != vlan_filtering) {
1292-
netdev_err(bridge_dev,
1293-
"VLAN filtering is global to the switch!\n");
1294-
return -EINVAL;
1295-
}
1296-
}
1297-
12981286
b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid);
12991287
new_pvid = pvid;
1300-
if (dev->vlan_filtering_enabled && !vlan_filtering) {
1288+
if (!vlan_filtering) {
13011289
/* Filtering is currently enabled, use the default PVID since
13021290
* the bridge does not expect tagging anymore
13031291
*/
13041292
dev->ports[port].pvid = pvid;
13051293
new_pvid = b53_default_pvid(dev);
1306-
} else if (!dev->vlan_filtering_enabled && vlan_filtering) {
1294+
} else {
13071295
/* Filtering is currently disabled, restore the previous PVID */
13081296
new_pvid = dev->ports[port].pvid;
13091297
}
@@ -1329,7 +1317,7 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port,
13291317
if (vlan->vid_end > dev->num_vlans)
13301318
return -ERANGE;
13311319

1332-
b53_enable_vlan(dev, true, dev->vlan_filtering_enabled);
1320+
b53_enable_vlan(dev, true, ds->vlan_filtering);
13331321

13341322
return 0;
13351323
}

drivers/net/dsa/b53/b53_priv.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ struct b53_device {
139139
unsigned int num_vlans;
140140
struct b53_vlan *vlans;
141141
bool vlan_enabled;
142-
bool vlan_filtering_enabled;
143142
unsigned int num_ports;
144143
struct b53_port *ports;
145144
};

drivers/net/dsa/mt7530.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -828,11 +828,9 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
828828
mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
829829
VLAN_ATTR(MT7530_VLAN_TRANSPARENT));
830830

831-
priv->ports[port].vlan_filtering = false;
832-
833831
for (i = 0; i < MT7530_NUM_PORTS; i++) {
834832
if (dsa_is_user_port(ds, i) &&
835-
priv->ports[i].vlan_filtering) {
833+
dsa_port_is_vlan_filtering(&ds->ports[i])) {
836834
all_user_ports_removed = false;
837835
break;
838836
}
@@ -891,8 +889,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
891889
* And the other port's port matrix cannot be broken when the
892890
* other port is still a VLAN-aware port.
893891
*/
894-
if (!priv->ports[i].vlan_filtering &&
895-
dsa_is_user_port(ds, i) && i != port) {
892+
if (dsa_is_user_port(ds, i) && i != port &&
893+
!dsa_port_is_vlan_filtering(&ds->ports[i])) {
896894
if (dsa_to_port(ds, i)->bridge_dev != bridge)
897895
continue;
898896
if (priv->ports[i].enable)
@@ -910,8 +908,6 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
910908
PCR_MATRIX(BIT(MT7530_CPU_PORT)));
911909
priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
912910

913-
mt7530_port_set_vlan_unaware(ds, port);
914-
915911
mutex_unlock(&priv->reg_mutex);
916912
}
917913

@@ -1013,10 +1009,6 @@ static int
10131009
mt7530_port_vlan_filtering(struct dsa_switch *ds, int port,
10141010
bool vlan_filtering)
10151011
{
1016-
struct mt7530_priv *priv = ds->priv;
1017-
1018-
priv->ports[port].vlan_filtering = vlan_filtering;
1019-
10201012
if (vlan_filtering) {
10211013
/* The port is being kept as VLAN-unaware port when bridge is
10221014
* set up with vlan_filtering not being set, Otherwise, the
@@ -1025,6 +1017,8 @@ mt7530_port_vlan_filtering(struct dsa_switch *ds, int port,
10251017
*/
10261018
mt7530_port_set_vlan_aware(ds, port);
10271019
mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT);
1020+
} else {
1021+
mt7530_port_set_vlan_unaware(ds, port);
10281022
}
10291023

10301024
return 0;
@@ -1139,7 +1133,7 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port,
11391133
/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
11401134
* being set.
11411135
*/
1142-
if (!priv->ports[port].vlan_filtering)
1136+
if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
11431137
return;
11441138

11451139
mutex_lock(&priv->reg_mutex);
@@ -1170,7 +1164,7 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
11701164
/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
11711165
* being set.
11721166
*/
1173-
if (!priv->ports[port].vlan_filtering)
1167+
if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
11741168
return 0;
11751169

11761170
mutex_lock(&priv->reg_mutex);

drivers/net/dsa/mt7530.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,6 @@ struct mt7530_port {
410410
bool enable;
411411
u32 pm;
412412
u16 pvid;
413-
bool vlan_filtering;
414413
};
415414

416415
/* struct mt7530_priv - This is the main data structure for holding the state

include/net/dsa.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ struct dsa_port {
161161
const char *mac;
162162
struct device_node *dn;
163163
unsigned int ageing_time;
164+
bool vlan_filtering;
164165
u8 stp_state;
165166
struct net_device *bridge_dev;
166167
struct devlink_port devlink_port;
@@ -227,6 +228,16 @@ struct dsa_switch {
227228
/* Number of switch port queues */
228229
unsigned int num_tx_queues;
229230

231+
/* Disallow bridge core from requesting different VLAN awareness
232+
* settings on ports if not hardware-supported
233+
*/
234+
bool vlan_filtering_is_global;
235+
236+
/* In case vlan_filtering_is_global is set, the VLAN awareness state
237+
* should be retrieved from here and not from the per-port settings.
238+
*/
239+
bool vlan_filtering;
240+
230241
unsigned long *bitmap;
231242
unsigned long _bitmap;
232243

@@ -294,6 +305,16 @@ static inline unsigned int dsa_upstream_port(struct dsa_switch *ds, int port)
294305
return dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index);
295306
}
296307

308+
static inline bool dsa_port_is_vlan_filtering(const struct dsa_port *dp)
309+
{
310+
const struct dsa_switch *ds = dp->ds;
311+
312+
if (ds->vlan_filtering_is_global)
313+
return ds->vlan_filtering;
314+
else
315+
return dp->vlan_filtering;
316+
}
317+
297318
typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
298319
bool is_static, void *data);
299320
struct dsa_switch_ops {

net/dsa/dsa_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ int dsa_port_vlan_add(struct dsa_port *dp,
171171
struct switchdev_trans *trans);
172172
int dsa_port_vlan_del(struct dsa_port *dp,
173173
const struct switchdev_obj_port_vlan *vlan);
174+
int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags);
175+
int dsa_port_vid_del(struct dsa_port *dp, u16 vid);
174176
int dsa_port_link_register_of(struct dsa_port *dp);
175177
void dsa_port_link_unregister_of(struct dsa_port *dp);
176178

net/dsa/port.c

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,67 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
154154
dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
155155
}
156156

157+
static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
158+
bool vlan_filtering)
159+
{
160+
struct dsa_switch *ds = dp->ds;
161+
int i;
162+
163+
if (!ds->vlan_filtering_is_global)
164+
return true;
165+
166+
/* For cases where enabling/disabling VLAN awareness is global to the
167+
* switch, we need to handle the case where multiple bridges span
168+
* different ports of the same switch device and one of them has a
169+
* different setting than what is being requested.
170+
*/
171+
for (i = 0; i < ds->num_ports; i++) {
172+
struct net_device *other_bridge;
173+
174+
other_bridge = dsa_to_port(ds, i)->bridge_dev;
175+
if (!other_bridge)
176+
continue;
177+
/* If it's the same bridge, it also has same
178+
* vlan_filtering setting => no need to check
179+
*/
180+
if (other_bridge == dp->bridge_dev)
181+
continue;
182+
if (br_vlan_enabled(other_bridge) != vlan_filtering) {
183+
dev_err(ds->dev, "VLAN filtering is a global setting\n");
184+
return false;
185+
}
186+
}
187+
return true;
188+
}
189+
157190
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
158191
struct switchdev_trans *trans)
159192
{
160193
struct dsa_switch *ds = dp->ds;
194+
int err;
161195

162196
/* bridge skips -EOPNOTSUPP, so skip the prepare phase */
163197
if (switchdev_trans_ph_prepare(trans))
164198
return 0;
165199

166-
if (ds->ops->port_vlan_filtering)
167-
return ds->ops->port_vlan_filtering(ds, dp->index,
168-
vlan_filtering);
200+
if (!ds->ops->port_vlan_filtering)
201+
return 0;
202+
203+
if (!dsa_port_can_apply_vlan_filtering(dp, vlan_filtering))
204+
return -EINVAL;
205+
206+
if (dsa_port_is_vlan_filtering(dp) == vlan_filtering)
207+
return 0;
208+
209+
err = ds->ops->port_vlan_filtering(ds, dp->index,
210+
vlan_filtering);
211+
if (err)
212+
return err;
169213

214+
if (ds->vlan_filtering_is_global)
215+
ds->vlan_filtering = vlan_filtering;
216+
else
217+
dp->vlan_filtering = vlan_filtering;
170218
return 0;
171219
}
172220

@@ -322,6 +370,37 @@ int dsa_port_vlan_del(struct dsa_port *dp,
322370
return 0;
323371
}
324372

373+
int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags)
374+
{
375+
struct switchdev_obj_port_vlan vlan = {
376+
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
377+
.flags = flags,
378+
.vid_begin = vid,
379+
.vid_end = vid,
380+
};
381+
struct switchdev_trans trans;
382+
int err;
383+
384+
trans.ph_prepare = true;
385+
err = dsa_port_vlan_add(dp, &vlan, &trans);
386+
if (err == -EOPNOTSUPP)
387+
return 0;
388+
389+
trans.ph_prepare = false;
390+
return dsa_port_vlan_add(dp, &vlan, &trans);
391+
}
392+
393+
int dsa_port_vid_del(struct dsa_port *dp, u16 vid)
394+
{
395+
struct switchdev_obj_port_vlan vlan = {
396+
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
397+
.vid_begin = vid,
398+
.vid_end = vid,
399+
};
400+
401+
return dsa_port_vlan_del(dp, &vlan);
402+
}
403+
325404
static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
326405
{
327406
struct device_node *phy_dn;

net/dsa/slave.c

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,13 +1001,6 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
10011001
u16 vid)
10021002
{
10031003
struct dsa_port *dp = dsa_slave_to_port(dev);
1004-
struct switchdev_obj_port_vlan vlan = {
1005-
.vid_begin = vid,
1006-
.vid_end = vid,
1007-
/* This API only allows programming tagged, non-PVID VIDs */
1008-
.flags = 0,
1009-
};
1010-
struct switchdev_trans trans;
10111004
struct bridge_vlan_info info;
10121005
int ret;
10131006

@@ -1024,25 +1017,14 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
10241017
return -EBUSY;
10251018
}
10261019

1027-
trans.ph_prepare = true;
1028-
ret = dsa_port_vlan_add(dp, &vlan, &trans);
1029-
if (ret == -EOPNOTSUPP)
1030-
return 0;
1031-
1032-
trans.ph_prepare = false;
1033-
return dsa_port_vlan_add(dp, &vlan, &trans);
1020+
/* This API only allows programming tagged, non-PVID VIDs */
1021+
return dsa_port_vid_add(dp, vid, 0);
10341022
}
10351023

10361024
static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
10371025
u16 vid)
10381026
{
10391027
struct dsa_port *dp = dsa_slave_to_port(dev);
1040-
struct switchdev_obj_port_vlan vlan = {
1041-
.vid_begin = vid,
1042-
.vid_end = vid,
1043-
/* This API only allows programming tagged, non-PVID VIDs */
1044-
.flags = 0,
1045-
};
10461028
struct bridge_vlan_info info;
10471029
int ret;
10481030

@@ -1059,7 +1041,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
10591041
return -EBUSY;
10601042
}
10611043

1062-
ret = dsa_port_vlan_del(dp, &vlan);
1044+
ret = dsa_port_vid_del(dp, vid);
10631045
if (ret == -EOPNOTSUPP)
10641046
ret = 0;
10651047

0 commit comments

Comments
 (0)