* [PATCH net-next 1/5] net: dsa: mv88e6xxx: lock mutex in vlan_prepare
2019-08-01 18:36 [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations Vivien Didelot
@ 2019-08-01 18:36 ` Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 2/5] net: dsa: mv88e6xxx: explicit entry passed to vtu_getnext Vivien Didelot
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
andrew, netdev, davem
Lock the mutex in the mv88e6xxx_port_vlan_prepare function
called by the DSA stack, instead of doing it in the internal
mv88e6xxx_port_check_hw_vlan helper.
Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2e500428670c..1b2cb46d3b53 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1453,12 +1453,10 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
if (!vid_begin)
return -EOPNOTSUPP;
- mv88e6xxx_reg_lock(chip);
-
do {
err = mv88e6xxx_vtu_getnext(chip, &vlan);
if (err)
- goto unlock;
+ return err;
if (!vlan.valid)
break;
@@ -1487,15 +1485,11 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
port, vlan.vid, i,
netdev_name(dsa_to_port(ds, i)->bridge_dev));
- err = -EOPNOTSUPP;
- goto unlock;
+ return -EOPNOTSUPP;
}
} while (vlan.vid < vid_end);
-unlock:
- mv88e6xxx_reg_unlock(chip);
-
- return err;
+ return 0;
}
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
@@ -1529,15 +1523,15 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
/* If the requested port doesn't belong to the same bridge as the VLAN
* members, do not support it (yet) and fallback to software VLAN.
*/
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
vlan->vid_end);
- if (err)
- return err;
+ mv88e6xxx_reg_unlock(chip);
/* We don't need any dynamic resource from the kernel (yet),
* so skip the prepare phase.
*/
- return 0;
+ return err;
}
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
--
2.22.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 2/5] net: dsa: mv88e6xxx: explicit entry passed to vtu_getnext
2019-08-01 18:36 [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 1/5] net: dsa: mv88e6xxx: lock mutex in vlan_prepare Vivien Didelot
@ 2019-08-01 18:36 ` Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 3/5] net: dsa: mv88e6xxx: call vtu_getnext directly in db load/purge Vivien Didelot
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
andrew, netdev, davem
mv88e6xxx_vtu_getnext interprets two members from the input
mv88e6xxx_vtu_entry structure: the (excluded) vid member to start
the iteration from, and the valid argument specifying whether the VID
must be written or not (only required once at the start of a loop).
Explicit the assignation of these two fields right before calling
mv88e6xxx_vtu_getnext, as it is done in the mv88e6xxx_vtu_get wrapper.
Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 1b2cb46d3b53..c825fa3477fa 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1361,9 +1361,7 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
{
DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
- struct mv88e6xxx_vtu_entry vlan = {
- .vid = chip->info->max_vid,
- };
+ struct mv88e6xxx_vtu_entry vlan;
int i, err;
bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
@@ -1378,6 +1376,9 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
}
/* Set every FID bit used by the VLAN entries */
+ vlan.vid = chip->info->max_vid;
+ vlan.valid = false;
+
do {
err = mv88e6xxx_vtu_getnext(chip, &vlan);
if (err)
@@ -1441,9 +1442,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
u16 vid_begin, u16 vid_end)
{
struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_vtu_entry vlan = {
- .vid = vid_begin - 1,
- };
+ struct mv88e6xxx_vtu_entry vlan;
int i, err;
/* DSA and CPU ports have to be members of multiple vlans */
@@ -1453,6 +1452,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
if (!vid_begin)
return -EOPNOTSUPP;
+ vlan.vid = vid_begin - 1;
+ vlan.valid = false;
+
do {
err = mv88e6xxx_vtu_getnext(chip, &vlan);
if (err)
@@ -1789,9 +1791,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
- struct mv88e6xxx_vtu_entry vlan = {
- .vid = chip->info->max_vid,
- };
+ struct mv88e6xxx_vtu_entry vlan;
u16 fid;
int err;
@@ -1805,6 +1805,9 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
return err;
/* Dump VLANs' Filtering Information Databases */
+ vlan.vid = chip->info->max_vid;
+ vlan.valid = false;
+
do {
err = mv88e6xxx_vtu_getnext(chip, &vlan);
if (err)
--
2.22.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 3/5] net: dsa: mv88e6xxx: call vtu_getnext directly in db load/purge
2019-08-01 18:36 [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 1/5] net: dsa: mv88e6xxx: lock mutex in vlan_prepare Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 2/5] net: dsa: mv88e6xxx: explicit entry passed to vtu_getnext Vivien Didelot
@ 2019-08-01 18:36 ` Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 4/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_del Vivien Didelot
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
andrew, netdev, davem
mv88e6xxx_vtu_getnext is simple enough to call it directly in the
mv88e6xxx_port_db_load_purge function and explicit the return code
expected by switchdev for software VLANs when an hardware VLAN does
not exist.
Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c825fa3477fa..42ab57dbc790 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1540,23 +1540,36 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
const unsigned char *addr, u16 vid,
u8 state)
{
- struct mv88e6xxx_vtu_entry vlan;
struct mv88e6xxx_atu_entry entry;
+ struct mv88e6xxx_vtu_entry vlan;
+ u16 fid;
int err;
/* Null VLAN ID corresponds to the port private database */
- if (vid == 0)
- err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
- else
- err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
- if (err)
- return err;
+ if (vid == 0) {
+ err = mv88e6xxx_port_get_fid(chip, port, &fid);
+ if (err)
+ return err;
+ } else {
+ vlan.vid = vid - 1;
+ vlan.valid = false;
+
+ err = mv88e6xxx_vtu_getnext(chip, &vlan);
+ if (err)
+ return err;
+
+ /* switchdev expects -EOPNOTSUPP to honor software VLANs */
+ if (vlan.vid != vid || !vlan.valid)
+ return -EOPNOTSUPP;
+
+ fid = vlan.fid;
+ }
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
ether_addr_copy(entry.mac, addr);
eth_addr_dec(entry.mac);
- err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
+ err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
if (err)
return err;
@@ -1577,7 +1590,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
entry.state = state;
}
- return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
+ return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
}
static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
--
2.22.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 4/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_del
2019-08-01 18:36 [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations Vivien Didelot
` (2 preceding siblings ...)
2019-08-01 18:36 ` [PATCH net-next 3/5] net: dsa: mv88e6xxx: call vtu_getnext directly in db load/purge Vivien Didelot
@ 2019-08-01 18:36 ` Vivien Didelot
2019-08-01 18:36 ` [PATCH net-next 5/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_add Vivien Didelot
2019-08-01 20:43 ` [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations David Miller
5 siblings, 0 replies; 7+ messages in thread
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
andrew, netdev, davem
Wrapping mv88e6xxx_vtu_getnext makes the code less easy to read.
Explicit the call to mv88e6xxx_vtu_getnext in _mv88e6xxx_port_vlan_del
and the return value expected by switchdev in case of software VLANs.
At the same time, rename the helper using an old underscore convention.
Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 42ab57dbc790..50a6dbcc669c 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1671,18 +1671,27 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
mv88e6xxx_reg_unlock(chip);
}
-static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
- int port, u16 vid)
+static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
+ int port, u16 vid)
{
struct mv88e6xxx_vtu_entry vlan;
int i, err;
- err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
+ if (!vid)
+ return -EOPNOTSUPP;
+
+ vlan.vid = vid - 1;
+ vlan.valid = false;
+
+ err = mv88e6xxx_vtu_getnext(chip, &vlan);
if (err)
return err;
- /* Tell switchdev if this VLAN is handled in software */
- if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+ /* If the VLAN doesn't exist in hardware or the port isn't a member,
+ * tell switchdev that this VLAN is likely handled in software.
+ */
+ if (vlan.vid != vid || !vlan.valid ||
+ vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
return -EOPNOTSUPP;
vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
@@ -1721,7 +1730,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
goto unlock;
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
- err = _mv88e6xxx_port_vlan_del(chip, port, vid);
+ err = mv88e6xxx_port_vlan_leave(chip, port, vid);
if (err)
goto unlock;
--
2.22.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 5/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_add
2019-08-01 18:36 [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations Vivien Didelot
` (3 preceding siblings ...)
2019-08-01 18:36 ` [PATCH net-next 4/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_del Vivien Didelot
@ 2019-08-01 18:36 ` Vivien Didelot
2019-08-01 20:43 ` [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations David Miller
5 siblings, 0 replies; 7+ messages in thread
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
andrew, netdev, davem
Wrapping mv88e6xxx_vtu_getnext makes the code less easy to read and
_mv88e6xxx_port_vlan_add is the only function requiring the preparation
of a new VLAN entry.
To simplify things up, remove the mv88e6xxx_vtu_get wrapper and
explicit the VLAN lookup in _mv88e6xxx_port_vlan_add. This rework
also avoids programming the broadcast entries again when changing a
port's membership, e.g. from tagged to untagged.
At the same time, rename the helper using an old underscore convention.
Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 93 +++++++++++++++-----------------
1 file changed, 44 insertions(+), 49 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 50a6dbcc669c..8c4216e7a4bb 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1401,43 +1401,6 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
return mv88e6xxx_g1_atu_flush(chip, *fid, true);
}
-static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
- struct mv88e6xxx_vtu_entry *entry, bool new)
-{
- int err;
-
- if (!vid)
- return -EOPNOTSUPP;
-
- entry->vid = vid - 1;
- entry->valid = false;
-
- err = mv88e6xxx_vtu_getnext(chip, entry);
- if (err)
- return err;
-
- if (entry->vid == vid && entry->valid)
- return 0;
-
- if (new) {
- int i;
-
- /* Initialize a fresh VLAN entry */
- memset(entry, 0, sizeof(*entry));
- entry->vid = vid;
-
- /* Exclude all ports */
- for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
- entry->member[i] =
- MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
-
- return mv88e6xxx_atu_new(chip, &entry->fid);
- }
-
- /* switchdev expects -EOPNOTSUPP to honor software VLANs */
- return -EOPNOTSUPP;
-}
-
static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
u16 vid_begin, u16 vid_end)
{
@@ -1616,26 +1579,58 @@ static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
return 0;
}
-static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
+static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
u16 vid, u8 member)
{
+ const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
struct mv88e6xxx_vtu_entry vlan;
- int err;
+ int i, err;
- err = mv88e6xxx_vtu_get(chip, vid, &vlan, true);
+ if (!vid)
+ return -EOPNOTSUPP;
+
+ vlan.vid = vid - 1;
+ vlan.valid = false;
+
+ err = mv88e6xxx_vtu_getnext(chip, &vlan);
if (err)
return err;
- if (vlan.valid && vlan.member[port] == member)
- return 0;
- vlan.valid = true;
- vlan.member[port] = member;
+ if (vlan.vid != vid || !vlan.valid) {
+ memset(&vlan, 0, sizeof(vlan));
- err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
- if (err)
- return err;
+ err = mv88e6xxx_atu_new(chip, &vlan.fid);
+ if (err)
+ return err;
- return mv88e6xxx_broadcast_setup(chip, vid);
+ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
+ if (i == port)
+ vlan.member[i] = member;
+ else
+ vlan.member[i] = non_member;
+
+ vlan.vid = vid;
+ vlan.valid = true;
+
+ err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
+ if (err)
+ return err;
+ } else if (vlan.member[port] != member) {
+ vlan.member[port] = member;
+
+ err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
+ if (err)
+ return err;
+ } else {
+ dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
+ port, vid);
+ }
+
+ return 0;
}
static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
@@ -1660,7 +1655,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
mv88e6xxx_reg_lock(chip);
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
- if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
+ if (mv88e6xxx_port_vlan_join(chip, port, vid, member))
dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
vid, untagged ? 'u' : 't');
--
2.22.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations
2019-08-01 18:36 [PATCH net-next 0/5] net: dsa: mv88e6xxx: avoid some redundant VTU operations Vivien Didelot
` (4 preceding siblings ...)
2019-08-01 18:36 ` [PATCH net-next 5/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_add Vivien Didelot
@ 2019-08-01 20:43 ` David Miller
5 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2019-08-01 20:43 UTC (permalink / raw)
To: vivien.didelot; +Cc: linux-kernel, rasmus.villemoes, f.fainelli, andrew, netdev
From: Vivien Didelot <vivien.didelot@gmail.com>
Date: Thu, 1 Aug 2019 14:36:32 -0400
> The mv88e6xxx driver currently uses a mv88e6xxx_vtu_get wrapper to get a
> single entry and uses a boolean to eventually initialize a fresh one.
>
> However the fresh entry is only needed in one place and mv88e6xxx_vtu_getnext
> is simple enough to call it directly. Doing so makes the code easier to read,
> especially for the return code expected by switchdev to honor software VLANs.
>
> In addition to not loading the VTU again when an entry is already correctly
> programmed, this also allows to avoid programming the broadcast entries
> again when updating a port's membership, from e.g. tagged to untagged.
>
> This patch series removes the mv88e6xxx_vtu_get wrapper in favor of direct
> calls to mv88e6xxx_vtu_getnext, and also renames the _mv88e6xxx_port_vlan_add
> and _mv88e6xxx_port_vlan_del helpers using an old underscore prefix convention.
>
> In case the port's membership is already correctly programmed in hardware,
> the following debug message may be printed:
>
> [ 745.989884] mv88e6085 2188000.ethernet-1:00: p4: already a member of VLAN 42
Series applied, thanks Vivien.
^ permalink raw reply [flat|nested] 7+ messages in thread