Add support for offloading learning and broadcast flooding flags. With
this in place, mv88e6xx supports offloading of all bridge port flags
that are currently supported by the bridge.
Broadcast flooding is somewhat awkward to control as there is no
per-port bit for this like there is for unknown unicast and unknown
multicast. Instead we have to update the ATU entry for the broadcast
address for all currently used FIDs.
v1 -> v2:
- Ensure that mv88e6xxx_vtu_get handles VID 0 (Vladimir)
- Fixed off-by-one in mv88e6xxx_port_set_assoc_vector (Vladimir)
- Fast age all entries on port when disabling learning (Vladimir)
- Correctly detect bridge flags on LAG ports (Vladimir)
Tobias Waldekranz (8):
net: dsa: Add helper to resolve bridge port from DSA port
net: dsa: mv88e6xxx: Avoid useless attempts to fast-age LAGs
net: dsa: mv88e6xxx: Provide generic VTU iterator
net: dsa: mv88e6xxx: Remove some bureaucracy around querying the VTU
net: dsa: mv88e6xxx: Use standard helper for broadcast address
net: dsa: mv88e6xxx: Flood all traffic classes on standalone ports
net: dsa: mv88e6xxx: Offload bridge learning flag
net: dsa: mv88e6xxx: Offload bridge broadcast flooding flag
drivers/net/dsa/mv88e6xxx/chip.c | 272 ++++++++++++++++++++++---------
drivers/net/dsa/mv88e6xxx/port.c | 21 +++
drivers/net/dsa/mv88e6xxx/port.h | 2 +
include/net/dsa.h | 14 ++
net/dsa/dsa_priv.h | 14 +-
5 files changed, 234 insertions(+), 89 deletions(-)
--
2.25.1
When a port is a part of a LAG, the ATU will create dynamic entries
belonging to the LAG ID when learning is enabled. So trying to
fast-age those out using the constituent port will have no
effect. Unfortunately the hardware does not support move operations on
LAGs so there is no obvious way to transform the request to target the
LAG instead.
Instead we document this known limitation and at least avoid wasting
any time on it.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 7 +++++++
1 file changed, 7 insertions(+)
@@ -1479,6 +1479,13 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)structmv88e6xxx_chip*chip=ds->priv;interr;+if(dsa_to_port(ds,port)->lag_dev)+/* Hardware is incapable of fast-aging a LAG through a+*regularATUmoveoperation.Untilwehavesomething+*morefancyinplacethisisano-op.+*/+return;+mv88e6xxx_reg_lock(chip);err=mv88e6xxx_g1_atu_remove(chip,0,port,false);mv88e6xxx_reg_unlock(chip);
In order for a driver to be able to query a bridge for information
about itself, e.g. reading out port flags, it has to use a netdev that
is known to the bridge. In the simple case, that is just the netdev
representing the port, e.g. swp0 or swp1 in this example:
br0
/ \
swp0 swp1
But in the case of an offloaded lag, this will be the bond or team
interface, e.g. bond0 in this example:
br0
/
bond0
/ \
swp0 swp1
Add a helper that hides some of this complexity from the
drivers. Then, redefine dsa_port_offloads_bridge_port using the helper
to avoid double accounting of the set of possible offloaded uppers.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
include/net/dsa.h | 14 ++++++++++++++
net/dsa/dsa_priv.h | 14 +-------------
2 files changed, 15 insertions(+), 13 deletions(-)
@@ -233,19 +233,7 @@ extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;staticinlinebooldsa_port_offloads_bridge_port(structdsa_port*dp,structnet_device*dev){-/* Switchdev offloading can be configured on: */--if(dev==dp->slave)-/* DSA ports directly connected to a bridge, and event-*wasemittedfortheportsthemselves.-*/-returntrue;--if(dp->lag_dev==dev)-/* DSA ports connected to a bridge via a LAG */-returntrue;--returnfalse;+returndsa_port_to_bridge_port(dp)==dev;}staticinlinebooldsa_port_offloads_bridge(structdsa_port*dp,
Use the conventional declaration style of a MAC address in the
kernel (u8 addr[ETH_ALEN]) for the broadcast address, then set it
using the existing helper.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
The hardware has a somewhat quirky protocol for reading out the VTU
entry for a particular VID. But there is no reason why we cannot
create a better API for ourselves in the driver.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 45 ++++++++++++++------------------
1 file changed, 20 insertions(+), 25 deletions(-)
@@ -1502,13 +1502,23 @@ static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)returnmv88e6xxx_g1_vtu_flush(chip);}-staticintmv88e6xxx_vtu_getnext(structmv88e6xxx_chip*chip,-structmv88e6xxx_vtu_entry*entry)+staticintmv88e6xxx_vtu_get(structmv88e6xxx_chip*chip,u16vid,+structmv88e6xxx_vtu_entry*entry){+interr;+if(!chip->info->ops->vtu_getnext)return-EOPNOTSUPP;-returnchip->info->ops->vtu_getnext(chip,entry);+entry->vid=vid?vid-1:mv88e6xxx_max_vid(chip);+entry->valid=false;++err=chip->info->ops->vtu_getnext(chip,entry);++if(entry->vid!=vid)+entry->valid=false;++returnerr;}staticintmv88e6xxx_vtu_walk(structmv88e6xxx_chip*chip,
@@ -1615,19 +1625,13 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,if(dsa_is_dsa_port(ds,port)||dsa_is_cpu_port(ds,port))return0;-vlan.vid=vid-1;-vlan.valid=false;--err=mv88e6xxx_vtu_getnext(chip,&vlan);+err=mv88e6xxx_vtu_get(chip,vid,&vlan);if(err)returnerr;if(!vlan.valid)return0;-if(vlan.vid!=vid)-return0;-for(i=0;i<mv88e6xxx_num_ports(chip);++i){if(dsa_is_dsa_port(ds,i)||dsa_is_cpu_port(ds,i))continue;
@@ -1709,15 +1713,12 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,if(err)returnerr;}else{-vlan.vid=vid-1;-vlan.valid=false;--err=mv88e6xxx_vtu_getnext(chip,&vlan);+err=mv88e6xxx_vtu_get(chip,vid,&vlan);if(err)returnerr;/* switchdev expects -EOPNOTSUPP to honor software VLANs */-if(vlan.vid!=vid||!vlan.valid)+if(!vlan.valid)return-EOPNOTSUPP;fid=vlan.fid;
@@ -1994,14 +1995,11 @@ static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,structmv88e6xxx_vtu_entryvlan;inti,err;-vlan.vid=vid-1;-vlan.valid=false;--err=mv88e6xxx_vtu_getnext(chip,&vlan);+err=mv88e6xxx_vtu_get(chip,vid,&vlan);if(err)returnerr;-if(vlan.vid!=vid||!vlan.valid){+if(!vlan.valid){memset(&vlan,0,sizeof(vlan));err=mv88e6xxx_atu_new(chip,&vlan.fid);
@@ -2097,17 +2095,14 @@ static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,if(!vid)return-EOPNOTSUPP;-vlan.vid=vid-1;-vlan.valid=false;--err=mv88e6xxx_vtu_getnext(chip,&vlan);+err=mv88e6xxx_vtu_get(chip,vid,&vlan);if(err)returnerr;/* If the VLAN doesn't exist in hardware or the port isn't a member,*tellswitchdevthatthisVLANislikelyhandledinsoftware.*/-if(vlan.vid!=vid||!vlan.valid||+if(!vlan.valid||vlan.member[port]==MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)return-EOPNOTSUPP;
Allow a user to control automatic learning per port.
Many chips have an explicit "LearningDisable"-bit that can be used for
this, but we opt for setting/clearing the PAV instead, as it works on
all devices at least as far back as 6083.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 37 +++++++++++++++++++++++++-------
drivers/net/dsa/mv88e6xxx/port.c | 21 ++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 2 ++
3 files changed, 52 insertions(+), 8 deletions(-)
@@ -2740,15 +2740,20 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)returnerr;}-/* Port Association Vector: when learning source addresses-*ofpackets,addtheaddresstotheaddressdatabaseusing-*aportbitmapthathasonlythebitforthisportsetand-*theotherbitsclear.+/* Port Association Vector: disable automatic address learning+*onalluserportssincetheystartoutinstandalone+*mode.Whenjoiningabridge,learningwillbeconfiguredto+*matchthebridgeportsettings.Enablelearningonall+*DSA/CPUports.NOTE:FROM_CPUframesalwaysbypassthe+*learningprocess.+*+*DisableHoldAt1,IntOnAgeOut,LockedPort,IgnoreWrongData,+*andRefreshLocked.I.e.setupstandardautomaticlearning.*/-reg=1<<port;-/* Disable learning for CPU port */-if(dsa_is_cpu_port(ds,port))+if(dsa_is_user_port(ds,port))reg=0;+else+reg=1<<port;err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,reg);
@@ -5604,7 +5609,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,structmv88e6xxx_chip*chip=ds->priv;conststructmv88e6xxx_ops*ops;-if(flags.mask&~(BR_FLOOD|BR_MCAST_FLOOD))+if(flags.mask&~(BR_LEARNING|BR_FLOOD|BR_MCAST_FLOOD))return-EINVAL;ops=chip->info->ops;
@@ -5623,10 +5628,23 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,structnetlink_ext_ack*extack){structmv88e6xxx_chip*chip=ds->priv;+booldo_fast_age=false;interr=-EOPNOTSUPP;mv88e6xxx_reg_lock(chip);+if(flags.mask&BR_LEARNING){+boollearning=!!(flags.val&BR_LEARNING);+u16pav=learning?(1<<port):0;++err=mv88e6xxx_port_set_assoc_vector(chip,port,pav);+if(err)+gotoout;++if(!learning)+do_fast_age=true;+}+if(flags.mask&BR_FLOOD){boolunicast=!!(flags.val&BR_FLOOD);
@@ -5648,6 +5666,9 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,out:mv88e6xxx_reg_unlock(chip);+if(do_fast_age)+mv88e6xxx_port_fast_age(ds,port);+returnerr;}
@@ -1309,6 +1309,27 @@ int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)0x0001);}+/* Offset 0x0B: Port Association Vector */++intmv88e6xxx_port_set_assoc_vector(structmv88e6xxx_chip*chip,intport,+u16pav)+{+u16reg,mask;+interr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,+®);+if(err)+returnerr;++mask=mv88e6xxx_port_mask(chip);+reg&=~mask;+reg|=pav&mask;++returnmv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,+reg);+}+/* Offset 0x0C: Port ATU Control */intmv88e6xxx_port_disable_learn_limit(structmv88e6xxx_chip*chip,intport)
@@ -407,6 +407,8 @@ int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,size_tsize);intmv88e6095_port_egress_rate_limiting(structmv88e6xxx_chip*chip,intport);intmv88e6097_port_egress_rate_limiting(structmv88e6xxx_chip*chip,intport);+intmv88e6xxx_port_set_assoc_vector(structmv88e6xxx_chip*chip,intport,+u16pav);intmv88e6097_port_pause_limit(structmv88e6xxx_chip*chip,intport,u8in,u8out);intmv88e6390_port_pause_limit(structmv88e6xxx_chip*chip,intport,u8in,
These switches have two modes of classifying broadcast:
1. Broadcast is multicast.
2. Broadcast is its own unique thing that is always flooded
everywhere.
This driver uses the first option, making sure to load the broadcast
address into all active databases. Because of this, we can support
per-port broadcast flooding by (1) making sure to only set the subset
of ports that have it enabled whenever joining a new bridge or VLAN,
and (2) by updating all active databases whenever the setting is
changed on a port.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 73 +++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
@@ -1982,6 +1982,21 @@ static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)interr;for(port=0;port<mv88e6xxx_num_ports(chip);port++){+structdsa_port*dp=dsa_to_port(chip->ds,port);+structnet_device*brport;++if(dsa_is_unused_port(chip->ds,port))+continue;++brport=dsa_port_to_bridge_port(dp);++if(dp->bridge_dev&&+!br_port_flag_is_set(brport,BR_BCAST_FLOOD))+/* Skip bridged user ports where broadcast+*floodingisdisabled.+*/+continue;+err=mv88e6xxx_port_add_broadcast(chip,port,vid);if(err)returnerr;
@@ -1990,6 +2005,53 @@ static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)return0;}+structmv88e6xxx_port_broadcast_sync_ctx{+intport;+boolflood;+};++staticint+mv88e6xxx_port_broadcast_sync_vlan(structmv88e6xxx_chip*chip,+conststructmv88e6xxx_vtu_entry*vlan,+void*_ctx)+{+structmv88e6xxx_port_broadcast_sync_ctx*ctx=_ctx;+u8broadcast[ETH_ALEN];+u8state;++if(ctx->flood)+state=MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;+else+state=MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED;++eth_broadcast_addr(broadcast);++returnmv88e6xxx_port_db_load_purge(chip,ctx->port,broadcast,+vlan->vid,state);+}++staticintmv88e6xxx_port_broadcast_sync(structmv88e6xxx_chip*chip,intport,+boolflood)+{+structmv88e6xxx_port_broadcast_sync_ctxctx={+.port=port,+.flood=flood,+};+structmv88e6xxx_vtu_entryvid0={+.vid=0,+};+interr;++/* Update the port's private database... */+err=mv88e6xxx_port_broadcast_sync_vlan(chip,&vid0,&ctx);+if(err)+returnerr;++/* ...and the database for all VLANs. */+returnmv88e6xxx_vtu_walk(chip,mv88e6xxx_port_broadcast_sync_vlan,+&ctx);+}+staticintmv88e6xxx_port_vlan_join(structmv88e6xxx_chip*chip,intport,u16vid,u8member,boolwarn){
@@ -5609,7 +5671,8 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,structmv88e6xxx_chip*chip=ds->priv;conststructmv88e6xxx_ops*ops;-if(flags.mask&~(BR_LEARNING|BR_FLOOD|BR_MCAST_FLOOD))+if(flags.mask&~(BR_LEARNING|BR_FLOOD|BR_MCAST_FLOOD|+BR_BCAST_FLOOD))return-EINVAL;ops=chip->info->ops;
@@ -5663,6 +5726,14 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,gotoout;}+if(flags.mask&BR_BCAST_FLOOD){+boolbroadcast=!!(flags.val&BR_BCAST_FLOOD);++err=mv88e6xxx_port_broadcast_sync(chip,port,broadcast);+if(err)+gotoout;+}+out:mv88e6xxx_reg_unlock(chip);
Move the intricacies of correctly iterating over the VTU to a common
implementation.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 100 ++++++++++++++++++++-----------
1 file changed, 64 insertions(+), 36 deletions(-)
@@ -1511,6 +1511,37 @@ static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,returnchip->info->ops->vtu_getnext(chip,entry);}+staticintmv88e6xxx_vtu_walk(structmv88e6xxx_chip*chip,+int(*cb)(structmv88e6xxx_chip*chip,+conststructmv88e6xxx_vtu_entry*entry,+void*priv),+void*priv)+{+structmv88e6xxx_vtu_entryentry={+.vid=mv88e6xxx_max_vid(chip),+.valid=false,+};+interr;++if(!chip->info->ops->vtu_getnext)+return-EOPNOTSUPP;++do{+err=chip->info->ops->vtu_getnext(chip,&entry);+if(err)+returnerr;++if(!entry.valid)+break;++err=cb(chip,&entry,priv);+if(err)+returnerr;+}while(entry.vid<mv88e6xxx_max_vid(chip));++return0;+}+staticintmv88e6xxx_vtu_loadpurge(structmv88e6xxx_chip*chip,structmv88e6xxx_vtu_entry*entry){
@@ -1520,9 +1551,18 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,returnchip->info->ops->vtu_loadpurge(chip,entry);}+staticintmv88e6xxx_fid_map_vlan(structmv88e6xxx_chip*chip,+conststructmv88e6xxx_vtu_entry*entry,+void*_fid_bitmap)+{+unsignedlong*fid_bitmap=_fid_bitmap;++set_bit(entry->fid,fid_bitmap);+return0;+}+intmv88e6xxx_fid_map(structmv88e6xxx_chip*chip,unsignedlong*fid_bitmap){-structmv88e6xxx_vtu_entryvlan;inti,err;u16fid;
@@ -1538,21 +1578,7 @@ int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap)}/* Set every FID bit used by the VLAN entries */-vlan.vid=mv88e6xxx_max_vid(chip);-vlan.valid=false;--do{-err=mv88e6xxx_vtu_getnext(chip,&vlan);-if(err)-returnerr;--if(!vlan.valid)-break;--set_bit(vlan.fid,fid_bitmap);-}while(vlan.vid<mv88e6xxx_max_vid(chip));--return0;+returnmv88e6xxx_vtu_walk(chip,mv88e6xxx_fid_map_vlan,fid_bitmap);}staticintmv88e6xxx_atu_new(structmv88e6xxx_chip*chip,u16*fid)
@@ -2198,10 +2224,30 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,returnerr;}+structmv88e6xxx_port_db_dump_vlan_ctx{+intport;+dsa_fdb_dump_cb_t*cb;+void*data;+};++staticintmv88e6xxx_port_db_dump_vlan(structmv88e6xxx_chip*chip,+conststructmv88e6xxx_vtu_entry*entry,+void*_data)+{+structmv88e6xxx_port_db_dump_vlan_ctx*ctx=_data;++returnmv88e6xxx_port_db_dump_fid(chip,entry->fid,entry->vid,+ctx->port,ctx->cb,ctx->data);+}+staticintmv88e6xxx_port_db_dump(structmv88e6xxx_chip*chip,intport,dsa_fdb_dump_cb_t*cb,void*data){-structmv88e6xxx_vtu_entryvlan;+structmv88e6xxx_port_db_dump_vlan_ctxctx={+.port=port,+.cb=cb,+.data=data,+};u16fid;interr;
@@ -2214,25 +2260,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,if(err)returnerr;-/* Dump VLANs' Filtering Information Databases */-vlan.vid=mv88e6xxx_max_vid(chip);-vlan.valid=false;--do{-err=mv88e6xxx_vtu_getnext(chip,&vlan);-if(err)-returnerr;--if(!vlan.valid)-break;--err=mv88e6xxx_port_db_dump_fid(chip,vlan.fid,vlan.vid,port,-cb,data);-if(err)-returnerr;-}while(vlan.vid<mv88e6xxx_max_vid(chip));--returnerr;+returnmv88e6xxx_vtu_walk(chip,mv88e6xxx_port_db_dump_vlan,&ctx);}staticintmv88e6xxx_port_fdb_dump(structdsa_switch*ds,intport,
In accordance with the comment in dsa_port_bridge_leave, standalone
ports shall be configured to flood all types of traffic. This change
aligns the mv88e6xxx driver with that policy.
Previously a standalone port would initially not egress any unknown
traffic, but after joining and then leaving a bridge, it would.
This does not matter that much since we only ever send FROM_CPUs on
standalone ports, but it seems prudent to make sure that the initial
values match those that are applied after a bridging/unbridging cycle.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
@@ -2489,19 +2489,15 @@ static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)staticintmv88e6xxx_setup_egress_floods(structmv88e6xxx_chip*chip,intport){-structdsa_switch*ds=chip->ds;-boolflood;interr;-/* Upstream ports flood frames with unknown unicast or multicast DA */-flood=dsa_is_cpu_port(ds,port)||dsa_is_dsa_port(ds,port);if(chip->info->ops->port_set_ucast_flood){-err=chip->info->ops->port_set_ucast_flood(chip,port,flood);+err=chip->info->ops->port_set_ucast_flood(chip,port,true);if(err)returnerr;}if(chip->info->ops->port_set_mcast_flood){-err=chip->info->ops->port_set_mcast_flood(chip,port,flood);+err=chip->info->ops->port_set_mcast_flood(chip,port,true);if(err)returnerr;}
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:27:52
On Thu, Mar 18, 2021 at 03:15:45PM +0100, Tobias Waldekranz wrote:
Move the intricacies of correctly iterating over the VTU to a common
implementation.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:28:59
On Thu, Mar 18, 2021 at 03:15:46PM +0100, Tobias Waldekranz wrote:
The hardware has a somewhat quirky protocol for reading out the VTU
entry for a particular VID. But there is no reason why we cannot
create a better API for ourselves in the driver.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:29:30
On Thu, Mar 18, 2021 at 03:15:47PM +0100, Tobias Waldekranz wrote:
Use the conventional declaration style of a MAC address in the
kernel (u8 addr[ETH_ALEN]) for the broadcast address, then set it
using the existing helper.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:31:09
On Thu, Mar 18, 2021 at 03:15:49PM +0100, Tobias Waldekranz wrote:
Allow a user to control automatic learning per port.
Many chips have an explicit "LearningDisable"-bit that can be used for
this, but we opt for setting/clearing the PAV instead, as it works on
all devices at least as far back as 6083.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:36:02
On Thu, Mar 18, 2021 at 03:15:50PM +0100, Tobias Waldekranz wrote:
quoted hunk
These switches have two modes of classifying broadcast:
1. Broadcast is multicast.
2. Broadcast is its own unique thing that is always flooded
everywhere.
This driver uses the first option, making sure to load the broadcast
address into all active databases. Because of this, we can support
per-port broadcast flooding by (1) making sure to only set the subset
of ports that have it enabled whenever joining a new bridge or VLAN,
and (2) by updating all active databases whenever the setting is
changed on a port.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 73 +++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
I think I would have liked to see a dsa_port_to_bridge_port helper that
actually returns NULL when dp->bridge_dev is NULL.
This would make your piece of code look as follows:
brport = dsa_port_to_bridge_port(dp);
if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD)
continue;
+ /* Skip bridged user ports where broadcast
+ * flooding is disabled.
+ */
+ continue;
+
err = mv88e6xxx_port_add_broadcast(chip, port, vid);
if (err)
return err;
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:37:06
On Thu, Mar 18, 2021 at 03:15:44PM +0100, Tobias Waldekranz wrote:
When a port is a part of a LAG, the ATU will create dynamic entries
belonging to the LAG ID when learning is enabled. So trying to
fast-age those out using the constituent port will have no
effect. Unfortunately the hardware does not support move operations on
LAGs so there is no obvious way to transform the request to target the
LAG instead.
Instead we document this known limitation and at least avoid wasting
any time on it.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-03-18 14:45:05
On Thu, Mar 18, 2021 at 03:15:43PM +0100, Tobias Waldekranz wrote:
quoted hunk
In order for a driver to be able to query a bridge for information
about itself, e.g. reading out port flags, it has to use a netdev that
is known to the bridge. In the simple case, that is just the netdev
representing the port, e.g. swp0 or swp1 in this example:
br0
/ \
swp0 swp1
But in the case of an offloaded lag, this will be the bond or team
interface, e.g. bond0 in this example:
br0
/
bond0
/ \
swp0 swp1
Add a helper that hides some of this complexity from the
drivers. Then, redefine dsa_port_offloads_bridge_port using the helper
to avoid double accounting of the set of possible offloaded uppers.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
include/net/dsa.h | 14 ++++++++++++++
net/dsa/dsa_priv.h | 14 +-------------
2 files changed, 15 insertions(+), 13 deletions(-)
According to my comment from 8/8, you could have replaced this here with
if (!dp->bridge_dev)
return NULL;
I think it's more intuitive to not return a bridge port if there isn't
any bridge to speak of. Whether you prefer to do that or not is up to
you, here's my review tag anyway.
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
In order for a driver to be able to query a bridge for information
about itself, e.g. reading out port flags, it has to use a netdev that
is known to the bridge. In the simple case, that is just the netdev
representing the port, e.g. swp0 or swp1 in this example:
br0
/ \
swp0 swp1
But in the case of an offloaded lag, this will be the bond or team
interface, e.g. bond0 in this example:
br0
/
bond0
/ \
swp0 swp1
Add a helper that hides some of this complexity from the
drivers. Then, redefine dsa_port_offloads_bridge_port using the helper
to avoid double accounting of the set of possible offloaded uppers.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
When a port is a part of a LAG, the ATU will create dynamic entries
belonging to the LAG ID when learning is enabled. So trying to
fast-age those out using the constituent port will have no
effect. Unfortunately the hardware does not support move operations on
LAGs so there is no obvious way to transform the request to target the
LAG instead.
Instead we document this known limitation and at least avoid wasting
any time on it.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Move the intricacies of correctly iterating over the VTU to a common
implementation.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
The hardware has a somewhat quirky protocol for reading out the VTU
entry for a particular VID. But there is no reason why we cannot
create a better API for ourselves in the driver.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Use the conventional declaration style of a MAC address in the
kernel (u8 addr[ETH_ALEN]) for the broadcast address, then set it
using the existing helper.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Allow a user to control automatic learning per port.
Many chips have an explicit "LearningDisable"-bit that can be used for
this, but we opt for setting/clearing the PAV instead, as it works on
all devices at least as far back as 6083.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
On Thu, Mar 18, 2021 at 03:15:50PM +0100, Tobias Waldekranz wrote:
quoted
These switches have two modes of classifying broadcast:
1. Broadcast is multicast.
2. Broadcast is its own unique thing that is always flooded
everywhere.
This driver uses the first option, making sure to load the broadcast
address into all active databases. Because of this, we can support
per-port broadcast flooding by (1) making sure to only set the subset
of ports that have it enabled whenever joining a new bridge or VLAN,
and (2) by updating all active databases whenever the setting is
changed on a port.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 73 +++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
I think I would have liked to see a dsa_port_to_bridge_port helper that
actually returns NULL when dp->bridge_dev is NULL.
This would make your piece of code look as follows:
brport = dsa_port_to_bridge_port(dp);
if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD)
continue;
Agreed, with that fixed:
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
--
Florian