[PATCH net-next v2 4/5] net: dsa: mv88e6xxx: exclude all ports in new VLAN

2017-06-07 Thread Vivien Didelot
Now that the DSA core adds the CPU and DSA ports itself to the new VLAN
entry, there is no need to include them as members of this VLAN when
initializing a new VTU entry.

As of now, initialize a new VTU entry with all ports excluded.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 962b4e873bf9..41202b1d6d7f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1159,11 +1159,10 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip 
*chip, u16 vid,
entry->valid = true;
entry->vid = vid;
 
-   /* Include only CPU and DSA ports */
+   /* Exclude all ports */
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
-   entry->member[i] = dsa_is_normal_port(chip->ds, i) ?
-   GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER :
-   GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
+   entry->member[i] =
+   GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
 
return mv88e6xxx_atu_new(chip, &entry->fid);
}
-- 
2.13.1



[PATCH net-next v2 0/5] net: dsa: add cross-chip VLAN support

2017-06-07 Thread Vivien Didelot
The current code in DSA does not support cross-chip VLAN. This means
that in a multi-chip environment such as this one (similar to ZII Rev B)

 [CPU] (mdio)
(eth0) |   :   :  :
  _|_______
 [__sw0__]--[__sw1__]--[__sw2__]
  |  |  ||  |  ||  |  |
  v  v  vv  v  vv  v  v
  p1 p2 p3   p4 p5 p6   p7 p8 p9 

adding a VLAN to p9 won't be enough to reach the CPU, until at least one
port of sw0 and sw1 join the VLAN as well and become aware of the VID.

This patchset makes the DSA core program the VLAN on the CPU and DSA
links itself, which brings seamlessly cross-chip VLAN support to DSA.

With this series applied*, the hardware VLAN tables of a 3-switch setup
look like this after adding a VLAN to only one port of the end switch:

# cat /sys/class/net/br0/bridge/default_pvid 
42
# cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
# ip link set up master br0 dev lan6
# cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
 VID  FID  SID  0  1  2  3  4  5  6
  4210  x  x  x  x  x  =  =
 VID  FID  SID  0  1  2  3  4  5  6
  4210  x  x  x  x  x  =  =
 VID  FID  SID  0  1  2  3  4  5  6  7  8  9
  4210  u  x  x  x  x  x  x  x  x  =

('x' is excluded, 'u' is untagged, '=' is unmodified DSA and CPU ports.)

Completely removing a VLAN entry (which is currently the responsibility
of drivers anyway) is not supported yet since it requires some caching.

(*) the output is shown from this out-of-tree debugfs patch:
https://github.com/vivien/linux/commit/7b61a684b9d6b6a499135a587c7f62a1fddceb8b.patch

Changes in v2:
  - canonical incrementation (port++ instead of ++port)
  - check CPU and DSA ports before purging a VLAN
  - add Reviewed-by tags

Vivien Didelot (5):
  net: dsa: mv88e6xxx: define membership on VLAN add
  net: dsa: check VLAN capability of every switch
  net: dsa: add CPU and DSA ports as VLAN members
  net: dsa: mv88e6xxx: exclude all ports in new VLAN
  net: dsa: mv88e6xxx: do not skip ports on VLAN del

 drivers/net/dsa/mv88e6xxx/chip.c | 27 ++-
 net/dsa/switch.c | 30 --
 2 files changed, 34 insertions(+), 23 deletions(-)

-- 
2.13.1



[PATCH net-next v2 3/5] net: dsa: add CPU and DSA ports as VLAN members

2017-06-07 Thread Vivien Didelot
In a multi-chip switch fabric, it is currently the responsibility of the
driver to add the CPU or DSA (interconnecting chips together) ports as
members of a new VLAN entry. This makes the drivers more complicated.

We want the DSA drivers to be stupid and the DSA core being the one
responsible for caring about the abstracted switch logic and topology.

Make the DSA core program the CPU and DSA ports as part of the VLAN.

This makes all chips of the data path to be aware of VIDs spanning the
the whole fabric and thus, seamlessly add support for cross-chip VLAN.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 net/dsa/switch.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index f235ae1e9777..f1029a8d0e20 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -166,6 +166,9 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
bitmap_zero(members, ds->num_ports);
if (ds->index == info->sw_index)
set_bit(info->port, members);
+   for (port = 0; port < ds->num_ports; port++)
+   if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+   set_bit(port, members);
 
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
-- 
2.13.1



[PATCH net-next v2 1/5] net: dsa: mv88e6xxx: define membership on VLAN add

2017-06-07 Thread Vivien Didelot
Define the target port membership of the VLAN entry in
mv88e6xxx_port_vlan_add where ds is scoped.

Allow the DSA core to call later the port_vlan_add operation for CPU or
DSA ports, by using the Unmodified membership for these ports, as in the
current behavior.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 44c87027623b..962b4e873bf9 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1274,7 +1274,7 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int 
port,
 }
 
 static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
-   u16 vid, bool untagged)
+   u16 vid, u8 member)
 {
struct mv88e6xxx_vtu_entry vlan;
int err;
@@ -1283,9 +1283,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip 
*chip, int port,
if (err)
return err;
 
-   vlan.member[port] = untagged ?
-   GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
-   GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
+   vlan.member[port] = member;
 
return mv88e6xxx_vtu_loadpurge(chip, &vlan);
 }
@@ -1297,15 +1295,23 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch 
*ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+   u8 member;
u16 vid;
 
if (!chip->info->max_vid)
return;
 
+   if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
+   member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
+   else if (untagged)
+   member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED;
+   else
+   member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
+
mutex_lock(&chip->reg_lock);
 
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
-   if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
+   if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
netdev_err(ds->ports[port].netdev,
   "failed to add VLAN %d%c\n",
   vid, untagged ? 'u' : 't');
-- 
2.13.1



[PATCH net-next v2 2/5] net: dsa: check VLAN capability of every switch

2017-06-07 Thread Vivien Didelot
Now that the VLAN object is propagated to every switch chip of the
switch fabric, we can easily ensure that they all support the required
VLAN operations before modifying an entry on a single switch.

To achieve that, remove the condition skipping other target switches,
and add a bitmap of VLAN members, eventually containing the target port,
if we are programming the switch target.

This will allow us to easily add other VLAN members, such as the DSA or
CPU ports (to introduce cross-chip VLAN support) or the other port
members if we want to reduce hardware accesses later.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 net/dsa/switch.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index d8e5c311ee7c..f235ae1e9777 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -159,19 +159,27 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
 {
const struct switchdev_obj_port_vlan *vlan = info->vlan;
struct switchdev_trans *trans = info->trans;
+   DECLARE_BITMAP(members, ds->num_ports);
+   int port, err;
 
-   /* Do not care yet about other switch chips of the fabric */
-   if (ds->index != info->sw_index)
-   return 0;
+   /* Build a mask of VLAN members */
+   bitmap_zero(members, ds->num_ports);
+   if (ds->index == info->sw_index)
+   set_bit(info->port, members);
 
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
return -EOPNOTSUPP;
 
-   return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans);
+   for_each_set_bit(port, members, ds->num_ports) {
+   err = ds->ops->port_vlan_prepare(ds, port, vlan, trans);
+   if (err)
+   return err;
+   }
}
 
-   ds->ops->port_vlan_add(ds, info->port, vlan, trans);
+   for_each_set_bit(port, members, ds->num_ports)
+   ds->ops->port_vlan_add(ds, port, vlan, trans);
 
return 0;
 }
@@ -181,14 +189,13 @@ static int dsa_switch_vlan_del(struct dsa_switch *ds,
 {
const struct switchdev_obj_port_vlan *vlan = info->vlan;
 
-   /* Do not care yet about other switch chips of the fabric */
-   if (ds->index != info->sw_index)
-   return 0;
-
if (!ds->ops->port_vlan_del)
return -EOPNOTSUPP;
 
-   return ds->ops->port_vlan_del(ds, info->port, vlan);
+   if (ds->index == info->sw_index)
+   return ds->ops->port_vlan_del(ds, info->port, vlan);
+
+   return 0;
 }
 
 static int dsa_switch_event(struct notifier_block *nb,
-- 
2.13.1



[PATCH net-next v2 5/5] net: dsa: mv88e6xxx: do not skip ports on VLAN del

2017-06-07 Thread Vivien Didelot
The mv88e6xxx driver currently tries to be smart and remove by itself a
VLAN entry from the VTU when the driven switch sees no user ports as
members of the VLAN.

This is bad in a multi-chip switch fabric, since a chip in between
others may have no bridge port members, but still needs to be aware of
the VID in order to correctly pass frames in the data path.

Now that the DSA core explicitly manages DSA and CPU ports, do not skip
them when checking remaining VLAN members.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 41202b1d6d7f..0534eb706caa 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1325,7 +1325,6 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch 
*ds, int port,
 static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
int port, u16 vid)
 {
-   struct dsa_switch *ds = chip->ds;
struct mv88e6xxx_vtu_entry vlan;
int i, err;
 
@@ -1342,9 +1341,6 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip 
*chip,
/* keep the VLAN unless all ports are excluded */
vlan.valid = false;
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
-   if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
-   continue;
-
if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
vlan.valid = true;
break;
-- 
2.13.1



Re: [PATCH net-next 2/5] net: dsa: check VLAN capability of every switch

2017-06-07 Thread Vivien Didelot
Hi Florian,

Florian Fainelli  writes:

> On 06/06/2017 01:56 PM, Vivien Didelot wrote:
>> Now that the VLAN object is propagated to every switch chip of the
>> switch fabric, we can easily ensure that they all support the required
>> VLAN operations before modifying an entry on a single switch.
>> 
>> To achieve that, remove the condition skipping other target switches,
>> and add a bitmap of VLAN members, eventually containing the target port,
>> if we are programming the switch target.
>
> You could add in the commit message that with this commit, there is not
> actually a functional change yet because we have one (and only one) bit
> set in the members bitmap.

Hum there is a small functional change though: if one interconnected
switch of the fabric does not support the VLAN operations, -EOPNOTSUPP
is returned (even though the target switch is VLAN capable.)

Thanks,

Vivien


Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: do not purge a VTU entry

2017-06-07 Thread Vivien Didelot
Hi Florian,

Florian Fainelli  writes:

> On 06/06/2017 01:56 PM, Vivien Didelot wrote:
>> The mv88e6xxx driver currently tries to be smart and remove by itself a
>> VLAN entry from the VTU when the driven switch sees no user ports as
>> members of the VLAN.
>> 
>> This is bad in a multi-chip switch fabric, since a chip in between
>> others may have no bridge port members, but still needs to be aware of
>> the VID in order to correctly pass frames in the data path.
>> 
>> Remove the code purging a VTU entry when updating a port membership.
>
> In that case the switch sitting between two other chips and passing
> traffic would still have at least two of its DSA ports be part of a VTU
> entry, right?

That is correct.

>
> So could not we just do 
>
>> 
>> Signed-off-by: Vivien Didelot 
>> ---
>>  drivers/net/dsa/mv88e6xxx/chip.c | 15 +--
>>  1 file changed, 1 insertion(+), 14 deletions(-)
>> 
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c 
>> b/drivers/net/dsa/mv88e6xxx/chip.c
>> index 522f023bb17e..64c0f88f9e79 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.c
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
>> @@ -1325,9 +1325,8 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch 
>> *ds, int port,
>>  static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
>>  int port, u16 vid)
>>  {
>> -struct dsa_switch *ds = chip->ds;
>>  struct mv88e6xxx_vtu_entry vlan;
>> -int i, err;
>> +int err;
>>  
>>  err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
>>  if (err)
>> @@ -1339,18 +1338,6 @@ static int _mv88e6xxx_port_vlan_del(struct 
>> mv88e6xxx_chip *chip,
>>  
>>  vlan.member[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
>>  
>> -/* keep the VLAN unless all ports are excluded */
>> -vlan.valid = false;
>> -for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
>> -if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
>> -continue;
>
> ... break the loop here?

I can remove only the dsa_is_{cpu,dsa}_port condition above, this will
make the code ready for when the DSA core will remove VLAN on DSA ports.

Thanks!

Vivien


[PATCH net-next 0/5] net: dsa: add cross-chip VLAN support

2017-06-06 Thread Vivien Didelot
The current code in DSA does not support cross-chip VLAN. This means
that in a multi-chip environment such as this one (similar to ZII Rev B)

 [CPU] (mdio)
(eth0) |   :   :  :
  _|_______
 [__sw0__]--[__sw1__]--[__sw2__]
  |  |  ||  |  ||  |  |
  v  v  vv  v  vv  v  v
  p1 p2 p3   p4 p5 p6   p7 p8 p9 

adding a VLAN to p9 won't be enough to reach the CPU, until at least one
port of sw0 and sw1 join the VLAN as well and become aware of the VID.

This patchset makes the DSA core program the VLAN on the CPU and DSA
links itself, which brings seamlessly cross-chip VLAN support to DSA.

With this series applied*, the hardware VLAN tables of a 3-switch setup
look like this after adding a VLAN to only one port of the end switch:

# cat /sys/class/net/br0/bridge/default_pvid 
42
# cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
# ip link set up master br0 dev lan6
# cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
 VID  FID  SID  0  1  2  3  4  5  6
  4210  x  x  x  x  x  =  =
 VID  FID  SID  0  1  2  3  4  5  6
  4210  x  x  x  x  x  =  =
 VID  FID  SID  0  1  2  3  4  5  6  7  8  9
  4210  u  x  x  x  x  x  x  x  x  =

('x' is excluded, 'u' is untagged, '=' is unmodified DSA and CPU ports.)

Completely removing a VLAN entry (which is currently the responsibility
of drivers anyway) is not supported yet since it requires some caching.

(*) the output is shown from this out-of-tree debugfs patch:
https://github.com/vivien/linux/commit/7b61a684b9d6b6a499135a587c7f62a1fddceb8b.patch

Vivien Didelot (5):
  net: dsa: mv88e6xxx: define membership on VLAN add
  net: dsa: check VLAN capability of every switch
  net: dsa: add CPU and DSA ports as VLAN members
  net: dsa: mv88e6xxx: exclude all ports in new VLAN
  net: dsa: mv88e6xxx: do not purge a VTU entry

 drivers/net/dsa/mv88e6xxx/chip.c | 38 +++---
 net/dsa/switch.c | 30 --
 2 files changed, 35 insertions(+), 33 deletions(-)

-- 
2.13.0



[PATCH net-next 1/5] net: dsa: mv88e6xxx: define membership on VLAN add

2017-06-06 Thread Vivien Didelot
Define the target port membership of the VLAN entry in
mv88e6xxx_port_vlan_add where ds is scoped.

Allow the DSA core to call later the port_vlan_add operation for CPU or
DSA ports, by using the Unmodified membership for these ports, as in the
current behavior.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 117f275e3fb6..93078bbe3cb5 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1274,7 +1274,7 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int 
port,
 }
 
 static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
-   u16 vid, bool untagged)
+   u16 vid, u8 member)
 {
struct mv88e6xxx_vtu_entry vlan;
int err;
@@ -1283,9 +1283,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip 
*chip, int port,
if (err)
return err;
 
-   vlan.member[port] = untagged ?
-   GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
-   GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
+   vlan.member[port] = member;
 
return mv88e6xxx_vtu_loadpurge(chip, &vlan);
 }
@@ -1297,15 +1295,23 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch 
*ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+   u8 member;
u16 vid;
 
if (!chip->info->max_vid)
return;
 
+   if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
+   member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
+   else if (untagged)
+   member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED;
+   else
+   member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
+
mutex_lock(&chip->reg_lock);
 
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
-   if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
+   if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
netdev_err(ds->ports[port].netdev,
   "failed to add VLAN %d%c\n",
   vid, untagged ? 'u' : 't');
-- 
2.13.0



[PATCH net-next 3/5] net: dsa: add CPU and DSA ports as VLAN members

2017-06-06 Thread Vivien Didelot
In a multi-chip switch fabric, it is currently the responsibility of the
driver to add the CPU or DSA (interconnecting chips together) ports as
members of a new VLAN entry. This makes the drivers more complicated.

We want the DSA drivers to be stupid and the DSA core being the one
responsible for caring about the abstracted switch logic and topology.

Make the DSA core program the CPU and DSA ports as part of the VLAN.

This makes all chips of the data path to be aware of VIDs spanning the
the whole fabric and thus, seamlessly add support for cross-chip VLAN.

Signed-off-by: Vivien Didelot 
---
 net/dsa/switch.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index f235ae1e9777..f913cdfe6585 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -166,6 +166,9 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
bitmap_zero(members, ds->num_ports);
if (ds->index == info->sw_index)
set_bit(info->port, members);
+   for (port = 0; port < ds->num_ports; ++port)
+   if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+   set_bit(port, members);
 
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
-- 
2.13.0



[PATCH net-next 4/5] net: dsa: mv88e6xxx: exclude all ports in new VLAN

2017-06-06 Thread Vivien Didelot
Now that the DSA core adds the CPU and DSA ports itself to the new VLAN
entry, there is no need to include them as members of this VLAN when
initializing a new VTU entry.

As of now, initialize a new VTU entry with all ports excluded.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 93078bbe3cb5..522f023bb17e 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1159,11 +1159,10 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip 
*chip, u16 vid,
entry->valid = true;
entry->vid = vid;
 
-   /* Include only CPU and DSA ports */
+   /* Exclude all ports */
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
-   entry->member[i] = dsa_is_normal_port(chip->ds, i) ?
-   GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER :
-   GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
+   entry->member[i] =
+   GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
 
return mv88e6xxx_atu_new(chip, &entry->fid);
}
-- 
2.13.0



[PATCH net-next 5/5] net: dsa: mv88e6xxx: do not purge a VTU entry

2017-06-06 Thread Vivien Didelot
The mv88e6xxx driver currently tries to be smart and remove by itself a
VLAN entry from the VTU when the driven switch sees no user ports as
members of the VLAN.

This is bad in a multi-chip switch fabric, since a chip in between
others may have no bridge port members, but still needs to be aware of
the VID in order to correctly pass frames in the data path.

Remove the code purging a VTU entry when updating a port membership.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 15 +--
 1 file changed, 1 insertion(+), 14 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 522f023bb17e..64c0f88f9e79 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1325,9 +1325,8 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch 
*ds, int port,
 static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
int port, u16 vid)
 {
-   struct dsa_switch *ds = chip->ds;
struct mv88e6xxx_vtu_entry vlan;
-   int i, err;
+   int err;
 
err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
if (err)
@@ -1339,18 +1338,6 @@ static int _mv88e6xxx_port_vlan_del(struct 
mv88e6xxx_chip *chip,
 
vlan.member[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
 
-   /* keep the VLAN unless all ports are excluded */
-   vlan.valid = false;
-   for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
-   if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
-   continue;
-
-   if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
-   vlan.valid = true;
-   break;
-   }
-   }
-
err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
if (err)
return err;
-- 
2.13.0



[PATCH net-next 2/5] net: dsa: check VLAN capability of every switch

2017-06-06 Thread Vivien Didelot
Now that the VLAN object is propagated to every switch chip of the
switch fabric, we can easily ensure that they all support the required
VLAN operations before modifying an entry on a single switch.

To achieve that, remove the condition skipping other target switches,
and add a bitmap of VLAN members, eventually containing the target port,
if we are programming the switch target.

This will allow us to easily add other VLAN members, such as the DSA or
CPU ports (to introduce cross-chip VLAN support) or the other port
members if we want to reduce hardware accesses later.

Signed-off-by: Vivien Didelot 
---
 net/dsa/switch.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index d8e5c311ee7c..f235ae1e9777 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -159,19 +159,27 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
 {
const struct switchdev_obj_port_vlan *vlan = info->vlan;
struct switchdev_trans *trans = info->trans;
+   DECLARE_BITMAP(members, ds->num_ports);
+   int port, err;
 
-   /* Do not care yet about other switch chips of the fabric */
-   if (ds->index != info->sw_index)
-   return 0;
+   /* Build a mask of VLAN members */
+   bitmap_zero(members, ds->num_ports);
+   if (ds->index == info->sw_index)
+   set_bit(info->port, members);
 
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
return -EOPNOTSUPP;
 
-   return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans);
+   for_each_set_bit(port, members, ds->num_ports) {
+   err = ds->ops->port_vlan_prepare(ds, port, vlan, trans);
+   if (err)
+   return err;
+   }
}
 
-   ds->ops->port_vlan_add(ds, info->port, vlan, trans);
+   for_each_set_bit(port, members, ds->num_ports)
+   ds->ops->port_vlan_add(ds, port, vlan, trans);
 
return 0;
 }
@@ -181,14 +189,13 @@ static int dsa_switch_vlan_del(struct dsa_switch *ds,
 {
const struct switchdev_obj_port_vlan *vlan = info->vlan;
 
-   /* Do not care yet about other switch chips of the fabric */
-   if (ds->index != info->sw_index)
-   return 0;
-
if (!ds->ops->port_vlan_del)
return -EOPNOTSUPP;
 
-   return ds->ops->port_vlan_del(ds, info->port, vlan);
+   if (ds->index == info->sw_index)
+   return ds->ops->port_vlan_del(ds, info->port, vlan);
+
+   return 0;
 }
 
 static int dsa_switch_event(struct notifier_block *nb,
-- 
2.13.0



[PATCH net-next] net: dsa: mv88e6xxx: fix 6085 frame mode masking

2017-06-05 Thread Vivien Didelot
The register bits used for the frame mode were masked with DSA (0x1)
instead of the mask value (0x3) in the 6085 implementation of
port_set_frame_mode. Fix this.

Fixes: 56995cbc3540 ("net: dsa: mv88e6xxx: Refactor CPU and DSA port setup")
Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/port.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 360c77854f2a..3719ece60c61 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -451,7 +451,7 @@ int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip 
*chip, int port,
if (err)
return err;
 
-   reg &= ~PORT_CONTROL_FRAME_MODE_DSA;
+   reg &= ~PORT_CONTROL_FRAME_MASK;
 
switch (mode) {
case MV88E6XXX_FRAME_MODE_NORMAL:
-- 
2.13.0



Re: [PATCH net] net: dsa: Fix stale cpu_switch reference after unbind then bind

2017-06-03 Thread Vivien Didelot
Hi Florian,

Florian Fainelli  writes:

> Commit 9520ed8fb841 ("net: dsa: use cpu_switch instead of ds[0]")
> replaced the use of dst->ds[0] with dst->cpu_switch since that is
> functionally equivalent, however, we can now run into an use after free
> scenario after unbinding then rebinding the switch driver.
>
> The use after free happens because we do correctly initialize
> dst->cpu_switch the first time we probe in dsa_cpu_parse(), then we
> unbind the driver: dsa_dst_unapply() is called, and we rebind again.
> dst->cpu_switch now points to a freed "ds" structure, and so when we
> finally dereference it in dsa_cpu_port_ethtool_setup(), we oops.
>
> To fix this, simply set dst->cpu_switch to NULL in dsa_dst_unapply()
> which guarantees that we always correctly re-assign dst->cpu_switch in
> dsa_cpu_parse().
>
> Fixes: 9520ed8fb841 ("net: dsa: use cpu_switch instead of ds[0]")
> Signed-off-by: Florian Fainelli 

Reviewed-by: Vivien Didelot 

Thanks!

Vivien


[PATCH net-next 5/5] net: dsa: mv88e6xxx: move the Global 2 macros

2017-06-02 Thread Vivien Didelot
Move the GLOBAL2_* macros where they belong, in the related global2.h
header.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.h| 101 ---
 drivers/net/dsa/mv88e6xxx/global2.c |   2 -
 drivers/net/dsa/mv88e6xxx/global2.h | 103 
 3 files changed, 103 insertions(+), 103 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 7e558e9ba35d..98c24af977fd 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -33,107 +33,6 @@
 #define SMI_CMD_OP_45_READ_DATA_INC((3 << 10) | SMI_CMD_BUSY)
 #define SMI_DATA   0x01
 
-#define GLOBAL2_INT_SOURCE 0x00
-#define GLOBAL2_INT_SOURCE_WATCHDOG15
-#define GLOBAL2_INT_MASK   0x01
-#define GLOBAL2_MGMT_EN_2X 0x02
-#define GLOBAL2_MGMT_EN_0X 0x03
-#define GLOBAL2_FLOW_CONTROL   0x04
-#define GLOBAL2_SWITCH_MGMT0x05
-#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATABIT(15)
-#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS  BIT(14)
-#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG   BIT(13)
-#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRIBIT(7)
-#define GLOBAL2_SWITCH_MGMT_RSVD2CPU   BIT(3)
-#define GLOBAL2_DEVICE_MAPPING 0x06
-#define GLOBAL2_DEVICE_MAPPING_UPDATE  BIT(15)
-#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT8
-#define GLOBAL2_DEVICE_MAPPING_PORT_MASK   0x0f
-#define GLOBAL2_TRUNK_MASK 0x07
-#define GLOBAL2_TRUNK_MASK_UPDATE  BIT(15)
-#define GLOBAL2_TRUNK_MASK_NUM_SHIFT   12
-#define GLOBAL2_TRUNK_MASK_HASKBIT(11)
-#define GLOBAL2_TRUNK_MAPPING  0x08
-#define GLOBAL2_TRUNK_MAPPING_UPDATE   BIT(15)
-#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11
-#define GLOBAL2_IRL_CMD0x09
-#define GLOBAL2_IRL_CMD_BUSY   BIT(15)
-#define GLOBAL2_IRL_CMD_OP_INIT_ALL((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY)
-#define GLOBAL2_IRL_CMD_OP_INIT_SEL((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY)
-#define GLOBAL2_IRL_CMD_OP_WRITE_SEL   ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY)
-#define GLOBAL2_IRL_CMD_OP_READ_SEL((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY)
-#define GLOBAL2_IRL_DATA   0x0a
-#define GLOBAL2_PVT_ADDR   0x0b
-#define GLOBAL2_PVT_ADDR_BUSY  BIT(15)
-#define GLOBAL2_PVT_ADDR_OP_INIT_ONES  ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY)
-#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN((0x03 << 12) | 
GLOBAL2_PVT_ADDR_BUSY)
-#define GLOBAL2_PVT_ADDR_OP_READ   ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY)
-#define GLOBAL2_PVT_DATA   0x0c
-#define GLOBAL2_SWITCH_MAC 0x0d
-#define GLOBAL2_ATU_STATS  0x0e
-#define GLOBAL2_PRIO_OVERRIDE  0x0f
-#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP  BIT(7)
-#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT  4
-#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARPBIT(3)
-#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT0
-#define GLOBAL2_EEPROM_CMD 0x14
-#define GLOBAL2_EEPROM_CMD_BUSYBIT(15)
-#define GLOBAL2_EEPROM_CMD_OP_WRITE((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY)
-#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY)
-#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY)
-#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11)
-#define GLOBAL2_EEPROM_CMD_WRITE_ENBIT(10)
-#define GLOBAL2_EEPROM_CMD_ADDR_MASK   0xff
-#define GLOBAL2_EEPROM_DATA0x15
-#define GLOBAL2_EEPROM_ADDR0x15 /* 6390, 6341 */
-#define GLOBAL2_PTP_AVB_OP 0x16
-#define GLOBAL2_PTP_AVB_DATA   0x17
-#define GLOBAL2_SMI_PHY_CMD0x18
-#define GLOBAL2_SMI_PHY_CMD_BUSY   BIT(15)
-#define GLOBAL2_SMI_PHY_CMD_EXTERNAL   BIT(13)
-#define GLOBAL2_SMI_PHY_CMD_MODE_22BIT(12)
-#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA   ((0x1 << 10) | \
-GLOBAL2_SMI_PHY_CMD_MODE_22 | \
-GLOBAL2_SMI_PHY_CMD_BUSY)
-#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA((0x2 << 10) | \
-GLOBAL2_SMI_PHY_CMD_MODE_22 | \
-GLOBAL2_SMI_PHY_CMD_BUSY)
-#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR   ((0x0 << 10) | \
-GLOBAL2_SMI_PHY_CMD_BUSY)
-#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA   ((0x1 << 10) | \
-GLOBAL2_SMI_PHY_CMD_BUSY)
-#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA((0x3 << 10) | \
-GLOBAL2_SMI_PHY_CMD_BUSY)
-
-#define GLOBAL2_SMI_PHY_DATA   0x19
-#define GLOBAL2_SCRATCH_MISC   0x1a
-#define GLOBAL2_SCRATCH_BUSY   BIT(15)
-#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8
-#define GLOBAL2_SCRATCH_VALUE_MASK 0xff
-#de

[PATCH net-next 3/5] net: dsa: mv88e6xxx: move the Port macros

2017-06-02 Thread Vivien Didelot
Move the PORT_* macros where they belong, in the related port.h header.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.h | 160 ---
 drivers/net/dsa/mv88e6xxx/port.h | 160 +++
 2 files changed, 160 insertions(+), 160 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 2929132fb52d..a7c71a43503b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -33,166 +33,6 @@
 #define SMI_CMD_OP_45_READ_DATA_INC((3 << 10) | SMI_CMD_BUSY)
 #define SMI_DATA   0x01
 
-#define PORT_STATUS0x00
-#define PORT_STATUS_PAUSE_EN   BIT(15)
-#define PORT_STATUS_MY_PAUSE   BIT(14)
-#define PORT_STATUS_HD_FLOWBIT(13)
-#define PORT_STATUS_PHY_DETECT BIT(12)
-#define PORT_STATUS_LINK   BIT(11)
-#define PORT_STATUS_DUPLEX BIT(10)
-#define PORT_STATUS_SPEED_MASK 0x0300
-#define PORT_STATUS_SPEED_10   0x
-#define PORT_STATUS_SPEED_100  0x0100
-#define PORT_STATUS_SPEED_1000 0x0200
-#define PORT_STATUS_EEEBIT(6) /* 6352 */
-#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */
-#define PORT_STATUS_MGMII  BIT(6) /* 6185 */
-#define PORT_STATUS_TX_PAUSED  BIT(5)
-#define PORT_STATUS_FLOW_CTRL  BIT(4)
-#define PORT_STATUS_CMODE_MASK 0x0f
-#define PORT_STATUS_CMODE_100BASE_X0x8
-#define PORT_STATUS_CMODE_1000BASE_X   0x9
-#define PORT_STATUS_CMODE_SGMII0xa
-#define PORT_STATUS_CMODE_2500BASEX0xb
-#define PORT_STATUS_CMODE_XAUI 0xc
-#define PORT_STATUS_CMODE_RXAUI0xd
-#define PORT_PCS_CTRL  0x01
-#define PORT_PCS_CTRL_RGMII_DELAY_RXCLKBIT(15)
-#define PORT_PCS_CTRL_RGMII_DELAY_TXCLKBIT(14)
-#define PORT_PCS_CTRL_FORCE_SPEED  BIT(13) /* 6390 */
-#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */
-#define PORT_PCS_CTRL_200BASE  BIT(12) /* 6352 */
-#define PORT_PCS_CTRL_FC   BIT(7)
-#define PORT_PCS_CTRL_FORCE_FC BIT(6)
-#define PORT_PCS_CTRL_LINK_UP  BIT(5)
-#define PORT_PCS_CTRL_FORCE_LINK   BIT(4)
-#define PORT_PCS_CTRL_DUPLEX_FULL  BIT(3)
-#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2)
-#define PORT_PCS_CTRL_SPEED_MASK   (0x03)
-#define PORT_PCS_CTRL_SPEED_10 (0x00)
-#define PORT_PCS_CTRL_SPEED_100(0x01)
-#define PORT_PCS_CTRL_SPEED_200(0x02) /* 6065 and non Gb chips 
*/
-#define PORT_PCS_CTRL_SPEED_1000   (0x02)
-#define PORT_PCS_CTRL_SPEED_1  (0x03) /* 6390X */
-#define PORT_PCS_CTRL_SPEED_UNFORCED   (0x03)
-#define PORT_PAUSE_CTRL0x02
-#define PORT_FLOW_CTRL_LIMIT_IN((0x00 << 8) | BIT(15))
-#define PORT_FLOW_CTRL_LIMIT_OUT   ((0x01 << 8) | BIT(15))
-#define PORT_SWITCH_ID 0x03
-#define PORT_SWITCH_ID_PROD_NUM_6085   0x04a
-#define PORT_SWITCH_ID_PROD_NUM_6095   0x095
-#define PORT_SWITCH_ID_PROD_NUM_6097   0x099
-#define PORT_SWITCH_ID_PROD_NUM_6131   0x106
-#define PORT_SWITCH_ID_PROD_NUM_6320   0x115
-#define PORT_SWITCH_ID_PROD_NUM_6123   0x121
-#define PORT_SWITCH_ID_PROD_NUM_6141   0x340
-#define PORT_SWITCH_ID_PROD_NUM_6161   0x161
-#define PORT_SWITCH_ID_PROD_NUM_6165   0x165
-#define PORT_SWITCH_ID_PROD_NUM_6171   0x171
-#define PORT_SWITCH_ID_PROD_NUM_6172   0x172
-#define PORT_SWITCH_ID_PROD_NUM_6175   0x175
-#define PORT_SWITCH_ID_PROD_NUM_6176   0x176
-#define PORT_SWITCH_ID_PROD_NUM_6185   0x1a7
-#define PORT_SWITCH_ID_PROD_NUM_6190   0x190
-#define PORT_SWITCH_ID_PROD_NUM_6190X  0x0a0
-#define PORT_SWITCH_ID_PROD_NUM_6191   0x191
-#define PORT_SWITCH_ID_PROD_NUM_6240   0x240
-#define PORT_SWITCH_ID_PROD_NUM_6290   0x290
-#define PORT_SWITCH_ID_PROD_NUM_6321   0x310
-#define PORT_SWITCH_ID_PROD_NUM_6341   0x341
-#define PORT_SWITCH_ID_PROD_NUM_6352   0x352
-#define PORT_SWITCH_ID_PROD_NUM_6350   0x371
-#define PORT_SWITCH_ID_PROD_NUM_6351   0x375
-#define PORT_SWITCH_ID_PROD_NUM_6390   0x390
-#define PORT_SWITCH_ID_PROD_NUM_6390X  0x0a1
-#define PORT_CONTROL   0x04
-#define PORT_CONTROL_USE_CORE_TAG  BIT(15)
-#define PORT_CONTROL_DROP_ON_LOCK  BIT(14)
-#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12)
-#define PORT_CONTROL_EGRESS_UNTAGGED   (0x1 << 12)
-#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12)
-#define PORT_CONTROL_EGRESS_ADD_TAG(0x3 << 12)
-#define PORT_CONTROL_EGRESS_MASK   (0x3 << 12)
-#define PORT_CONTROL_HEADERBIT(11)
-#define PORT_CONTROL_IGMP_MLD_SNOOPBIT(10)
-#define PORT_CONTROL_DOUBLE_TAGBIT(9)
-#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8)
-#define PORT_CONTROL_FRAME_MODE_DSA(0x1 << 8)
-#define PORT_CONTROL_FRAME_MODE_PROVIDER   (0x2 << 8)
-#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA  (0x3 << 8)
-#define PORT_CONTROL_FRAME_MASK(0x3 << 8)
-#define PORT_CONTROL_DS

[PATCH net-next 0/5] net: dsa: mv88e6xxx: move registers macros

2017-06-02 Thread Vivien Didelot
This patchset brings no functional changes.

It is the first step of a cleanup renaming the chip header file and
moving the Register definitions _as is_ in their proper header files.

A following patchset will prefix them with the appropriate model
(MV88E6XXX_ or e.g. MV88E6390_) to respect an implicit namespace and
easily identify model subtleties in registers layout, as correctly done
in the newly added serdes.h header.

Vivien Didelot (5):
  net: dsa: mv88e6xxx: rename chip header
  net: dsa: mv88e6xxx: move PHY macros
  net: dsa: mv88e6xxx: move the Port macros
  net: dsa: mv88e6xxx: move the Global 1 macros
  net: dsa: mv88e6xxx: move the Global 2 macros

 drivers/net/dsa/mv88e6xxx/chip.c|   2 +-
 drivers/net/dsa/mv88e6xxx/chip.h| 522 ++
 drivers/net/dsa/mv88e6xxx/global1.c |   2 +-
 drivers/net/dsa/mv88e6xxx/global1.h | 143 -
 drivers/net/dsa/mv88e6xxx/global1_atu.c |   2 +-
 drivers/net/dsa/mv88e6xxx/global1_vtu.c |   2 +-
 drivers/net/dsa/mv88e6xxx/global2.c |   6 +-
 drivers/net/dsa/mv88e6xxx/global2.h | 105 +++-
 drivers/net/dsa/mv88e6xxx/mv88e6xxx.h   | 927 
 drivers/net/dsa/mv88e6xxx/phy.c |   2 +-
 drivers/net/dsa/mv88e6xxx/phy.h |   3 +
 drivers/net/dsa/mv88e6xxx/port.c|   3 +-
 drivers/net/dsa/mv88e6xxx/port.h| 162 +-
 drivers/net/dsa/mv88e6xxx/serdes.c  |   2 +-
 drivers/net/dsa/mv88e6xxx/serdes.h  |   2 +-
 15 files changed, 944 insertions(+), 941 deletions(-)
 create mode 100644 drivers/net/dsa/mv88e6xxx/chip.h
 delete mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx.h

-- 
2.13.0



[PATCH net-next 4/5] net: dsa: mv88e6xxx: move the Global 1 macros

2017-06-02 Thread Vivien Didelot
Move the GLOBAL_* macros where they belong, in the related global1.h
header. Include it in global2.c which uses GLOBAL_STATUS_IRQ_DEVICE.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.h| 141 
 drivers/net/dsa/mv88e6xxx/global1.h | 141 
 drivers/net/dsa/mv88e6xxx/global2.c |   1 +
 3 files changed, 142 insertions(+), 141 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index a7c71a43503b..7e558e9ba35d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -33,147 +33,6 @@
 #define SMI_CMD_OP_45_READ_DATA_INC((3 << 10) | SMI_CMD_BUSY)
 #define SMI_DATA   0x01
 
-#define GLOBAL_STATUS  0x00
-#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */
-#define GLOBAL_STATUS_PPU_STATE_MASK   (0x3 << 14) /* 6165 6185 */
-#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST   (0x0 << 14)
-#define GLOBAL_STATUS_PPU_STATE_INITIALIZING   (0x1 << 14)
-#define GLOBAL_STATUS_PPU_STATE_DISABLED   (0x2 << 14)
-#define GLOBAL_STATUS_PPU_STATE_POLLING(0x3 << 14)
-#define GLOBAL_STATUS_INIT_READY   BIT(11)
-#define GLOBAL_STATUS_IRQ_AVB  8
-#define GLOBAL_STATUS_IRQ_DEVICE   7
-#define GLOBAL_STATUS_IRQ_STATS6
-#define GLOBAL_STATUS_IRQ_VTU_PROBLEM  5
-#define GLOBAL_STATUS_IRQ_VTU_DONE 4
-#define GLOBAL_STATUS_IRQ_ATU_PROBLEM  3
-#define GLOBAL_STATUS_IRQ_ATU_DONE 2
-#define GLOBAL_STATUS_IRQ_TCAM_DONE1
-#define GLOBAL_STATUS_IRQ_EEPROM_DONE  0
-#define GLOBAL_MAC_01  0x01
-#define GLOBAL_MAC_23  0x02
-#define GLOBAL_MAC_45  0x03
-#define GLOBAL_ATU_FID 0x01
-#define GLOBAL_VTU_FID 0x02
-#define GLOBAL_VTU_FID_MASK0xfff
-#define GLOBAL_VTU_SID 0x03/* 6097 6165 6351 6352 */
-#define GLOBAL_VTU_SID_MASK0x3f
-#define GLOBAL_CONTROL 0x04
-#define GLOBAL_CONTROL_SW_RESETBIT(15)
-#define GLOBAL_CONTROL_PPU_ENABLE  BIT(14)
-#define GLOBAL_CONTROL_DISCARD_EXCESS  BIT(13) /* 6352 */
-#define GLOBAL_CONTROL_SCHED_PRIO  BIT(11) /* 6152 */
-#define GLOBAL_CONTROL_MAX_FRAME_1632  BIT(10) /* 6152 */
-#define GLOBAL_CONTROL_RELOAD_EEPROM   BIT(9)  /* 6152 */
-#define GLOBAL_CONTROL_DEVICE_EN   BIT(7)
-#define GLOBAL_CONTROL_STATS_DONE_EN   BIT(6)
-#define GLOBAL_CONTROL_VTU_PROBLEM_EN  BIT(5)
-#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4)
-#define GLOBAL_CONTROL_ATU_PROBLEM_EN  BIT(3)
-#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2)
-#define GLOBAL_CONTROL_TCAM_EN BIT(1)
-#define GLOBAL_CONTROL_EEPROM_DONE_EN  BIT(0)
-#define GLOBAL_VTU_OP  0x05
-#define GLOBAL_VTU_OP_BUSY BIT(15)
-#define GLOBAL_VTU_OP_FLUSH_ALL((0x01 << 12) | 
GLOBAL_VTU_OP_BUSY)
-#define GLOBAL_VTU_OP_VTU_LOAD_PURGE   ((0x03 << 12) | GLOBAL_VTU_OP_BUSY)
-#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY)
-#define GLOBAL_VTU_OP_STU_LOAD_PURGE   ((0x05 << 12) | GLOBAL_VTU_OP_BUSY)
-#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY)
-#define GLOBAL_VTU_VID 0x06
-#define GLOBAL_VTU_VID_MASK0xfff
-#define GLOBAL_VTU_VID_PAGEBIT(13)
-#define GLOBAL_VTU_VID_VALID   BIT(12)
-#define GLOBAL_VTU_DATA_0_30x07
-#define GLOBAL_VTU_DATA_4_70x08
-#define GLOBAL_VTU_DATA_8_11   0x09
-#define GLOBAL_VTU_STU_DATA_MASK   0x03
-#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED  0x00
-#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED0x01
-#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED  0x02
-#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER  0x03
-#define GLOBAL_STU_DATA_PORT_STATE_DISABLED0x00
-#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING0x01
-#define GLOBAL_STU_DATA_PORT_STATE_LEARNING0x02
-#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING  0x03
-#define GLOBAL_ATU_CONTROL 0x0a
-#define GLOBAL_ATU_CONTROL_LEARN2ALL   BIT(3)
-#define GLOBAL_ATU_OP  0x0b
-#define GLOBAL_ATU_OP_BUSY BIT(15)
-#define GLOBAL_ATU_OP_NOP  (0 << 12)
-#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL   ((1 << 12) | GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC((2 << 12) | GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_OP_LOAD_DB  ((3 << 12) | GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_OP_GET_NEXT_DB  ((4 << 12) | GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB((5 << 12) | 
GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_OP_GET_CLR_VIOLATION  ((7 << 12) | 
GLOBAL_ATU_OP_BUSY)
-#define GLOBAL_ATU_DATA0x0c
-#define GLOBAL_ATU_DATA_TRUNK  BIT(15)
-#define GLOBAL_ATU_DATA_TRUNK_ID_MASK  0x00f0
-#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4

[PATCH net-next 1/5] net: dsa: mv88e6xxx: rename chip header

2017-06-02 Thread Vivien Didelot
The mv88e6xxx.h is meant to contains the chip structures and data.
Rename it to chip.h, as for other source/header pairs of the driver.

At the same time, ensure that relative header inclusions are separated
by a newline and sorted alphabetically.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c  | 2 +-
 drivers/net/dsa/mv88e6xxx/{mv88e6xxx.h => chip.h} | 9 +
 drivers/net/dsa/mv88e6xxx/global1.c   | 2 +-
 drivers/net/dsa/mv88e6xxx/global1.h   | 2 +-
 drivers/net/dsa/mv88e6xxx/global1_atu.c   | 2 +-
 drivers/net/dsa/mv88e6xxx/global1_vtu.c   | 2 +-
 drivers/net/dsa/mv88e6xxx/global2.c   | 3 ++-
 drivers/net/dsa/mv88e6xxx/global2.h   | 2 +-
 drivers/net/dsa/mv88e6xxx/phy.c   | 2 +-
 drivers/net/dsa/mv88e6xxx/port.c  | 3 ++-
 drivers/net/dsa/mv88e6xxx/port.h  | 2 +-
 drivers/net/dsa/mv88e6xxx/serdes.c| 2 +-
 drivers/net/dsa/mv88e6xxx/serdes.h| 2 +-
 13 files changed, 19 insertions(+), 16 deletions(-)
 rename drivers/net/dsa/mv88e6xxx/{mv88e6xxx.h => chip.h} (99%)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7cf470c3e662..0176254cb3c7 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -33,7 +33,7 @@
 #include 
 #include 
 
-#include "mv88e6xxx.h"
+#include "chip.h"
 #include "global1.h"
 #include "global2.h"
 #include "phy.h"
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h 
b/drivers/net/dsa/mv88e6xxx/chip.h
similarity index 99%
rename from drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
rename to drivers/net/dsa/mv88e6xxx/chip.h
index 9087cb009cc3..ae7aed533aa5 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -1,5 +1,5 @@
 /*
- * Marvell 88e6xxx common definitions
+ * Marvell 88E6xxx Ethernet switch single-chip definition
  *
  * Copyright (c) 2008 Marvell Semiconductor
  *
@@ -9,8 +9,8 @@
  * (at your option) any later version.
  */
 
-#ifndef __MV88E6XXX_H
-#define __MV88E6XXX_H
+#ifndef _MV88E6XXX_CHIP_H
+#define _MV88E6XXX_CHIP_H
 
 #include 
 #include 
@@ -924,4 +924,5 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, 
int reg,
 u16 update);
 int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask);
 struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip);
-#endif
+
+#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c 
b/drivers/net/dsa/mv88e6xxx/global1.c
index 39825837a1c9..4081ff0d38a0 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -12,7 +12,7 @@
  * (at your option) any later version.
  */
 
-#include "mv88e6xxx.h"
+#include "chip.h"
 #include "global1.h"
 
 int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h 
b/drivers/net/dsa/mv88e6xxx/global1.h
index 46a4ea0f8c47..3b8f356b348c 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -15,7 +15,7 @@
 #ifndef _MV88E6XXX_GLOBAL1_H
 #define _MV88E6XXX_GLOBAL1_H
 
-#include "mv88e6xxx.h"
+#include "chip.h"
 
 int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
 int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c 
b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index fa7e7db5171b..6b0cf44dc07d 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -10,7 +10,7 @@
  * (at your option) any later version.
  */
 
-#include "mv88e6xxx.h"
+#include "chip.h"
 #include "global1.h"
 
 /* Offset 0x01: ATU FID Register */
diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c 
b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
index 9aea22d4c9e2..bf593c7aaa9b 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
@@ -11,7 +11,7 @@
  * (at your option) any later version.
  */
 
-#include "mv88e6xxx.h"
+#include "chip.h"
 #include "global1.h"
 
 /* Offset 0x02: VTU FID Register */
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c 
b/drivers/net/dsa/mv88e6xxx/global2.c
index b3fea55071e3..0defce71e381 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.c
+++ b/drivers/net/dsa/mv88e6xxx/global2.c
@@ -15,7 +15,8 @@
 
 #include 
 #include 
-#include "mv88e6xxx.h"
+
+#include "chip.h"
 #include "global2.h"
 
 #define ADDR_GLOBAL2   0x1c
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h 
b/drivers/net/dsa/mv88e6xxx/global2.h
index 96046bb12ca1..b5cfe041ee59 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -15,7 +15,7 @@
 #ifndef _MV88E6

[PATCH net-next 2/5] net: dsa: mv88e6xxx: move PHY macros

2017-06-02 Thread Vivien Didelot
Move the PHY_* macros where they belong, in the related phy.h header.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.h | 4 
 drivers/net/dsa/mv88e6xxx/phy.h  | 3 +++
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index ae7aed533aa5..2929132fb52d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -33,10 +33,6 @@
 #define SMI_CMD_OP_45_READ_DATA_INC((3 << 10) | SMI_CMD_BUSY)
 #define SMI_DATA   0x01
 
-/* PHY Registers */
-#define PHY_PAGE   0x16
-#define PHY_PAGE_COPPER0x00
-
 #define PORT_STATUS0x00
 #define PORT_STATUS_PAUSE_EN   BIT(15)
 #define PORT_STATUS_MY_PAUSE   BIT(14)
diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h
index 91fe3c3e9aea..4131a4e8206a 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.h
+++ b/drivers/net/dsa/mv88e6xxx/phy.h
@@ -14,6 +14,9 @@
 #ifndef _MV88E6XXX_PHY_H
 #define _MV88E6XXX_PHY_H
 
+#define PHY_PAGE   0x16
+#define PHY_PAGE_COPPER0x00
+
 /* PHY Registers accesses implementations */
 int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
   int addr, int reg, u16 *val);
-- 
2.13.0



Re: [PATCH net] net: dsa: Move dsa_switch_{suspend,resume} out of legacy.c

2017-06-02 Thread Vivien Didelot
Florian Fainelli  writes:

> dsa_switch_suspend() and dsa_switch_resume() are functions that belong in
> net/dsa/dsa.c and are not part of the legacy platform support code.
>
> Fixes: a6a71f19fe5e ("net: dsa: isolate legacy code")
> Signed-off-by: Florian Fainelli 

Reviewed-by: Vivien Didelot 


[PATCH net-next v3 5/5] net: dsa: factor skb freeing on xmit

2017-06-01 Thread Vivien Didelot
As of a86d8becc3f0 ("net: dsa: Factor bottom tag receive functions"),
the rcv caller frees the original SKB in case or error.

Be symmetric with that and make the xmit caller do the same.

At the same time, fix the checkpatch NULL comparison check:

CHECK: Comparison to NULL could be written "!nskb"
#208: FILE: net/dsa/tag_trailer.c:35:
+   if (nskb == NULL)

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c   | 8 ++--
 net/dsa/tag_brcm.c| 6 +-
 net/dsa/tag_dsa.c | 8 ++--
 net/dsa/tag_edsa.c| 8 ++--
 net/dsa/tag_ksz.c | 4 +---
 net/dsa/tag_lan9303.c | 5 +
 net/dsa/tag_mtk.c | 6 +-
 net/dsa/tag_qca.c | 6 +-
 net/dsa/tag_trailer.c | 4 +---
 9 files changed, 16 insertions(+), 39 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0442b6bf52fa..1cfdb31a2f44 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -357,10 +357,14 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, 
struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
 
-   /* Transmit function may have to reallocate the original SKB */
+   /* Transmit function may have to reallocate the original SKB,
+* in which case it must have freed it. Only free it here on error.
+*/
nskb = p->xmit(skb, dev);
-   if (!nskb)
+   if (!nskb) {
+   kfree_skb(skb);
return NETDEV_TX_OK;
+   }
 
/* SKB for netpoll still need to be mangled with the protocol-specific
 * tag to be successfully transmitted
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 635ecb6781e4..c03860907f28 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -65,7 +65,7 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
u8 *brcm_tag;
 
if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
-   goto out_free;
+   return NULL;
 
skb_push(skb, BRCM_TAG_LEN);
 
@@ -86,10 +86,6 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
brcm_tag[3] = (1 << p->dp->index) & BRCM_IG_DSTMAP1_MASK;
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev,
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 089c99c8ed51..12867a4b458f 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -28,7 +28,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
 */
if (skb->protocol == htons(ETH_P_8021Q)) {
if (skb_cow_head(skb, 0) < 0)
-   goto out_free;
+   return NULL;
 
/*
 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
@@ -46,7 +46,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
} else {
if (skb_cow_head(skb, DSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, DSA_HLEN);
 
memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
@@ -62,10 +62,6 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index a7eed1d43d80..67a9d26f9075 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -30,7 +30,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
 */
if (skb->protocol == htons(ETH_P_8021Q)) {
if (skb_cow_head(skb, DSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, DSA_HLEN);
 
memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
@@ -55,7 +55,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
} else {
if (skb_cow_head(skb, EDSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, EDSA_HLEN);
 
memmove(skb->data, skb->data + EDSA_HLEN, 2 * ETH_ALEN);
@@ -75,10 +75,6 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index dfcd2fff5b13..b94a334a1d02 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -46,10 +46,8 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, 

[PATCH net-next v3 4/5] net: dsa: remove out_drop label in taggers rcv

2017-06-01 Thread Vivien Didelot
Many rcv functions from net/dsa/tag_*.c have a useless out_drop goto
label which simply returns NULL. Kill it in favor of the obvious.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 net/dsa/tag_brcm.c| 11 ---
 net/dsa/tag_dsa.c | 13 +
 net/dsa/tag_edsa.c| 13 +
 net/dsa/tag_mtk.c |  9 +++--
 net/dsa/tag_qca.c | 11 ---
 net/dsa/tag_trailer.c |  9 +++--
 6 files changed, 24 insertions(+), 42 deletions(-)

diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 9f204f18ada3..635ecb6781e4 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -104,27 +104,27 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, 
struct net_device *dev,
ds = dst->cpu_dp->ds;
 
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
-   goto out_drop;
+   return NULL;
 
/* skb->data points to the EtherType, the tag is right before it */
brcm_tag = skb->data - 2;
 
/* The opcode should never be different than 0b000 */
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
-   goto out_drop;
+   return NULL;
 
/* We should never see a reserved reason code without knowing how to
 * handle it
 */
if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
-   goto out_drop;
+   return NULL;
 
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
 
/* Validate port against switch setup, either the port is totally */
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
-   goto out_drop;
+   return NULL;
 
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
@@ -137,9 +137,6 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, 
struct net_device *dev,
skb->dev = ds->ports[source_port].netdev;
 
return skb;
-
-out_drop:
-   return NULL;
 }
 
 const struct dsa_device_ops brcm_netdev_ops = {
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 3b62a57956a3..089c99c8ed51 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -79,7 +79,7 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev,
int source_port;
 
if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
-   goto out_drop;
+   return NULL;
 
/*
 * The ethertype field is part of the DSA header.
@@ -90,7 +90,7 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev,
 * Check that frame type is either TO_CPU or FORWARD.
 */
if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
-   goto out_drop;
+   return NULL;
 
/*
 * Determine source device and port.
@@ -103,14 +103,14 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, 
struct net_device *dev,
 * port is a registered DSA port.
 */
if (source_device >= DSA_MAX_SWITCHES)
-   goto out_drop;
+   return NULL;
 
ds = dst->ds[source_device];
if (!ds)
-   goto out_drop;
+   return NULL;
 
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
-   goto out_drop;
+   return NULL;
 
/*
 * Convert the DSA header to an 802.1q header if the 'tagged'
@@ -161,9 +161,6 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev,
skb->dev = ds->ports[source_port].netdev;
 
return skb;
-
-out_drop:
-   return NULL;
 }
 
 const struct dsa_device_ops dsa_netdev_ops = {
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index f95cafd05702..a7eed1d43d80 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -92,7 +92,7 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct 
net_device *dev,
int source_port;
 
if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
-   goto out_drop;
+   return NULL;
 
/*
 * Skip the two null bytes after the ethertype.
@@ -103,7 +103,7 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct 
net_device *dev,
 * Check that frame type is either TO_CPU or FORWARD.
 */
if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
-   goto out_drop;
+   return NULL;
 
/*
 * Determine source device and port.
@@ -116,14 +116,14 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, 
struct net_device *dev,
 * port is a registered DSA port.
 */
if (source_device >= DSA_MAX_SWITCHES)
-   goto out_drop;
+   return NULL;
 
ds = dst->ds[sour

[PATCH net-next v3 1/5] net: dsa: comment hot path requirements

2017-06-01 Thread Vivien Didelot
The DSA layer uses inline helpers and copy of the tagging functions for
faster access in hot path. Add comments to detail that.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h  | 3 +++
 net/dsa/dsa_priv.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 7de1234ba136..18ca0a935c96 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -127,6 +127,8 @@ struct dsa_switch_tree {
 * protocol to use.
 */
struct net_device   *master_netdev;
+
+   /* Copy of tag_ops->rcv for faster access in hot path */
struct sk_buff *(*rcv)(struct sk_buff *skb,
   struct net_device *dev,
   struct packet_type *pt,
@@ -465,6 +467,7 @@ struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev);
 
 struct net_device *dsa_dev_to_net_device(struct device *dev);
 
+/* Keep inline for faster access in hot path */
 static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
 {
return dst->rcv != NULL;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 7459d5735d8b..db2a7b9edfb8 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -73,6 +73,7 @@ struct dsa_device_ops {
 };
 
 struct dsa_slave_priv {
+   /* Copy of dp->ds->dst->tag_ops->xmit for faster access in hot path */
struct sk_buff *(*xmit)(struct sk_buff *skb,
struct net_device *dev);
 
-- 
2.13.0



[PATCH net-next v3 0/5] net: dsa: tagger simplification

2017-06-01 Thread Vivien Didelot
This series clarifies the hot path, removes the labels in tagging
implementations, and frees the original SKB in the xmit caller.

Changes in v3:
  - drop removal of usused rcv arguments because they will be used later
  - include the new ksz tagging implementation
  - add reviewers' tags

Changes in v2:
  - do not remove tagger function copies
  - document hot path requirements
  - make netdev_uses_dsa simpler
  - add reviewers' tags

Vivien Didelot (5):
  net: dsa: comment hot path requirements
  net: dsa: do not cast dst
  net: dsa: remove dsa_uses_tagged_protocol
  net: dsa: remove out_drop label in taggers rcv
  net: dsa: factor skb freeing on xmit

 include/net/dsa.h | 11 ---
 net/dsa/dsa2.c|  2 +-
 net/dsa/dsa_priv.h|  1 +
 net/dsa/legacy.c  |  2 +-
 net/dsa/slave.c   |  8 ++--
 net/dsa/tag_brcm.c| 17 +
 net/dsa/tag_dsa.c | 21 +++--
 net/dsa/tag_edsa.c| 21 +++--
 net/dsa/tag_ksz.c |  4 +---
 net/dsa/tag_lan9303.c |  5 +
 net/dsa/tag_mtk.c | 15 ---
 net/dsa/tag_qca.c | 17 +
 net/dsa/tag_trailer.c | 13 -
 13 files changed, 47 insertions(+), 90 deletions(-)

-- 
2.13.0



[PATCH net-next v3 3/5] net: dsa: remove dsa_uses_tagged_protocol

2017-06-01 Thread Vivien Didelot
Since dev->dsa_ptr is a pointer to a dsa_switch_tree, there is no need
to have another inline helper just to check rcv.

Remove dsa_uses_tagged_protocol and check dsa_ptr && dsa_ptr->rcv
together at the same time.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h | 8 +---
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 18ca0a935c96..448d8bc77707 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -468,16 +468,10 @@ struct mii_bus *dsa_host_dev_to_mii_bus(struct device 
*dev);
 struct net_device *dsa_dev_to_net_device(struct device *dev);
 
 /* Keep inline for faster access in hot path */
-static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
-{
-   return dst->rcv != NULL;
-}
-
 static inline bool netdev_uses_dsa(struct net_device *dev)
 {
 #if IS_ENABLED(CONFIG_NET_DSA)
-   if (dev->dsa_ptr != NULL)
-   return dsa_uses_tagged_protocol(dev->dsa_ptr);
+   return dev->dsa_ptr && dev->dsa_ptr->rcv;
 #endif
return false;
 }
-- 
2.13.0



[PATCH net-next v3 2/5] net: dsa: do not cast dst

2017-06-01 Thread Vivien Didelot
dsa_ptr is not a void pointer anymore since Nov 2011, as of cf50dcc24f82
("dsa: Change dsa_uses_{dsa, trailer}_tags() into inline functions"),
but an explicit dsa_switch_tree pointer, thus remove the (void *) cast.

Reviewed-by: Florian Fainelli 
Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa2.c   | 2 +-
 net/dsa/legacy.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index c0a4576db4a2..21b44a9828f6 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -454,7 +454,7 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
 * sent to the tag format's receive function.
 */
wmb();
-   dst->master_netdev->dsa_ptr = (void *)dst;
+   dst->master_netdev->dsa_ptr = dst;
dst->applied = true;
 
return 0;
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c
index ac4379b8d7ac..d70a1a788d17 100644
--- a/net/dsa/legacy.c
+++ b/net/dsa/legacy.c
@@ -651,7 +651,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, 
struct net_device *dev,
 * sent to the tag format's receive function.
 */
wmb();
-   dev->dsa_ptr = (void *)dst;
+   dev->dsa_ptr = dst;
 
return 0;
 }
-- 
2.13.0



Re: [PATCH net-next v2 6/6] net: dsa: factor skb freeing on xmit

2017-05-31 Thread Vivien Didelot
Hi Florian,

Florian Fainelli  writes:

> On 05/30/2017 11:33 AM, Vivien Didelot wrote:
>> The taggers are currently responsible to free the original SKB if they
>> made a copy of it, or in case of error.
>> 
>> This patch simplifies this by freeing the original SKB in the
>> dsa_slave_xmit caller, but only if an error (NULL) is returned.
>
> Is not it a clearer contract if the tagging protocol must always free
> the original SKB, whether it succeeded in creating a new one or not?

The rcv caller frees the original SKB on error, as of a86d8becc3f0
("net: dsa: Factor bottom tag receive functions").

It'd be nice if we could make both xmit and rcv symmetric, and limit the
tagging implementations to only do their real job: tag/untag an SKB with
the destination/source port.

Thanks,

Vivien


Re: [PATCH net-next v2 4/6] net: dsa: remove unused arguments of tagger rcv

2017-05-30 Thread Vivien Didelot
Florian Fainelli  writes:

>> Is orig_dev really needed in the tagging implementation, or only in the
>> layer above? (dsa_slave_xmit and dsa_switch_rcv.)
>
> It's needed:
>
> https://github.com/ffainelli/linux/commits/switch-tag
> https://github.com/ffainelli/linux/commit/61f9ca70dd21bb8c1615f959934cd0ce80a2f3ce

Patch dropped!


Re: [PATCH net-next v2 4/6] net: dsa: remove unused arguments of tagger rcv

2017-05-30 Thread Vivien Didelot
Hi Florian,

Florian Fainelli  writes:

> I actually have a patch pending that adds support for HW
> insertion/extraction of switch tags (broadcom HW supports that) which
> require the orig_dev to be there so we know what features are supported
> by the master network device.

Is orig_dev really needed in the tagging implementation, or only in the
layer above? (dsa_slave_xmit and dsa_switch_rcv.)

> Do you mind dropping this one from your patch series?

I don't mind if they are actually needed in taggers. I'd wait for
reviews of the other patches before respinning though.

Thanks,

Vivien


Re: [PATCH V2 2/3] net-next: dsa: add multi cpu port support

2017-05-30 Thread Vivien Didelot
Hi John,

Vivien Didelot  writes:

>> +int port_cpu = ds->ports[port].upstream;
>
> ds->ports[port] is p->dp.

I misread this part, p is not yet allocated in that chunk, please ignore
this one comment ;-)

Thanks,

Vivien


Re: [PATCH V2 2/3] net-next: dsa: add multi cpu port support

2017-05-30 Thread Vivien Didelot
Hi John,

John Crispin  writes:

> +static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p)
> +{
> + return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p);
> +}

This looks confusing to me. What DSA calls an "upstream" port for the
moment is the port which goes to the CPU interface.

 CPU0 (eth0)
   |
   | sw0 sw1 sw2
 [p0 p1 p2]--[p0 p1 p2]--[p0 p1 p2]
  |   |   |  |
  eth1 eth2eth3  eth4

So in the example above, sw1p0 is an upstream port, but sw1p2 is not.
This is why dsa_upstream_port makes use of ds->rtable.

> @@ -1140,11 +1140,16 @@ int dsa_slave_create(struct dsa_switch *ds, struct 
> device *parent,
>   struct net_device *master;
>   struct net_device *slave_dev;
>   struct dsa_slave_priv *p;
> + int port_cpu = ds->ports[port].upstream;

ds->ports[port] is p->dp.

>   int ret;
>  
> - master = ds->dst->master_netdev;
> - if (ds->master_netdev)
> + if (port_cpu && ds->ports[port_cpu].ethernet)

0 is a valid port index for a CPU, e.g. Marvell 88E6390.

> + master = ds->ports[port_cpu].ethernet;
> + else if (ds->master_netdev)
>   master = ds->master_netdev;
> + else
> + master = ds->dst->master_netdev;
> + master->dsa_ptr = (void *)ds->dst;
>  
>   slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name,
>NET_NAME_UNKNOWN, ether_setup);
> @@ -1173,6 +1178,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct 
> device *parent,
>   p->dp = &ds->ports[port];
>   INIT_LIST_HEAD(&p->mall_tc_list);
>   p->xmit = dst->tag_ops->xmit;
> + p->master = master;

I'm a bit confused why we need all these references to net devices. We
now have ds->master_netdev, dst->master_netdev, dp->ethernet and
p->master...

Wouldn't it be simpler if we only had dp->ethernet (or whichever more
explicit name) for the conduit interface used to send/receive frames?

Maybe I am missing something, in which case I'm sorry in advance.


Thanks,

Vivien


[PATCH net-next v2 6/6] net: dsa: factor skb freeing on xmit

2017-05-30 Thread Vivien Didelot
The taggers are currently responsible to free the original SKB if they
made a copy of it, or in case of error.

This patch simplifies this by freeing the original SKB in the
dsa_slave_xmit caller, but only if an error (NULL) is returned.

It is still the responsibility of the tagger to free the original SKB if
it returned a copy of it.

At the same time, fix the checkpatch NULL comparison check:

CHECK: Comparison to NULL could be written "!nskb"
#208: FILE: net/dsa/tag_trailer.c:35:
+   if (nskb == NULL)

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c   | 8 ++--
 net/dsa/tag_brcm.c| 6 +-
 net/dsa/tag_dsa.c | 8 ++--
 net/dsa/tag_edsa.c| 8 ++--
 net/dsa/tag_lan9303.c | 5 +
 net/dsa/tag_mtk.c | 6 +-
 net/dsa/tag_qca.c | 6 +-
 net/dsa/tag_trailer.c | 4 +---
 8 files changed, 15 insertions(+), 36 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 887e26695519..4473aec9dcda 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -362,10 +362,14 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, 
struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
 
-   /* Transmit function may have to reallocate the original SKB */
+   /* Transmit function may have to reallocate the original SKB,
+* in which case it must have freed it. Only free it here on error.
+*/
nskb = p->xmit(skb, dev);
-   if (!nskb)
+   if (!nskb) {
+   kfree_skb(skb);
return NETDEV_TX_OK;
+   }
 
/* SKB for netpoll still need to be mangled with the protocol-specific
 * tag to be successfully transmitted
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 10fa4c0ca46b..5db6bcfde025 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -65,7 +65,7 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
u8 *brcm_tag;
 
if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
-   goto out_free;
+   return NULL;
 
skb_push(skb, BRCM_TAG_LEN);
 
@@ -86,10 +86,6 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
brcm_tag[3] = (1 << p->dp->index) & BRCM_IG_DSTMAP1_MASK;
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev)
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 9f5fecaa4a93..6837ca9160a8 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -28,7 +28,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
 */
if (skb->protocol == htons(ETH_P_8021Q)) {
if (skb_cow_head(skb, 0) < 0)
-   goto out_free;
+   return NULL;
 
/*
 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
@@ -46,7 +46,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
} else {
if (skb_cow_head(skb, DSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, DSA_HLEN);
 
memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
@@ -62,10 +62,6 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index a9a06e19abeb..96ddc90472a2 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -30,7 +30,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
 */
if (skb->protocol == htons(ETH_P_8021Q)) {
if (skb_cow_head(skb, DSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, DSA_HLEN);
 
memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
@@ -55,7 +55,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
} else {
if (skb_cow_head(skb, EDSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, EDSA_HLEN);
 
memmove(skb->data, skb->data + EDSA_HLEN, 2 * ETH_ALEN);
@@ -75,10 +75,6 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index 82e150486497..e33348101e8f 100644
---

[PATCH net-next v2 4/6] net: dsa: remove unused arguments of tagger rcv

2017-05-30 Thread Vivien Didelot
The struct dsa_device_ops defines the rcv function with 2 unused
arguments struct packet_type *pt, and struct net_device *orig_dev.

This patch removes them from the definition and implementations.

Reviewed-by: Andrew Lunn 
Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h | 4 +---
 net/dsa/dsa.c | 2 +-
 net/dsa/dsa_priv.h| 4 +---
 net/dsa/tag_brcm.c| 4 +---
 net/dsa/tag_dsa.c | 4 +---
 net/dsa/tag_edsa.c| 4 +---
 net/dsa/tag_lan9303.c | 3 +--
 net/dsa/tag_mtk.c | 4 +---
 net/dsa/tag_qca.c | 4 +---
 net/dsa/tag_trailer.c | 4 +---
 10 files changed, 10 insertions(+), 27 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 4675b52c964c..9e128e447f0b 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -129,9 +129,7 @@ struct dsa_switch_tree {
 
/* Copy of tag_ops->rcv for faster access in hot path */
struct sk_buff *(*rcv)(struct sk_buff *skb,
-  struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev);
+  struct net_device *dev);
 
/*
 * Original copy of the master netdev ethtool_ops
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 3288a80d4d6c..58594784ab94 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -204,7 +204,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct 
net_device *dev,
if (!skb)
return 0;
 
-   nskb = dst->rcv(skb, dev, pt, orig_dev);
+   nskb = dst->rcv(skb, dev);
if (!nskb) {
kfree_skb(skb);
return 0;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 2ce9fec9eec5..1a69d70fcd3a 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -67,9 +67,7 @@ struct dsa_notifier_vlan_info {
 
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
-   struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev);
+   struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev);
 };
 
 struct dsa_slave_priv {
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 9f204f18ada3..c8bff4d7543d 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -92,9 +92,7 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
return NULL;
 }
 
-static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev,
-   struct packet_type *pt,
-   struct net_device *orig_dev)
+static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 3b62a57956a3..41f78e42f9ba 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -68,9 +68,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
return NULL;
 }
 
-static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev)
+static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index f95cafd05702..36389fc8fe06 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -81,9 +81,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
return NULL;
 }
 
-static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
-   struct packet_type *pt,
-   struct net_device *orig_dev)
+static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index afd59330b5f1..82e150486497 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -71,8 +71,7 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, 
struct net_device *dev)
return NULL;
 }
 
-static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
-   struct packet_type *pt, struct net_device *orig_dev)
+static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
 {
u16 *lan9303_tag;
struct dsa_switch_tree *dst = dev->dsa_ptr;
diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
index d1258e84cd71..7c9764c8d61b 100644
--- a/net/dsa/tag_mtk.c
+++ b/net/dsa/tag_mtk.c
@@ -47,9 +47,7 @@ static struct sk_buff *mtk_tag_xmi

[PATCH net-next v2 2/6] net: dsa: do not cast dst

2017-05-30 Thread Vivien Didelot
dsa_ptr is not a void pointer anymore since Nov 2011, as of cf50dcc24f82
("dsa: Change dsa_uses_{dsa, trailer}_tags() into inline functions"),
but an explicit dsa_switch_tree pointer, thus remove the (void *) cast.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa2.c   | 2 +-
 net/dsa/legacy.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 4301f52e4f5a..c4afeca6f478 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -454,7 +454,7 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
 * sent to the tag format's receive function.
 */
wmb();
-   dst->master_netdev->dsa_ptr = (void *)dst;
+   dst->master_netdev->dsa_ptr = dst;
dst->applied = true;
 
return 0;
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c
index ac4379b8d7ac..d70a1a788d17 100644
--- a/net/dsa/legacy.c
+++ b/net/dsa/legacy.c
@@ -651,7 +651,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, 
struct net_device *dev,
 * sent to the tag format's receive function.
 */
wmb();
-   dev->dsa_ptr = (void *)dst;
+   dev->dsa_ptr = dst;
 
return 0;
 }
-- 
2.13.0



[PATCH net-next v2 1/6] net: dsa: comment hot path requirements

2017-05-30 Thread Vivien Didelot
The DSA layer uses inline helpers and copies of the tagging functions
for faster access in hot path. Add comments to detail that.

Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h  | 3 +++
 net/dsa/dsa_priv.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index c0e567c0c824..58297e4c6b31 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -126,6 +126,8 @@ struct dsa_switch_tree {
 * protocol to use.
 */
struct net_device   *master_netdev;
+
+   /* Copy of tag_ops->rcv for faster access in hot path */
struct sk_buff *(*rcv)(struct sk_buff *skb,
   struct net_device *dev,
   struct packet_type *pt,
@@ -464,6 +466,7 @@ struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev);
 
 struct net_device *dsa_dev_to_net_device(struct device *dev);
 
+/* Keep inline for faster access in hot path */
 static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
 {
return dst->rcv != NULL;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c1d4180651af..2ce9fec9eec5 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -73,6 +73,7 @@ struct dsa_device_ops {
 };
 
 struct dsa_slave_priv {
+   /* Copy of dp->ds->dst->tag_ops->xmit for faster access in hot path */
struct sk_buff *(*xmit)(struct sk_buff *skb,
struct net_device *dev);
 
-- 
2.13.0



[PATCH net-next v2 0/6] net: dsa: tagger simplification

2017-05-30 Thread Vivien Didelot
This patchset removes the unused arguments of the taggers rcv function
and the unneeded labels in their implementations, and handles freeing of
the original SKB in the xmit caller.

Changes in v2:
  - do not remove tagger function copies
  - document hot path requirements
  - make netdev_uses_dsa simpler
  - add reviewers' tags

Vivien Didelot (6):
  net: dsa: comment hot path requirements
  net: dsa: do not cast dst
  net: dsa: remove dsa_uses_tagged_protocol
  net: dsa: remove unused arguments of tagger rcv
  net: dsa: remove out_drop label in taggers rcv
  net: dsa: factor skb freeing on xmit

 include/net/dsa.h | 15 +--
 net/dsa/dsa.c |  2 +-
 net/dsa/dsa2.c|  2 +-
 net/dsa/dsa_priv.h|  5 ++---
 net/dsa/legacy.c  |  2 +-
 net/dsa/slave.c   |  8 ++--
 net/dsa/tag_brcm.c| 21 ++---
 net/dsa/tag_dsa.c | 25 -
 net/dsa/tag_edsa.c| 25 -
 net/dsa/tag_lan9303.c |  8 ++--
 net/dsa/tag_mtk.c | 19 +--
 net/dsa/tag_qca.c | 21 ++---
 net/dsa/tag_trailer.c | 17 +
 13 files changed, 56 insertions(+), 114 deletions(-)

-- 
2.13.0



[PATCH net-next v2 5/6] net: dsa: remove out_drop label in taggers rcv

2017-05-30 Thread Vivien Didelot
Many rcv functions from net/dsa/tag_*.c have a useless out_drop goto
label which simply returns NULL. Kill it in favor of the obvious.

Signed-off-by: Vivien Didelot 
---
 net/dsa/tag_brcm.c| 11 ---
 net/dsa/tag_dsa.c | 13 +
 net/dsa/tag_edsa.c| 13 +
 net/dsa/tag_mtk.c |  9 +++--
 net/dsa/tag_qca.c | 11 ---
 net/dsa/tag_trailer.c |  9 +++--
 6 files changed, 24 insertions(+), 42 deletions(-)

diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index c8bff4d7543d..10fa4c0ca46b 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -102,27 +102,27 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, 
struct net_device *dev)
ds = dst->cpu_dp->ds;
 
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
-   goto out_drop;
+   return NULL;
 
/* skb->data points to the EtherType, the tag is right before it */
brcm_tag = skb->data - 2;
 
/* The opcode should never be different than 0b000 */
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
-   goto out_drop;
+   return NULL;
 
/* We should never see a reserved reason code without knowing how to
 * handle it
 */
if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
-   goto out_drop;
+   return NULL;
 
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
 
/* Validate port against switch setup, either the port is totally */
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
-   goto out_drop;
+   return NULL;
 
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
@@ -135,9 +135,6 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, 
struct net_device *dev)
skb->dev = ds->ports[source_port].netdev;
 
return skb;
-
-out_drop:
-   return NULL;
 }
 
 const struct dsa_device_ops brcm_netdev_ops = {
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 41f78e42f9ba..9f5fecaa4a93 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -77,7 +77,7 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
int source_port;
 
if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
-   goto out_drop;
+   return NULL;
 
/*
 * The ethertype field is part of the DSA header.
@@ -88,7 +88,7 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
 * Check that frame type is either TO_CPU or FORWARD.
 */
if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
-   goto out_drop;
+   return NULL;
 
/*
 * Determine source device and port.
@@ -101,14 +101,14 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, 
struct net_device *dev)
 * port is a registered DSA port.
 */
if (source_device >= DSA_MAX_SWITCHES)
-   goto out_drop;
+   return NULL;
 
ds = dst->ds[source_device];
if (!ds)
-   goto out_drop;
+   return NULL;
 
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
-   goto out_drop;
+   return NULL;
 
/*
 * Convert the DSA header to an 802.1q header if the 'tagged'
@@ -159,9 +159,6 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
skb->dev = ds->ports[source_port].netdev;
 
return skb;
-
-out_drop:
-   return NULL;
 }
 
 const struct dsa_device_ops dsa_netdev_ops = {
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 36389fc8fe06..a9a06e19abeb 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -90,7 +90,7 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
int source_port;
 
if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
-   goto out_drop;
+   return NULL;
 
/*
 * Skip the two null bytes after the ethertype.
@@ -101,7 +101,7 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
 * Check that frame type is either TO_CPU or FORWARD.
 */
if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
-   goto out_drop;
+   return NULL;
 
/*
 * Determine source device and port.
@@ -114,14 +114,14 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, 
struct net_device *dev)
 * port is a registered DSA port.
 */
if (source_device >= DSA_MAX_SWITCHES)
-   goto out_drop;
+   return NULL;
 
ds = dst->ds[source_device];
if (!ds)
- 

[PATCH net-next v2 3/6] net: dsa: remove dsa_uses_tagged_protocol

2017-05-30 Thread Vivien Didelot
Since dev->dsa_ptr is a pointer to a dsa_switch_tree, there is no need
to have another inline helper just to check rcv.

Remove dsa_uses_tagged_protocol and check dsa_ptr && dsa_ptr->rcv
together at the same time.

Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h | 8 +---
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 58297e4c6b31..4675b52c964c 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -467,16 +467,10 @@ struct mii_bus *dsa_host_dev_to_mii_bus(struct device 
*dev);
 struct net_device *dsa_dev_to_net_device(struct device *dev);
 
 /* Keep inline for faster access in hot path */
-static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
-{
-   return dst->rcv != NULL;
-}
-
 static inline bool netdev_uses_dsa(struct net_device *dev)
 {
 #if IS_ENABLED(CONFIG_NET_DSA)
-   if (dev->dsa_ptr != NULL)
-   return dsa_uses_tagged_protocol(dev->dsa_ptr);
+   return dev->dsa_ptr && dev->dsa_ptr->rcv;
 #endif
return false;
 }
-- 
2.13.0



Re: [PATCH net-next 1/7] net: dsa: hide dsa_uses_tagged_protocol code

2017-05-30 Thread Vivien Didelot
Hi Andrew,

Andrew Lunn  writes:

> On Tue, May 30, 2017 at 11:56:30AM -0400, Vivien Didelot wrote:
>> Hi Andrew, David,
>> 
>> David Miller  writes:
>> 
>> >>> +bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
>> >>> +{
>> >>> +return !!dst->rcv;
>> >>> +}
>> >>> +
>> >> 
>> >> You need to be careful here. This is in the hot path. Every frame
>> >> received uses this code. And think about a distro kernel, which might
>> >> have DSA enabled by default, yet is unlikely to have any switches. You
>> >> are adding a function call which can be called millions of times per
>> >> second
>> >
>> > Yeah, we really can't make this change.
>> >
>> > This isn't glibc where we're trying to hide the implementation of "FILE *"
>> > behind accessor functions that caller can't see.  We inline things when
>> > performance dictates, and it does here.
>> 
>> Thanks for the explanation, this wasn't obvious to me at all. So inline
>> is mandatory here. Would a dereference like "!!dst->tag_ops->rcv" have
>> an significant impact on performance?
>
> The additional dereference could cause a cache miss when accessing
> tag_ops, which is expensive. dst will be in cache, so dst->rcv should
> always be cheap.

OK! That was interesting. I'm dropping the first 2 patches.

Thanks,

Vivien


Re: [PATCH net-next 1/7] net: dsa: hide dsa_uses_tagged_protocol code

2017-05-30 Thread Vivien Didelot
Hi Andrew, David,

David Miller  writes:

>>> +bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
>>> +{
>>> +   return !!dst->rcv;
>>> +}
>>> +
>> 
>> You need to be careful here. This is in the hot path. Every frame
>> received uses this code. And think about a distro kernel, which might
>> have DSA enabled by default, yet is unlikely to have any switches. You
>> are adding a function call which can be called millions of times per
>> second
>
> Yeah, we really can't make this change.
>
> This isn't glibc where we're trying to hide the implementation of "FILE *"
> behind accessor functions that caller can't see.  We inline things when
> performance dictates, and it does here.

Thanks for the explanation, this wasn't obvious to me at all. So inline
is mandatory here. Would a dereference like "!!dst->tag_ops->rcv" have
an significant impact on performance?

Thanks,

Vivien


Re: [PATCH net-next 6/7] net: dsa: remove useless copy of tagger xmit

2017-05-30 Thread Vivien Didelot
Hi Andrew,

Andrew Lunn  writes:

>>  /* Transmit function may have to reallocate the original SKB */
>> -nskb = p->xmit(skb, dev);
>> +nskb = p->dp->ds->dst->tag_ops->xmit(skb, dev);
>
> This is also the hot path for DSA transmit. Do we really want to do 4
> extra pointer dereferences a million times per second, compared to one
> copy during setup?

Yep I get the idea. It felt weird to copy structure members like this
and not at least reusing the dsa_device_ops structure.

Thanks,

Vivien


Re: [PATCH net-next 4/7] net: dsa: free orig skb on rcv if reallocated

2017-05-30 Thread Vivien Didelot
Hi Andrew,

Andrew Lunn  writes:

> On Tue, May 30, 2017 at 10:21:28AM -0400, Vivien Didelot wrote:
>> If the receive function of a tagger reallocated the SKB, the original
>> SKB is currently not freed. Fix this and free it on both copy or error.
>
> I don't see any of the receive functions reallocate the skb. It might
> be better to just simplify the code to take away the option to return
> a different skb.

I think it was written such way to be symmetrical with the xmit
implementation, where the trailer tagger does reallocate the skb.

I would say that keeping the symmetry is simpler from the point of view
of the tagging implementations, but I don't have strong opinion here.

Thanks,

Vivien


[PATCH net-next 7/7] net: dsa: factor skb freeing on xmit

2017-05-30 Thread Vivien Didelot
The taggers are currently responsible to free the original SKB if they
made a copy of it, or in case of error.

This patch simplifies this by freeing the original SKB in the
dsa_slave_xmit caller if it differs from the return SKB (copy or NULL.)

At the same time, fix the checkpatch NULL comparison check:

CHECK: Comparison to NULL could be written "!nskb"
#208: FILE: net/dsa/tag_trailer.c:35:
+   if (nskb == NULL)

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c   | 2 ++
 net/dsa/tag_brcm.c| 6 +-
 net/dsa/tag_dsa.c | 8 ++--
 net/dsa/tag_edsa.c| 8 ++--
 net/dsa/tag_lan9303.c | 5 +
 net/dsa/tag_mtk.c | 6 +-
 net/dsa/tag_qca.c | 6 +-
 net/dsa/tag_trailer.c | 5 +
 8 files changed, 11 insertions(+), 35 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index ebad2af4d3a8..a520c822436e 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -364,6 +364,8 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, 
struct net_device *dev)
 
/* Transmit function may have to reallocate the original SKB */
nskb = p->dp->ds->dst->tag_ops->xmit(skb, dev);
+   if (nskb != skb)
+   kfree_skb(skb);
if (!nskb)
return NETDEV_TX_OK;
 
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 10fa4c0ca46b..5db6bcfde025 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -65,7 +65,7 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
u8 *brcm_tag;
 
if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
-   goto out_free;
+   return NULL;
 
skb_push(skb, BRCM_TAG_LEN);
 
@@ -86,10 +86,6 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
brcm_tag[3] = (1 << p->dp->index) & BRCM_IG_DSTMAP1_MASK;
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev)
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 9f5fecaa4a93..6837ca9160a8 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -28,7 +28,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
 */
if (skb->protocol == htons(ETH_P_8021Q)) {
if (skb_cow_head(skb, 0) < 0)
-   goto out_free;
+   return NULL;
 
/*
 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
@@ -46,7 +46,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
} else {
if (skb_cow_head(skb, DSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, DSA_HLEN);
 
memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
@@ -62,10 +62,6 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index a9a06e19abeb..96ddc90472a2 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -30,7 +30,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
 */
if (skb->protocol == htons(ETH_P_8021Q)) {
if (skb_cow_head(skb, DSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, DSA_HLEN);
 
memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
@@ -55,7 +55,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
} else {
if (skb_cow_head(skb, EDSA_HLEN) < 0)
-   goto out_free;
+   return NULL;
skb_push(skb, EDSA_HLEN);
 
memmove(skb->data, skb->data + EDSA_HLEN, 2 * ETH_ALEN);
@@ -75,10 +75,6 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
}
 
return skb;
-
-out_free:
-   kfree_skb(skb);
-   return NULL;
 }
 
 static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index 82e150486497..e33348101e8f 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -52,7 +52,7 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, 
struct net_device *dev)
if (skb_cow_head(skb, LAN9303_TAG_LEN) < 0) {
dev_dbg(&dev->dev,
"Cannot make room for the special tag. Dropping 
packet\n");
-   goto out_free;
+   return NULL;
}
 
/* provide 

[PATCH net-next 1/7] net: dsa: hide dsa_uses_tagged_protocol code

2017-05-30 Thread Vivien Didelot
Hide the implementation of dsa_uses_tagged_protocol in dsa.c since this
helper will be extended to access the opaque dsa_device_ops structure.

At the same time, fix the checkpatch comparison check:

CHECK: Comparison to NULL could be written "dst->rcv"
#41: FILE: net/dsa/dsa.c:32:
+   return dst->rcv != NULL;

Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h | 5 +
 net/dsa/dsa.c | 5 +
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index c0e567c0c824..cb5d668b265d 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -464,10 +464,7 @@ struct mii_bus *dsa_host_dev_to_mii_bus(struct device 
*dev);
 
 struct net_device *dsa_dev_to_net_device(struct device *dev);
 
-static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
-{
-   return dst->rcv != NULL;
-}
+bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst);
 
 static inline bool netdev_uses_dsa(struct net_device *dev)
 {
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 3288a80d4d6c..7a8a0358299b 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -27,6 +27,11 @@
 
 #include "dsa_priv.h"
 
+bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
+{
+   return !!dst->rcv;
+}
+
 static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
struct net_device *dev)
 {
-- 
2.13.0



[PATCH net-next 2/7] net: dsa: remove useless rcv copy in DSA tree

2017-05-30 Thread Vivien Didelot
The dsa_switch_tree holds a copy of the rcv member of the dsa_device_ops
structure. dst->rcv is always assigned to dst->tag_ops->rcv. Remove this
useless copy.

Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h | 4 
 net/dsa/dsa.c | 4 ++--
 net/dsa/dsa2.c| 2 --
 net/dsa/legacy.c  | 2 --
 4 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index cb5d668b265d..4b82766715e9 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -126,10 +126,6 @@ struct dsa_switch_tree {
 * protocol to use.
 */
struct net_device   *master_netdev;
-   struct sk_buff *(*rcv)(struct sk_buff *skb,
-  struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev);
 
/*
 * Original copy of the master netdev ethtool_ops
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 7a8a0358299b..861dc0e5020d 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -29,7 +29,7 @@
 
 bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
 {
-   return !!dst->rcv;
+   return dst->tag_ops && dst->tag_ops->rcv;
 }
 
 static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
@@ -209,7 +209,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct 
net_device *dev,
if (!skb)
return 0;
 
-   nskb = dst->rcv(skb, dev, pt, orig_dev);
+   nskb = dst->tag_ops->rcv(skb, dev, pt, orig_dev);
if (!nskb) {
kfree_skb(skb);
return 0;
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 4301f52e4f5a..12306c15ed51 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -528,8 +528,6 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index,
return PTR_ERR(dst->tag_ops);
}
 
-   dst->rcv = dst->tag_ops->rcv;
-
return 0;
 }
 
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c
index ac4379b8d7ac..738c5c2d7d3c 100644
--- a/net/dsa/legacy.c
+++ b/net/dsa/legacy.c
@@ -150,8 +150,6 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, 
struct device *parent)
dst->tag_ops = dsa_resolve_tag_protocol(tag_protocol);
if (IS_ERR(dst->tag_ops))
return PTR_ERR(dst->tag_ops);
-
-   dst->rcv = dst->tag_ops->rcv;
}
 
memcpy(ds->rtable, cd->rtable, sizeof(ds->rtable));
-- 
2.13.0



[PATCH net-next 3/7] net: dsa: remove unused arguments of tagger rcv

2017-05-30 Thread Vivien Didelot
The struct dsa_device_ops defines the rcv function with 2 unused
arguments struct packet_type *pt, and struct net_device *orig_dev.

This patch removes them from the definition and implementations.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa.c | 2 +-
 net/dsa/dsa_priv.h| 4 +---
 net/dsa/tag_brcm.c| 4 +---
 net/dsa/tag_dsa.c | 4 +---
 net/dsa/tag_edsa.c| 4 +---
 net/dsa/tag_lan9303.c | 3 +--
 net/dsa/tag_mtk.c | 4 +---
 net/dsa/tag_qca.c | 4 +---
 net/dsa/tag_trailer.c | 4 +---
 9 files changed, 9 insertions(+), 24 deletions(-)

diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 861dc0e5020d..98173a3f6fd1 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -209,7 +209,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct 
net_device *dev,
if (!skb)
return 0;
 
-   nskb = dst->tag_ops->rcv(skb, dev, pt, orig_dev);
+   nskb = dst->tag_ops->rcv(skb, dev);
if (!nskb) {
kfree_skb(skb);
return 0;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c1d4180651af..0fdd2a8a4ad8 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -67,9 +67,7 @@ struct dsa_notifier_vlan_info {
 
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
-   struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev);
+   struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev);
 };
 
 struct dsa_slave_priv {
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 9f204f18ada3..c8bff4d7543d 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -92,9 +92,7 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, 
struct net_device *dev
return NULL;
 }
 
-static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev,
-   struct packet_type *pt,
-   struct net_device *orig_dev)
+static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device 
*dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 3b62a57956a3..41f78e42f9ba 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -68,9 +68,7 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
return NULL;
 }
 
-static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev)
+static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index f95cafd05702..36389fc8fe06 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -81,9 +81,7 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct 
net_device *dev)
return NULL;
 }
 
-static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
-   struct packet_type *pt,
-   struct net_device *orig_dev)
+static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index afd59330b5f1..82e150486497 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -71,8 +71,7 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, 
struct net_device *dev)
return NULL;
 }
 
-static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
-   struct packet_type *pt, struct net_device *orig_dev)
+static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
 {
u16 *lan9303_tag;
struct dsa_switch_tree *dst = dev->dsa_ptr;
diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
index d1258e84cd71..7c9764c8d61b 100644
--- a/net/dsa/tag_mtk.c
+++ b/net/dsa/tag_mtk.c
@@ -47,9 +47,7 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
return NULL;
 }
 
-static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
-  struct packet_type *pt,
-  struct net_device *orig_dev)
+static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 {
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 2451007699b7..d38bd5cbfad8 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -66,9 +66,7 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, 
struct net_device *dev)
return NULL;

[PATCH net-next 0/7] net: dsa: tagger simplification

2017-05-30 Thread Vivien Didelot
The DSA layer has a dsa_device_ops structure containing two members to
tag and untag the proprietary switch header, called xmit and rcv.

The switch tree and slave private structures respectively hold a useless
copy of the rcv and xmit functions. The tagging implementations use
useless goto labels and only the rcv caller (partially) handles the SKB
freeing. The rcv function also contains unused arguments.

This patchset removes the copy of rcv and xmit functions, the unused
arguments of the rcv signature and the useless labels, and handles
freeing of the SKB in the xmit caller.

Vivien Didelot (7):
  net: dsa: hide dsa_uses_tagged_protocol code
  net: dsa: remove useless rcv copy in DSA tree
  net: dsa: remove unused arguments of tagger rcv
  net: dsa: free orig skb on rcv if reallocated
  net: dsa: remove useless goto label in tagger rcv
  net: dsa: remove useless copy of tagger xmit
  net: dsa: factor skb freeing on xmit

 include/net/dsa.h |  9 +
 net/dsa/dsa.c | 12 +---
 net/dsa/dsa2.c|  2 --
 net/dsa/dsa_priv.h|  7 +--
 net/dsa/legacy.c  |  2 --
 net/dsa/slave.c   |  6 +++---
 net/dsa/tag_brcm.c| 21 ++---
 net/dsa/tag_dsa.c | 25 -
 net/dsa/tag_edsa.c| 25 -
 net/dsa/tag_lan9303.c |  8 ++--
 net/dsa/tag_mtk.c | 19 +--
 net/dsa/tag_qca.c | 21 ++---
 net/dsa/tag_trailer.c | 18 +-
 13 files changed, 54 insertions(+), 121 deletions(-)

-- 
2.13.0



[PATCH net-next 4/7] net: dsa: free orig skb on rcv if reallocated

2017-05-30 Thread Vivien Didelot
If the receive function of a tagger reallocated the SKB, the original
SKB is currently not freed. Fix this and free it on both copy or error.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 98173a3f6fd1..0b6f2c7d7d1c 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -209,11 +209,12 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct 
net_device *dev,
if (!skb)
return 0;
 
+   /* Receive function may have to reallocate the original SKB */
nskb = dst->tag_ops->rcv(skb, dev);
-   if (!nskb) {
+   if (nskb != skb)
kfree_skb(skb);
+   if (!nskb)
return 0;
-   }
 
skb = nskb;
skb_push(skb, ETH_HLEN);
-- 
2.13.0



[PATCH net-next 6/7] net: dsa: remove useless copy of tagger xmit

2017-05-30 Thread Vivien Didelot
The dsa_slave_priv structure holds a copy of the dsa_device_ops xmit
function. It is always assigned to the switch tree xmit function.

Remove this useless copy.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h | 3 ---
 net/dsa/slave.c| 4 +---
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 0fdd2a8a4ad8..282a55639285 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -71,9 +71,6 @@ struct dsa_device_ops {
 };
 
 struct dsa_slave_priv {
-   struct sk_buff *(*xmit)(struct sk_buff *skb,
-   struct net_device *dev);
-
/* DSA port data, such as switch, port index, etc. */
struct dsa_port *dp;
 
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 887e26695519..ebad2af4d3a8 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -363,7 +363,7 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, 
struct net_device *dev)
dev->stats.tx_bytes += skb->len;
 
/* Transmit function may have to reallocate the original SKB */
-   nskb = p->xmit(skb, dev);
+   nskb = p->dp->ds->dst->tag_ops->xmit(skb, dev);
if (!nskb)
return NETDEV_TX_OK;
 
@@ -1136,7 +1136,6 @@ int dsa_slave_resume(struct net_device *slave_dev)
 int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 int port, const char *name)
 {
-   struct dsa_switch_tree *dst = ds->dst;
struct net_device *master;
struct net_device *slave_dev;
struct dsa_slave_priv *p;
@@ -1172,7 +1171,6 @@ int dsa_slave_create(struct dsa_switch *ds, struct device 
*parent,
p = netdev_priv(slave_dev);
p->dp = &ds->ports[port];
INIT_LIST_HEAD(&p->mall_tc_list);
-   p->xmit = dst->tag_ops->xmit;
 
p->old_pause = -1;
p->old_link = -1;
-- 
2.13.0



[PATCH net-next 5/7] net: dsa: remove useless goto label in tagger rcv

2017-05-30 Thread Vivien Didelot
Many rcv functions from net/dsa/tag_*.c have a useless out_drop goto
label which simply returns NULL. Kill it in favor of the obvious.

Signed-off-by: Vivien Didelot 
---
 net/dsa/tag_brcm.c| 11 ---
 net/dsa/tag_dsa.c | 13 +
 net/dsa/tag_edsa.c| 13 +
 net/dsa/tag_mtk.c |  9 +++--
 net/dsa/tag_qca.c | 11 ---
 net/dsa/tag_trailer.c |  9 +++--
 6 files changed, 24 insertions(+), 42 deletions(-)

diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index c8bff4d7543d..10fa4c0ca46b 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -102,27 +102,27 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, 
struct net_device *dev)
ds = dst->cpu_dp->ds;
 
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
-   goto out_drop;
+   return NULL;
 
/* skb->data points to the EtherType, the tag is right before it */
brcm_tag = skb->data - 2;
 
/* The opcode should never be different than 0b000 */
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
-   goto out_drop;
+   return NULL;
 
/* We should never see a reserved reason code without knowing how to
 * handle it
 */
if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
-   goto out_drop;
+   return NULL;
 
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
 
/* Validate port against switch setup, either the port is totally */
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
-   goto out_drop;
+   return NULL;
 
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
@@ -135,9 +135,6 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, 
struct net_device *dev)
skb->dev = ds->ports[source_port].netdev;
 
return skb;
-
-out_drop:
-   return NULL;
 }
 
 const struct dsa_device_ops brcm_netdev_ops = {
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 41f78e42f9ba..9f5fecaa4a93 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -77,7 +77,7 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
int source_port;
 
if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
-   goto out_drop;
+   return NULL;
 
/*
 * The ethertype field is part of the DSA header.
@@ -88,7 +88,7 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
 * Check that frame type is either TO_CPU or FORWARD.
 */
if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
-   goto out_drop;
+   return NULL;
 
/*
 * Determine source device and port.
@@ -101,14 +101,14 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, 
struct net_device *dev)
 * port is a registered DSA port.
 */
if (source_device >= DSA_MAX_SWITCHES)
-   goto out_drop;
+   return NULL;
 
ds = dst->ds[source_device];
if (!ds)
-   goto out_drop;
+   return NULL;
 
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
-   goto out_drop;
+   return NULL;
 
/*
 * Convert the DSA header to an 802.1q header if the 'tagged'
@@ -159,9 +159,6 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
skb->dev = ds->ports[source_port].netdev;
 
return skb;
-
-out_drop:
-   return NULL;
 }
 
 const struct dsa_device_ops dsa_netdev_ops = {
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 36389fc8fe06..a9a06e19abeb 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -90,7 +90,7 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
int source_port;
 
if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
-   goto out_drop;
+   return NULL;
 
/*
 * Skip the two null bytes after the ethertype.
@@ -101,7 +101,7 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct 
net_device *dev)
 * Check that frame type is either TO_CPU or FORWARD.
 */
if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
-   goto out_drop;
+   return NULL;
 
/*
 * Determine source device and port.
@@ -114,14 +114,14 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, 
struct net_device *dev)
 * port is a registered DSA port.
 */
if (source_device >= DSA_MAX_SWITCHES)
-   goto out_drop;
+   return NULL;
 
ds = dst->ds[source_device];
if (!ds)
- 

Re: [PATCH] net: dsa: mv88e6xxx: Add missing static to stub functions

2017-05-29 Thread Vivien Didelot
Hi Arnd,

Arnd Bergmann  writes:

> 'static' was not enough, the helpers must be 'static inline'
>
> net/dsa/mv88e6xxx/global2.h:123:12: error: 'mv88e6xxx_g2_misc_4_bit_port' 
> defined but not used [-Werror=unused-function]
> net/dsa/mv88e6xxx/global2.h:117:12: error: 'mv88e6xxx_g2_pvt_write' defined 
> but not used [-Werror=unused-function]
>
> Fixes: c21fbe29f858 ("net: dsa: mv88e6xxx: Add missing static to stub 
> functions")
> Signed-off-by: Arnd Bergmann 

Reviewed-by: Vivien Didelot 

Thanks,

Vivien


[PATCH net-next] net: dsa: mv88e6xxx: handle SERDES error appropriately

2017-05-26 Thread Vivien Didelot
mv88e6xxx_serdes_power returns an error, so no need to print an error
message inside of it. Rather print it in its caller when the error is
ignored, which is in the mv88e6xxx_port_disable void function.

Catch and return its error in the counterpart mv88e6xxx_port_enable.

Fixes: 04aca9938255 ("dsa: mv88e6xxx: Enable/Disable SERDES on port 
enable/disable")
Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 19 +++
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c2f38f6770aa..742c0eae7fa3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1806,16 +1806,10 @@ static int mv88e6xxx_setup_egress_floods(struct 
mv88e6xxx_chip *chip, int port)
 static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
  bool on)
 {
-   int err = 0;
+   if (chip->info->ops->serdes_power)
+   return chip->info->ops->serdes_power(chip, port, on);
 
-   if (chip->info->ops->serdes_power) {
-   err = chip->info->ops->serdes_power(chip, port, on);
-   if (err)
-   dev_err(chip->dev,
-   "Failed to change SERDES power: %d\n", err);
-   }
-
-   return err;
+   return 0;
 }
 
 static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
@@ -1982,10 +1976,10 @@ static int mv88e6xxx_port_enable(struct dsa_switch *ds, 
int port,
 struct phy_device *phydev)
 {
struct mv88e6xxx_chip *chip = ds->priv;
-   int err = 0;
+   int err;
 
mutex_lock(&chip->reg_lock);
-   mv88e6xxx_serdes_power(chip, port, true);
+   err = mv88e6xxx_serdes_power(chip, port, true);
mutex_unlock(&chip->reg_lock);
 
return err;
@@ -1997,7 +1991,8 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, 
int port,
struct mv88e6xxx_chip *chip = ds->priv;
 
mutex_lock(&chip->reg_lock);
-   mv88e6xxx_serdes_power(chip, port, false);
+   if (mv88e6xxx_serdes_power(chip, port, false))
+   dev_err(chip->dev, "failed to power off SERDES\n");
mutex_unlock(&chip->reg_lock);
 }
 
-- 
2.13.0



[PATCH net-next 1/3] net: dsa: mv88e6xxx: provide a PHY setup helper

2017-05-26 Thread Vivien Didelot
Similarly to the VTU, PVT and ATU setup, provide a mv88e6xxx_phy_setup
helper which wraps mv88e6xxx_ppu_enable, so that no more PPU-related
functions are exposed outside of phy.c.

Thus make mv88e6xxx_ppu_enable static.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 11 ---
 drivers/net/dsa/mv88e6xxx/phy.c  |  7 ++-
 drivers/net/dsa/mv88e6xxx/phy.h  |  2 +-
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 742c0eae7fa3..7f5f44f89389 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2034,13 +2034,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip 
*chip)
u32 upstream_port = dsa_upstream_port(ds);
int err;
 
-   /* Enable the PHY Polling Unit if present, don't discard any packets,
-* and mask all interrupt sources.
-*/
-   err = mv88e6xxx_ppu_enable(chip);
-   if (err)
-   return err;
-
if (chip->info->ops->g1_set_cpu_port) {
err = chip->info->ops->g1_set_cpu_port(chip, upstream_port);
if (err)
@@ -2140,6 +2133,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
goto unlock;
}
 
+   err = mv88e6xxx_phy_setup(chip);
+   if (err)
+   goto unlock;
+
err = mv88e6xxx_vtu_setup(chip);
if (err)
goto unlock;
diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
index 0d3e8aaedf50..b865b1e2b103 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.c
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -124,7 +124,7 @@ static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip 
*chip)
return chip->info->ops->ppu_disable(chip);
 }
 
-int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
+static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
 {
if (!chip->info->ops->ppu_enable)
return 0;
@@ -241,3 +241,8 @@ void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
mv88e6xxx_ppu_state_destroy(chip);
 }
+
+int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip)
+{
+   return mv88e6xxx_ppu_enable(chip);
+}
diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h
index 0961d781b726..dfa98549dfcd 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.h
+++ b/drivers/net/dsa/mv88e6xxx/phy.h
@@ -30,8 +30,8 @@ int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, 
struct mii_bus *bus,
   int addr, int reg, u16 *val);
 int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
int addr, int reg, u16 val);
-int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip);
 void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip);
 void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip);
+int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip);
 
 #endif /*_MV88E6XXX_PHY_H */
-- 
2.13.0



[PATCH net-next 0/3] net: dsa: mv88e6xxx: PHY nitpicks

2017-05-26 Thread Vivien Didelot
This patchset isolates more PPU code into phy.c and makes distinction
between PHY Registers read and write implementations vs. generic PHY
routines.

Vivien Didelot (3):
  net: dsa: mv88e6xxx: provide a PHY setup helper
  net: dsa: mv88e6xxx: rename PHY PPU accessors
  net: dsa: mv88e6xxx: rename PHY PPU functions

 drivers/net/dsa/mv88e6xxx/chip.c | 27 +++-
 drivers/net/dsa/mv88e6xxx/phy.c  | 45 ++--
 drivers/net/dsa/mv88e6xxx/phy.h  | 13 +++-
 3 files changed, 45 insertions(+), 40 deletions(-)

-- 
2.13.0



[PATCH net-next 2/3] net: dsa: mv88e6xxx: rename PHY PPU accessors

2017-05-26 Thread Vivien Didelot
Make it clear that mv88e6xxx_phy_ppu_{read,write} are an implementation
of the .phy_{read,write} operations, by renaming them with the mv88e6185
prefix, since 88E6185 it is the reference switch model supported in an
upstream board (ZII Dev Rev B), which makes use of them.

Distinguish the signatures of implementation specific and generic PHY
functions in the phy.h header.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/chip.c | 16 
 drivers/net/dsa/mv88e6xxx/phy.c  |  4 ++--
 drivers/net/dsa/mv88e6xxx/phy.h  | 11 +++
 3 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7f5f44f89389..070e82ac6132 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2371,8 +2371,8 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
 static const struct mv88e6xxx_ops mv88e6085_ops = {
/* MV88E6XXX_FAMILY_6097 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
-   .phy_read = mv88e6xxx_phy_ppu_read,
-   .phy_write = mv88e6xxx_phy_ppu_write,
+   .phy_read = mv88e6185_phy_ppu_read,
+   .phy_write = mv88e6185_phy_ppu_write,
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
@@ -2402,8 +2402,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
 static const struct mv88e6xxx_ops mv88e6095_ops = {
/* MV88E6XXX_FAMILY_6095 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
-   .phy_read = mv88e6xxx_phy_ppu_read,
-   .phy_write = mv88e6xxx_phy_ppu_write,
+   .phy_read = mv88e6185_phy_ppu_read,
+   .phy_write = mv88e6185_phy_ppu_write,
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
@@ -2480,8 +2480,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
 static const struct mv88e6xxx_ops mv88e6131_ops = {
/* MV88E6XXX_FAMILY_6185 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
-   .phy_read = mv88e6xxx_phy_ppu_read,
-   .phy_write = mv88e6xxx_phy_ppu_write,
+   .phy_read = mv88e6185_phy_ppu_read,
+   .phy_write = mv88e6185_phy_ppu_write,
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
@@ -2727,8 +2727,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
 static const struct mv88e6xxx_ops mv88e6185_ops = {
/* MV88E6XXX_FAMILY_6185 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
-   .phy_read = mv88e6xxx_phy_ppu_read,
-   .phy_write = mv88e6xxx_phy_ppu_write,
+   .phy_read = mv88e6185_phy_ppu_read,
+   .phy_write = mv88e6185_phy_ppu_write,
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
index b865b1e2b103..19e0128257e5 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.c
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -202,7 +202,7 @@ static void mv88e6xxx_ppu_state_destroy(struct 
mv88e6xxx_chip *chip)
del_timer_sync(&chip->ppu_timer);
 }
 
-int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
   int addr, int reg, u16 *val)
 {
int err;
@@ -216,7 +216,7 @@ int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, 
struct mii_bus *bus,
return err;
 }
 
-int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
int addr, int reg, u16 val)
 {
int err;
diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h
index dfa98549dfcd..91fe3c3e9aea 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.h
+++ b/drivers/net/dsa/mv88e6xxx/phy.h
@@ -14,10 +14,17 @@
 #ifndef _MV88E6XXX_PHY_H
 #define _MV88E6XXX_PHY_H
 
+/* PHY Registers accesses implementations */
 int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
   int addr, int reg, u16 *val);
 int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
int addr, int reg, u16 val);
+int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+  int addr, int reg, u16 *val);
+int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+   int addr, int reg, u16 val);
+
+/* Generic PHY operations */
 int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
   int reg, u16 *val);
 int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, 

[PATCH net-next 3/3] net: dsa: mv88e6xxx: rename PHY PPU functions

2017-05-26 Thread Vivien Didelot
Respect the implicit naming convention used in all register sets
specific files, by renaming the mv88e6xxx_ppu_* functions with the
mv88e6xxx_phy_* prefix.

This is simply a s/xxx_ppu/xxx_phy_ppu/ substitution.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/mv88e6xxx/phy.c | 38 +++---
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
index 19e0128257e5..d47a6e08d88c 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.c
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -116,7 +116,7 @@ int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, 
int phy,
return err;
 }
 
-static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
+static int mv88e6xxx_phy_ppu_disable(struct mv88e6xxx_chip *chip)
 {
if (!chip->info->ops->ppu_disable)
return 0;
@@ -124,7 +124,7 @@ static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip 
*chip)
return chip->info->ops->ppu_disable(chip);
 }
 
-static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
+static int mv88e6xxx_phy_ppu_enable(struct mv88e6xxx_chip *chip)
 {
if (!chip->info->ops->ppu_enable)
return 0;
@@ -132,7 +132,7 @@ static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
return chip->info->ops->ppu_enable(chip);
 }
 
-static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
+static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
 {
struct mv88e6xxx_chip *chip;
 
@@ -141,7 +141,7 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct 
*ugly)
mutex_lock(&chip->reg_lock);
 
if (mutex_trylock(&chip->ppu_mutex)) {
-   if (mv88e6xxx_ppu_enable(chip) == 0)
+   if (mv88e6xxx_phy_ppu_enable(chip) == 0)
chip->ppu_disabled = 0;
mutex_unlock(&chip->ppu_mutex);
}
@@ -149,14 +149,14 @@ static void mv88e6xxx_ppu_reenable_work(struct 
work_struct *ugly)
mutex_unlock(&chip->reg_lock);
 }
 
-static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
+static void mv88e6xxx_phy_ppu_reenable_timer(unsigned long _ps)
 {
struct mv88e6xxx_chip *chip = (void *)_ps;
 
schedule_work(&chip->ppu_work);
 }
 
-static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip)
+static int mv88e6xxx_phy_ppu_access_get(struct mv88e6xxx_chip *chip)
 {
int ret;
 
@@ -168,7 +168,7 @@ static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip 
*chip)
 * it.
 */
if (!chip->ppu_disabled) {
-   ret = mv88e6xxx_ppu_disable(chip);
+   ret = mv88e6xxx_phy_ppu_disable(chip);
if (ret < 0) {
mutex_unlock(&chip->ppu_mutex);
return ret;
@@ -182,22 +182,22 @@ static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip 
*chip)
return ret;
 }
 
-static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip)
+static void mv88e6xxx_phy_ppu_access_put(struct mv88e6xxx_chip *chip)
 {
/* Schedule a timer to re-enable the PHY polling unit. */
mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
mutex_unlock(&chip->ppu_mutex);
 }
 
-static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
+static void mv88e6xxx_phy_ppu_state_init(struct mv88e6xxx_chip *chip)
 {
mutex_init(&chip->ppu_mutex);
-   INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work);
-   setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer,
+   INIT_WORK(&chip->ppu_work, mv88e6xxx_phy_ppu_reenable_work);
+   setup_timer(&chip->ppu_timer, mv88e6xxx_phy_ppu_reenable_timer,
(unsigned long)chip);
 }
 
-static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip)
+static void mv88e6xxx_phy_ppu_state_destroy(struct mv88e6xxx_chip *chip)
 {
del_timer_sync(&chip->ppu_timer);
 }
@@ -207,10 +207,10 @@ int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, 
struct mii_bus *bus,
 {
int err;
 
-   err = mv88e6xxx_ppu_access_get(chip);
+   err = mv88e6xxx_phy_ppu_access_get(chip);
if (!err) {
err = mv88e6xxx_read(chip, addr, reg, val);
-   mv88e6xxx_ppu_access_put(chip);
+   mv88e6xxx_phy_ppu_access_put(chip);
}
 
return err;
@@ -221,10 +221,10 @@ int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, 
struct mii_bus *bus,
 {
int err;
 
-   err = mv88e6xxx_ppu_access_get(chip);
+   err = mv88e6xxx_phy_ppu_access_get(chip);
if (!err) {
err = mv88e6xxx_write(chip, addr, reg, val);
-   mv88e6xxx_ppu_access_put(chip);
+   mv88e6xxx_phy_ppu_access_put(chip);
}
 
return err;
@@ -233,16 +233,16 @@ int mv88e6185_phy_pp

[PATCH net-next] net: dsa: remove dev arg of dsa_register_switch

2017-05-26 Thread Vivien Didelot
The current dsa_register_switch function takes a useless struct device
pointer argument, which always equals ds->dev.

Drivers either call it with ds->dev, or with the same device pointer
passed to dsa_switch_alloc, which ends up being assigned to ds->dev.

This patch removes the second argument of the dsa_register_switch and
_dsa_register_switch functions.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/b53/b53_common.c |  2 +-
 drivers/net/dsa/dsa_loop.c   |  2 +-
 drivers/net/dsa/lan9303-core.c   |  2 +-
 drivers/net/dsa/mt7530.c |  2 +-
 drivers/net/dsa/mv88e6xxx/chip.c |  2 +-
 drivers/net/dsa/qca8k.c  |  2 +-
 include/net/dsa.h|  2 +-
 net/dsa/dsa2.c   | 10 +-
 8 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index fa099ed41652..37bd6bd3b8d0 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1991,7 +1991,7 @@ int b53_switch_register(struct b53_device *dev)
 
pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev);
 
-   return dsa_register_switch(dev->ds, dev->ds->dev);
+   return dsa_register_switch(dev->ds);
 }
 EXPORT_SYMBOL(b53_switch_register);
 
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index 5edf07beb9d2..79e62593ff4e 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -271,7 +271,7 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev)
 
dev_set_drvdata(&mdiodev->dev, ds);
 
-   return dsa_register_switch(ds, ds->dev);
+   return dsa_register_switch(ds);
 }
 
 static void dsa_loop_drv_remove(struct mdio_device *mdiodev)
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index c8b2423c8ef7..cd76e61f1fca 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -802,7 +802,7 @@ static int lan9303_register_switch(struct lan9303 *chip)
chip->ds->ops = &lan9303_switch_ops;
chip->ds->phys_mii_mask = chip->phy_addr_sel_strap ? 0xe : 0x7;
 
-   return dsa_register_switch(chip->ds, chip->dev);
+   return dsa_register_switch(chip->ds);
 }
 
 static void lan9303_probe_reset_gpio(struct lan9303 *chip,
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 4d2f45153ede..25e00d5e0eec 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1080,7 +1080,7 @@ mt7530_probe(struct mdio_device *mdiodev)
mutex_init(&priv->reg_mutex);
dev_set_drvdata(&mdiodev->dev, priv);
 
-   return dsa_register_switch(priv->ds, &mdiodev->dev);
+   return dsa_register_switch(priv->ds);
 }
 
 static void
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c2f38f6770aa..5e992a5745b0 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3892,7 +3892,7 @@ static int mv88e6xxx_register_switch(struct 
mv88e6xxx_chip *chip)
 
dev_set_drvdata(dev, ds);
 
-   return dsa_register_switch(ds, dev);
+   return dsa_register_switch(ds);
 }
 
 static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 0f6a011d8ed1..b3bee7eab45f 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -958,7 +958,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
mutex_init(&priv->reg_mutex);
dev_set_drvdata(&mdiodev->dev, priv);
 
-   return dsa_register_switch(priv->ds, &mdiodev->dev);
+   return dsa_register_switch(priv->ds);
 }
 
 static void
diff --git a/include/net/dsa.h b/include/net/dsa.h
index c0e567c0c824..d9bd6939229a 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -480,7 +480,7 @@ static inline bool netdev_uses_dsa(struct net_device *dev)
 
 struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n);
 void dsa_unregister_switch(struct dsa_switch *ds);
-int dsa_register_switch(struct dsa_switch *ds, struct device *dev);
+int dsa_register_switch(struct dsa_switch *ds);
 #ifdef CONFIG_PM_SLEEP
 int dsa_switch_suspend(struct dsa_switch *ds);
 int dsa_switch_resume(struct dsa_switch *ds);
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 4301f52e4f5a..c0a4576db4a2 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -686,10 +686,10 @@ static struct device_node *dsa_get_ports(struct 
dsa_switch *ds,
return ports;
 }
 
-static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
+static int _dsa_register_switch(struct dsa_switch *ds)
 {
-   struct dsa_chip_data *pdata = dev->platform_data;
-   struct device_node *np = dev->of_node;
+   struct dsa_chip_data *pdata = ds->dev->platform_data;
+   struct device_node *np = ds->dev->of_node;
struct

[PATCH net-next] net: dsa: remove dsa_port_is_bridged

2017-05-26 Thread Vivien Didelot
The helper is only used once and makes the code more complicated that it
should. Remove it and reorganize the variables so that it fits on 80
columns.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 13 -
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 887e26695519..0442b6bf52fa 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -69,18 +69,13 @@ static int dsa_slave_get_iflink(const struct net_device 
*dev)
return p->dp->ds->dst->master_netdev->ifindex;
 }
 
-static inline bool dsa_port_is_bridged(struct dsa_port *dp)
-{
-   return !!dp->bridge_dev;
-}
-
 static int dsa_slave_open(struct net_device *dev)
 {
struct dsa_slave_priv *p = netdev_priv(dev);
-   struct net_device *master = p->dp->ds->dst->master_netdev;
-   struct dsa_switch *ds = p->dp->ds;
-   u8 stp_state = dsa_port_is_bridged(p->dp) ?
-   BR_STATE_BLOCKING : BR_STATE_FORWARDING;
+   struct dsa_port *dp = p->dp;
+   struct dsa_switch *ds = dp->ds;
+   struct net_device *master = ds->dst->master_netdev;
+   u8 stp_state = dp->bridge_dev ? BR_STATE_BLOCKING : BR_STATE_FORWARDING;
int err;
 
if (!(master->flags & IFF_UP))
-- 
2.13.0



[PATCH net-next] net: dsa: b53: remove unused dev argument

2017-05-26 Thread Vivien Didelot
The port net device passed to b53_fdb_copy is not used. Remove it.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/b53/b53_common.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index fa099ed41652..6a5648a9cb09 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1281,8 +1281,7 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 
idx,
b53_arl_to_entry(ent, mac_vid, fwd_entry);
 }
 
-static int b53_fdb_copy(struct net_device *dev, int port,
-   const struct b53_arl_entry *ent,
+static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
struct switchdev_obj_port_fdb *fdb,
switchdev_obj_dump_cb_t *cb)
 {
@@ -1304,7 +1303,6 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
 switchdev_obj_dump_cb_t *cb)
 {
struct b53_device *priv = ds->priv;
-   struct net_device *dev = ds->ports[port].netdev;
struct b53_arl_entry results[2];
unsigned int count = 0;
int ret;
@@ -1320,13 +1318,13 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
return ret;
 
b53_arl_search_rd(priv, 0, &results[0]);
-   ret = b53_fdb_copy(dev, port, &results[0], fdb, cb);
+   ret = b53_fdb_copy(port, &results[0], fdb, cb);
if (ret)
return ret;
 
if (priv->num_arl_entries > 2) {
b53_arl_search_rd(priv, 1, &results[1]);
-   ret = b53_fdb_copy(dev, port, &results[1], fdb, cb);
+   ret = b53_fdb_copy(port, &results[1], fdb, cb);
if (ret)
return ret;
 
-- 
2.13.0



[PATCH net-next] net: dsa: support cross-chip ageing time

2017-05-23 Thread Vivien Didelot
Now that the switchdev bridge ageing time attribute is propagated to all
switch chips of the fabric, each switch can check if the requested value
is valid and program itself, so that the whole fabric shares a common
ageing time setting.

This is especially needed for switch chips in between others, containing
no bridge port members but evidently used in the data path.

To achieve that, remove the condition which skips the other switches. We
also don't need to identify the target switch anymore, thus remove the
sw_index member of the dsa_notifier_ageing_time_info notifier structure.

On ZII Dev Rev B (with two 88E6352 and one 88E6185) and ZII Dev Rev C
(with two 88E6390X), we have the following hardware configuration:

# ip link add name br0 type bridge
# ip link set master br0 dev lan6
br0: port 1(lan6) entered blocking state
br0: port 1(lan6) entered disabled state
# echo 2000 > /sys/class/net/br0/bridge/ageing_time

Before this patch:

zii-rev-b# cat /sys/kernel/debug/mv88e6xxx/sw*/age_time
30
30
15000

zii-rev-c# cat /sys/kernel/debug/mv88e6xxx/sw*/age_time
30
18750

After this patch:

zii-rev-b# cat /sys/kernel/debug/mv88e6xxx/sw*/age_time
15000
15000
15000

zii-rev-c# cat /sys/kernel/debug/mv88e6xxx/sw*/age_time
18750
18750

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h | 1 -
 net/dsa/port.c | 1 -
 net/dsa/switch.c   | 4 
 3 files changed, 6 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 1d52f9051d0e..c1d4180651af 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -32,7 +32,6 @@ enum {
 struct dsa_notifier_ageing_time_info {
struct switchdev_trans *trans;
unsigned int ageing_time;
-   int sw_index;
 };
 
 /* DSA_NOTIFIER_BRIDGE_* */
diff --git a/net/dsa/port.c b/net/dsa/port.c
index c88c0cec8454..efc3bce3a89d 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -135,7 +135,6 @@ int dsa_port_ageing_time(struct dsa_port *dp, clock_t 
ageing_clock,
unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
struct dsa_notifier_ageing_time_info info = {
.ageing_time = ageing_time,
-   .sw_index = dp->ds->index,
.trans = trans,
};
 
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index c1e4b2d5a3ae..d8e5c311ee7c 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -37,10 +37,6 @@ static int dsa_switch_ageing_time(struct dsa_switch *ds,
unsigned int ageing_time = info->ageing_time;
struct switchdev_trans *trans = info->trans;
 
-   /* Do not care yet about other switch chips of the fabric */
-   if (ds->index != info->sw_index)
-   return 0;
-
if (switchdev_trans_ph_prepare(trans)) {
if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
return -ERANGE;
-- 
2.13.0



Re: [PATCH net-next 17/20] net: dsa: add notifier for ageing time

2017-05-22 Thread Vivien Didelot
Hi Florian,

Florian Fainelli  writes:

> On 05/19/2017 02:00 PM, Vivien Didelot wrote:
>> This patch keeps the port-wide ageing time handling code in
>> dsa_port_ageing_time, pushes the requested ageing time value in a new
>> switch fabric notification, and moves the switch-wide ageing time
>> handling code in dsa_switch_ageing_time.
>> 
>> This has the effect that now not only the switch that the target port
>> belongs to can be programmed, but all switches composing the switch
>> fabric. For the moment, keep the current behavior and ignore other
>> switches.
>> 
>> Signed-off-by: Vivien Didelot 
>
> Reviewed-by: Florian Fainelli 
>
>> ---
>>  net/dsa/dsa_priv.h |  8 
>>  net/dsa/port.c | 37 -
>>  net/dsa/switch.c   | 46 ++
>>  3 files changed, 62 insertions(+), 29 deletions(-)
>> 
>> diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
>> index c19241eb094b..becaf8a61b13 100644
>> --- a/net/dsa/dsa_priv.h
>> +++ b/net/dsa/dsa_priv.h
>> @@ -17,10 +17,18 @@
>>  #include 
>>  
>>  enum {
>> +DSA_NOTIFIER_AGEING_TIME,
>>  DSA_NOTIFIER_BRIDGE_JOIN,
>>  DSA_NOTIFIER_BRIDGE_LEAVE,
>
> This is so we keep sorting notifier events alphabetically, right?

Correct. Thanks for your reviews and test!

 Vivien


[PATCH net-next 06/20] net: dsa: change scope of VLAN handlers

2017-05-19 Thread Vivien Didelot
Change the scope of the switchdev VLAN object handlers from the DSA
slave device to the generic DSA port, so that the future port-wide API
can also be used for other port types, such as CPU and DSA links.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 40 
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0921d306aedf..de39da69fd33 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -254,12 +254,10 @@ static int dsa_slave_set_mac_address(struct net_device 
*dev, void *a)
return 0;
 }
 
-static int dsa_slave_port_vlan_add(struct net_device *dev,
-  const struct switchdev_obj_port_vlan *vlan,
-  struct switchdev_trans *trans)
+static int dsa_port_vlan_add(struct dsa_port *dp,
+const struct switchdev_obj_port_vlan *vlan,
+struct switchdev_trans *trans)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_port *dp = p->dp;
struct dsa_switch *ds = dp->ds;
 
if (switchdev_trans_ph_prepare(trans)) {
@@ -274,27 +272,25 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
return 0;
 }
 
-static int dsa_slave_port_vlan_del(struct net_device *dev,
-  const struct switchdev_obj_port_vlan *vlan)
+static int dsa_port_vlan_del(struct dsa_port *dp,
+const struct switchdev_obj_port_vlan *vlan)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (!ds->ops->port_vlan_del)
return -EOPNOTSUPP;
 
-   return ds->ops->port_vlan_del(ds, p->dp->index, vlan);
+   return ds->ops->port_vlan_del(ds, dp->index, vlan);
 }
 
-static int dsa_slave_port_vlan_dump(struct net_device *dev,
-   struct switchdev_obj_port_vlan *vlan,
-   switchdev_obj_dump_cb_t *cb)
+static int dsa_port_vlan_dump(struct dsa_port *dp,
+ struct switchdev_obj_port_vlan *vlan,
+ switchdev_obj_dump_cb_t *cb)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (ds->ops->port_vlan_dump)
-   return ds->ops->port_vlan_dump(ds, p->dp->index, vlan, cb);
+   return ds->ops->port_vlan_dump(ds, dp->index, vlan, cb);
 
return -EOPNOTSUPP;
 }
@@ -499,9 +495,8 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans);
break;
case SWITCHDEV_OBJ_ID_PORT_VLAN:
-   err = dsa_slave_port_vlan_add(dev,
- SWITCHDEV_OBJ_PORT_VLAN(obj),
- trans);
+   err = dsa_port_vlan_add(dp, SWITCHDEV_OBJ_PORT_VLAN(obj),
+   trans);
break;
default:
err = -EOPNOTSUPP;
@@ -526,8 +521,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
break;
case SWITCHDEV_OBJ_ID_PORT_VLAN:
-   err = dsa_slave_port_vlan_del(dev,
- SWITCHDEV_OBJ_PORT_VLAN(obj));
+   err = dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj));
break;
default:
err = -EOPNOTSUPP;
@@ -553,9 +547,7 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
err = dsa_port_mdb_dump(dp, SWITCHDEV_OBJ_PORT_MDB(obj), cb);
break;
case SWITCHDEV_OBJ_ID_PORT_VLAN:
-   err = dsa_slave_port_vlan_dump(dev,
-  SWITCHDEV_OBJ_PORT_VLAN(obj),
-  cb);
+   err = dsa_port_vlan_dump(dp, SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
break;
default:
err = -EOPNOTSUPP;
-- 
2.13.0



[PATCH net-next 03/20] net: dsa: change scope of bridging code

2017-05-19 Thread Vivien Didelot
Now that the bridge join and leave functions only deal with a DSA port,
change their scope from the DSA slave net_device to the DSA generic
dsa_port.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 36 +---
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 371f6d267917..1ad62ef8c261 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -572,13 +572,11 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
return err;
 }
 
-static int dsa_slave_bridge_port_join(struct net_device *dev,
- struct net_device *br)
+static int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_notifier_bridge_info info = {
-   .sw_index = p->dp->ds->index,
-   .port = p->dp->index,
+   .sw_index = dp->ds->index,
+   .port = dp->index,
.br = br,
};
int err;
@@ -586,24 +584,22 @@ static int dsa_slave_bridge_port_join(struct net_device 
*dev,
/* Here the port is already bridged. Reflect the current configuration
 * so that drivers can program their chips accordingly.
 */
-   p->dp->bridge_dev = br;
+   dp->bridge_dev = br;
 
-   err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
+   err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
 
/* The bridging is rolled back on error */
if (err)
-   p->dp->bridge_dev = NULL;
+   dp->bridge_dev = NULL;
 
return err;
 }
 
-static void dsa_slave_bridge_port_leave(struct net_device *dev,
-   struct net_device *br)
+static void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_notifier_bridge_info info = {
-   .sw_index = p->dp->ds->index,
-   .port = p->dp->index,
+   .sw_index = dp->ds->index,
+   .port = dp->index,
.br = br,
};
int err;
@@ -611,16 +607,16 @@ static void dsa_slave_bridge_port_leave(struct net_device 
*dev,
/* Here the port is already unbridged. Reflect the current configuration
 * so that drivers can program their chips accordingly.
 */
-   p->dp->bridge_dev = NULL;
+   dp->bridge_dev = NULL;
 
-   err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
+   err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
if (err)
-   netdev_err(dev, "failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
+   pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
 
/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
 * so allow it to be in BR_STATE_FORWARDING to be kept functional
 */
-   dsa_port_set_state_now(p->dp, BR_STATE_FORWARDING);
+   dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
 }
 
 static int dsa_slave_port_attr_get(struct net_device *dev,
@@ -1526,14 +1522,16 @@ static bool dsa_slave_dev_check(struct net_device *dev)
 static int dsa_slave_changeupper(struct net_device *dev,
 struct netdev_notifier_changeupper_info *info)
 {
+   struct dsa_slave_priv *p = netdev_priv(dev);
+   struct dsa_port *dp = p->dp;
int err = NOTIFY_DONE;
 
if (netif_is_bridge_master(info->upper_dev)) {
if (info->linking) {
-   err = dsa_slave_bridge_port_join(dev, info->upper_dev);
+   err = dsa_port_bridge_join(dp, info->upper_dev);
err = notifier_from_errno(err);
} else {
-   dsa_slave_bridge_port_leave(dev, info->upper_dev);
+   dsa_port_bridge_leave(dp, info->upper_dev);
err = NOTIFY_OK;
}
}
-- 
2.13.0



[PATCH net-next 18/20] net: dsa: add FDB notifier

2017-05-19 Thread Vivien Didelot
Add two new DSA_NOTIFIER_FDB_ADD and DSA_NOTIFIER_FDB_DEL events to
notify not only a single switch, but all switches of a the fabric when
an FDB entry is added or removed.

For the moment, keep the current behavior and ignore other switches.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h | 10 ++
 net/dsa/port.c | 31 ++-
 net/dsa/switch.c   | 43 +++
 3 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index becaf8a61b13..6a7d0d7d0489 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -20,6 +20,8 @@ enum {
DSA_NOTIFIER_AGEING_TIME,
DSA_NOTIFIER_BRIDGE_JOIN,
DSA_NOTIFIER_BRIDGE_LEAVE,
+   DSA_NOTIFIER_FDB_ADD,
+   DSA_NOTIFIER_FDB_DEL,
 };
 
 /* DSA_NOTIFIER_AGEING_TIME */
@@ -36,6 +38,14 @@ struct dsa_notifier_bridge_info {
int port;
 };
 
+/* DSA_NOTIFIER_FDB_* */
+struct dsa_notifier_fdb_info {
+   const struct switchdev_obj_port_fdb *fdb;
+   struct switchdev_trans *trans;
+   int sw_index;
+   int port;
+};
+
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 59328a35394d..ed88d8381642 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -151,29 +151,26 @@ int dsa_port_fdb_add(struct dsa_port *dp,
 const struct switchdev_obj_port_fdb *fdb,
 struct switchdev_trans *trans)
 {
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans);
-   }
-
-   ds->ops->port_fdb_add(ds, dp->index, fdb, trans);
-
-   return 0;
+   struct dsa_notifier_fdb_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .trans = trans,
+   .fdb = fdb,
+   };
+
+   return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info);
 }
 
 int dsa_port_fdb_del(struct dsa_port *dp,
 const struct switchdev_obj_port_fdb *fdb)
 {
-   struct dsa_switch *ds = dp->ds;
+   struct dsa_notifier_fdb_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .fdb = fdb,
+   };
 
-   if (ds->ops->port_fdb_del)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_fdb_del(ds, dp->index, fdb);
+   return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info);
 }
 
 int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb,
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 540770ecc8b0..e71cc860d32c 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -84,6 +84,43 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
return 0;
 }
 
+static int dsa_switch_fdb_add(struct dsa_switch *ds,
+ struct dsa_notifier_fdb_info *info)
+{
+   const struct switchdev_obj_port_fdb *fdb = info->fdb;
+   struct switchdev_trans *trans = info->trans;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_fdb_prepare(ds, info->port, fdb, trans);
+   }
+
+   ds->ops->port_fdb_add(ds, info->port, fdb, trans);
+
+   return 0;
+}
+
+static int dsa_switch_fdb_del(struct dsa_switch *ds,
+ struct dsa_notifier_fdb_info *info)
+{
+   const struct switchdev_obj_port_fdb *fdb = info->fdb;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (!ds->ops->port_fdb_del)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_fdb_del(ds, info->port, fdb);
+}
+
 static int dsa_switch_event(struct notifier_block *nb,
unsigned long event, void *info)
 {
@@ -100,6 +137,12 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_BRIDGE_LEAVE:
err = dsa_switch_bridge_leave(ds, info);
break;
+   case DSA_NOTIFIER_FDB_ADD:
+   err = dsa_switch_fdb_add(ds, info);
+   break;
+   case DSA_NOTIFIER_FDB_DEL:
+   err = dsa_switch_fdb_del(ds, info);
+   break;
default:
err = -EOPNOTSUPP;
break;
-- 
2.13.0



[PATCH net-next 09/20] net: dsa: move port state setters

2017-05-19 Thread Vivien Didelot
Add a new port.c file to hold all DSA port-wide logic. This patch moves
in the code which sets a port state.

Signed-off-by: Vivien Didelot 
---
 net/dsa/Makefile   |  2 +-
 net/dsa/dsa_priv.h |  5 +
 net/dsa/port.c | 55 ++
 net/dsa/slave.c| 40 ---
 4 files changed, 61 insertions(+), 41 deletions(-)
 create mode 100644 net/dsa/port.c

diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index f8c0251d1f43..90e5aa6f7d0f 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -1,6 +1,6 @@
 # the core
 obj-$(CONFIG_NET_DSA) += dsa_core.o
-dsa_core-y += dsa.o slave.o dsa2.o switch.o legacy.o
+dsa_core-y += dsa.o dsa2.o legacy.o port.o slave.o switch.o
 
 # tagging formats
 dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c274130e3ac9..cda218cd9b05 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -60,6 +60,11 @@ void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds);
 int dsa_legacy_register(void);
 void dsa_legacy_unregister(void);
 
+/* port.c */
+int dsa_port_set_state(struct dsa_port *dp, u8 state,
+  struct switchdev_trans *trans);
+void dsa_port_set_state_now(struct dsa_port *dp, u8 state);
+
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
 void dsa_slave_mii_bus_init(struct dsa_switch *ds);
diff --git a/net/dsa/port.c b/net/dsa/port.c
new file mode 100644
index ..6cc4704190fd
--- /dev/null
+++ b/net/dsa/port.c
@@ -0,0 +1,55 @@
+/*
+ * Handling of a single switch port
+ *
+ * Copyright (c) 2017 Savoir-faire Linux Inc.
+ * Vivien Didelot 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include 
+
+#include "dsa_priv.h"
+
+int dsa_port_set_state(struct dsa_port *dp, u8 state,
+  struct switchdev_trans *trans)
+{
+   struct dsa_switch *ds = dp->ds;
+   int port = dp->index;
+
+   if (switchdev_trans_ph_prepare(trans))
+   return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
+
+   if (ds->ops->port_stp_state_set)
+   ds->ops->port_stp_state_set(ds, port, state);
+
+   if (ds->ops->port_fast_age) {
+   /* Fast age FDB entries or flush appropriate forwarding database
+* for the given port, if we are moving it from Learning or
+* Forwarding state, to Disabled or Blocking or Listening state.
+*/
+
+   if ((dp->stp_state == BR_STATE_LEARNING ||
+dp->stp_state == BR_STATE_FORWARDING) &&
+   (state == BR_STATE_DISABLED ||
+state == BR_STATE_BLOCKING ||
+state == BR_STATE_LISTENING))
+   ds->ops->port_fast_age(ds, port);
+   }
+
+   dp->stp_state = state;
+
+   return 0;
+}
+
+void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
+{
+   int err;
+
+   err = dsa_port_set_state(dp, state, NULL);
+   if (err)
+   pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index b0150f79dcdd..2c57c7205aa3 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -84,46 +84,6 @@ static inline bool dsa_port_is_bridged(struct dsa_port *dp)
return !!dp->bridge_dev;
 }
 
-static int dsa_port_set_state(struct dsa_port *dp, u8 state,
- struct switchdev_trans *trans)
-{
-   struct dsa_switch *ds = dp->ds;
-   int port = dp->index;
-
-   if (switchdev_trans_ph_prepare(trans))
-   return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
-
-   if (ds->ops->port_stp_state_set)
-   ds->ops->port_stp_state_set(ds, port, state);
-
-   if (ds->ops->port_fast_age) {
-   /* Fast age FDB entries or flush appropriate forwarding database
-* for the given port, if we are moving it from Learning or
-* Forwarding state, to Disabled or Blocking or Listening state.
-*/
-
-   if ((dp->stp_state == BR_STATE_LEARNING ||
-dp->stp_state == BR_STATE_FORWARDING) &&
-   (state == BR_STATE_DISABLED ||
-state == BR_STATE_BLOCKING ||
-state == BR_STATE_LISTENING))
-   ds->ops->port_fast_age(ds, port);
-   }
-
-   dp->stp_state = state;
-
-   return 0;
-}
-
-static void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
-{
-   int err;
-
-   err = dsa_port_set_state(dp, state, NULL);
-   if (err)
-  

[PATCH net-next 02/20] net: dsa: change scope of notifier call chain

2017-05-19 Thread Vivien Didelot
Change the scope of the fabric notification helper from the DSA slave to
the DSA port, since this is a DSA layer specific notion, that can be
used by non-slave ports (CPU and DSA).

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 403d1dfe7f50..371f6d267917 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -27,10 +27,9 @@
 
 static bool dsa_slave_dev_check(struct net_device *dev);
 
-static int dsa_slave_notify(struct net_device *dev, unsigned long e, void *v)
+static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct raw_notifier_head *nh = &p->dp->ds->dst->nh;
+   struct raw_notifier_head *nh = &dp->ds->dst->nh;
int err;
 
err = raw_notifier_call_chain(nh, e, v);
@@ -589,7 +588,7 @@ static int dsa_slave_bridge_port_join(struct net_device 
*dev,
 */
p->dp->bridge_dev = br;
 
-   err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_JOIN, &info);
+   err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
 
/* The bridging is rolled back on error */
if (err)
@@ -614,7 +613,7 @@ static void dsa_slave_bridge_port_leave(struct net_device 
*dev,
 */
p->dp->bridge_dev = NULL;
 
-   err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
+   err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
if (err)
netdev_err(dev, "failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
 
-- 
2.13.0



[PATCH net-next 15/20] net: dsa: move VLAN handlers

2017-05-19 Thread Vivien Didelot
Move the DSA port code which handles VLAN objects in port.c, where it
belongs.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  8 
 net/dsa/port.c | 41 +
 net/dsa/slave.c| 41 -
 3 files changed, 49 insertions(+), 41 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c2a595036746..16021a891095 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -84,6 +84,14 @@ int dsa_port_mdb_del(struct dsa_port *dp,
 const struct switchdev_obj_port_mdb *mdb);
 int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb,
  switchdev_obj_dump_cb_t *cb);
+int dsa_port_vlan_add(struct dsa_port *dp,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct switchdev_trans *trans);
+int dsa_port_vlan_del(struct dsa_port *dp,
+ const struct switchdev_obj_port_vlan *vlan);
+int dsa_port_vlan_dump(struct dsa_port *dp,
+  struct switchdev_obj_port_vlan *vlan,
+  switchdev_obj_dump_cb_t *cb);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 4ed0124a8d4b..f211b0dfb12d 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -247,3 +247,44 @@ int dsa_port_mdb_dump(struct dsa_port *dp, struct 
switchdev_obj_port_mdb *mdb,
 
return -EOPNOTSUPP;
 }
+
+int dsa_port_vlan_add(struct dsa_port *dp,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct switchdev_trans *trans)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_vlan_prepare(ds, dp->index, vlan, trans);
+   }
+
+   ds->ops->port_vlan_add(ds, dp->index, vlan, trans);
+
+   return 0;
+}
+
+int dsa_port_vlan_del(struct dsa_port *dp,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (!ds->ops->port_vlan_del)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_vlan_del(ds, dp->index, vlan);
+}
+
+int dsa_port_vlan_dump(struct dsa_port *dp,
+  struct switchdev_obj_port_vlan *vlan,
+  switchdev_obj_dump_cb_t *cb)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (ds->ops->port_vlan_dump)
+   return ds->ops->port_vlan_dump(ds, dp->index, vlan, cb);
+
+   return -EOPNOTSUPP;
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 9adcb8267d9a..887e26695519 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -204,47 +204,6 @@ static int dsa_slave_set_mac_address(struct net_device 
*dev, void *a)
return 0;
 }
 
-static int dsa_port_vlan_add(struct dsa_port *dp,
-const struct switchdev_obj_port_vlan *vlan,
-struct switchdev_trans *trans)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_vlan_prepare(ds, dp->index, vlan, trans);
-   }
-
-   ds->ops->port_vlan_add(ds, dp->index, vlan, trans);
-
-   return 0;
-}
-
-static int dsa_port_vlan_del(struct dsa_port *dp,
-const struct switchdev_obj_port_vlan *vlan)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (!ds->ops->port_vlan_del)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_vlan_del(ds, dp->index, vlan);
-}
-
-static int dsa_port_vlan_dump(struct dsa_port *dp,
- struct switchdev_obj_port_vlan *vlan,
- switchdev_obj_dump_cb_t *cb)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (ds->ops->port_vlan_dump)
-   return ds->ops->port_vlan_dump(ds, dp->index, vlan, cb);
-
-   return -EOPNOTSUPP;
-}
-
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
struct dsa_slave_priv *p = netdev_priv(dev);
-- 
2.13.0



[PATCH net-next 13/20] net: dsa: move FDB handlers

2017-05-19 Thread Vivien Didelot
Move the DSA port code which handles FDB objects in port.c, where it
belongs.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  7 +++
 net/dsa/port.c | 40 
 net/dsa/slave.c| 42 --
 3 files changed, 47 insertions(+), 42 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index b0f9837bf5ed..d003a2554c7a 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -70,6 +70,13 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool 
vlan_filtering,
struct switchdev_trans *trans);
 int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
 struct switchdev_trans *trans);
+int dsa_port_fdb_add(struct dsa_port *dp,
+const struct switchdev_obj_port_fdb *fdb,
+struct switchdev_trans *trans);
+int dsa_port_fdb_del(struct dsa_port *dp,
+const struct switchdev_obj_port_fdb *fdb);
+int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb,
+ switchdev_obj_dump_cb_t *cb);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 3382fdc07a11..18ec6d432152 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -167,3 +167,43 @@ int dsa_port_ageing_time(struct dsa_port *dp, clock_t 
ageing_clock,
 
return 0;
 }
+
+int dsa_port_fdb_add(struct dsa_port *dp,
+const struct switchdev_obj_port_fdb *fdb,
+struct switchdev_trans *trans)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans);
+   }
+
+   ds->ops->port_fdb_add(ds, dp->index, fdb, trans);
+
+   return 0;
+}
+
+int dsa_port_fdb_del(struct dsa_port *dp,
+const struct switchdev_obj_port_fdb *fdb)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (ds->ops->port_fdb_del)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_fdb_del(ds, dp->index, fdb);
+}
+
+int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb,
+ switchdev_obj_dump_cb_t *cb)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (ds->ops->port_fdb_dump)
+   return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb);
+
+   return -EOPNOTSUPP;
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 1b0f396c4314..d9b7bf759f44 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -245,48 +245,6 @@ static int dsa_port_vlan_dump(struct dsa_port *dp,
return -EOPNOTSUPP;
 }
 
-static int dsa_port_fdb_add(struct dsa_port *dp,
-   const struct switchdev_obj_port_fdb *fdb,
-   struct switchdev_trans *trans)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans);
-   }
-
-   ds->ops->port_fdb_add(ds, dp->index, fdb, trans);
-
-   return 0;
-}
-
-static int dsa_port_fdb_del(struct dsa_port *dp,
-   const struct switchdev_obj_port_fdb *fdb)
-{
-   struct dsa_switch *ds = dp->ds;
-   int ret = -EOPNOTSUPP;
-
-   if (ds->ops->port_fdb_del)
-   ret = ds->ops->port_fdb_del(ds, dp->index, fdb);
-
-   return ret;
-}
-
-static int dsa_port_fdb_dump(struct dsa_port *dp,
-struct switchdev_obj_port_fdb *fdb,
-switchdev_obj_dump_cb_t *cb)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (ds->ops->port_fdb_dump)
-   return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb);
-
-   return -EOPNOTSUPP;
-}
-
 static int dsa_port_mdb_add(struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb,
struct switchdev_trans *trans)
-- 
2.13.0



[PATCH net-next 07/20] net: dsa: change scope of VLAN filtering setter

2017-05-19 Thread Vivien Didelot
Change the scope of the switchdev VLAN filtering attribute setter from
the DSA slave device to the generic DSA port, so that the future
port-wide API can also be used for other port types, such as CPU and DSA
links.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 15 +++
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index de39da69fd33..216eb38a847d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -388,20 +388,18 @@ static int dsa_slave_ioctl(struct net_device *dev, struct 
ifreq *ifr, int cmd)
return -EOPNOTSUPP;
 }
 
-static int dsa_slave_vlan_filtering(struct net_device *dev,
-   const struct switchdev_attr *attr,
-   struct switchdev_trans *trans)
+static int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
+  struct switchdev_trans *trans)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
/* bridge skips -EOPNOTSUPP, so skip the prepare phase */
if (switchdev_trans_ph_prepare(trans))
return 0;
 
if (ds->ops->port_vlan_filtering)
-   return ds->ops->port_vlan_filtering(ds, p->dp->index,
-   attr->u.vlan_filtering);
+   return ds->ops->port_vlan_filtering(ds, dp->index,
+   vlan_filtering);
 
return 0;
 }
@@ -461,7 +459,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
ret = dsa_port_set_state(dp, attr->u.stp_state, trans);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
-   ret = dsa_slave_vlan_filtering(dev, attr, trans);
+   ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering,
+ trans);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
ret = dsa_slave_ageing_time(dev, attr, trans);
-- 
2.13.0



[PATCH net-next 14/20] net: dsa: move MDB handlers

2017-05-19 Thread Vivien Didelot
Move the DSA port code which handles MDB objects in port.c, where it
belongs.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  7 +++
 net/dsa/port.c | 40 
 net/dsa/slave.c| 41 -
 3 files changed, 47 insertions(+), 41 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d003a2554c7a..c2a595036746 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -77,6 +77,13 @@ int dsa_port_fdb_del(struct dsa_port *dp,
 const struct switchdev_obj_port_fdb *fdb);
 int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb,
  switchdev_obj_dump_cb_t *cb);
+int dsa_port_mdb_add(struct dsa_port *dp,
+const struct switchdev_obj_port_mdb *mdb,
+struct switchdev_trans *trans);
+int dsa_port_mdb_del(struct dsa_port *dp,
+const struct switchdev_obj_port_mdb *mdb);
+int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb,
+ switchdev_obj_dump_cb_t *cb);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 18ec6d432152..4ed0124a8d4b 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -207,3 +207,43 @@ int dsa_port_fdb_dump(struct dsa_port *dp, struct 
switchdev_obj_port_fdb *fdb,
 
return -EOPNOTSUPP;
 }
+
+int dsa_port_mdb_add(struct dsa_port *dp,
+const struct switchdev_obj_port_mdb *mdb,
+struct switchdev_trans *trans)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans);
+   }
+
+   ds->ops->port_mdb_add(ds, dp->index, mdb, trans);
+
+   return 0;
+}
+
+int dsa_port_mdb_del(struct dsa_port *dp,
+const struct switchdev_obj_port_mdb *mdb)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (ds->ops->port_mdb_del)
+   return ds->ops->port_mdb_del(ds, dp->index, mdb);
+
+   return -EOPNOTSUPP;
+}
+
+int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb,
+ switchdev_obj_dump_cb_t *cb)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   if (ds->ops->port_mdb_dump)
+   return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb);
+
+   return -EOPNOTSUPP;
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index d9b7bf759f44..9adcb8267d9a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -245,47 +245,6 @@ static int dsa_port_vlan_dump(struct dsa_port *dp,
return -EOPNOTSUPP;
 }
 
-static int dsa_port_mdb_add(struct dsa_port *dp,
-   const struct switchdev_obj_port_mdb *mdb,
-   struct switchdev_trans *trans)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans);
-   }
-
-   ds->ops->port_mdb_add(ds, dp->index, mdb, trans);
-
-   return 0;
-}
-
-static int dsa_port_mdb_del(struct dsa_port *dp,
-   const struct switchdev_obj_port_mdb *mdb)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (ds->ops->port_mdb_del)
-   return ds->ops->port_mdb_del(ds, dp->index, mdb);
-
-   return -EOPNOTSUPP;
-}
-
-static int dsa_port_mdb_dump(struct dsa_port *dp,
-struct switchdev_obj_port_mdb *mdb,
-switchdev_obj_dump_cb_t *cb)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   if (ds->ops->port_mdb_dump)
-   return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb);
-
-   return -EOPNOTSUPP;
-}
-
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
struct dsa_slave_priv *p = netdev_priv(dev);
-- 
2.13.0



[PATCH net-next 19/20] net: dsa: add MDB notifier

2017-05-19 Thread Vivien Didelot
Add two new DSA_NOTIFIER_MDB_ADD and DSA_NOTIFIER_MDB_DEL events to
notify not only a single switch, but all switches of a the fabric when
an MDB entry is added or removed.

For the moment, keep the current behavior and ignore other switches.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h | 10 ++
 net/dsa/port.c | 31 ++-
 net/dsa/switch.c   | 43 +++
 3 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 6a7d0d7d0489..2b60293b325c 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -22,6 +22,8 @@ enum {
DSA_NOTIFIER_BRIDGE_LEAVE,
DSA_NOTIFIER_FDB_ADD,
DSA_NOTIFIER_FDB_DEL,
+   DSA_NOTIFIER_MDB_ADD,
+   DSA_NOTIFIER_MDB_DEL,
 };
 
 /* DSA_NOTIFIER_AGEING_TIME */
@@ -46,6 +48,14 @@ struct dsa_notifier_fdb_info {
int port;
 };
 
+/* DSA_NOTIFIER_MDB_* */
+struct dsa_notifier_mdb_info {
+   const struct switchdev_obj_port_mdb *mdb;
+   struct switchdev_trans *trans;
+   int sw_index;
+   int port;
+};
+
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index ed88d8381642..c7c4920e7bc9 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -188,29 +188,26 @@ int dsa_port_mdb_add(struct dsa_port *dp,
 const struct switchdev_obj_port_mdb *mdb,
 struct switchdev_trans *trans)
 {
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans);
-   }
-
-   ds->ops->port_mdb_add(ds, dp->index, mdb, trans);
-
-   return 0;
+   struct dsa_notifier_mdb_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .trans = trans,
+   .mdb = mdb,
+   };
+
+   return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info);
 }
 
 int dsa_port_mdb_del(struct dsa_port *dp,
 const struct switchdev_obj_port_mdb *mdb)
 {
-   struct dsa_switch *ds = dp->ds;
+   struct dsa_notifier_mdb_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .mdb = mdb,
+   };
 
-   if (ds->ops->port_mdb_del)
-   return ds->ops->port_mdb_del(ds, dp->index, mdb);
-
-   return -EOPNOTSUPP;
+   return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info);
 }
 
 int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb,
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index e71cc860d32c..b7e8e45869fc 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -121,6 +121,43 @@ static int dsa_switch_fdb_del(struct dsa_switch *ds,
return ds->ops->port_fdb_del(ds, info->port, fdb);
 }
 
+static int dsa_switch_mdb_add(struct dsa_switch *ds,
+ struct dsa_notifier_mdb_info *info)
+{
+   const struct switchdev_obj_port_mdb *mdb = info->mdb;
+   struct switchdev_trans *trans = info->trans;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_mdb_prepare(ds, info->port, mdb, trans);
+   }
+
+   ds->ops->port_mdb_add(ds, info->port, mdb, trans);
+
+   return 0;
+}
+
+static int dsa_switch_mdb_del(struct dsa_switch *ds,
+ struct dsa_notifier_mdb_info *info)
+{
+   const struct switchdev_obj_port_mdb *mdb = info->mdb;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (!ds->ops->port_mdb_del)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_mdb_del(ds, info->port, mdb);
+}
+
 static int dsa_switch_event(struct notifier_block *nb,
unsigned long event, void *info)
 {
@@ -143,6 +180,12 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_FDB_DEL:
err = dsa_switch_fdb_del(ds, info);
break;
+   case DSA_NOTIFIER_MDB_ADD:
+   err = dsa_switch_mdb_add(ds, info);
+   break;
+   case DSA_NOTIFIER_MDB_DEL:
+   err = dsa_switch_mdb_del(ds, info);
+   break;
default:
err = -EOPNOTSUPP;
break;
-- 
2.13.0



[PATCH net-next 16/20] net: dsa: move notifier info to private header

2017-05-19 Thread Vivien Didelot
The DSA notifier events and info structure definitions are not meant for
DSA drivers and users, but only used internally by the DSA core files.

Move them from the public net/dsa.h file to the private dsa_priv.h file.

Also use this opportunity to turn the events into an anonymous enum,
because we don't care about the values, and this will prevent future
conflicts when adding (and sorting) new events.

Signed-off-by: Vivien Didelot 
---
 include/net/dsa.h  | 10 --
 net/dsa/dsa_priv.h | 12 
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 791fed62fb16..c0e567c0c824 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -285,16 +285,6 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
return ds->rtable[dst->cpu_dp->ds->index];
 }
 
-#define DSA_NOTIFIER_BRIDGE_JOIN   1
-#define DSA_NOTIFIER_BRIDGE_LEAVE  2
-
-/* DSA_NOTIFIER_BRIDGE_* */
-struct dsa_notifier_bridge_info {
-   struct net_device *br;
-   int sw_index;
-   int port;
-};
-
 struct dsa_switch_ops {
/*
 * Legacy probing.
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 16021a891095..c19241eb094b 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -16,6 +16,18 @@
 #include 
 #include 
 
+enum {
+   DSA_NOTIFIER_BRIDGE_JOIN,
+   DSA_NOTIFIER_BRIDGE_LEAVE,
+};
+
+/* DSA_NOTIFIER_BRIDGE_* */
+struct dsa_notifier_bridge_info {
+   struct net_device *br;
+   int sw_index;
+   int port;
+};
+
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
-- 
2.13.0



[PATCH net-next 12/20] net: dsa: move ageing time setter

2017-05-19 Thread Vivien Didelot
Move the DSA port code which sets a port ageing time in port.c, where it
belongs.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  2 ++
 net/dsa/port.c | 40 
 net/dsa/slave.c| 40 
 3 files changed, 42 insertions(+), 40 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c145223247c5..b0f9837bf5ed 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -68,6 +68,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct 
net_device *br);
 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
 int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
struct switchdev_trans *trans);
+int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
+struct switchdev_trans *trans);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index c9f95aaf25f1..3382fdc07a11 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -127,3 +127,43 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool 
vlan_filtering,
 
return 0;
 }
+
+static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds,
+   unsigned int ageing_time)
+{
+   int i;
+
+   for (i = 0; i < ds->num_ports; ++i) {
+   struct dsa_port *dp = &ds->ports[i];
+
+   if (dp->ageing_time && dp->ageing_time < ageing_time)
+   ageing_time = dp->ageing_time;
+   }
+
+   return ageing_time;
+}
+
+int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
+struct switchdev_trans *trans)
+{
+   unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
+   unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
+   struct dsa_switch *ds = dp->ds;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
+   return -ERANGE;
+   if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
+   return -ERANGE;
+   return 0;
+   }
+
+   /* Keep the fastest ageing time in case of multiple bridges */
+   dp->ageing_time = ageing_time;
+   ageing_time = dsa_fastest_ageing_time(ds, ageing_time);
+
+   if (ds->ops->set_ageing_time)
+   return ds->ops->set_ageing_time(ds, ageing_time);
+
+   return 0;
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 32e7e78313ba..1b0f396c4314 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -338,46 +338,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct 
ifreq *ifr, int cmd)
return -EOPNOTSUPP;
 }
 
-static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds,
-   unsigned int ageing_time)
-{
-   int i;
-
-   for (i = 0; i < ds->num_ports; ++i) {
-   struct dsa_port *dp = &ds->ports[i];
-
-   if (dp->ageing_time && dp->ageing_time < ageing_time)
-   ageing_time = dp->ageing_time;
-   }
-
-   return ageing_time;
-}
-
-static int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
-   struct switchdev_trans *trans)
-{
-   unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
-   unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
-   return -ERANGE;
-   if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
-   return -ERANGE;
-   return 0;
-   }
-
-   /* Keep the fastest ageing time in case of multiple bridges */
-   dp->ageing_time = ageing_time;
-   ageing_time = dsa_fastest_ageing_time(ds, ageing_time);
-
-   if (ds->ops->set_ageing_time)
-   return ds->ops->set_ageing_time(ds, ageing_time);
-
-   return 0;
-}
-
 static int dsa_slave_port_attr_set(struct net_device *dev,
   const struct switchdev_attr *attr,
   struct switchdev_trans *trans)
-- 
2.13.0



[PATCH net-next 10/20] net: dsa: move bridging routines

2017-05-19 Thread Vivien Didelot
Move the DSA port code which bridges a port in port.c, where it belongs.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  2 ++
 net/dsa/port.c | 58 ++
 net/dsa/slave.c| 57 -
 3 files changed, 60 insertions(+), 57 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index cda218cd9b05..f0b6cd3c8a65 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -64,6 +64,8 @@ void dsa_legacy_unregister(void);
 int dsa_port_set_state(struct dsa_port *dp, u8 state,
   struct switchdev_trans *trans);
 void dsa_port_set_state_now(struct dsa_port *dp, u8 state);
+int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
+void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 6cc4704190fd..da8577fb3d07 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -11,9 +11,20 @@
  */
 
 #include 
+#include 
 
 #include "dsa_priv.h"
 
+static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v)
+{
+   struct raw_notifier_head *nh = &dp->ds->dst->nh;
+   int err;
+
+   err = raw_notifier_call_chain(nh, e, v);
+
+   return notifier_to_errno(err);
+}
+
 int dsa_port_set_state(struct dsa_port *dp, u8 state,
   struct switchdev_trans *trans)
 {
@@ -53,3 +64,50 @@ void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
if (err)
pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
 }
+
+int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
+{
+   struct dsa_notifier_bridge_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .br = br,
+   };
+   int err;
+
+   /* Here the port is already bridged. Reflect the current configuration
+* so that drivers can program their chips accordingly.
+*/
+   dp->bridge_dev = br;
+
+   err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
+
+   /* The bridging is rolled back on error */
+   if (err)
+   dp->bridge_dev = NULL;
+
+   return err;
+}
+
+void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
+{
+   struct dsa_notifier_bridge_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .br = br,
+   };
+   int err;
+
+   /* Here the port is already unbridged. Reflect the current configuration
+* so that drivers can program their chips accordingly.
+*/
+   dp->bridge_dev = NULL;
+
+   err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
+   if (err)
+   pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
+
+   /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
+* so allow it to be in BR_STATE_FORWARDING to be kept functional
+*/
+   dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 2c57c7205aa3..ab298c41b8e7 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -27,16 +27,6 @@
 
 static bool dsa_slave_dev_check(struct net_device *dev);
 
-static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v)
-{
-   struct raw_notifier_head *nh = &dp->ds->dst->nh;
-   int err;
-
-   err = raw_notifier_call_chain(nh, e, v);
-
-   return notifier_to_errno(err);
-}
-
 /* slave mii_bus handling ***/
 static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
@@ -514,53 +504,6 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
return err;
 }
 
-static int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
-{
-   struct dsa_notifier_bridge_info info = {
-   .sw_index = dp->ds->index,
-   .port = dp->index,
-   .br = br,
-   };
-   int err;
-
-   /* Here the port is already bridged. Reflect the current configuration
-* so that drivers can program their chips accordingly.
-*/
-   dp->bridge_dev = br;
-
-   err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
-
-   /* The bridging is rolled back on error */
-   if (err)
-   dp->bridge_dev = NULL;
-
-   return err;
-}
-
-static void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
-{
-   struct dsa_notifier_bridge_info info = {
-   .sw_index = dp->ds->index,
-   .port = dp->index,
-   .br = br,
-   };
-   int err;
-
-   /* Here the port is already unbridged. Reflect the current configuration
-

[PATCH net-next 17/20] net: dsa: add notifier for ageing time

2017-05-19 Thread Vivien Didelot
This patch keeps the port-wide ageing time handling code in
dsa_port_ageing_time, pushes the requested ageing time value in a new
switch fabric notification, and moves the switch-wide ageing time
handling code in dsa_switch_ageing_time.

This has the effect that now not only the switch that the target port
belongs to can be programmed, but all switches composing the switch
fabric. For the moment, keep the current behavior and ignore other
switches.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  8 
 net/dsa/port.c | 37 -
 net/dsa/switch.c   | 46 ++
 3 files changed, 62 insertions(+), 29 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c19241eb094b..becaf8a61b13 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -17,10 +17,18 @@
 #include 
 
 enum {
+   DSA_NOTIFIER_AGEING_TIME,
DSA_NOTIFIER_BRIDGE_JOIN,
DSA_NOTIFIER_BRIDGE_LEAVE,
 };
 
+/* DSA_NOTIFIER_AGEING_TIME */
+struct dsa_notifier_ageing_time_info {
+   struct switchdev_trans *trans;
+   unsigned int ageing_time;
+   int sw_index;
+};
+
 /* DSA_NOTIFIER_BRIDGE_* */
 struct dsa_notifier_bridge_info {
struct net_device *br;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index f211b0dfb12d..59328a35394d 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -128,44 +128,23 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool 
vlan_filtering,
return 0;
 }
 
-static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds,
-   unsigned int ageing_time)
-{
-   int i;
-
-   for (i = 0; i < ds->num_ports; ++i) {
-   struct dsa_port *dp = &ds->ports[i];
-
-   if (dp->ageing_time && dp->ageing_time < ageing_time)
-   ageing_time = dp->ageing_time;
-   }
-
-   return ageing_time;
-}
-
 int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
 struct switchdev_trans *trans)
 {
unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
-   struct dsa_switch *ds = dp->ds;
+   struct dsa_notifier_ageing_time_info info = {
+   .ageing_time = ageing_time,
+   .sw_index = dp->ds->index,
+   .trans = trans,
+   };
 
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
-   return -ERANGE;
-   if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
-   return -ERANGE;
-   return 0;
-   }
+   if (switchdev_trans_ph_prepare(trans))
+   return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
 
-   /* Keep the fastest ageing time in case of multiple bridges */
dp->ageing_time = ageing_time;
-   ageing_time = dsa_fastest_ageing_time(ds, ageing_time);
 
-   if (ds->ops->set_ageing_time)
-   return ds->ops->set_ageing_time(ds, ageing_time);
-
-   return 0;
+   return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
 }
 
 int dsa_port_fdb_add(struct dsa_port *dp,
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index f477053308d2..540770ecc8b0 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -12,9 +12,52 @@
 
 #include 
 #include 
+#include 
 
 #include "dsa_priv.h"
 
+static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
+  unsigned int ageing_time)
+{
+   int i;
+
+   for (i = 0; i < ds->num_ports; ++i) {
+   struct dsa_port *dp = &ds->ports[i];
+
+   if (dp->ageing_time && dp->ageing_time < ageing_time)
+   ageing_time = dp->ageing_time;
+   }
+
+   return ageing_time;
+}
+
+static int dsa_switch_ageing_time(struct dsa_switch *ds,
+ struct dsa_notifier_ageing_time_info *info)
+{
+   unsigned int ageing_time = info->ageing_time;
+   struct switchdev_trans *trans = info->trans;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
+   return -ERANGE;
+   if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
+   return -ERANGE;
+   return 0;
+   }
+
+   /* Program the fastest ageing time in case of multiple bridges */
+   ageing_time = dsa_switch_fastest_ageing_time(ds

[PATCH net-next 00/20] net: dsa: distribute switch events

2017-05-19 Thread Vivien Didelot
DSA is by nature the support for a switch fabric, which can be composed
of a single, or multiple interconnected Ethernet switch chips.

The current DSA core behavior is to identify the slave port targeted by
a request (e.g. adding a VLAN entry), and program the switch chip to
which it belongs accordingly.

This is problematic in a multi-chip environment, since all chips of a
fabric must be aware of most configuration changes. Here are some
concrete examples in a 3-chip environment:

 [CPU] (mdio)
(eth0) |   :   :  :
  _|_______
 [__sw0__]--[__sw1__]--[__sw2__]
  |  |  ||  |  ||  |  |
  v  v  vv  v  vv  v  v
  p1 p2 p3   p4 p5 p6   p7 p8 p9

If you add a VLAN entry on p7, sw2 gets programmed, but frames won't
reach the CPU interface in a VLAN filtered setup. sw0 and sw1 also need
to be programmed. The same problem comes with MAC addresses (FDB, MDB),
or ageing time changes for instance.

This patch series uses the notification chain introduced for bridging,
to notify not only bridge, but switchdev attributes and objects events
to all switch chips of the fabric.

An ugly debug message printing the ignored event and switch info in the
code handling the switch VLAN events would give us:

# bridge vlan add dev p7 vid 42
sw0: ignoring DSA_NOTIFIER_VLAN_ADD for sw2 (prepare phase)
sw1: ignoring DSA_NOTIFIER_VLAN_ADD for sw2 (prepare phase)
sw0: ignoring DSA_NOTIFIER_VLAN_ADD for sw2 (commit phase)
sw1: ignoring DSA_NOTIFIER_VLAN_ADD for sw2 (commit phase)

To achieve that, patches 1-8 change the scope of the bridge and
switchdev callbacks from the DSA slave device to the generic DSA port,
so that the port-wide API can be used later for switch ports not exposed
to userspace, such as CPU and DSA links.

Patches 9-15 move the DSA port specific functions in a new port.c file.

Patches 16-20 introduce new events to notify the fabric about switchdev
attributes and objects manipulation.

This patch series only adds the plumbing to support a distributed
configuration, but for the moment, each switch chip ignores events from
other chips of the fabric, to keep the current behavior.

The next patch series will add support for cross-chip configuration of
bridge ageing time, VLAN and MAC address databases operations, etc.


Vivien Didelot (20):
  net: dsa: change scope of STP state setter
  net: dsa: change scope of notifier call chain
  net: dsa: change scope of bridging code
  net: dsa: change scope of FDB handlers
  net: dsa: change scope of MDB handlers
  net: dsa: change scope of VLAN handlers
  net: dsa: change scope of VLAN filtering setter
  net: dsa: change scope of ageing time setter
  net: dsa: move port state setters
  net: dsa: move bridging routines
  net: dsa: move VLAN filtering setter
  net: dsa: move ageing time setter
  net: dsa: move FDB handlers
  net: dsa: move MDB handlers
  net: dsa: move VLAN handlers
  net: dsa: move notifier info to private header
  net: dsa: add notifier for ageing time
  net: dsa: add FDB notifier
  net: dsa: add MDB notifier
  net: dsa: add VLAN notifier

 include/net/dsa.h  |  10 --
 net/dsa/Makefile   |   2 +-
 net/dsa/dsa_priv.h |  83 +
 net/dsa/port.c | 260 +++
 net/dsa/slave.c| 354 +
 net/dsa/switch.c   | 175 ++
 6 files changed, 547 insertions(+), 337 deletions(-)
 create mode 100644 net/dsa/port.c

-- 
2.13.0



[PATCH net-next 01/20] net: dsa: change scope of STP state setter

2017-05-19 Thread Vivien Didelot
Instead of having multiple STP state helpers scoping a slave device
supporting both the DSA logic and the switchdev binding, provide a
single dsa_port_set_state helper scoping a DSA port, as well as its
dsa_port_set_state_now wrapper which skips the prepare phase.

This allows us to better separate the DSA logic from the slave device
handling.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 44 ++--
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 91236d602301..403d1dfe7f50 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -85,13 +85,15 @@ static inline bool dsa_port_is_bridged(struct dsa_port *dp)
return !!dp->bridge_dev;
 }
 
-static void dsa_slave_set_state(struct net_device *dev, u8 state)
+static int dsa_port_set_state(struct dsa_port *dp, u8 state,
+ struct switchdev_trans *trans)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_port *dp = p->dp;
struct dsa_switch *ds = dp->ds;
int port = dp->index;
 
+   if (switchdev_trans_ph_prepare(trans))
+   return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
+
if (ds->ops->port_stp_state_set)
ds->ops->port_stp_state_set(ds, port, state);
 
@@ -110,6 +112,17 @@ static void dsa_slave_set_state(struct net_device *dev, u8 
state)
}
 
dp->stp_state = state;
+
+   return 0;
+}
+
+static void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
+{
+   int err;
+
+   err = dsa_port_set_state(dp, state, NULL);
+   if (err)
+   pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
 }
 
 static int dsa_slave_open(struct net_device *dev)
@@ -147,7 +160,7 @@ static int dsa_slave_open(struct net_device *dev)
goto clear_promisc;
}
 
-   dsa_slave_set_state(dev, stp_state);
+   dsa_port_set_state_now(p->dp, stp_state);
 
if (p->phy)
phy_start(p->phy);
@@ -189,7 +202,7 @@ static int dsa_slave_close(struct net_device *dev)
if (ds->ops->port_disable)
ds->ops->port_disable(ds, p->dp->index, p->phy);
 
-   dsa_slave_set_state(dev, BR_STATE_DISABLED);
+   dsa_port_set_state_now(p->dp, BR_STATE_DISABLED);
 
return 0;
 }
@@ -386,21 +399,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct 
ifreq *ifr, int cmd)
return -EOPNOTSUPP;
 }
 
-static int dsa_slave_stp_state_set(struct net_device *dev,
-  const struct switchdev_attr *attr,
-  struct switchdev_trans *trans)
-{
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans))
-   return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
-
-   dsa_slave_set_state(dev, attr->u.stp_state);
-
-   return 0;
-}
-
 static int dsa_slave_vlan_filtering(struct net_device *dev,
const struct switchdev_attr *attr,
struct switchdev_trans *trans)
@@ -465,11 +463,13 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
   const struct switchdev_attr *attr,
   struct switchdev_trans *trans)
 {
+   struct dsa_slave_priv *p = netdev_priv(dev);
+   struct dsa_port *dp = p->dp;
int ret;
 
switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
-   ret = dsa_slave_stp_state_set(dev, attr, trans);
+   ret = dsa_port_set_state(dp, attr->u.stp_state, trans);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
ret = dsa_slave_vlan_filtering(dev, attr, trans);
@@ -621,7 +621,7 @@ static void dsa_slave_bridge_port_leave(struct net_device 
*dev,
/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
 * so allow it to be in BR_STATE_FORWARDING to be kept functional
 */
-   dsa_slave_set_state(dev, BR_STATE_FORWARDING);
+   dsa_port_set_state_now(p->dp, BR_STATE_FORWARDING);
 }
 
 static int dsa_slave_port_attr_get(struct net_device *dev,
-- 
2.13.0



[PATCH net-next 04/20] net: dsa: change scope of FDB handlers

2017-05-19 Thread Vivien Didelot
Change the scope of the switchdev FDB object handlers from the DSA slave
device to the generic DSA port, so that the future port-wide API can
also be used for other port types, such as CPU and DSA links.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 50 --
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 1ad62ef8c261..e9c3ea09cc09 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -299,47 +299,44 @@ static int dsa_slave_port_vlan_dump(struct net_device 
*dev,
return -EOPNOTSUPP;
 }
 
-static int dsa_slave_port_fdb_add(struct net_device *dev,
- const struct switchdev_obj_port_fdb *fdb,
- struct switchdev_trans *trans)
+static int dsa_port_fdb_add(struct dsa_port *dp,
+   const struct switchdev_obj_port_fdb *fdb,
+   struct switchdev_trans *trans)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)
return -EOPNOTSUPP;
 
-   return ds->ops->port_fdb_prepare(ds, p->dp->index, fdb, trans);
+   return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans);
}
 
-   ds->ops->port_fdb_add(ds, p->dp->index, fdb, trans);
+   ds->ops->port_fdb_add(ds, dp->index, fdb, trans);
 
return 0;
 }
 
-static int dsa_slave_port_fdb_del(struct net_device *dev,
- const struct switchdev_obj_port_fdb *fdb)
+static int dsa_port_fdb_del(struct dsa_port *dp,
+   const struct switchdev_obj_port_fdb *fdb)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
int ret = -EOPNOTSUPP;
 
if (ds->ops->port_fdb_del)
-   ret = ds->ops->port_fdb_del(ds, p->dp->index, fdb);
+   ret = ds->ops->port_fdb_del(ds, dp->index, fdb);
 
return ret;
 }
 
-static int dsa_slave_port_fdb_dump(struct net_device *dev,
-  struct switchdev_obj_port_fdb *fdb,
-  switchdev_obj_dump_cb_t *cb)
+static int dsa_port_fdb_dump(struct dsa_port *dp,
+struct switchdev_obj_port_fdb *fdb,
+switchdev_obj_dump_cb_t *cb)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (ds->ops->port_fdb_dump)
-   return ds->ops->port_fdb_dump(ds, p->dp->index, fdb, cb);
+   return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb);
 
return -EOPNOTSUPP;
 }
@@ -488,6 +485,8 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
  const struct switchdev_obj *obj,
  struct switchdev_trans *trans)
 {
+   struct dsa_slave_priv *p = netdev_priv(dev);
+   struct dsa_port *dp = p->dp;
int err;
 
/* For the prepare phase, ensure the full set of changes is feasable in
@@ -497,9 +496,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_FDB:
-   err = dsa_slave_port_fdb_add(dev,
-SWITCHDEV_OBJ_PORT_FDB(obj),
-trans);
+   err = dsa_port_fdb_add(dp, SWITCHDEV_OBJ_PORT_FDB(obj), trans);
break;
case SWITCHDEV_OBJ_ID_PORT_MDB:
err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj),
@@ -521,12 +518,13 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 static int dsa_slave_port_obj_del(struct net_device *dev,
  const struct switchdev_obj *obj)
 {
+   struct dsa_slave_priv *p = netdev_priv(dev);
+   struct dsa_port *dp = p->dp;
int err;
 
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_FDB:
-   err = dsa_slave_port_fdb_del(dev,
-SWITCHDEV_OBJ_PORT_FDB(obj));
+   err = dsa_port_fdb_del(dp, SWITCHDEV_OBJ_PORT_FDB(obj));
break;
case SWITCHDEV_OBJ_ID_PORT_MDB:
err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
@@ -547,13 +545,13 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
   struct switchdev_obj *obj,
   switchdev_obj_dump_cb_t *cb)
 {
+

[PATCH net-next 05/20] net: dsa: change scope of MDB handlers

2017-05-19 Thread Vivien Didelot
Change the scope of the switchdev MDB object handlers from the DSA slave
device to the generic DSA port, so that the future port-wide API can
also be used for other port types, such as CPU and DSA links.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 41 ++---
 1 file changed, 18 insertions(+), 23 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index e9c3ea09cc09..0921d306aedf 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -341,46 +341,43 @@ static int dsa_port_fdb_dump(struct dsa_port *dp,
return -EOPNOTSUPP;
 }
 
-static int dsa_slave_port_mdb_add(struct net_device *dev,
- const struct switchdev_obj_port_mdb *mdb,
- struct switchdev_trans *trans)
+static int dsa_port_mdb_add(struct dsa_port *dp,
+   const struct switchdev_obj_port_mdb *mdb,
+   struct switchdev_trans *trans)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
return -EOPNOTSUPP;
 
-   return ds->ops->port_mdb_prepare(ds, p->dp->index, mdb, trans);
+   return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans);
}
 
-   ds->ops->port_mdb_add(ds, p->dp->index, mdb, trans);
+   ds->ops->port_mdb_add(ds, dp->index, mdb, trans);
 
return 0;
 }
 
-static int dsa_slave_port_mdb_del(struct net_device *dev,
- const struct switchdev_obj_port_mdb *mdb)
+static int dsa_port_mdb_del(struct dsa_port *dp,
+   const struct switchdev_obj_port_mdb *mdb)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (ds->ops->port_mdb_del)
-   return ds->ops->port_mdb_del(ds, p->dp->index, mdb);
+   return ds->ops->port_mdb_del(ds, dp->index, mdb);
 
return -EOPNOTSUPP;
 }
 
-static int dsa_slave_port_mdb_dump(struct net_device *dev,
-  struct switchdev_obj_port_mdb *mdb,
-  switchdev_obj_dump_cb_t *cb)
+static int dsa_port_mdb_dump(struct dsa_port *dp,
+struct switchdev_obj_port_mdb *mdb,
+switchdev_obj_dump_cb_t *cb)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
+   struct dsa_switch *ds = dp->ds;
 
if (ds->ops->port_mdb_dump)
-   return ds->ops->port_mdb_dump(ds, p->dp->index, mdb, cb);
+   return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb);
 
return -EOPNOTSUPP;
 }
@@ -499,8 +496,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
err = dsa_port_fdb_add(dp, SWITCHDEV_OBJ_PORT_FDB(obj), trans);
break;
case SWITCHDEV_OBJ_ID_PORT_MDB:
-   err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj),
-trans);
+   err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans);
break;
case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = dsa_slave_port_vlan_add(dev,
@@ -527,7 +523,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
err = dsa_port_fdb_del(dp, SWITCHDEV_OBJ_PORT_FDB(obj));
break;
case SWITCHDEV_OBJ_ID_PORT_MDB:
-   err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
+   err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
break;
case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = dsa_slave_port_vlan_del(dev,
@@ -554,8 +550,7 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
err = dsa_port_fdb_dump(dp, SWITCHDEV_OBJ_PORT_FDB(obj), cb);
break;
case SWITCHDEV_OBJ_ID_PORT_MDB:
-   err = dsa_slave_port_mdb_dump(dev, SWITCHDEV_OBJ_PORT_MDB(obj),
- cb);
+   err = dsa_port_mdb_dump(dp, SWITCHDEV_OBJ_PORT_MDB(obj), cb);
break;
case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = dsa_slave_port_vlan_dump(dev,
-- 
2.13.0



[PATCH net-next 11/20] net: dsa: move VLAN filtering setter

2017-05-19 Thread Vivien Didelot
Move the DSA port code which sets VLAN filtering on a port in port.c,
where it belongs.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h |  2 ++
 net/dsa/port.c | 16 
 net/dsa/slave.c| 16 
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index f0b6cd3c8a65..c145223247c5 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -66,6 +66,8 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state,
 void dsa_port_set_state_now(struct dsa_port *dp, u8 state);
 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
+int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
+   struct switchdev_trans *trans);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index da8577fb3d07..c9f95aaf25f1 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -111,3 +111,19 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct 
net_device *br)
 */
dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
 }
+
+int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
+   struct switchdev_trans *trans)
+{
+   struct dsa_switch *ds = dp->ds;
+
+   /* bridge skips -EOPNOTSUPP, so skip the prepare phase */
+   if (switchdev_trans_ph_prepare(trans))
+   return 0;
+
+   if (ds->ops->port_vlan_filtering)
+   return ds->ops->port_vlan_filtering(ds, dp->index,
+   vlan_filtering);
+
+   return 0;
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index ab298c41b8e7..32e7e78313ba 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -338,22 +338,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct 
ifreq *ifr, int cmd)
return -EOPNOTSUPP;
 }
 
-static int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
-  struct switchdev_trans *trans)
-{
-   struct dsa_switch *ds = dp->ds;
-
-   /* bridge skips -EOPNOTSUPP, so skip the prepare phase */
-   if (switchdev_trans_ph_prepare(trans))
-   return 0;
-
-   if (ds->ops->port_vlan_filtering)
-   return ds->ops->port_vlan_filtering(ds, dp->index,
-   vlan_filtering);
-
-   return 0;
-}
-
 static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds,
unsigned int ageing_time)
 {
-- 
2.13.0



[PATCH net-next 20/20] net: dsa: add VLAN notifier

2017-05-19 Thread Vivien Didelot
Add two new DSA_NOTIFIER_VLAN_ADD and DSA_NOTIFIER_VLAN_DEL events to
notify not only a single switch, but all switches of a the fabric when
an VLAN entry is added or removed.

For the moment, keep the current behavior and ignore other switches.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa_priv.h | 10 ++
 net/dsa/port.c | 31 ++-
 net/dsa/switch.c   | 43 +++
 3 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 2b60293b325c..1d52f9051d0e 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -24,6 +24,8 @@ enum {
DSA_NOTIFIER_FDB_DEL,
DSA_NOTIFIER_MDB_ADD,
DSA_NOTIFIER_MDB_DEL,
+   DSA_NOTIFIER_VLAN_ADD,
+   DSA_NOTIFIER_VLAN_DEL,
 };
 
 /* DSA_NOTIFIER_AGEING_TIME */
@@ -56,6 +58,14 @@ struct dsa_notifier_mdb_info {
int port;
 };
 
+/* DSA_NOTIFIER_VLAN_* */
+struct dsa_notifier_vlan_info {
+   const struct switchdev_obj_port_vlan *vlan;
+   struct switchdev_trans *trans;
+   int sw_index;
+   int port;
+};
+
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index c7c4920e7bc9..c88c0cec8454 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -225,29 +225,26 @@ int dsa_port_vlan_add(struct dsa_port *dp,
  const struct switchdev_obj_port_vlan *vlan,
  struct switchdev_trans *trans)
 {
-   struct dsa_switch *ds = dp->ds;
-
-   if (switchdev_trans_ph_prepare(trans)) {
-   if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_vlan_prepare(ds, dp->index, vlan, trans);
-   }
-
-   ds->ops->port_vlan_add(ds, dp->index, vlan, trans);
-
-   return 0;
+   struct dsa_notifier_vlan_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .trans = trans,
+   .vlan = vlan,
+   };
+
+   return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info);
 }
 
 int dsa_port_vlan_del(struct dsa_port *dp,
  const struct switchdev_obj_port_vlan *vlan)
 {
-   struct dsa_switch *ds = dp->ds;
+   struct dsa_notifier_vlan_info info = {
+   .sw_index = dp->ds->index,
+   .port = dp->index,
+   .vlan = vlan,
+   };
 
-   if (!ds->ops->port_vlan_del)
-   return -EOPNOTSUPP;
-
-   return ds->ops->port_vlan_del(ds, dp->index, vlan);
+   return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
 }
 
 int dsa_port_vlan_dump(struct dsa_port *dp,
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index b7e8e45869fc..c1e4b2d5a3ae 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -158,6 +158,43 @@ static int dsa_switch_mdb_del(struct dsa_switch *ds,
return ds->ops->port_mdb_del(ds, info->port, mdb);
 }
 
+static int dsa_switch_vlan_add(struct dsa_switch *ds,
+  struct dsa_notifier_vlan_info *info)
+{
+   const struct switchdev_obj_port_vlan *vlan = info->vlan;
+   struct switchdev_trans *trans = info->trans;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (switchdev_trans_ph_prepare(trans)) {
+   if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans);
+   }
+
+   ds->ops->port_vlan_add(ds, info->port, vlan, trans);
+
+   return 0;
+}
+
+static int dsa_switch_vlan_del(struct dsa_switch *ds,
+  struct dsa_notifier_vlan_info *info)
+{
+   const struct switchdev_obj_port_vlan *vlan = info->vlan;
+
+   /* Do not care yet about other switch chips of the fabric */
+   if (ds->index != info->sw_index)
+   return 0;
+
+   if (!ds->ops->port_vlan_del)
+   return -EOPNOTSUPP;
+
+   return ds->ops->port_vlan_del(ds, info->port, vlan);
+}
+
 static int dsa_switch_event(struct notifier_block *nb,
unsigned long event, void *info)
 {
@@ -186,6 +223,12 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_MDB_DEL:
err = dsa_switch_mdb_del(ds, info);
break;
+   case DSA_NOTIFIER_VLAN_ADD:
+   err = dsa_switch_vlan_add(ds, info);
+   break;
+   case DSA_NOTIFIER_VLAN_DEL:
+   err = dsa_switch_vlan_del(ds, info);
+   break;
default:
err = -EOPNOTSUPP;
break;
-- 
2.13.0



[PATCH net-next 08/20] net: dsa: change scope of ageing time setter

2017-05-19 Thread Vivien Didelot
Change the scope of the switchdev bridge ageing time attribute setter
from the DSA slave device to the generic DSA port, so that the future
port-wide API can also be used for other port types, such as CPU and DSA
links.

Also ds->ports is now a contiguous array of dsa_port structures, thus
their addresses cannot be NULL. Remove the useless check in
dsa_fastest_ageing_time.

Signed-off-by: Vivien Didelot 
---
 net/dsa/slave.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 216eb38a847d..b0150f79dcdd 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -412,21 +412,19 @@ static unsigned int dsa_fastest_ageing_time(struct 
dsa_switch *ds,
for (i = 0; i < ds->num_ports; ++i) {
struct dsa_port *dp = &ds->ports[i];
 
-   if (dp && dp->ageing_time && dp->ageing_time < ageing_time)
+   if (dp->ageing_time && dp->ageing_time < ageing_time)
ageing_time = dp->ageing_time;
}
 
return ageing_time;
 }
 
-static int dsa_slave_ageing_time(struct net_device *dev,
-const struct switchdev_attr *attr,
-struct switchdev_trans *trans)
+static int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
+   struct switchdev_trans *trans)
 {
-   struct dsa_slave_priv *p = netdev_priv(dev);
-   struct dsa_switch *ds = p->dp->ds;
-   unsigned long ageing_jiffies = clock_t_to_jiffies(attr->u.ageing_time);
+   unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
+   struct dsa_switch *ds = dp->ds;
 
if (switchdev_trans_ph_prepare(trans)) {
if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
@@ -437,7 +435,7 @@ static int dsa_slave_ageing_time(struct net_device *dev,
}
 
/* Keep the fastest ageing time in case of multiple bridges */
-   p->dp->ageing_time = ageing_time;
+   dp->ageing_time = ageing_time;
ageing_time = dsa_fastest_ageing_time(ds, ageing_time);
 
if (ds->ops->set_ageing_time)
@@ -463,7 +461,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
  trans);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
-   ret = dsa_slave_ageing_time(dev, attr, trans);
+   ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans);
break;
default:
ret = -EOPNOTSUPP;
-- 
2.13.0



Re: [PATCH net-next 3/6] net: bridge: break if __br_mdb_del fails

2017-05-18 Thread Vivien Didelot
Hi Nikolay,

Nikolay Aleksandrov  writes:

>> OK good to know. That intention wasn't obvious. I can make __br_mdb_del
>> return void instead? What about the rest of the patchset if I do so?
>
> If you make it return void we will not be able to return proper error value
> when doing a single operation (the else case). About the rest I see only some
> minor style issues, I'll comment on the respective patches. Another minor nit 
> is 
> using switch() instead of if/else for the message types but that is really up 
> to 
> you, I don't mind either way. :-)

Ho OK I understand better the batch vs single delete operation now.
__br_mdb_do hardly makes sense now, because we don't know which case we
are handling... But factorizing br_mdb_do still makes sense. I'll come
up with something.

Thanks,

Vivien


Re: [PATCH net-next 3/6] net: bridge: break if __br_mdb_del fails

2017-05-18 Thread Vivien Didelot
Hi Nikolay,

Nikolay Aleksandrov  writes:

>>  err = __br_mdb_del(br, entry);
>> -if (!err)
>> -__br_mdb_notify(dev, p, entry, RTM_DELMDB);
>> +if (err)
>> +break;
>> +__br_mdb_notify(dev, p, entry, RTM_DELMDB);
>>  }
>>  } else {
>>  err = __br_mdb_del(br, entry);
>> 
>
> This can potentially break user-space scripts that rely on the best-effort
> behaviour, this is the normal "delete without vid & enabled vlan filtering".
> You can check the fdb delete code which does the same, this was intentional.
>
> You can add an mdb entry without a vid to all vlans, add a vlan and then try
> to remove it from all vlans where it is present - with this patch obviously
> that will fail at the new vlan.

OK good to know. That intention wasn't obvious. I can make __br_mdb_del
return void instead? What about the rest of the patchset if I do so?

Thanks,

Vivien


[PATCH net-next 6/6] net: bridge: add br_mdb_do

2017-05-17 Thread Vivien Didelot
Now that the two functions br_mdb_add and br_mdb_del are identical, keep
a single function named br_mdb_do and register it for both RTM_NEWMDB
and RTM_DELMDB message types.

Signed-off-by: Vivien Didelot 
---
 net/bridge/br_mdb.c | 61 +
 1 file changed, 5 insertions(+), 56 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index d280b20587cb..1a1da25f3727 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -556,57 +556,6 @@ static int __br_mdb_add(struct net_bridge_port *p, struct 
br_mdb_entry *entry)
return ret;
 }
 
-static int __br_mdb_do(struct net_bridge_port *p, struct br_mdb_entry *entry,
-  int msgtype);
-
-static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
- struct netlink_ext_ack *extack)
-{
-   struct net *net = sock_net(skb->sk);
-   struct net_bridge_vlan_group *vg;
-   struct net_device *dev, *pdev;
-   struct br_mdb_entry *entry;
-   struct net_bridge_port *p;
-   struct net_bridge_vlan *v;
-   struct net_bridge *br;
-   int msgtype = nlh->nlmsg_type;
-   int err;
-
-   err = br_mdb_parse(skb, nlh, &dev, &entry);
-   if (err < 0)
-   return err;
-
-   br = netdev_priv(dev);
-
-   if (!netif_running(br->dev) || br->multicast_disabled)
-   return -EINVAL;
-
-   /* If vlan filtering is enabled and VLAN is not specified
-* install mdb entry on all vlans configured on the port.
-*/
-   pdev = __dev_get_by_index(net, entry->ifindex);
-   if (!pdev)
-   return -ENODEV;
-
-   p = br_port_get_rtnl(pdev);
-   if (!p || p->br != br || p->state == BR_STATE_DISABLED)
-   return -EINVAL;
-
-   vg = nbp_vlan_group(p);
-   if (br_vlan_enabled(br) && vg && entry->vid == 0) {
-   list_for_each_entry(v, &vg->vlan_list, vlist) {
-   entry->vid = v->vid;
-   err = __br_mdb_do(p, entry, msgtype);
-   if (err)
-   break;
-   }
-   } else {
-   err = __br_mdb_do(p, entry, msgtype);
-   }
-
-   return err;
-}
-
 static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
 {
struct net_bridge_mdb_htable *mdb;
@@ -668,8 +617,8 @@ static int __br_mdb_do(struct net_bridge_port *p, struct 
br_mdb_entry *entry,
return err;
 }
 
-static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
- struct netlink_ext_ack *extack)
+static int br_mdb_do(struct sk_buff *skb, struct nlmsghdr *nlh,
+struct netlink_ext_ack *extack)
 {
struct net *net = sock_net(skb->sk);
struct net_bridge_vlan_group *vg;
@@ -691,7 +640,7 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr 
*nlh,
return -EINVAL;
 
/* If vlan filtering is enabled and VLAN is not specified
-* delete mdb entry on all vlans configured on the port.
+* add or delete mdb entry on all vlans configured on the port.
 */
pdev = __dev_get_by_index(net, entry->ifindex);
if (!pdev)
@@ -719,8 +668,8 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr 
*nlh,
 void br_mdb_init(void)
 {
rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL);
-   rtnl_register(PF_BRIDGE, RTM_NEWMDB, br_mdb_add, NULL, NULL);
-   rtnl_register(PF_BRIDGE, RTM_DELMDB, br_mdb_del, NULL, NULL);
+   rtnl_register(PF_BRIDGE, RTM_NEWMDB, br_mdb_do, NULL, NULL);
+   rtnl_register(PF_BRIDGE, RTM_DELMDB, br_mdb_do, NULL, NULL);
 }
 
 void br_mdb_uninit(void)
-- 
2.13.0



[PATCH net-next 5/6] net: bridge: get msgtype from nlmsghdr in mdb ops

2017-05-17 Thread Vivien Didelot
Retrieve the message type from the nlmsghdr structure instead of
hardcoding it in both br_mdb_add and br_mdb_del.

Signed-off-by: Vivien Didelot 
---
 net/bridge/br_mdb.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index a72d5e6f339f..d280b20587cb 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -569,6 +569,7 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr 
*nlh,
struct net_bridge_port *p;
struct net_bridge_vlan *v;
struct net_bridge *br;
+   int msgtype = nlh->nlmsg_type;
int err;
 
err = br_mdb_parse(skb, nlh, &dev, &entry);
@@ -595,12 +596,12 @@ static int br_mdb_add(struct sk_buff *skb, struct 
nlmsghdr *nlh,
if (br_vlan_enabled(br) && vg && entry->vid == 0) {
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
-   err = __br_mdb_do(p, entry, RTM_NEWMDB);
+   err = __br_mdb_do(p, entry, msgtype);
if (err)
break;
}
} else {
-   err = __br_mdb_do(p, entry, RTM_NEWMDB);
+   err = __br_mdb_do(p, entry, msgtype);
}
 
return err;
@@ -677,6 +678,7 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr 
*nlh,
struct net_bridge_port *p;
struct net_bridge_vlan *v;
struct net_bridge *br;
+   int msgtype = nlh->nlmsg_type;
int err;
 
err = br_mdb_parse(skb, nlh, &dev, &entry);
@@ -703,12 +705,12 @@ static int br_mdb_del(struct sk_buff *skb, struct 
nlmsghdr *nlh,
if (br_vlan_enabled(br) && vg && entry->vid == 0) {
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
-   err = __br_mdb_do(p, entry, RTM_DELMDB);
+   err = __br_mdb_do(p, entry, msgtype);
if (err)
break;
}
} else {
-   err = __br_mdb_do(p, entry, RTM_DELMDB);
+   err = __br_mdb_do(p, entry, msgtype);
}
 
return err;
-- 
2.13.0



[PATCH net-next 4/6] net: bridge: add __br_mdb_do

2017-05-17 Thread Vivien Didelot
br_mdb_add and br_mdb_del call respectively __br_mdb_add and
__br_mdb_del and notify the message type on success.

Factorize this in a new __br_mdb_do function which add or delete a
br_mdb_entry depending on the message type, then notify it.

Note that the dev argument is p->br->dev, so no need to pass it twice.

Signed-off-by: Vivien Didelot 
---
 net/bridge/br_mdb.c | 33 +++--
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 24fb4179..a72d5e6f339f 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -556,6 +556,9 @@ static int __br_mdb_add(struct net_bridge_port *p, struct 
br_mdb_entry *entry)
return ret;
 }
 
+static int __br_mdb_do(struct net_bridge_port *p, struct br_mdb_entry *entry,
+  int msgtype);
+
 static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
  struct netlink_ext_ack *extack)
 {
@@ -592,15 +595,12 @@ static int br_mdb_add(struct sk_buff *skb, struct 
nlmsghdr *nlh,
if (br_vlan_enabled(br) && vg && entry->vid == 0) {
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
-   err = __br_mdb_add(p, entry);
+   err = __br_mdb_do(p, entry, RTM_NEWMDB);
if (err)
break;
-   __br_mdb_notify(dev, p, entry, RTM_NEWMDB);
}
} else {
-   err = __br_mdb_add(p, entry);
-   if (!err)
-   __br_mdb_notify(dev, p, entry, RTM_NEWMDB);
+   err = __br_mdb_do(p, entry, RTM_NEWMDB);
}
 
return err;
@@ -651,6 +651,22 @@ static int __br_mdb_del(struct net_bridge *br, struct 
br_mdb_entry *entry)
return err;
 }
 
+static int __br_mdb_do(struct net_bridge_port *p, struct br_mdb_entry *entry,
+  int msgtype)
+{
+   int err = -EINVAL;
+
+   if (msgtype == RTM_NEWMDB)
+   err = __br_mdb_add(p, entry);
+   else if (msgtype == RTM_DELMDB)
+   err = __br_mdb_del(p->br, entry);
+
+   if (!err)
+   __br_mdb_notify(p->br->dev, p, entry, msgtype);
+
+   return err;
+}
+
 static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
  struct netlink_ext_ack *extack)
 {
@@ -687,15 +703,12 @@ static int br_mdb_del(struct sk_buff *skb, struct 
nlmsghdr *nlh,
if (br_vlan_enabled(br) && vg && entry->vid == 0) {
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
-   err = __br_mdb_del(br, entry);
+   err = __br_mdb_do(p, entry, RTM_DELMDB);
if (err)
break;
-   __br_mdb_notify(dev, p, entry, RTM_DELMDB);
}
} else {
-   err = __br_mdb_del(br, entry);
-   if (!err)
-   __br_mdb_notify(dev, p, entry, RTM_DELMDB);
+   err = __br_mdb_do(p, entry, RTM_DELMDB);
}
 
return err;
-- 
2.13.0



[PATCH net-next 1/6] net: bridge: pass net_bridge_port to __br_mdb_add

2017-05-17 Thread Vivien Didelot
The __br_mdb_add function uses exactly the same mechanism as its caller
br_mdb_add to retrieve the net_bridge_port pointer from br_mdb_entry.

Remove it and pass directly the net_bridge_port pointer to __br_mdb_add.

Signed-off-by: Vivien Didelot 
---
 net/bridge/br_mdb.c | 18 --
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index b0845480a3ae..bef0331f46a4 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -542,25 +542,15 @@ static int br_mdb_add_group(struct net_bridge *br, struct 
net_bridge_port *port,
return 0;
 }
 
-static int __br_mdb_add(struct net *net, struct net_bridge *br,
-   struct br_mdb_entry *entry)
+static int __br_mdb_add(struct net_bridge_port *p, struct br_mdb_entry *entry)
 {
+   struct net_bridge *br = p->br;
struct br_ip ip;
-   struct net_device *dev;
-   struct net_bridge_port *p;
int ret;
 
if (!netif_running(br->dev) || br->multicast_disabled)
return -EINVAL;
 
-   dev = __dev_get_by_index(net, entry->ifindex);
-   if (!dev)
-   return -ENODEV;
-
-   p = br_port_get_rtnl(dev);
-   if (!p || p->br != br || p->state == BR_STATE_DISABLED)
-   return -EINVAL;
-
__mdb_entry_to_br_ip(entry, &ip);
 
spin_lock_bh(&br->multicast_lock);
@@ -602,13 +592,13 @@ static int br_mdb_add(struct sk_buff *skb, struct 
nlmsghdr *nlh,
if (br_vlan_enabled(br) && vg && entry->vid == 0) {
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
-   err = __br_mdb_add(net, br, entry);
+   err = __br_mdb_add(p, entry);
if (err)
break;
__br_mdb_notify(dev, p, entry, RTM_NEWMDB);
}
} else {
-   err = __br_mdb_add(net, br, entry);
+   err = __br_mdb_add(p, entry);
if (!err)
__br_mdb_notify(dev, p, entry, RTM_NEWMDB);
}
-- 
2.13.0



[PATCH net-next 2/6] net: bridge: check multicast bridge only once

2017-05-17 Thread Vivien Didelot
__br_mdb_add and __br_mdb_del both check that the bridge is up and
running and that multicast is enabled on it before doing any operation.

Since they can be called multiple times by br_mdb_add and br_mdb_del,
move the check in their caller functions so that it is done just once.

Signed-off-by: Vivien Didelot 
---
 net/bridge/br_mdb.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index bef0331f46a4..d20a01622b20 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -548,9 +548,6 @@ static int __br_mdb_add(struct net_bridge_port *p, struct 
br_mdb_entry *entry)
struct br_ip ip;
int ret;
 
-   if (!netif_running(br->dev) || br->multicast_disabled)
-   return -EINVAL;
-
__mdb_entry_to_br_ip(entry, &ip);
 
spin_lock_bh(&br->multicast_lock);
@@ -577,6 +574,9 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr 
*nlh,
 
br = netdev_priv(dev);
 
+   if (!netif_running(br->dev) || br->multicast_disabled)
+   return -EINVAL;
+
/* If vlan filtering is enabled and VLAN is not specified
 * install mdb entry on all vlans configured on the port.
 */
@@ -615,9 +615,6 @@ static int __br_mdb_del(struct net_bridge *br, struct 
br_mdb_entry *entry)
struct br_ip ip;
int err = -EINVAL;
 
-   if (!netif_running(br->dev) || br->multicast_disabled)
-   return -EINVAL;
-
__mdb_entry_to_br_ip(entry, &ip);
 
spin_lock_bh(&br->multicast_lock);
@@ -672,6 +669,9 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr 
*nlh,
 
br = netdev_priv(dev);
 
+   if (!netif_running(br->dev) || br->multicast_disabled)
+   return -EINVAL;
+
/* If vlan filtering is enabled and VLAN is not specified
 * delete mdb entry on all vlans configured on the port.
 */
-- 
2.13.0



[PATCH net-next 3/6] net: bridge: break if __br_mdb_del fails

2017-05-17 Thread Vivien Didelot
Be symmetric with br_mdb_add and break if __br_mdb_del returns an error.

Signed-off-by: Vivien Didelot 
---
 net/bridge/br_mdb.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index d20a01622b20..24fb4179 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -688,8 +688,9 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr 
*nlh,
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
err = __br_mdb_del(br, entry);
-   if (!err)
-   __br_mdb_notify(dev, p, entry, RTM_DELMDB);
+   if (err)
+   break;
+   __br_mdb_notify(dev, p, entry, RTM_DELMDB);
}
} else {
err = __br_mdb_del(br, entry);
-- 
2.13.0



[PATCH net-next 0/6] net: bridge: factorize MDB new and del functions

2017-05-17 Thread Vivien Didelot
The br_mdb.c file implements both br_mdb_add and br_mdb_del functions, to
handle respectively the RTM_NEWMDB and RTM_DELMDB message types.

But these two functions are really similar. This patch series factorizes
them into a single br_mdb_do rtnl_doit_func function to reduce
boilerplate and simplify the MDB handling code.

Vivien Didelot (6):
  net: bridge: pass net_bridge_port to __br_mdb_add
  net: bridge: check multicast bridge only once
  net: bridge: break if __br_mdb_del fails
  net: bridge: add __br_mdb_do
  net: bridge: get msgtype from nlmsghdr in mdb ops
  net: bridge: add br_mdb_do

 net/bridge/br_mdb.c | 107 +++-
 1 file changed, 31 insertions(+), 76 deletions(-)

-- 
2.13.0



[PATCH net-next 1/3] net: dsa: include dsa.h only once

2017-05-17 Thread Vivien Didelot
The public include/net/dsa.h file is meant for DSA drivers, while all
DSA core files share a common private header net/dsa/dsa_priv.h file.

Ensure that dsa_priv.h is the only DSA core file to include net/dsa.h,
and add a new line to separate absolute and relative headers at the same
time.

Signed-off-by: Vivien Didelot 
---
 net/dsa/dsa.c | 2 +-
 net/dsa/dsa2.c| 2 +-
 net/dsa/dsa_priv.h| 1 +
 net/dsa/legacy.c  | 2 +-
 net/dsa/slave.c   | 2 +-
 net/dsa/switch.c  | 3 ++-
 net/dsa/tag_brcm.c| 2 +-
 net/dsa/tag_dsa.c | 2 +-
 net/dsa/tag_edsa.c| 2 +-
 net/dsa/tag_lan9303.c | 2 +-
 net/dsa/tag_mtk.c | 2 +-
 net/dsa/tag_qca.c | 2 +-
 net/dsa/tag_trailer.c | 2 +-
 13 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 26130ae438da..54a52f4661b1 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -24,7 +24,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 2ac62349ba12..4301f52e4f5a 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -18,7 +18,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 static LIST_HEAD(dsa_switch_trees);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index f4a88e485213..904d5476c6e0 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct dsa_device_ops {
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c
index bb28b011ba5a..ac4379b8d7ac 100644
--- a/net/dsa/legacy.c
+++ b/net/dsa/legacy.c
@@ -22,7 +22,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 /* switch driver registration ***/
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 77324c483d14..fb13c5d7d587 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -17,13 +17,13 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
+
 #include "dsa_priv.h"
 
 static bool dsa_slave_dev_check(struct net_device *dev);
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index ca6e26e514f0..f477053308d2 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -12,7 +12,8 @@
 
 #include 
 #include 
-#include 
+
+#include "dsa_priv.h"
 
 static int dsa_switch_bridge_join(struct dsa_switch *ds,
  struct dsa_notifier_bridge_info *info)
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 658ddee63dc9..9f204f18ada3 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -12,7 +12,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 /* This tag length is 4 bytes, older ones were 6 bytes, we do not
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 1c6633f0de01..3b62a57956a3 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -11,7 +11,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 #define DSA_HLEN   4
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index d9c668aa5e54..f95cafd05702 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -11,7 +11,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 #define DSA_HLEN   4
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index 70130ed5c21a..afd59330b5f1 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -14,7 +14,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 /* To define the outgoing port and to discover the incoming port a regular
diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
index 837cdddb53f0..d1258e84cd71 100644
--- a/net/dsa/tag_mtk.c
+++ b/net/dsa/tag_mtk.c
@@ -13,7 +13,7 @@
  */
 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 #define MTK_HDR_LEN4
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index be3b67750ac8..2451007699b7 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -12,7 +12,7 @@
  */
 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 #define QCA_HDR_LEN2
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index aa05e276ea22..7488ab2932ab 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -11,7 +11,7 @@
 #include 
 #include 
 #include 
-#include 
+
 #include "dsa_priv.h"
 
 static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device 
*dev)
-- 
2.13.0



[PATCH net-next 0/3] net: dsa: headers cleanup

2017-05-17 Thread Vivien Didelot
The DSA core files share a common private header file. Include the DSA
public header there instead of independently in each core source file.

DSA core and its drivers use switchdev, thus include switchdev.h in the
public DSA header. This allows us to get rid of the forward declaration
and use typedef defined by switchdev.

Vivien Didelot (3):
  net: dsa: include dsa.h only once
  net: dsa: include switchdev.h only once
  net: dsa: use switchdev_obj_dump_cb_t everywhere

 drivers/net/dsa/b53/b53_common.c |  7 +++
 drivers/net/dsa/b53/b53_priv.h   |  4 ++--
 drivers/net/dsa/bcm_sf2.c|  1 -
 drivers/net/dsa/dsa_loop.c   |  3 +--
 drivers/net/dsa/mt7530.c |  3 +--
 drivers/net/dsa/mv88e6xxx/chip.c | 11 +--
 drivers/net/dsa/qca8k.c  |  3 +--
 include/net/dsa.h| 13 -
 net/dsa/dsa.c|  2 +-
 net/dsa/dsa2.c   |  2 +-
 net/dsa/dsa_priv.h   |  1 +
 net/dsa/legacy.c |  2 +-
 net/dsa/slave.c  |  3 +--
 net/dsa/switch.c |  3 ++-
 net/dsa/tag_brcm.c   |  2 +-
 net/dsa/tag_dsa.c|  2 +-
 net/dsa/tag_edsa.c   |  2 +-
 net/dsa/tag_lan9303.c|  2 +-
 net/dsa/tag_mtk.c|  2 +-
 net/dsa/tag_qca.c|  2 +-
 net/dsa/tag_trailer.c|  2 +-
 21 files changed, 31 insertions(+), 41 deletions(-)

-- 
2.13.0



[PATCH net-next 2/3] net: dsa: include switchdev.h only once

2017-05-17 Thread Vivien Didelot
DSA drivers and core use switchdev. Include switchdev.h only once, in
the dsa.h public header, so that inclusion in DSA drivers or forward
declarations of switchdev structures in not necessary anymore.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/b53/b53_common.c | 1 -
 drivers/net/dsa/bcm_sf2.c| 1 -
 drivers/net/dsa/dsa_loop.c   | 1 -
 drivers/net/dsa/mt7530.c | 1 -
 drivers/net/dsa/mv88e6xxx/chip.c | 1 -
 drivers/net/dsa/qca8k.c  | 1 -
 include/net/dsa.h| 7 +--
 net/dsa/slave.c  | 1 -
 8 files changed, 1 insertion(+), 13 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 658a12c888a8..fbc3eb17c7a3 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -29,7 +29,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #include "b53_regs.h"
 #include "b53_priv.h"
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 215d41c1e71f..687a8bae5d73 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -28,7 +28,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 
 #include "bcm_sf2.h"
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index a19e1781e9bb..6afab16d13dd 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -17,7 +17,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 
 #include "dsa_loop.h"
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index b070c167e70f..1bcbe15870ed 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -28,7 +28,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #include "mt7530.h"
 
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d034d8cd7d22..386d878569ed 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -32,7 +32,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #include "mv88e6xxx.h"
 #include "global1.h"
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 942b9ac7f92a..149f109dbffb 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -18,7 +18,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 118a8bd2fd9a..61984895a9ad 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct tc_action;
 struct phy_device;
@@ -284,12 +285,6 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
return ds->rtable[dst->cpu_dp->ds->index];
 }
 
-struct switchdev_trans;
-struct switchdev_obj;
-struct switchdev_obj_port_fdb;
-struct switchdev_obj_port_mdb;
-struct switchdev_obj_port_vlan;
-
 #define DSA_NOTIFIER_BRIDGE_JOIN   1
 #define DSA_NOTIFIER_BRIDGE_LEAVE  2
 
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index fb13c5d7d587..91236d602301 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -18,7 +18,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
-- 
2.13.0



[PATCH net-next 3/3] net: dsa: use switchdev_obj_dump_cb_t everywhere

2017-05-17 Thread Vivien Didelot
Now that the DSA public header includes switchdev.h, use the provided
switchdev_obj_dump_cb_t typedef for the object dump callback.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/b53/b53_common.c |  6 +++---
 drivers/net/dsa/b53/b53_priv.h   |  4 ++--
 drivers/net/dsa/dsa_loop.c   |  2 +-
 drivers/net/dsa/mt7530.c |  2 +-
 drivers/net/dsa/mv88e6xxx/chip.c | 10 +-
 drivers/net/dsa/qca8k.c  |  2 +-
 include/net/dsa.h|  6 +++---
 7 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index fbc3eb17c7a3..fa099ed41652 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1055,7 +1055,7 @@ EXPORT_SYMBOL(b53_vlan_del);
 
 int b53_vlan_dump(struct dsa_switch *ds, int port,
  struct switchdev_obj_port_vlan *vlan,
- int (*cb)(struct switchdev_obj *obj))
+ switchdev_obj_dump_cb_t *cb)
 {
struct b53_device *dev = ds->priv;
u16 vid, vid_start = 0, pvid;
@@ -1284,7 +1284,7 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 
idx,
 static int b53_fdb_copy(struct net_device *dev, int port,
const struct b53_arl_entry *ent,
struct switchdev_obj_port_fdb *fdb,
-   int (*cb)(struct switchdev_obj *obj))
+   switchdev_obj_dump_cb_t *cb)
 {
if (!ent->is_valid)
return 0;
@@ -1301,7 +1301,7 @@ static int b53_fdb_copy(struct net_device *dev, int port,
 
 int b53_fdb_dump(struct dsa_switch *ds, int port,
 struct switchdev_obj_port_fdb *fdb,
-int (*cb)(struct switchdev_obj *obj))
+switchdev_obj_dump_cb_t *cb)
 {
struct b53_device *priv = ds->priv;
struct net_device *dev = ds->ports[port].netdev;
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index a9dc90a01438..155a9c48c317 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -395,7 +395,7 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
 const struct switchdev_obj_port_vlan *vlan);
 int b53_vlan_dump(struct dsa_switch *ds, int port,
  struct switchdev_obj_port_vlan *vlan,
- int (*cb)(struct switchdev_obj *obj));
+ switchdev_obj_dump_cb_t *cb);
 int b53_fdb_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb,
struct switchdev_trans *trans);
@@ -406,7 +406,7 @@ int b53_fdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb);
 int b53_fdb_dump(struct dsa_switch *ds, int port,
 struct switchdev_obj_port_fdb *fdb,
-int (*cb)(struct switchdev_obj *obj));
+switchdev_obj_dump_cb_t *cb);
 int b53_mirror_add(struct dsa_switch *ds, int port,
   struct dsa_mall_mirror_tc_entry *mirror, bool ingress);
 void b53_mirror_del(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index 6afab16d13dd..5edf07beb9d2 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -187,7 +187,7 @@ static int dsa_loop_port_vlan_del(struct dsa_switch *ds, 
int port,
 
 static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port,
   struct switchdev_obj_port_vlan *vlan,
-  int (*cb)(struct switchdev_obj *obj))
+  switchdev_obj_dump_cb_t *cb)
 {
struct dsa_loop_priv *ps = ds->priv;
struct mii_bus *bus = ps->bus;
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 1bcbe15870ed..4d2f45153ede 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -853,7 +853,7 @@ mt7530_port_fdb_del(struct dsa_switch *ds, int port,
 static int
 mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
 struct switchdev_obj_port_fdb *fdb,
-int (*cb)(struct switchdev_obj *obj))
+switchdev_obj_dump_cb_t *cb)
 {
struct mt7530_priv *priv = ds->priv;
struct mt7530_fdb _fdb = { 0 };
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 386d878569ed..41de250dbcc3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1268,7 +1268,7 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip 
*chip,
 
 static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_vlan *vlan,
-   int (*cb)(struct switchdev_obj *obj))
+   switchdev_obj_dump_cb_t *cb)
 {
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_vtu_e

[PATCH net-next] net: dsa: store CPU port pointer in the tree

2017-05-16 Thread Vivien Didelot
A dsa_switch_tree instance holds a dsa_switch pointer and a port index
to identify the switch port to which the CPU is attached.

Now that the DSA layer has a dsa_port structure to hold this data, use
it to point the switch CPU port.

This patch simply substitutes s/dst->cpu_switch/dst->cpu_dp->ds/ and
s/dst->cpu_port/dst->cpu_dp->index/.

Signed-off-by: Vivien Didelot 
---
 drivers/net/dsa/b53/b53_common.c |  4 ++--
 drivers/net/dsa/bcm_sf2.c|  4 ++--
 drivers/net/dsa/mv88e6060.c  |  2 +-
 drivers/net/dsa/qca8k.c  |  2 +-
 include/net/dsa.h| 13 ++---
 net/dsa/dsa2.c   | 14 ++
 net/dsa/legacy.c | 10 --
 net/dsa/slave.c  | 10 +-
 net/dsa/tag_brcm.c   |  2 +-
 net/dsa/tag_qca.c|  2 +-
 net/dsa/tag_trailer.c|  2 +-
 11 files changed, 30 insertions(+), 35 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index fa0eece21eef..658a12c888a8 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1344,7 +1344,7 @@ EXPORT_SYMBOL(b53_fdb_dump);
 int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br)
 {
struct b53_device *dev = ds->priv;
-   s8 cpu_port = ds->dst->cpu_port;
+   s8 cpu_port = ds->dst->cpu_dp->index;
u16 pvlan, reg;
unsigned int i;
 
@@ -1390,7 +1390,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct 
net_device *br)
 {
struct b53_device *dev = ds->priv;
struct b53_vlan *vl = &dev->vlans[0];
-   s8 cpu_port = ds->dst->cpu_port;
+   s8 cpu_port = ds->dst->cpu_dp->index;
unsigned int i;
u16 pvlan, reg, pvid;
 
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 2be963252ca5..215d41c1e71f 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -228,7 +228,7 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int 
port,
  struct phy_device *phy)
 {
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
-   s8 cpu_port = ds->dst[ds->index].cpu_port;
+   s8 cpu_port = ds->dst->cpu_dp->index;
unsigned int i;
u32 reg;
 
@@ -832,7 +832,7 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int 
port,
 {
struct net_device *p = ds->dst[ds->index].master_netdev;
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
-   s8 cpu_port = ds->dst[ds->index].cpu_port;
+   s8 cpu_port = ds->dst->cpu_dp->index;
struct ethtool_wolinfo pwol;
 
p->ethtool_ops->get_wol(p, &pwol);
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 5934b7a4c448..dce7fa57eb55 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -176,7 +176,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int 
p)
  ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
   (dsa_is_cpu_port(ds, p) ?
ds->enabled_port_mask :
-   BIT(ds->dst->cpu_port)));
+   BIT(ds->dst->cpu_dp->index)));
 
/* Port Association Vector: when learning source addresses
 * of packets, add the address to the address database using
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index a4fd4ccf7b67..942b9ac7f92a 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -507,7 +507,7 @@ qca8k_setup(struct dsa_switch *ds)
pr_warn("regmap initialization failed");
 
/* Initialize CPU port pad mode (xMII type, delays...) */
-   phy_mode = of_get_phy_mode(ds->ports[ds->dst->cpu_port].dn);
+   phy_mode = of_get_phy_mode(ds->dst->cpu_dp->dn);
if (phy_mode < 0) {
pr_err("Can't find phy-mode for master device\n");
return phy_mode;
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 8e24677b1c62..118a8bd2fd9a 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -137,10 +137,9 @@ struct dsa_switch_tree {
const struct ethtool_ops *master_orig_ethtool_ops;
 
/*
-* The switch and port to which the CPU is attached.
+* The switch port to which the CPU is attached.
 */
-   struct dsa_switch   *cpu_switch;
-   s8  cpu_port;
+   struct dsa_port *cpu_dp;
 
/*
 * Data for the individual switch chips.
@@ -251,7 +250,7 @@ struct dsa_switch {
 
 static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
 {
-   return !!(ds == ds->dst->cpu_switch && p == ds->dst->cpu_port);
+   return ds->dst->cpu_dp == &ds->ports[p];
 }
 
 static inline bool dsa_is_dsa_port(struc

[PATCH net-next v2 03/18] net: dsa: mv88e6xxx: move VTU Operation accessors

2017-05-01 Thread Vivien Didelot
Move the helper functions to access the Global 1 VTU Operation register
to a new global1_vtu.c file, and get rid of the old underscore prefix
naming convention. This file will be extended will all VTU/STU related
code.

Signed-off-by: Vivien Didelot 
Reviewed-by: Andrew Lunn 
---
 drivers/net/dsa/mv88e6xxx/Makefile  |  1 +
 drivers/net/dsa/mv88e6xxx/chip.c| 39 +
 drivers/net/dsa/mv88e6xxx/global1.h |  3 +++
 drivers/net/dsa/mv88e6xxx/global1_vtu.c | 33 
 4 files changed, 47 insertions(+), 29 deletions(-)
 create mode 100644 drivers/net/dsa/mv88e6xxx/global1_vtu.c

diff --git a/drivers/net/dsa/mv88e6xxx/Makefile 
b/drivers/net/dsa/mv88e6xxx/Makefile
index 31d37a90cec7..6edd869c8d6f 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
 mv88e6xxx-objs := chip.o
 mv88e6xxx-objs += global1.o
 mv88e6xxx-objs += global1_atu.o
+mv88e6xxx-objs += global1_vtu.o
 mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o
 mv88e6xxx-objs += port.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index f025d3c22dba..bf0350432337 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3,9 +3,6 @@
  *
  * Copyright (c) 2008 Marvell Semiconductor
  *
- * Copyright (c) 2015 CMC Electronics, Inc.
- * Added support for VLAN Table Unit operations
- *
  * Copyright (c) 2016 Andrew Lunn 
  *
  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
@@ -1266,31 +1263,15 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch 
*ds, int port)
netdev_err(ds->ports[port].netdev, "failed to flush ATU\n");
 }
 
-static int _mv88e6xxx_vtu_wait(struct mv88e6xxx_chip *chip)
-{
-   return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY);
-}
-
-static int _mv88e6xxx_vtu_cmd(struct mv88e6xxx_chip *chip, u16 op)
-{
-   int err;
-
-   err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op);
-   if (err)
-   return err;
-
-   return _mv88e6xxx_vtu_wait(chip);
-}
-
 static int _mv88e6xxx_vtu_stu_flush(struct mv88e6xxx_chip *chip)
 {
int ret;
 
-   ret = _mv88e6xxx_vtu_wait(chip);
+   ret = mv88e6xxx_g1_vtu_op_wait(chip);
if (ret < 0)
return ret;
 
-   return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_FLUSH_ALL);
+   return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_FLUSH_ALL);
 }
 
 static int _mv88e6xxx_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
@@ -1380,11 +1361,11 @@ static int _mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip 
*chip,
u16 val;
int err;
 
-   err = _mv88e6xxx_vtu_wait(chip);
+   err = mv88e6xxx_g1_vtu_op_wait(chip);
if (err)
return err;
 
-   err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
+   err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
if (err)
return err;
 
@@ -1493,7 +1474,7 @@ static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip 
*chip,
u16 reg = 0;
int err;
 
-   err = _mv88e6xxx_vtu_wait(chip);
+   err = mv88e6xxx_g1_vtu_op_wait(chip);
if (err)
return err;
 
@@ -1532,7 +1513,7 @@ static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip 
*chip,
if (err)
return err;
 
-   return _mv88e6xxx_vtu_cmd(chip, op);
+   return mv88e6xxx_g1_vtu_op(chip, op);
 }
 
 static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip *chip, u8 sid,
@@ -1542,7 +1523,7 @@ static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip 
*chip, u8 sid,
u16 val;
int err;
 
-   err = _mv88e6xxx_vtu_wait(chip);
+   err = mv88e6xxx_g1_vtu_op_wait(chip);
if (err)
return err;
 
@@ -1551,7 +1532,7 @@ static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip 
*chip, u8 sid,
if (err)
return err;
 
-   err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
+   err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
if (err)
return err;
 
@@ -1583,7 +1564,7 @@ static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip 
*chip,
u16 reg = 0;
int err;
 
-   err = _mv88e6xxx_vtu_wait(chip);
+   err = mv88e6xxx_g1_vtu_op_wait(chip);
if (err)
return err;
 
@@ -1606,7 +1587,7 @@ static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip 
*chip,
if (err)
return err;
 
-   return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
+   return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
 }
 
 static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h 
b/drivers/net/dsa/mv88e6xxx/global1.h
index e30cbe480d5b..c153d07d2065 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/n

<    1   2   3   4   5   6   7   8   9   10   >