* [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches.
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
@ 2022-09-06 6:34 ` Mattias Forsblad
2022-09-06 12:29 ` Andrew Lunn
2022-09-06 21:46 ` Florian Fainelli
2022-09-06 6:34 ` [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling Mattias Forsblad
` (5 subsequent siblings)
6 siblings, 2 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 6:34 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Mattias Forsblad
Add RMU enable functionality for some Marvell SOHO switches.
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 6 +++
drivers/net/dsa/mv88e6xxx/chip.h | 1 +
drivers/net/dsa/mv88e6xxx/global1.c | 76 +++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 3 ++
4 files changed, 86 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 6f4ea39ab466..46e12b53a9e4 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4098,6 +4098,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.ppu_disable = mv88e6185_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
.rmu_disable = mv88e6085_g1_rmu_disable,
+ .rmu_enable = mv88e6085_g1_rmu_enable,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
@@ -4181,6 +4182,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6085_g1_rmu_disable,
+ .rmu_enable = mv88e6085_g1_rmu_enable,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.phylink_get_caps = mv88e6095_phylink_get_caps,
@@ -5300,6 +5302,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6352_g1_rmu_disable,
+ .rmu_enable = mv88e6352_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
@@ -5367,6 +5370,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -5434,6 +5438,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
@@ -5504,6 +5509,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6390_g1_rmu_disable,
+ .rmu_enable = mv88e6390_g1_rmu_enable,
.atu_get_hash = mv88e6165_g1_atu_get_hash,
.atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e693154cf803..7ce3c41f6caf 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -637,6 +637,7 @@ struct mv88e6xxx_ops {
/* Remote Management Unit operations */
int (*rmu_disable)(struct mv88e6xxx_chip *chip);
+ int (*rmu_enable)(struct mv88e6xxx_chip *chip, int port);
/* Precision Time Protocol operations */
const struct mv88e6xxx_ptp_ops *ptp_ops;
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 5848112036b0..f6c288ece0ba 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -466,18 +466,94 @@ int mv88e6085_g1_rmu_disable(struct mv88e6xxx_chip *chip)
MV88E6085_G1_CTL2_RM_ENABLE, 0);
}
+int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
+{
+ int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
+
+ dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
+
+ switch (upstream_port) {
+ case 9:
+ val = MV88E6085_G1_CTL2_RM_ENABLE;
+ break;
+ case 10:
+ val = MV88E6085_G1_CTL2_RM_ENABLE | MV88E6085_G1_CTL2_P10RM;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6085_G1_CTL2_P10RM |
+ MV88E6085_G1_CTL2_RM_ENABLE, val);
+}
+
int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK,
MV88E6352_G1_CTL2_RMU_MODE_DISABLED);
}
+int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
+{
+ int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
+ int upstream_port;
+
+ upstream_port = dsa_switch_upstream_port(chip->ds);
+ dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
+ if (upstream_port < 0)
+ return -EOPNOTSUPP;
+
+ switch (upstream_port) {
+ case 4:
+ val = MV88E6352_G1_CTL2_RMU_MODE_PORT_4;
+ break;
+ case 5:
+ val = MV88E6352_G1_CTL2_RMU_MODE_PORT_5;
+ break;
+ case 6:
+ val = MV88E6352_G1_CTL2_RMU_MODE_PORT_6;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK,
+ val);
+}
+
int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_RMU_MODE_MASK,
MV88E6390_G1_CTL2_RMU_MODE_DISABLED);
}
+int mv88e6390_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
+{
+ int val = MV88E6390_G1_CTL2_RMU_MODE_DISABLED;
+
+ dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
+
+ switch (upstream_port) {
+ case 0:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_0;
+ break;
+ case 1:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_1;
+ break;
+ case 9:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_9;
+ break;
+ case 10:
+ val = MV88E6390_G1_CTL2_RMU_MODE_PORT_10;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_RMU_MODE_MASK,
+ val);
+}
+
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_HIST_MODE_MASK,
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 65958b2a0d3a..29c0c8acb583 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -313,8 +313,11 @@ int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_set_cascade_port(struct mv88e6xxx_chip *chip, int port);
int mv88e6085_g1_rmu_disable(struct mv88e6xxx_chip *chip);
+int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port);
int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip);
+int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port);
int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip);
+int mv88e6390_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port);
int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index);
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches.
2022-09-06 6:34 ` [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches Mattias Forsblad
@ 2022-09-06 12:29 ` Andrew Lunn
2022-09-07 5:55 ` Mattias Forsblad
2022-09-06 21:46 ` Florian Fainelli
1 sibling, 1 reply; 19+ messages in thread
From: Andrew Lunn @ 2022-09-06 12:29 UTC (permalink / raw)
To: Mattias Forsblad
Cc: netdev, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
> +int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
> +{
> + int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
> +
> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
> +
> + switch (upstream_port) {
>
> +int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
> +{
> + int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
> + int upstream_port;
> +
> + upstream_port = dsa_switch_upstream_port(chip->ds);
> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
> + if (upstream_port < 0)
> + return -EOPNOTSUPP;
> +
> + switch (upstream_port) {
> +int mv88e6390_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
> +{
> + int val = MV88E6390_G1_CTL2_RMU_MODE_DISABLED;
> +
> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
> +
> + switch (upstream_port) {
Why is 6352 different to 6085 and 6390? This is the sort of thing
which should be explained in the commit message. The commit message is
about the 'Why?' of the change. You could explain why there is this
difference, so a reviewer does not need to ask.
Andrew
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches.
2022-09-06 12:29 ` Andrew Lunn
@ 2022-09-07 5:55 ` Mattias Forsblad
0 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-07 5:55 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
On 2022-09-06 14:29, Andrew Lunn wrote:
>> +int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
>> +{
>> + int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
>> +
>> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
>> +
>> + switch (upstream_port) {
>
>>
>> +int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
>> +{
>> + int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
>> + int upstream_port;
>> +
>> + upstream_port = dsa_switch_upstream_port(chip->ds);
>> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
>> + if (upstream_port < 0)
>> + return -EOPNOTSUPP;
>> +
>> + switch (upstream_port) {
>
>> +int mv88e6390_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
>> +{
>> + int val = MV88E6390_G1_CTL2_RMU_MODE_DISABLED;
>> +
>> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
>> +
>> + switch (upstream_port) {
>
>
> Why is 6352 different to 6085 and 6390? This is the sort of thing
> which should be explained in the commit message. The commit message is
> about the 'Why?' of the change. You could explain why there is this
> difference, so a reviewer does not need to ask.
>
> Andrew
I'm sorry, I must have slipped on the keyboard :/ It should be similar for
all functions. I'll fix that.
Mattias
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches.
2022-09-06 6:34 ` [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches Mattias Forsblad
2022-09-06 12:29 ` Andrew Lunn
@ 2022-09-06 21:46 ` Florian Fainelli
2022-09-07 6:29 ` Mattias Forsblad
1 sibling, 1 reply; 19+ messages in thread
From: Florian Fainelli @ 2022-09-06 21:46 UTC (permalink / raw)
To: Mattias Forsblad, netdev
Cc: Andrew Lunn, Vivien Didelot, Vladimir Oltean, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
On 9/5/2022 11:34 PM, Mattias Forsblad wrote:
> Add RMU enable functionality for some Marvell SOHO switches.
>
> Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
> ---
[snip]
> +int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
> +{
> + int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
> +
> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
This debug print is in every chip-specific function, so maybe you can
consider moving it to mv88e6xxx_master_change()?
> +
> + switch (upstream_port) {
> + case 9:
> + val = MV88E6085_G1_CTL2_RM_ENABLE;
> + break;
> + case 10:
> + val = MV88E6085_G1_CTL2_RM_ENABLE | MV88E6085_G1_CTL2_P10RM;
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + return mv88e6xxx_g1_ctl2_mask(chip, MV88E6085_G1_CTL2_P10RM |
> + MV88E6085_G1_CTL2_RM_ENABLE, val);
> +}
> +
> int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip)
> {
> return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK,
> MV88E6352_G1_CTL2_RMU_MODE_DISABLED);
> }
>
> +int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
Can we name this argument upstream_port and pass it a
dsa_switch_upstream_port() port already?
--
Florian
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches.
2022-09-06 21:46 ` Florian Fainelli
@ 2022-09-07 6:29 ` Mattias Forsblad
0 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-07 6:29 UTC (permalink / raw)
To: Florian Fainelli, netdev
Cc: Andrew Lunn, Vivien Didelot, Vladimir Oltean, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
On 2022-09-06 23:46, Florian Fainelli wrote:
>
>
> On 9/5/2022 11:34 PM, Mattias Forsblad wrote:
>> Add RMU enable functionality for some Marvell SOHO switches.
>>
>> Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
>> ---
>
> [snip]
>
>> +int mv88e6085_g1_rmu_enable(struct mv88e6xxx_chip *chip, int upstream_port)
>> +{
>> + int val = MV88E6352_G1_CTL2_RMU_MODE_DISABLED;
>> +
>> + dev_dbg(chip->dev, "RMU: Enabling on port %d", upstream_port);
>
> This debug print is in every chip-specific function, so maybe you can consider moving it to mv88e6xxx_master_change()?
>
Ofc, will fix.
>> +
>> + switch (upstream_port) {
>> + case 9:
>> + val = MV88E6085_G1_CTL2_RM_ENABLE;
>> + break;
>> + case 10:
>> + val = MV88E6085_G1_CTL2_RM_ENABLE | MV88E6085_G1_CTL2_P10RM;
>> + break;
>> + default:
>> + return -EOPNOTSUPP;
>> + }
>> +
>> + return mv88e6xxx_g1_ctl2_mask(chip, MV88E6085_G1_CTL2_P10RM |
>> + MV88E6085_G1_CTL2_RM_ENABLE, val);
>> +}
>> +
>> int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip)
>> {
>> return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK,
>> MV88E6352_G1_CTL2_RMU_MODE_DISABLED);
>> }
>> +int mv88e6352_g1_rmu_enable(struct mv88e6xxx_chip *chip, int port)
>
> Can we name this argument upstream_port and pass it a dsa_switch_upstream_port() port already?
Will fix.
Mattias
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
2022-09-06 6:34 ` [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches Mattias Forsblad
@ 2022-09-06 6:34 ` Mattias Forsblad
2022-09-06 12:43 ` Andrew Lunn
` (2 more replies)
2022-09-06 6:34 ` [PATCH net-next v4 3/6] net: dsa: Introduce dsa tagger data operation Mattias Forsblad
` (4 subsequent siblings)
6 siblings, 3 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 6:34 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Mattias Forsblad
Add common control functions for drivers that need
to send and wait for control frames.
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
---
include/net/dsa.h | 13 +++++++++++++
net/dsa/dsa.c | 28 ++++++++++++++++++++++++++++
net/dsa/dsa2.c | 2 ++
3 files changed, 43 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index f2ce12860546..70a358641235 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -495,6 +495,8 @@ struct dsa_switch {
unsigned int max_num_bridges;
unsigned int num_ports;
+
+ struct completion inband_done;
};
static inline struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p)
@@ -1390,6 +1392,17 @@ void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
unsigned int count);
+int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
+ struct completion *completion, unsigned long timeout);
+static inline void dsa_switch_inband_complete(struct dsa_switch *ds, struct completion *completion)
+{
+ /* Custom completion? */
+ if (completion)
+ complete(completion);
+ else
+ complete(&ds->inband_done);
+}
+
#define dsa_tag_driver_module_drivers(__dsa_tag_drivers_array, __count) \
static int __init dsa_tag_driver_module_init(void) \
{ \
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index be7b320cda76..2d7add779b6f 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -324,6 +324,34 @@ int dsa_switch_resume(struct dsa_switch *ds)
EXPORT_SYMBOL_GPL(dsa_switch_resume);
#endif
+int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
+ struct completion *completion, unsigned long timeout)
+{
+ int ret;
+ struct completion *com;
+
+ /* Custom completion? */
+ if (completion)
+ com = completion;
+ else
+ com = &ds->inband_done;
+
+ reinit_completion(com);
+
+ if (skb)
+ dev_queue_xmit(skb);
+
+ ret = wait_for_completion_timeout(com, msecs_to_jiffies(timeout));
+ if (ret <= 0) {
+ dev_dbg(ds->dev, "DSA inband: timeout waiting for answer\n");
+
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_switch_inband_tx);
+
static struct packet_type dsa_pack_type __read_mostly = {
.type = cpu_to_be16(ETH_P_XDSA),
.func = dsa_switch_rcv,
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index ed56c7a554b8..a1b3ecfdffb8 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1746,6 +1746,8 @@ static int dsa_switch_probe(struct dsa_switch *ds)
dsa_tree_put(dst);
}
+ init_completion(&ds->inband_done);
+
return err;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling
2022-09-06 6:34 ` [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling Mattias Forsblad
@ 2022-09-06 12:43 ` Andrew Lunn
2022-09-07 6:19 ` Mattias Forsblad
2022-09-06 21:44 ` Florian Fainelli
2022-09-08 11:32 ` Paolo Abeni
2 siblings, 1 reply; 19+ messages in thread
From: Andrew Lunn @ 2022-09-06 12:43 UTC (permalink / raw)
To: Mattias Forsblad
Cc: netdev, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
On Tue, Sep 06, 2022 at 08:34:46AM +0200, Mattias Forsblad wrote:
> Add common control functions for drivers that need
> to send and wait for control frames.
It would be nice to explain why a custom complete is needed. Ideally,
it should not be needed at all.
> Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
> ---
> include/net/dsa.h | 13 +++++++++++++
> net/dsa/dsa.c | 28 ++++++++++++++++++++++++++++
> net/dsa/dsa2.c | 2 ++
> 3 files changed, 43 insertions(+)
>
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index f2ce12860546..70a358641235 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -495,6 +495,8 @@ struct dsa_switch {
> unsigned int max_num_bridges;
>
> unsigned int num_ports;
> +
> + struct completion inband_done;
> };
>
> static inline struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p)
> @@ -1390,6 +1392,17 @@ void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
> void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
> unsigned int count);
>
> +int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
> + struct completion *completion, unsigned long timeout);
Blank line please.
> +static inline void dsa_switch_inband_complete(struct dsa_switch *ds, struct completion *completion)
> +{
> + /* Custom completion? */
> + if (completion)
> + complete(completion);
> + else
> + complete(&ds->inband_done);
> +}
> +
> #define dsa_tag_driver_module_drivers(__dsa_tag_drivers_array, __count) \
> static int __init dsa_tag_driver_module_init(void) \
> { \
> diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
> index be7b320cda76..2d7add779b6f 100644
> --- a/net/dsa/dsa.c
> +++ b/net/dsa/dsa.c
> @@ -324,6 +324,34 @@ int dsa_switch_resume(struct dsa_switch *ds)
> EXPORT_SYMBOL_GPL(dsa_switch_resume);
> #endif
>
> +int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
> + struct completion *completion, unsigned long timeout)
> +{
> + int ret;
> + struct completion *com;
Reverse christmas tree. Longest lines first.
> +
> + /* Custom completion? */
> + if (completion)
> + com = completion;
> + else
> + com = &ds->inband_done;
> +
> + reinit_completion(com);
> +
> + if (skb)
> + dev_queue_xmit(skb);
> +
> + ret = wait_for_completion_timeout(com, msecs_to_jiffies(timeout));
> + if (ret <= 0) {
> + dev_dbg(ds->dev, "DSA inband: timeout waiting for answer\n");
> +
> + return -ETIMEDOUT;
> + }
It looks like wait_for_completion_timeout() can return a negative
error code. You should return that error code, not replace it with
-ETIMEDOUT. If it returns 0, then it has timed out, and returning
-ETIMEDOUT does make sense. If the completion is indicated before the
timeout, the return value is the remaining time. So you can return a
positive number here. It is worth documenting that, since a common
patterns is:
err = dsa_switch_inband_tx()
if (err)
return err;
does not work in this case.
Andrew
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling
2022-09-06 12:43 ` Andrew Lunn
@ 2022-09-07 6:19 ` Mattias Forsblad
0 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-07 6:19 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
On 2022-09-06 14:43, Andrew Lunn wrote:
> On Tue, Sep 06, 2022 at 08:34:46AM +0200, Mattias Forsblad wrote:
>> Add common control functions for drivers that need
>> to send and wait for control frames.
>
> It would be nice to explain why a custom complete is needed. Ideally,
> it should not be needed at all.
>
My first approach was with without a custom complete as I only used
one single complete instance. However, when migrating the qca8k driver
I noticed they use two different complete instances, one in
qca8k_mgmt_eth_data and one in qca8k_mib_eth_data. This leads
to the suggestion that the qca8k implementation could have several
requests in-flight, thus the custom completion parameter.
>> Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
>> ---
>> include/net/dsa.h | 13 +++++++++++++
>> net/dsa/dsa.c | 28 ++++++++++++++++++++++++++++
>> net/dsa/dsa2.c | 2 ++
>> 3 files changed, 43 insertions(+)
>>
>> diff --git a/include/net/dsa.h b/include/net/dsa.h
>> index f2ce12860546..70a358641235 100644
>> --- a/include/net/dsa.h
>> +++ b/include/net/dsa.h
>> @@ -495,6 +495,8 @@ struct dsa_switch {
>> unsigned int max_num_bridges;
>>
>> unsigned int num_ports;
>> +
>> + struct completion inband_done;
>> };
>>
>> static inline struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p)
>> @@ -1390,6 +1392,17 @@ void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
>> void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
>> unsigned int count);
>>
>> +int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
>> + struct completion *completion, unsigned long timeout);
>
> Blank line please.
>
Will fix.
>> +static inline void dsa_switch_inband_complete(struct dsa_switch *ds, struct completion *completion)
>> +{
>> + /* Custom completion? */
>> + if (completion)
>> + complete(completion);
>> + else
>> + complete(&ds->inband_done);
>> +}
>> +
>> #define dsa_tag_driver_module_drivers(__dsa_tag_drivers_array, __count) \
>> static int __init dsa_tag_driver_module_init(void) \
>> { \
>> diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
>> index be7b320cda76..2d7add779b6f 100644
>> --- a/net/dsa/dsa.c
>> +++ b/net/dsa/dsa.c
>> @@ -324,6 +324,34 @@ int dsa_switch_resume(struct dsa_switch *ds)
>> EXPORT_SYMBOL_GPL(dsa_switch_resume);
>> #endif
>>
>> +int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
>> + struct completion *completion, unsigned long timeout)
>> +{
>> + int ret;
>> + struct completion *com;
>
> Reverse christmas tree. Longest lines first.
>
Duh, again? Sorry, will fix.
>> +
>> + /* Custom completion? */
>> + if (completion)
>> + com = completion;
>> + else
>> + com = &ds->inband_done;
>> +
>> + reinit_completion(com);
>> +
>> + if (skb)
>> + dev_queue_xmit(skb);
>> +
>> + ret = wait_for_completion_timeout(com, msecs_to_jiffies(timeout));
>> + if (ret <= 0) {
>> + dev_dbg(ds->dev, "DSA inband: timeout waiting for answer\n");
>> +
>> + return -ETIMEDOUT;
>> + }
>
> It looks like wait_for_completion_timeout() can return a negative
> error code. You should return that error code, not replace it with
> -ETIMEDOUT. If it returns 0, then it has timed out, and returning
> -ETIMEDOUT does make sense. If the completion is indicated before the
> timeout, the return value is the remaining time. So you can return a
> positive number here. It is worth documenting that, since a common
> patterns is:
>
> err = dsa_switch_inband_tx()
> if (err)
> return err;
>
> does not work in this case.
>
> Andrew
Will fix.
Mattias
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling
2022-09-06 6:34 ` [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling Mattias Forsblad
2022-09-06 12:43 ` Andrew Lunn
@ 2022-09-06 21:44 ` Florian Fainelli
2022-09-08 11:32 ` Paolo Abeni
2 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2022-09-06 21:44 UTC (permalink / raw)
To: Mattias Forsblad, netdev
Cc: Andrew Lunn, Vivien Didelot, Vladimir Oltean, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
On 9/5/2022 11:34 PM, Mattias Forsblad wrote:
> Add common control functions for drivers that need
> to send and wait for control frames.
>
> Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
With the feedback from Andrew addressed:
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
--
Florian
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling
2022-09-06 6:34 ` [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling Mattias Forsblad
2022-09-06 12:43 ` Andrew Lunn
2022-09-06 21:44 ` Florian Fainelli
@ 2022-09-08 11:32 ` Paolo Abeni
2 siblings, 0 replies; 19+ messages in thread
From: Paolo Abeni @ 2022-09-08 11:32 UTC (permalink / raw)
To: Mattias Forsblad, netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski
On Tue, 2022-09-06 at 08:34 +0200, Mattias Forsblad wrote:
> Add common control functions for drivers that need
> to send and wait for control frames.
>
> Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
> ---
> include/net/dsa.h | 13 +++++++++++++
> net/dsa/dsa.c | 28 ++++++++++++++++++++++++++++
> net/dsa/dsa2.c | 2 ++
> 3 files changed, 43 insertions(+)
>
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index f2ce12860546..70a358641235 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -495,6 +495,8 @@ struct dsa_switch {
> unsigned int max_num_bridges;
>
> unsigned int num_ports;
> +
> + struct completion inband_done;
> };
>
> static inline struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p)
> @@ -1390,6 +1392,17 @@ void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
> void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
> unsigned int count);
>
> +int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
> + struct completion *completion, unsigned long timeout);
> +static inline void dsa_switch_inband_complete(struct dsa_switch *ds, struct completion *completion)
> +{
> + /* Custom completion? */
> + if (completion)
> + complete(completion);
> + else
> + complete(&ds->inband_done);
> +}
> +
> #define dsa_tag_driver_module_drivers(__dsa_tag_drivers_array, __count) \
> static int __init dsa_tag_driver_module_init(void) \
> { \
> diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
> index be7b320cda76..2d7add779b6f 100644
> --- a/net/dsa/dsa.c
> +++ b/net/dsa/dsa.c
> @@ -324,6 +324,34 @@ int dsa_switch_resume(struct dsa_switch *ds)
> EXPORT_SYMBOL_GPL(dsa_switch_resume);
> #endif
>
> +int dsa_switch_inband_tx(struct dsa_switch *ds, struct sk_buff *skb,
> + struct completion *completion, unsigned long timeout)
> +{
> + int ret;
> + struct completion *com;
> +
> + /* Custom completion? */
> + if (completion)
> + com = completion;
> + else
> + com = &ds->inband_done;
Since a new version is need, you can as well do:
com = completion ? : &ds->inband_done;
Thanks!
Paolo
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH net-next v4 3/6] net: dsa: Introduce dsa tagger data operation.
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
2022-09-06 6:34 ` [PATCH net-next v4 1/6] net: dsa: mv88e6xxx: Add RMU enable for select switches Mattias Forsblad
2022-09-06 6:34 ` [PATCH net-next v4 2/6] net: dsa: Add convenience functions for frame handling Mattias Forsblad
@ 2022-09-06 6:34 ` Mattias Forsblad
2022-09-06 13:08 ` Andrew Lunn
2022-09-06 6:34 ` [PATCH net-next v4 4/6] net: dsa: mv88e6xxxx: Add RMU functionality Mattias Forsblad
` (3 subsequent siblings)
6 siblings, 1 reply; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 6:34 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Mattias Forsblad
Support connecting dsa tagger for frame2reg decoding
with it's associated hookup functions.
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
---
include/net/dsa.h | 5 +++++
net/dsa/tag_dsa.c | 32 +++++++++++++++++++++++++++++---
2 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 70a358641235..21f9eadb9543 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -130,6 +130,11 @@ struct dsa_lag {
refcount_t refcount;
};
+struct dsa_tagger_data {
+ void (*decode_frame2reg)(struct net_device *netdev,
+ struct sk_buff *skb);
+};
+
struct dsa_switch_tree {
struct list_head list;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index e4b6e3f2a3db..3dd1dcddaf05 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -198,7 +198,10 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
u8 extra)
{
+ struct dsa_tagger_data *tagger_data;
+ struct dsa_port *dp = dev->dsa_ptr;
bool trap = false, trunk = false;
+ struct dsa_switch *ds = dp->ds;
int source_device, source_port;
enum dsa_code code;
enum dsa_cmd cmd;
@@ -218,9 +221,9 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
switch (code) {
case DSA_CODE_FRAME2REG:
- /* Remote management is not implemented yet,
- * drop.
- */
+ tagger_data = ds->tagger_data;
+ if (likely(tagger_data->decode_frame2reg))
+ tagger_data->decode_frame2reg(dev, skb);
return NULL;
case DSA_CODE_ARP_MIRROR:
case DSA_CODE_POLICY_MIRROR:
@@ -323,6 +326,25 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
return skb;
}
+static int dsa_tag_connect(struct dsa_switch *ds)
+{
+ struct dsa_tagger_data *tagger_data;
+
+ tagger_data = kzalloc(sizeof(*tagger_data), GFP_KERNEL);
+ if (!tagger_data)
+ return -ENOMEM;
+
+ ds->tagger_data = tagger_data;
+
+ return 0;
+}
+
+static void dsa_tag_disconnect(struct dsa_switch *ds)
+{
+ kfree(ds->tagger_data);
+ ds->tagger_data = NULL;
+}
+
#if IS_ENABLED(CONFIG_NET_DSA_TAG_DSA)
static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -343,6 +365,8 @@ static const struct dsa_device_ops dsa_netdev_ops = {
.proto = DSA_TAG_PROTO_DSA,
.xmit = dsa_xmit,
.rcv = dsa_rcv,
+ .connect = dsa_tag_connect,
+ .disconnect = dsa_tag_disconnect,
.needed_headroom = DSA_HLEN,
};
@@ -385,6 +409,8 @@ static const struct dsa_device_ops edsa_netdev_ops = {
.proto = DSA_TAG_PROTO_EDSA,
.xmit = edsa_xmit,
.rcv = edsa_rcv,
+ .connect = dsa_tag_connect,
+ .disconnect = dsa_tag_disconnect,
.needed_headroom = EDSA_HLEN,
};
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 3/6] net: dsa: Introduce dsa tagger data operation.
2022-09-06 6:34 ` [PATCH net-next v4 3/6] net: dsa: Introduce dsa tagger data operation Mattias Forsblad
@ 2022-09-06 13:08 ` Andrew Lunn
2022-09-06 13:51 ` Vladimir Oltean
0 siblings, 1 reply; 19+ messages in thread
From: Andrew Lunn @ 2022-09-06 13:08 UTC (permalink / raw)
To: Mattias Forsblad
Cc: netdev, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
> switch (code) {
> case DSA_CODE_FRAME2REG:
> - /* Remote management is not implemented yet,
> - * drop.
> - */
> + tagger_data = ds->tagger_data;
> + if (likely(tagger_data->decode_frame2reg))
> + tagger_data->decode_frame2reg(dev, skb);
> return NULL;
> case DSA_CODE_ARP_MIRROR:
> case DSA_CODE_POLICY_MIRROR:
> @@ -323,6 +326,25 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
> return skb;
> }
> +static void dsa_tag_disconnect(struct dsa_switch *ds)
> +{
> + kfree(ds->tagger_data);
> + ds->tagger_data = NULL;
> +}
Probably a question for Vladimir.
Is there a potential use after free here? Is it guaranteed that the
masters dev->dsa_ptr will be cleared before the disconnect function is
called?
Also, the receive function checks for tagger_data->decode_frame2reg,
but does not check for tagger_data != NULL.
This is just a straight copy of tag_qca, so if there are issues here,
they are probably not new issues.
Andrew
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 3/6] net: dsa: Introduce dsa tagger data operation.
2022-09-06 13:08 ` Andrew Lunn
@ 2022-09-06 13:51 ` Vladimir Oltean
0 siblings, 0 replies; 19+ messages in thread
From: Vladimir Oltean @ 2022-09-06 13:51 UTC (permalink / raw)
To: Andrew Lunn
Cc: Mattias Forsblad, netdev, Vivien Didelot, Florian Fainelli,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
On Tue, Sep 06, 2022 at 03:08:23PM +0200, Andrew Lunn wrote:
> > switch (code) {
> > case DSA_CODE_FRAME2REG:
> > - /* Remote management is not implemented yet,
> > - * drop.
> > - */
> > + tagger_data = ds->tagger_data;
> > + if (likely(tagger_data->decode_frame2reg))
> > + tagger_data->decode_frame2reg(dev, skb);
> > return NULL;
> > case DSA_CODE_ARP_MIRROR:
> > case DSA_CODE_POLICY_MIRROR:
> > @@ -323,6 +326,25 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
> > return skb;
> > }
>
> > +static void dsa_tag_disconnect(struct dsa_switch *ds)
> > +{
> > + kfree(ds->tagger_data);
> > + ds->tagger_data = NULL;
> > +}
>
>
> Probably a question for Vladimir.
>
> Is there a potential use after free here? Is it guaranteed that the
> masters dev->dsa_ptr will be cleared before the disconnect function is
> called?
There is no use after free because there is no free...
There are 3 cases of tag protocol disconnect, one is on error path of
bidirectional connection (handled properly), another is on tag protocol
change (handled properly; we only allow it with the master down), and
another is on switch driver removal (handled incorrectly, we don't do
anything here).
The following patch is compile tested only. However it should answer
your question of order of operations too.
From d93b2ddf0e0f4e82d6b0bac4591b346e8cd0fdb9 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Tue, 6 Sep 2022 16:24:41 +0300
Subject: [PATCH] net: dsa: don't leak tagger-owned storage on switch driver
unbind
In the initial commit dc452a471dba ("net: dsa: introduce tagger-owned
storage for private and shared data"), we had a call to
tag_ops->disconnect(dst) issued from dsa_tree_free(), which is called at
tree teardown time.
There were problems with connecting to a switch tree as a whole, so this
got reworked to connecting to individual switches within the tree. In
this process, tag_ops->disconnect(ds) was made to be called only from
switch.c (cross-chip notifiers emitted as a result of dynamic tag proto
changes), but the normal driver teardown code path wasn't replaced with
anything.
Solve this problem by adding a function that does the opposite of
dsa_switch_setup_tag_protocol(), which is called from the equivalent
spot in dsa_switch_teardown(). The positioning here also ensures that we
won't have any use-after-free in tagging protocol (*rcv) ops, since the
teardown sequence is as follows:
dsa_tree_teardown
-> dsa_tree_teardown_master
-> dsa_master_teardown
-> unsets master->dsa_ptr, making no further packets match the
ETH_P_XDSA packet type handler
-> dsa_tree_teardown_ports
-> dsa_port_teardown
-> dsa_slave_destroy
-> unregisters DSA net devices, there is even a synchronize_net()
in unregister_netdevice_many()
-> dsa_tree_teardown_switches
-> dsa_switch_teardown
-> dsa_switch_teardown_tag_protocol
-> finally frees the tagger-owned storage
Fixes: 7f2973149c22 ("net: dsa: make tagging protocols connect to individual switches from a tree")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
net/dsa/dsa2.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index ed56c7a554b8..4bb0a203b85c 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -864,6 +864,14 @@ static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds)
return err;
}
+static void dsa_switch_teardown_tag_protocol(struct dsa_switch *ds)
+{
+ const struct dsa_device_ops *tag_ops = ds->dst->tag_ops;
+
+ if (tag_ops->disconnect)
+ tag_ops->disconnect(ds);
+}
+
static int dsa_switch_setup(struct dsa_switch *ds)
{
struct dsa_devlink_priv *dl_priv;
@@ -967,6 +975,8 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
ds->slave_mii_bus = NULL;
}
+ dsa_switch_teardown_tag_protocol(ds);
+
if (ds->ops->teardown)
ds->ops->teardown(ds);
--
2.34.1
>
> Also, the receive function checks for tagger_data->decode_frame2reg,
> but does not check for tagger_data != NULL.
>
> This is just a straight copy of tag_qca, so if there are issues here,
> they are probably not new issues.
It checks for tagger_data->decode_frame2reg because the "dsa" or "edsa"
tagging protocol drivers could also be connected to the dsa_loop driver,
for testing. That driver won't populate tagger_data->decode_frame2reg().
What is supposed to happen is that if the tagging protocol driver has no
subscriber for management Ethernet frames, nothing happens with them,
they are just freed right away. This is the model of separate switch
driver and tag protocol driver.
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH net-next v4 4/6] net: dsa: mv88e6xxxx: Add RMU functionality.
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
` (2 preceding siblings ...)
2022-09-06 6:34 ` [PATCH net-next v4 3/6] net: dsa: Introduce dsa tagger data operation Mattias Forsblad
@ 2022-09-06 6:34 ` Mattias Forsblad
2022-09-06 6:34 ` [PATCH net-next v4 5/6] net: dsa: mv88e6xxx: rmon: Use RMU for reading RMON data Mattias Forsblad
` (2 subsequent siblings)
6 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 6:34 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Mattias Forsblad
The Marvell SOHO switches supports a secondary control
channel for accessing data in the switch. Special crafted
ethernet frames can access functions in the switch.
These frames is handled by the Remote Management Unit (RMU)
in the switch. Accessing data structures is specially
efficient and lessens the access contention on the MDIO
bus.
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 28 ++-
drivers/net/dsa/mv88e6xxx/chip.h | 18 ++
drivers/net/dsa/mv88e6xxx/rmu.c | 307 +++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/rmu.h | 28 +++
5 files changed, 374 insertions(+), 8 deletions(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/rmu.c
create mode 100644 drivers/net/dsa/mv88e6xxx/rmu.h
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index c8eca2b6f959..105d7bd832c9 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
mv88e6xxx-objs += serdes.o
mv88e6xxx-objs += smi.o
+mv88e6xxx-objs += rmu.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 46e12b53a9e4..bbdf229c9e71 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -42,6 +42,7 @@
#include "ptp.h"
#include "serdes.h"
#include "smi.h"
+#include "rmu.h"
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
{
@@ -1535,14 +1536,6 @@ static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
return 0;
}
-static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
-{
- if (chip->info->ops->rmu_disable)
- return chip->info->ops->rmu_disable(chip);
-
- return 0;
-}
-
static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
{
if (chip->info->ops->pot_clear)
@@ -6867,6 +6860,23 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
return err_sync ? : err_pvt;
}
+static int mv88e6xxx_connect_tag_protocol(struct dsa_switch *ds,
+ enum dsa_tag_protocol proto)
+{
+ struct dsa_tagger_data *tagger_data = ds->tagger_data;
+
+ switch (proto) {
+ case DSA_TAG_PROTO_DSA:
+ case DSA_TAG_PROTO_EDSA:
+ tagger_data->decode_frame2reg = mv88e6xxx_decode_frame2reg_handler;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.get_tag_protocol = mv88e6xxx_get_tag_protocol,
.change_tag_protocol = mv88e6xxx_change_tag_protocol,
@@ -6932,6 +6942,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.crosschip_lag_change = mv88e6xxx_crosschip_lag_change,
.crosschip_lag_join = mv88e6xxx_crosschip_lag_join,
.crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave,
+ .master_state_change = mv88e6xxx_master_change,
+ .connect_tag_protocol = mv88e6xxx_connect_tag_protocol,
};
static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 7ce3c41f6caf..e81935a9573d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -282,6 +282,17 @@ struct mv88e6xxx_port {
struct devlink_region *region;
};
+struct mv88e6xxx_rmu {
+ /* RMU resources */
+ struct net_device *master_netdev;
+ const struct mv88e6xxx_bus_ops *ops;
+ /* Mutex for RMU operations */
+ struct mutex mutex;
+ u16 got_id;
+ u8 request_cmd;
+ int inband_seqno;
+};
+
enum mv88e6xxx_region_id {
MV88E6XXX_REGION_GLOBAL1 = 0,
MV88E6XXX_REGION_GLOBAL2,
@@ -410,6 +421,9 @@ struct mv88e6xxx_chip {
/* Bridge MST to SID mappings */
struct list_head msts;
+
+ /* RMU resources */
+ struct mv88e6xxx_rmu rmu;
};
struct mv88e6xxx_bus_ops {
@@ -805,4 +819,8 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
+static inline bool mv88e6xxx_rmu_available(struct mv88e6xxx_chip *chip)
+{
+ return chip->rmu.master_netdev ? 1 : 0;
+}
#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
new file mode 100644
index 000000000000..2109e4557467
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Marvell 88E6xxx Switch Remote Management Unit Support
+ *
+ * Copyright (c) 2022 Mattias Forsblad <mattias.forsblad@gmail.com>
+ *
+ */
+
+#include <asm/unaligned.h>
+#include "rmu.h"
+#include "global1.h"
+
+#define MV88E6XXX_DSA_HLEN 4
+
+static const u8 rmu_dest_addr[ETH_ALEN] = { 0x01, 0x50, 0x43, 0x00, 0x00, 0x00 };
+
+#define MV88E6XXX_RMU_L2_BYTE1_RESV_VAL 0x3e
+#define MV88E6XXX_RMU 1
+#define MV88E6XXX_RMU_PRIO 6
+#define MV88E6XXX_RMU_RESV2 0xf
+
+#define MV88E6XXX_SOURCE_PORT GENMASK(6, 3)
+#define MV88E6XXX_SOURCE_DEV GENMASK(5, 0)
+#define MV88E6XXX_CPU_CODE_MASK GENMASK(7, 6)
+#define MV88E6XXX_TRG_DEV_MASK GENMASK(4, 0)
+#define MV88E6XXX_RMU_CODE_MASK GENMASK(1, 1)
+#define MV88E6XXX_RMU_PRIO_MASK GENMASK(7, 5)
+#define MV88E6XXX_RMU_L2_BYTE1_RESV GENMASK(7, 2)
+#define MV88E6XXX_RMU_L2_BYTE2_RESV GENMASK(3, 0)
+
+#define MV88E6XXX_RMU_RESP_FORMAT_1 0x0001
+#define MV88E6XXX_RMU_RESP_FORMAT_2 0x0002
+#define MV88E6XXX_RMU_RESP_ERROR 0xffff
+
+#define MV88E6XXX_RMU_RESP_CODE_GOT_ID 0x0000
+#define MV88E6XXX_RMU_RESP_CODE_DUMP_MIB 0x1020
+
+static void mv88e6xxx_rmu_create_l2(struct sk_buff *skb, struct dsa_port *dp)
+{
+ struct mv88e6xxx_chip *chip = dp->ds->priv;
+ struct ethhdr *eth;
+ u8 *edsa_header;
+ u8 *dsa_header;
+ u8 extra = 0;
+
+ if (chip->tag_protocol == DSA_TAG_PROTO_EDSA)
+ extra = 4;
+
+ /* Create RMU L2 header */
+ dsa_header = skb_push(skb, 6);
+ dsa_header[0] = FIELD_PREP(MV88E6XXX_CPU_CODE_MASK, MV88E6XXX_RMU);
+ dsa_header[0] |= FIELD_PREP(MV88E6XXX_TRG_DEV_MASK, dp->ds->index);
+ dsa_header[1] = FIELD_PREP(MV88E6XXX_RMU_CODE_MASK, 1);
+ dsa_header[1] |= FIELD_PREP(MV88E6XXX_RMU_L2_BYTE1_RESV, MV88E6XXX_RMU_L2_BYTE1_RESV_VAL);
+ dsa_header[2] = FIELD_PREP(MV88E6XXX_RMU_PRIO_MASK, MV88E6XXX_RMU_PRIO);
+ dsa_header[2] |= MV88E6XXX_RMU_L2_BYTE2_RESV;
+ dsa_header[3] = ++chip->rmu.inband_seqno;
+ dsa_header[4] = 0;
+ dsa_header[5] = 0;
+
+ /* Insert RMU MAC destination address /w extra if needed */
+ skb_push(skb, ETH_ALEN * 2 + extra);
+ eth = (struct ethhdr *)skb->data;
+ memcpy(eth->h_dest, rmu_dest_addr, ETH_ALEN);
+ memcpy(eth->h_source, chip->rmu.master_netdev->dev_addr, ETH_ALEN);
+
+ if (extra) {
+ edsa_header = (u8 *)ð->h_proto;
+ edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff;
+ edsa_header[1] = ETH_P_EDSA & 0xff;
+ edsa_header[2] = 0x00;
+ edsa_header[3] = 0x00;
+ }
+}
+
+static int mv88e6xxx_rmu_send_wait(struct mv88e6xxx_chip *chip, int port,
+ int request, const char *msg, int len)
+{
+ struct dsa_port *dp;
+ struct sk_buff *skb;
+ unsigned char *data;
+ int ret = 0;
+
+ dp = dsa_to_port(chip->ds, port);
+ if (!dp)
+ return 0;
+
+ skb = netdev_alloc_skb(chip->rmu.master_netdev, 64);
+ if (!skb)
+ return -ENOMEM;
+
+ /* Take height for an eventual EDSA header */
+ skb_reserve(skb, 2 * ETH_HLEN + 4);
+ skb_reset_network_header(skb);
+
+ /* Insert RMU L3 message */
+ data = skb_put(skb, len);
+ memcpy(data, msg, len);
+
+ mv88e6xxx_rmu_create_l2(skb, dp);
+
+ mutex_lock(&chip->rmu.mutex);
+
+ chip->rmu.request_cmd = request;
+
+ ret = dsa_switch_inband_tx(dp->ds, skb, NULL, MV88E6XXX_RMU_WAIT_TIME_MS);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "RMU: timeout waiting for request %d (%pe) on port %d\n",
+ request, ERR_PTR(ret), port);
+ }
+
+ mutex_unlock(&chip->rmu.mutex);
+
+ return ret > 0 ? 0 : ret;
+}
+
+static int mv88e6xxx_rmu_get_id(struct mv88e6xxx_chip *chip, int port)
+{
+ const u8 get_id[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ int ret = -1;
+
+ if (chip->rmu.got_id)
+ return 0;
+
+ ret = mv88e6xxx_rmu_send_wait(chip, port, MV88E6XXX_RMU_REQ_GET_ID, get_id, 8);
+ if (ret) {
+ dev_dbg(chip->dev, "RMU: error for command GET_ID %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mv88e6xxx_rmu_stats_get(struct mv88e6xxx_chip *chip, int port, uint64_t *data)
+{
+ u8 dump_mib[8] = { 0x00, 0x01, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00 };
+ int ret;
+
+ ret = mv88e6xxx_rmu_get_id(chip, port);
+ if (ret)
+ return ret;
+
+ /* Send a GET_MIB command */
+ dump_mib[7] = port;
+ ret = mv88e6xxx_rmu_send_wait(chip, port, MV88E6XXX_RMU_REQ_DUMP_MIB, dump_mib, 8);
+ if (ret) {
+ dev_dbg(chip->dev, "RMU: error for command DUMP_MIB %pe port %d\n",
+ ERR_PTR(ret), port);
+ return ret;
+ }
+
+ /* Update MIB for port */
+ if (chip->info->ops->stats_get_stats)
+ return chip->info->ops->stats_get_stats(chip, port, data);
+
+ return 0;
+}
+
+void mv88e6xxx_master_change(struct dsa_switch *ds, const struct net_device *master,
+ bool operational)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct dsa_port *cpu_dp;
+ int port;
+
+ cpu_dp = master->dsa_ptr;
+ port = dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index);
+
+ mv88e6xxx_reg_lock(chip);
+
+ if (operational) {
+ if (chip->info->ops->rmu_enable) {
+ if (!chip->info->ops->rmu_enable(chip, port))
+ chip->rmu.master_netdev = (struct net_device *)master;
+ else
+ dev_err(chip->dev, "RMU: Unable to enable on port %d", port);
+ }
+
+ } else {
+ chip->rmu.master_netdev = NULL;
+ if (chip->info->ops->rmu_disable)
+ chip->info->ops->rmu_disable(chip);
+ }
+
+ mv88e6xxx_reg_unlock(chip);
+}
+
+static void mv88e6xxx_prod_id_handler(struct dsa_switch *ds, struct sk_buff *skb)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ u16 prodnum;
+
+ prodnum = get_unaligned_be16(&skb->data[2]);
+ chip->rmu.got_id = prodnum;
+ dev_dbg_ratelimited(chip->dev, "RMU: received id OK with product number: 0x%04x\n",
+ chip->rmu.got_id);
+}
+
+static void mv88e6xxx_mib_handler(struct dsa_switch *ds, struct sk_buff *skb)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_port *p;
+ u8 port;
+ int i;
+
+ port = FIELD_GET(MV88E6XXX_SOURCE_PORT, skb->data[7]);
+ p = &chip->ports[port];
+ if (!p) {
+ dev_err_ratelimited(chip->dev, "RMU: illegal port number in response: %d\n", port);
+ return;
+ }
+
+ /* Copy whole array for further
+ * processing according to chip type
+ */
+ for (i = 0; i < MV88E6XXX_RMU_MAX_RMON; i++)
+ p->rmu_raw_stats[i] = get_unaligned_be32(&skb->data[12 + i * 4]);
+}
+
+static int mv88e6xxx_validate_mac(struct dsa_switch *ds, struct sk_buff *skb)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ unsigned char *ethhdr;
+
+ /* Check matching MAC */
+ ethhdr = skb_mac_header(skb);
+ if (!ether_addr_equal(chip->rmu.master_netdev->dev_addr, ethhdr)) {
+ dev_dbg_ratelimited(ds->dev, "RMU: mismatching MAC address for request. Rx %pM expecting %pM\n",
+ ethhdr, chip->rmu.master_netdev->dev_addr);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void mv88e6xxx_decode_frame2reg_handler(struct net_device *dev, struct sk_buff *skb)
+{
+ struct dsa_port *dp = dev->dsa_ptr;
+ struct dsa_switch *ds = dp->ds;
+ struct mv88e6xxx_chip *chip;
+ int source_device;
+ u8 *dsa_header;
+ u16 format;
+ u16 code;
+ u8 seqno;
+
+ if (mv88e6xxx_validate_mac(ds, skb))
+ return;
+
+ /* Decode Frame2Reg DSA portion */
+ dsa_header = skb->data - 2;
+
+ source_device = FIELD_GET(MV88E6XXX_SOURCE_DEV, dsa_header[0]);
+ ds = dsa_switch_find(ds->dst->index, source_device);
+ if (!ds) {
+ net_dbg_ratelimited("RMU: Didn't find switch with index %d", source_device);
+ return;
+ }
+
+ chip = ds->priv;
+ seqno = dsa_header[3];
+ if (seqno != chip->rmu.inband_seqno) {
+ net_dbg_ratelimited("RMU: wrong seqno received. Was %d, expected %d",
+ seqno, chip->rmu.inband_seqno);
+ return;
+ }
+
+ /* Pull DSA L2 data */
+ skb_pull(skb, MV88E6XXX_DSA_HLEN);
+
+ format = get_unaligned_be16(&skb->data[0]);
+ if (format != MV88E6XXX_RMU_RESP_FORMAT_1 &&
+ format != MV88E6XXX_RMU_RESP_FORMAT_2) {
+ net_dbg_ratelimited("RMU: received unknown format 0x%04x", format);
+ return;
+ }
+
+ code = get_unaligned_be16(&skb->data[4]);
+ if (code == MV88E6XXX_RMU_RESP_ERROR) {
+ net_dbg_ratelimited("RMU: error response code 0x%04x", code);
+ return;
+ }
+
+ if (code == MV88E6XXX_RMU_RESP_CODE_GOT_ID)
+ mv88e6xxx_prod_id_handler(ds, skb);
+ else if (code == MV88E6XXX_RMU_RESP_CODE_DUMP_MIB)
+ mv88e6xxx_mib_handler(ds, skb);
+
+ dsa_switch_inband_complete(ds, NULL);
+}
+
+static const struct mv88e6xxx_bus_ops mv88e6xxx_bus_ops = {
+ .get_rmon = mv88e6xxx_rmu_stats_get,
+};
+
+int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
+{
+ mutex_init(&chip->rmu.mutex);
+
+ chip->rmu.ops = &mv88e6xxx_bus_ops;
+
+ if (chip->info->ops->rmu_disable)
+ return chip->info->ops->rmu_disable(chip);
+
+ return 0;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
new file mode 100644
index 000000000000..cf84b7005331
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Marvell 88E6xxx Switch Remote Management Unit Support
+ *
+ * Copyright (c) 2022 Mattias Forsblad <mattias.forsblad@gmail.com>
+ *
+ */
+
+#ifndef _MV88E6XXX_RMU_H_
+#define _MV88E6XXX_RMU_H_
+
+#include "chip.h"
+
+#define MV88E6XXX_RMU_MAX_RMON 64
+
+#define MV88E6XXX_RMU_REQ_GET_ID 1
+#define MV88E6XXX_RMU_REQ_DUMP_MIB 2
+
+#define MV88E6XXX_RMU_WAIT_TIME_MS 20
+
+int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip);
+
+void mv88e6xxx_master_change(struct dsa_switch *ds, const struct net_device *master,
+ bool operational);
+
+void mv88e6xxx_decode_frame2reg_handler(struct net_device *dev, struct sk_buff *skb);
+
+#endif /* _MV88E6XXX_RMU_H_ */
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH net-next v4 5/6] net: dsa: mv88e6xxx: rmon: Use RMU for reading RMON data
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
` (3 preceding siblings ...)
2022-09-06 6:34 ` [PATCH net-next v4 4/6] net: dsa: mv88e6xxxx: Add RMU functionality Mattias Forsblad
@ 2022-09-06 6:34 ` Mattias Forsblad
2022-09-06 6:34 ` [PATCH net-next v4 6/6] net: dsa: qca8k: Use new convenience functions Mattias Forsblad
2022-09-06 8:07 ` [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Marek Behún
6 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 6:34 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Mattias Forsblad
Use the Remote Management Unit for efficiently accessing
the RMON data.
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 39 ++++++++++++++++++++++++++------
drivers/net/dsa/mv88e6xxx/chip.h | 2 ++
2 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index bbdf229c9e71..f32048de68fc 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1234,16 +1234,30 @@ static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
u16 bank1_select, u16 histogram)
{
struct mv88e6xxx_hw_stat *stat;
+ int offset = 0;
+ u64 high;
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
if (stat->type & types) {
- mv88e6xxx_reg_lock(chip);
- data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
- bank1_select,
- histogram);
- mv88e6xxx_reg_unlock(chip);
+ if (mv88e6xxx_rmu_available(chip) &&
+ !(stat->type & STATS_TYPE_PORT)) {
+ if (stat->type & STATS_TYPE_BANK1)
+ offset = 32;
+
+ data[j] = chip->ports[port].rmu_raw_stats[stat->reg + offset];
+ if (stat->size == 8) {
+ high = chip->ports[port].rmu_raw_stats[stat->reg + offset
+ + 1];
+ data[j] += (high << 32);
+ }
+ } else {
+ mv88e6xxx_reg_lock(chip);
+ data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
+ bank1_select, histogram);
+ mv88e6xxx_reg_unlock(chip);
+ }
j++;
}
@@ -1312,8 +1326,8 @@ static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
mv88e6xxx_reg_unlock(chip);
}
-static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
- uint64_t *data)
+static void mv88e6xxx_get_ethtool_stats_mdio(struct dsa_switch *ds, int port,
+ uint64_t *data)
{
struct mv88e6xxx_chip *chip = ds->priv;
int ret;
@@ -1327,7 +1341,18 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
return;
mv88e6xxx_get_stats(chip, port, data);
+}
+static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
+ uint64_t *data)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+
+ /* If RMU isn't available fall back to MDIO access. */
+ if (mv88e6xxx_rmu_available(chip))
+ chip->rmu.ops->get_rmon(chip, port, data);
+ else
+ mv88e6xxx_get_ethtool_stats_mdio(ds, port, data);
}
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e81935a9573d..c7477b716473 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -266,6 +266,7 @@ struct mv88e6xxx_vlan {
struct mv88e6xxx_port {
struct mv88e6xxx_chip *chip;
int port;
+ u64 rmu_raw_stats[64];
struct mv88e6xxx_vlan bridge_pvid;
u64 serdes_stats[2];
u64 atu_member_violation;
@@ -430,6 +431,7 @@ struct mv88e6xxx_bus_ops {
int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
int (*init)(struct mv88e6xxx_chip *chip);
+ int (*get_rmon)(struct mv88e6xxx_chip *chip, int port, uint64_t *data);
};
struct mv88e6xxx_mdio_bus {
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH net-next v4 6/6] net: dsa: qca8k: Use new convenience functions
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
` (4 preceding siblings ...)
2022-09-06 6:34 ` [PATCH net-next v4 5/6] net: dsa: mv88e6xxx: rmon: Use RMU for reading RMON data Mattias Forsblad
@ 2022-09-06 6:34 ` Mattias Forsblad
2022-09-06 8:07 ` [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Marek Behún
6 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 6:34 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Mattias Forsblad
Use the new common convenience functions for sending and
waiting for frames.
Signed-off-by: Mattias Forsblad <mattias.forsblad@gmail.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 61 +++++++++-----------------------
1 file changed, 17 insertions(+), 44 deletions(-)
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 1d3e7782a71f..7c9782be8dfe 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -160,7 +160,7 @@ static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)
QCA_HDR_MGMT_DATA2_LEN);
}
- complete(&mgmt_eth_data->rw_done);
+ dsa_switch_inband_complete(ds, &mgmt_eth_data->rw_done);
}
static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
@@ -228,6 +228,7 @@ static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num)
static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
{
struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
+ struct dsa_switch *ds = priv->ds;
struct sk_buff *skb;
bool ack;
int ret;
@@ -248,17 +249,12 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
skb->dev = priv->mgmt_master;
- reinit_completion(&mgmt_eth_data->rw_done);
-
/* Increment seq_num and set it in the mdio pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
- dev_queue_xmit(skb);
-
- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
+ ret = dsa_switch_inband_tx(ds, skb, &mgmt_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
*val = mgmt_eth_data->data[0];
if (len > QCA_HDR_MGMT_DATA1_LEN)
@@ -280,6 +276,7 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
{
struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
+ struct dsa_switch *ds = priv->ds;
struct sk_buff *skb;
bool ack;
int ret;
@@ -300,17 +297,12 @@ static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
skb->dev = priv->mgmt_master;
- reinit_completion(&mgmt_eth_data->rw_done);
-
/* Increment seq_num and set it in the mdio pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
- dev_queue_xmit(skb);
-
- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
+ ret = dsa_switch_inband_tx(ds, skb, &mgmt_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
ack = mgmt_eth_data->ack;
@@ -441,24 +433,21 @@ static struct regmap_config qca8k_regmap_config = {
};
static int
-qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data,
+qca8k_phy_eth_busy_wait(struct qca8k_priv *priv,
struct sk_buff *read_skb, u32 *val)
{
+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL);
+ struct dsa_switch *ds = priv->ds;
bool ack;
int ret;
- reinit_completion(&mgmt_eth_data->rw_done);
-
/* Increment seq_num and set it in the copy pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
- dev_queue_xmit(skb);
-
- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
- QCA8K_ETHERNET_TIMEOUT);
+ ret = dsa_switch_inband_tx(ds, skb, &mgmt_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
ack = mgmt_eth_data->ack;
@@ -480,6 +469,7 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
struct sk_buff *write_skb, *clear_skb, *read_skb;
struct qca8k_mgmt_eth_data *mgmt_eth_data;
u32 write_val, clear_val = 0, val;
+ struct dsa_switch *ds = priv->ds;
struct net_device *mgmt_master;
int ret, ret1;
bool ack;
@@ -540,17 +530,12 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
clear_skb->dev = mgmt_master;
write_skb->dev = mgmt_master;
- reinit_completion(&mgmt_eth_data->rw_done);
-
/* Increment seq_num and set it in the write pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
- dev_queue_xmit(write_skb);
-
- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
- QCA8K_ETHERNET_TIMEOUT);
+ ret = dsa_switch_inband_tx(ds, write_skb, &mgmt_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
ack = mgmt_eth_data->ack;
@@ -569,7 +554,7 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1,
!(val & QCA8K_MDIO_MASTER_BUSY), 0,
QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
- mgmt_eth_data, read_skb, &val);
+ priv, read_skb, &val);
if (ret < 0 && ret1 < 0) {
ret = ret1;
@@ -577,17 +562,13 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
}
if (read) {
- reinit_completion(&mgmt_eth_data->rw_done);
-
/* Increment seq_num and set it in the read pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
- dev_queue_xmit(read_skb);
-
- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
- QCA8K_ETHERNET_TIMEOUT);
+ ret = dsa_switch_inband_tx(ds, read_skb, &mgmt_eth_data->rw_done,
+ QCA8K_ETHERNET_TIMEOUT);
ack = mgmt_eth_data->ack;
@@ -606,17 +587,12 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
kfree_skb(read_skb);
}
exit:
- reinit_completion(&mgmt_eth_data->rw_done);
-
/* Increment seq_num and set it in the clear pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
- dev_queue_xmit(clear_skb);
-
- wait_for_completion_timeout(&mgmt_eth_data->rw_done,
- QCA8K_ETHERNET_TIMEOUT);
+ ret = dsa_switch_inband_tx(ds, clear_skb, &mgmt_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
mutex_unlock(&mgmt_eth_data->mutex);
@@ -1528,7 +1504,7 @@ static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *sk
exit:
/* Complete on receiving all the mib packet */
if (refcount_dec_and_test(&mib_eth_data->port_parsed))
- complete(&mib_eth_data->rw_done);
+ dsa_switch_inband_complete(ds, &mib_eth_data->rw_done);
}
static int
@@ -1543,8 +1519,6 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
mutex_lock(&mib_eth_data->mutex);
- reinit_completion(&mib_eth_data->rw_done);
-
mib_eth_data->req_port = dp->index;
mib_eth_data->data = data;
refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS);
@@ -1562,8 +1536,7 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
if (ret)
goto exit;
- ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
-
+ ret = dsa_switch_inband_tx(ds, NULL, &mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
exit:
mutex_unlock(&mib_eth_data->mutex);
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support
2022-09-06 6:34 [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Mattias Forsblad
` (5 preceding siblings ...)
2022-09-06 6:34 ` [PATCH net-next v4 6/6] net: dsa: qca8k: Use new convenience functions Mattias Forsblad
@ 2022-09-06 8:07 ` Marek Behún
2022-09-06 9:45 ` Mattias Forsblad
6 siblings, 1 reply; 19+ messages in thread
From: Marek Behún @ 2022-09-06 8:07 UTC (permalink / raw)
To: Mattias Forsblad
Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
Vladimir Oltean, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
On Tue, 6 Sep 2022 08:34:44 +0200
Mattias Forsblad <mattias.forsblad@gmail.com> wrote:
> The Marvell SOHO switches have the ability to receive and transmit
> Remote Management Frames (Frame2Reg) to the CPU through the
> attached network interface.
> This is handled by the Remote Management Unit (RMU) in the switch
> These frames can contain different payloads:
> single switch register read and writes, daisy chained switch
> register read and writes, RMON/MIB dump/dump clear and ATU dump.
> The dump functions are very costly over MDIO but it's
> only a couple of network packets via the RMU.
>
> Next step could be to implement ATU dump.
> We've found that the gain to use RMU for single register
> read and writes is neglible.
>
> qca8k
> =====
> There's a newly introduced convenience function for sending
> and waiting for frames. Changes have been made for the qca8k
> driver to use this. Please test for regressions.
>
> RFC -> v1:
> - Track master interface availability.
> - Validate destination MAC for incoming frames.
> - Rate limit outputs.
> - Cleanup setup function validating upstream port on switch.
> - Fix return values when setting up RMU.
> - Prefix defines correctly.
> - Fix aligned accesses.
> - Validate that switch exists for incoming frames.
> - Split RMON stats function.
>
> v1 -> v2:
> - Remove unused variable.
>
> v2 -> v3:
> - Rewrite after feedback. Use tagger_data to handle
> frames more like qca8k.
> - qca8k: Change to use convenience functions introduced.
> Requesting test of this.
>
> v3 -> v4:
> - Separated patches more granular.
>
> Regards,
> Mattias Forsblad
Nitpick: in subject, the order of components separated by ':' infers
hierarchy, so your subject
net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support
means:
component net
subcompoment dsa
subcomponent mv88e6xxx
subcomponent qca8k (this is wrong since qca8k is separate
driver, not a subcomponent of mv88e6xxx)
You should use ',' to separate mv88e6xxx and qca8k, something like
net: dsa: mv88e6xxx, qca8k: rmon: Add RMU support
Since this is not an actual patch, but instead a cover letter only,
it's not a problem (at least not for me). But please try not to do it
in actual patches.
Marek
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support
2022-09-06 8:07 ` [PATCH net-next v4 0/6] net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support Marek Behún
@ 2022-09-06 9:45 ` Mattias Forsblad
0 siblings, 0 replies; 19+ messages in thread
From: Mattias Forsblad @ 2022-09-06 9:45 UTC (permalink / raw)
To: Marek Behún
Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
Vladimir Oltean, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
On 2022-09-06 10:07, Marek Behún wrote:
> Nitpick: in subject, the order of components separated by ':' infers
> hierarchy, so your subject
> net: dsa: mv88e6xxx: qca8k: rmon: Add RMU support
> means:
> component net
> subcompoment dsa
> subcomponent mv88e6xxx
> subcomponent qca8k (this is wrong since qca8k is separate
> driver, not a subcomponent of mv88e6xxx)
>
> You should use ',' to separate mv88e6xxx and qca8k, something like
> net: dsa: mv88e6xxx, qca8k: rmon: Add RMU support
>
> Since this is not an actual patch, but instead a cover letter only,
> it's not a problem (at least not for me). But please try not to do it
> in actual patches.
>
> Marek
Ah, ok I see your point. Thanks.
/Mattias
^ permalink raw reply [flat|nested] 19+ messages in thread