2016-11-30 23:00:54

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 0/6] net: dsa: mv88e6xxx: rework reset and PPU code

Old Marvell chips (like 88E6060) don't have a PHY Polling Unit (PPU).

Next chips (like 88E6185) have a PPU, which has exclusive access to the
PHY registers, thus must be disabled before access.

Newer chips (like 88E6352) have an indirect mechanism to access the PHY
registers whenever, thus loose control over the PPU (alway enabled).

Here's a summary:

Model | PPU? | Has PPU ctrl? | PPU state readable? | PHY access
----- | ---- | -------------- | ------------------- | ----------
6060 | no | no | no | direct
6185 | yes | yes, PPUEn bit | yes, PPUState 2-bit | direct w/ PPU dis.
6352 | yes | no | yes, PPUState 1-bit | indirect
6390 | yes | no | yes, InitState bit | indirect

Depending on the PPU control, a switch may have to restart the PPU when
resetting the switch. Once the switch is reset, we must wait for the PPU
state to be active polling again before accessing the registers.

For that purpose, add new operations to the chips to enable/disable the
PPU and check its polling state, and execute software reset. With these
new ops in place, rework the switch reset code and finally get rid of
the MV88E6XXX_FLAG_PPU* flags.

Vivien Didelot (6):
net: dsa: mv88e6xxx: add helper to disable ports
net: dsa: mv88e6xxx: add helper to hardware reset
net: dsa: mv88e6xxx: add a software reset op
net: dsa: mv88e6xxx: add a PPU polling op
net: dsa: mv88e6xxx: add helper for switch ready
net: dsa: mv88e6xxx: add PPU enable/disable ops

drivers/net/dsa/mv88e6xxx/chip.c | 241 ++++++++++++++++++++++------------
drivers/net/dsa/mv88e6xxx/global1.c | 111 ++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 10 ++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 35 ++---
4 files changed, 292 insertions(+), 105 deletions(-)

--
2.10.2


2016-11-30 22:59:59

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 2/6] net: dsa: mv88e6xxx: add helper to hardware reset

Add an helper to toggle the eventual GPIO connected to the reset pin.

Signed-off-by: Vivien Didelot <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c89701e..4a862c2 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2361,6 +2361,19 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
mutex_unlock(&chip->reg_lock);
}

+static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
+{
+ struct gpio_desc *gpiod = chip->reset;
+
+ /* If there is a GPIO connected to the reset pin, toggle it */
+ if (gpiod) {
+ gpiod_set_value_cansleep(gpiod, 1);
+ usleep_range(10000, 20000);
+ gpiod_set_value_cansleep(gpiod, 0);
+ usleep_range(10000, 20000);
+ }
+}
+
static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
{
int i, err;
@@ -2385,7 +2398,6 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
{
bool ppu_active = mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU_ACTIVE);
u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
- struct gpio_desc *gpiod = chip->reset;
unsigned long timeout;
u16 reg;
int err;
@@ -2394,13 +2406,7 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
if (err)
return err;

- /* If there is a gpio connected to the reset pin, toggle it */
- if (gpiod) {
- gpiod_set_value_cansleep(gpiod, 1);
- usleep_range(10000, 20000);
- gpiod_set_value_cansleep(gpiod, 0);
- usleep_range(10000, 20000);
- }
+ mv88e6xxx_hardware_reset(chip);

/* Reset the switch. Keep the PPU active if requested. The PPU
* needs to be active to support indirect phy register access
--
2.10.2

2016-11-30 23:00:02

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 5/6] net: dsa: mv88e6xxx: add helper for switch ready

All Marvell switches (even 88E6060) have a bit to inform that the switch
is ready to accept frames. Implement that in mv88e6xxx_g1_init_ready().

If the switch has a PPU, we must wait until its state is active polling,
otherwise we cannot access PortStatus registers. Nicely wrap all that in
a mv88e6xxx_wait_switch_ready() helper for the switch reset code.

Signed-off-by: Vivien Didelot <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 52 +++++++++++++++++++++--------------
drivers/net/dsa/mv88e6xxx/global1.c | 15 ++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 1 +
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 +
4 files changed, 48 insertions(+), 21 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index db4014c..f5d5370 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2363,6 +2363,36 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
mutex_unlock(&chip->reg_lock);
}

+static int mv88e6xxx_wait_switch_ready(struct mv88e6xxx_chip *chip)
+{
+ const unsigned long timeout = jiffies + 1 * HZ;
+ bool ready;
+ int err;
+
+ /* Wait up to 1 second for switch to be ready.
+ * The switch is ready when all units inside the device (ATU, VTU, etc.)
+ * have finished their initialization and are ready to accept frames.
+ */
+ while (time_before(jiffies, timeout)) {
+ err = mv88e6xxx_g1_init_ready(chip, &ready);
+ if (err)
+ return err;
+
+ if (ready)
+ break;
+
+ usleep_range(1000, 2000);
+ }
+
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ /* If there is a PPU, the PortStatus registers must not be written to by
+ * software until the PPU is active polling, so wait until then.
+ */
+ return mv88e6xxx_ppu_wait(chip, true);
+}
+
static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
{
if (chip->info->ops->reset)
@@ -2406,10 +2436,6 @@ static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)

static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
{
- bool ppu_active = mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU_ACTIVE);
- u16 is_reset = (ppu_active ? 0x8800 : 0xc800);
- unsigned long timeout;
- u16 reg;
int err;

err = mv88e6xxx_disable_ports(chip);
@@ -2422,23 +2448,7 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
if (err)
return err;

- /* Wait up to one second for reset to complete. */
- timeout = jiffies + 1 * HZ;
- while (time_before(jiffies, timeout)) {
- err = mv88e6xxx_g1_read(chip, 0x00, &reg);
- if (err)
- return err;
-
- if ((reg & is_reset) == is_reset)
- break;
- usleep_range(1000, 2000);
- }
- if (time_after(jiffies, timeout))
- err = -ETIMEDOUT;
- else
- err = 0;
-
- return err;
+ return mv88e6xxx_wait_switch_ready(chip);
}

static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 371d96a..4d69cec 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -66,6 +66,21 @@ int mv88e6352_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling)
return 0;
}

+int mv88e6xxx_g1_init_ready(struct mv88e6xxx_chip *chip, bool *ready)
+{
+ u16 val;
+ int err;
+
+ /* Check the value of the InitReady bit 11 */
+ err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
+ if (err)
+ return err;
+
+ *ready = !!(val & GLOBAL_STATUS_INIT_READY);
+
+ return 0;
+}
+
/* Offset 0x04: Switch Global Control Register */

int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index cdccf473..6f0fb7f 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -22,6 +22,7 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);

int mv88e6185_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling);
int mv88e6352_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling);
+int mv88e6xxx_g1_init_ready(struct mv88e6xxx_chip *chip, bool *ready);

int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 9ae228c..cd0f414 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -180,6 +180,7 @@
#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_STATS 6
--
2.10.2

2016-11-30 23:00:04

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 3/6] net: dsa: mv88e6xxx: add a software reset op

Marvell chips have different way to issue a software reset.

Old chips (such as 88E6060) have a reset bit in an ATU control register.

Newer chips moved this bit in a Global control register. Chips with
controllable PPU should reset the PPU when resetting the switch.

Add a new reset operation to implement these differences and introduce a
mv88e6xxx_software_reset() helper to wrap it conveniently.

Signed-off-by: Vivien Didelot <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 42 ++++++++++++++++++++++++++++-------
drivers/net/dsa/mv88e6xxx/global1.c | 35 +++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 4 ++++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 3 +++
4 files changed, 76 insertions(+), 8 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 4a862c2..6bb7571 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2361,6 +2361,14 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
mutex_unlock(&chip->reg_lock);
}

+static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
+{
+ if (chip->info->ops->reset)
+ return chip->info->ops->reset(chip);
+
+ return 0;
+}
+
static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
{
struct gpio_desc *gpiod = chip->reset;
@@ -2408,14 +2416,7 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)

mv88e6xxx_hardware_reset(chip);

- /* Reset the switch. Keep the PPU active if requested. The PPU
- * needs to be active to support indirect phy register access
- * through global registers 0x18 and 0x19.
- */
- if (ppu_active)
- err = mv88e6xxx_g1_write(chip, 0x04, 0xc000);
- else
- err = mv88e6xxx_g1_write(chip, 0x04, 0xc400);
+ err = mv88e6xxx_software_reset(chip);
if (err)
return err;

@@ -3211,6 +3212,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6185_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -3225,6 +3227,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6185_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6097_ops = {
@@ -3239,6 +3242,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6185_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3253,6 +3257,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3267,6 +3272,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6185_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3281,6 +3287,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3295,6 +3302,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3310,6 +3318,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3327,6 +3336,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3342,6 +3352,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3359,6 +3370,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3373,6 +3385,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6185_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6190_ops = {
@@ -3389,6 +3402,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -3405,6 +3419,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -3421,6 +3436,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3438,6 +3454,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -3454,6 +3471,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3470,6 +3488,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6320_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3486,6 +3505,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6320_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3501,6 +3521,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3516,6 +3537,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3533,6 +3555,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3549,6 +3572,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3565,6 +3589,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_ops mv88e6391_ops = {
@@ -3581,6 +3606,7 @@ static const struct mv88e6xxx_ops mv88e6391_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .reset = mv88e6352_g1_reset,
};

static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 5fcf23d..27f37a7 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -33,6 +33,41 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
}

+/* Offset 0x04: Switch Global Control Register */
+
+int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart
+ * the PPU, including re-doing PHY detection and initialization
+ */
+ err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
+ if (err)
+ return err;
+
+ val |= GLOBAL_CONTROL_SW_RESET;
+ val |= GLOBAL_CONTROL_PPU_ENABLE;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
+}
+
+int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ /* Set the SWReset bit 15 */
+ err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
+ if (err)
+ return err;
+
+ val |= GLOBAL_CONTROL_SW_RESET;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
+}
+
/* Offset 0x1c: Global Control 2 */

int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index df3794c..868a281 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -19,6 +19,10 @@
int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
+
+int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
+int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
+
int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index ab52c37..9e51405 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -765,6 +765,9 @@ struct mv88e6xxx_ops {
int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 val);

+ /* Switch Software Reset */
+ int (*reset)(struct mv88e6xxx_chip *chip);
+
/* RGMII Receive/Transmit Timing Control
* Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise.
*/
--
2.10.2

2016-11-30 23:00:01

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 1/6] net: dsa: mv88e6xxx: add helper to disable ports

Before resetting a switch, the ports should be set to the Disabled state
and the transmit queues should be drained.

Add an helper to explicit that.

Signed-off-by: Vivien Didelot <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ce2f7ff..c89701e 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2361,6 +2361,26 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
mutex_unlock(&chip->reg_lock);
}

+static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
+{
+ int i, err;
+
+ /* Set all ports to the Disabled state */
+ for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
+ err = mv88e6xxx_port_set_state(chip, i,
+ PORT_CONTROL_STATE_DISABLED);
+ if (err)
+ return err;
+ }
+
+ /* Wait for transmit queues to drain,
+ * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
+ */
+ usleep_range(2000, 4000);
+
+ return 0;
+}
+
static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
{
bool ppu_active = mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU_ACTIVE);
@@ -2369,18 +2389,10 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
unsigned long timeout;
u16 reg;
int err;
- int i;

- /* Set all ports to the disabled state. */
- for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
- err = mv88e6xxx_port_set_state(chip, i,
- PORT_CONTROL_STATE_DISABLED);
- if (err)
- return err;
- }
-
- /* Wait for transmit queues to drain. */
- usleep_range(2000, 4000);
+ err = mv88e6xxx_disable_ports(chip);
+ if (err)
+ return err;

/* If there is a gpio connected to the reset pin, toggle it */
if (gpiod) {
--
2.10.2

2016-11-30 23:00:53

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 4/6] net: dsa: mv88e6xxx: add a PPU polling op

Marvell chips with controllable PPU have 2 bits to identify the PPU
state. Chips without PPU control have their PPU enable by default and
have only 1 bit to read the PPU state.

The only state we care about is the PPU active and polling state
(meaning PortStatus registers are available for reading).

Add a .ppu_polling op check this state and use it in the PPU
enable/disable routines. It will also be used later in the switch reset
code.

Signed-off-by: Vivien Didelot <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 70 +++++++++++++++++++++++------------
drivers/net/dsa/mv88e6xxx/global1.c | 33 +++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 3 ++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 13 ++++---
4 files changed, 89 insertions(+), 30 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 6bb7571..db4014c 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -525,10 +525,32 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
return mv88e6xxx_write(chip, addr, reg, val);
}

+static int mv88e6xxx_ppu_wait(struct mv88e6xxx_chip *chip, bool state)
+{
+ bool polling;
+ int i, err;
+
+ if (!chip->info->ops->ppu_polling)
+ return 0;
+
+ for (i = 0; i < 16; i++) {
+ err = chip->info->ops->ppu_polling(chip, &polling);
+ if (err)
+ return err;
+
+ usleep_range(1000, 2000);
+
+ if (polling == state)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
{
u16 val;
- int i, err;
+ int err;

err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
if (err)
@@ -539,23 +561,13 @@ static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
if (err)
return err;

- for (i = 0; i < 16; i++) {
- err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
- if (err)
- return err;
-
- usleep_range(1000, 2000);
- if ((val & GLOBAL_STATUS_PPU_MASK) != GLOBAL_STATUS_PPU_POLLING)
- return 0;
- }
-
- return -ETIMEDOUT;
+ return mv88e6xxx_ppu_wait(chip, false);
}

static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
{
u16 val;
- int i, err;
+ int err;

err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
if (err)
@@ -566,17 +578,7 @@ static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
if (err)
return err;

- for (i = 0; i < 16; i++) {
- err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
- if (err)
- return err;
-
- usleep_range(1000, 2000);
- if ((val & GLOBAL_STATUS_PPU_MASK) == GLOBAL_STATUS_PPU_POLLING)
- return 0;
- }
-
- return -ETIMEDOUT;
+ return mv88e6xxx_ppu_wait(chip, true);
}

static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
@@ -3212,6 +3214,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6185_g1_ppu_polling,
.reset = mv88e6185_g1_reset,
};

@@ -3227,6 +3230,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6185_g1_ppu_polling,
.reset = mv88e6185_g1_reset,
};

@@ -3242,6 +3246,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6185_g1_ppu_polling,
.reset = mv88e6185_g1_reset,
};

@@ -3272,6 +3277,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6185_g1_ppu_polling,
.reset = mv88e6185_g1_reset,
};

@@ -3318,6 +3324,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3336,6 +3343,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3352,6 +3360,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3370,6 +3379,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3385,6 +3395,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6185_g1_ppu_polling,
.reset = mv88e6185_g1_reset,
};

@@ -3402,6 +3413,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3419,6 +3431,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3436,6 +3449,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3454,6 +3468,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3471,6 +3486,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3521,6 +3537,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3537,6 +3554,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3555,6 +3573,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3572,6 +3591,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3589,6 +3609,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

@@ -3606,6 +3627,7 @@ static const struct mv88e6xxx_ops mv88e6391_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .ppu_polling = mv88e6352_g1_ppu_polling,
.reset = mv88e6352_g1_reset,
};

diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 27f37a7..371d96a 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -33,6 +33,39 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
}

+/* Offset 0x00: Switch Global Status Register */
+
+int mv88e6185_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling)
+{
+ u16 state;
+ int err;
+
+ /* Check the value of the PPUState bits 15:14 */
+ err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
+ if (err)
+ return err;
+
+ state &= GLOBAL_STATUS_PPU_STATE_MASK;
+ *polling = state == GLOBAL_STATUS_PPU_STATE_POLLING;
+
+ return 0;
+}
+
+int mv88e6352_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling)
+{
+ u16 state;
+ int err;
+
+ /* Check the value of the PPUState (or InitState) bit 15 */
+ err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
+ if (err)
+ return err;
+
+ *polling = !!(state & GLOBAL_STATUS_PPU_STATE);
+
+ return 0;
+}
+
/* Offset 0x04: Switch Global Control Register */

int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 868a281..cdccf473 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -20,6 +20,9 @@ int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);

+int mv88e6185_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling);
+int mv88e6352_g1_ppu_polling(struct mv88e6xxx_chip *chip, bool *polling);
+
int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);

diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 9e51405..9ae228c 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -175,12 +175,11 @@

#define GLOBAL_STATUS 0x00
#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */
-/* Two bits for 6165, 6185 etc */
-#define GLOBAL_STATUS_PPU_MASK (0x3 << 14)
-#define GLOBAL_STATUS_PPU_DISABLED_RST (0x0 << 14)
-#define GLOBAL_STATUS_PPU_INITIALIZING (0x1 << 14)
-#define GLOBAL_STATUS_PPU_DISABLED (0x2 << 14)
-#define GLOBAL_STATUS_PPU_POLLING (0x3 << 14)
+#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_IRQ_AVB 8
#define GLOBAL_STATUS_IRQ_DEVICE 7
#define GLOBAL_STATUS_IRQ_STATS 6
@@ -765,6 +764,8 @@ struct mv88e6xxx_ops {
int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 val);

+ /* PHY Polling Unit (PPU) operations */
+ int (*ppu_polling)(struct mv88e6xxx_chip *chip, bool *polling);
/* Switch Software Reset */
int (*reset)(struct mv88e6xxx_chip *chip);

--
2.10.2

2016-11-30 23:01:37

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next 6/6] net: dsa: mv88e6xxx: add PPU enable/disable ops

Some Marvell chips can enable/disable the PPU on demand. This is needed
to access the PHY registers when there is no indirection mechanism.

Add two new ppu_enable and ppu_disable ops to describe this and finally
get rid of the MV88E6XXX_FLAG_PPU* flags.

Signed-off-by: Vivien Didelot <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 49 ++++++++++++++++-------------------
drivers/net/dsa/mv88e6xxx/global1.c | 28 ++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 2 ++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 18 +++----------
4 files changed, 56 insertions(+), 41 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index f5d5370..78e3aeb 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -549,15 +549,12 @@ static int mv88e6xxx_ppu_wait(struct mv88e6xxx_chip *chip, bool state)

static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
{
- u16 val;
int err;

- err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
- if (err)
- return err;
+ if (!chip->info->ops->ppu_disable)
+ return 0;

- err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL,
- val & ~GLOBAL_CONTROL_PPU_ENABLE);
+ err = chip->info->ops->ppu_disable(chip);
if (err)
return err;

@@ -566,15 +563,12 @@ static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)

static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
{
- u16 val;
int err;

- err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
- if (err)
- return err;
+ if (!chip->info->ops->ppu_enable)
+ return 0;

- err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL,
- val | GLOBAL_CONTROL_PPU_ENABLE);
+ err = chip->info->ops->ppu_enable(chip);
if (err)
return err;

@@ -2775,18 +2769,11 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
/* Enable the PHY Polling Unit if present, don't discard any packets,
* and mask all interrupt sources.
*/
- err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &reg);
- if (err < 0)
- return err;
-
- reg &= ~GLOBAL_CONTROL_PPU_ENABLE;
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU) ||
- mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU_ACTIVE))
- reg |= GLOBAL_CONTROL_PPU_ENABLE;
-
- err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg);
- if (err)
- return err;
+ if (chip->info->ops->ppu_enable) {
+ err = chip->info->ops->ppu_enable(chip);
+ if (err)
+ return err;
+ }

/* Configure the upstream port, and configure it as the port to which
* ingress and egress and ARP monitor frames are to be sent.
@@ -3225,6 +3212,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
.ppu_polling = mv88e6185_g1_ppu_polling,
+ .ppu_enable = mv88e6xxx_g1_ppu_enable,
+ .ppu_disable = mv88e6xxx_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
};

@@ -3241,6 +3230,8 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
.ppu_polling = mv88e6185_g1_ppu_polling,
+ .ppu_enable = mv88e6xxx_g1_ppu_enable,
+ .ppu_disable = mv88e6xxx_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
};

@@ -3257,6 +3248,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
.ppu_polling = mv88e6185_g1_ppu_polling,
+ .ppu_enable = mv88e6xxx_g1_ppu_enable,
+ .ppu_disable = mv88e6xxx_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
};

@@ -3288,6 +3281,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
.ppu_polling = mv88e6185_g1_ppu_polling,
+ .ppu_enable = mv88e6xxx_g1_ppu_enable,
+ .ppu_disable = mv88e6xxx_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
};

@@ -3406,6 +3401,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
.ppu_polling = mv88e6185_g1_ppu_polling,
+ .ppu_enable = mv88e6xxx_g1_ppu_enable,
+ .ppu_disable = mv88e6xxx_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
};

@@ -4037,13 +4034,13 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)

static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
{
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU))
+ if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
mv88e6xxx_ppu_state_init(chip);
}

static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
{
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU))
+ if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
mv88e6xxx_ppu_state_destroy(chip);
}

diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 4d69cec..355231a 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -116,6 +116,34 @@ int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
return mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
}

+int mv88e6xxx_g1_ppu_enable(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
+ if (err)
+ return err;
+
+ val |= GLOBAL_CONTROL_PPU_ENABLE;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
+}
+
+int mv88e6xxx_g1_ppu_disable(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
+ if (err)
+ return err;
+
+ val &= ~GLOBAL_CONTROL_PPU_ENABLE;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
+}
+
/* Offset 0x1c: Global Control 2 */

int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 6f0fb7f..736e4da 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -26,6 +26,8 @@ int mv88e6xxx_g1_init_ready(struct mv88e6xxx_chip *chip, bool *ready);

int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
+int mv88e6xxx_g1_ppu_enable(struct mv88e6xxx_chip *chip);
+int mv88e6xxx_g1_ppu_disable(struct mv88e6xxx_chip *chip);

int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index cd0f414..116766c 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -460,12 +460,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_CAP_G2_PVT_DATA, /* (0x0c) Cross Chip Port VLAN Data */
MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */

- /* PHY Polling Unit.
- * See GLOBAL_CONTROL_PPU_ENABLE and GLOBAL_STATUS_PPU_POLLING.
- */
- MV88E6XXX_CAP_PPU,
- MV88E6XXX_CAP_PPU_ACTIVE,
-
/* Per VLAN Spanning Tree Unit (STU).
* The Port State database, if present, is accessed through VTU
* operations and dedicated SID registers. See GLOBAL_VTU_SID.
@@ -508,8 +502,6 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAG_G2_PVT_DATA BIT_ULL(MV88E6XXX_CAP_G2_PVT_DATA)
#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT)

-#define MV88E6XXX_FLAG_PPU BIT_ULL(MV88E6XXX_CAP_PPU)
-#define MV88E6XXX_FLAG_PPU_ACTIVE BIT_ULL(MV88E6XXX_CAP_PPU_ACTIVE)
#define MV88E6XXX_FLAG_STU BIT_ULL(MV88E6XXX_CAP_STU)
#define MV88E6XXX_FLAG_TEMP BIT_ULL(MV88E6XXX_CAP_TEMP)
#define MV88E6XXX_FLAG_TEMP_LIMIT BIT_ULL(MV88E6XXX_CAP_TEMP_LIMIT)
@@ -538,7 +530,6 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAGS_FAMILY_6095 \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
- MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_MULTI_CHIP)

@@ -549,7 +540,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
- MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
@@ -576,7 +566,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_INT | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
- MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VTU)

#define MV88E6XXX_FLAGS_FAMILY_6320 \
@@ -586,7 +575,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
- MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
MV88E6XXX_FLAG_VTU | \
@@ -603,7 +591,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
- MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_VTU | \
@@ -621,7 +608,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
- MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
@@ -636,7 +622,6 @@ struct mv88e6xxx_ops;
#define MV88E6XXX_FLAGS_FAMILY_6390 \
(MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_GLOBAL2 | \
- MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
@@ -767,6 +752,9 @@ struct mv88e6xxx_ops {

/* PHY Polling Unit (PPU) operations */
int (*ppu_polling)(struct mv88e6xxx_chip *chip, bool *polling);
+ int (*ppu_enable)(struct mv88e6xxx_chip *chip);
+ int (*ppu_disable)(struct mv88e6xxx_chip *chip);
+
/* Switch Software Reset */
int (*reset)(struct mv88e6xxx_chip *chip);

--
2.10.2

2016-11-30 23:20:53

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 1/6] net: dsa: mv88e6xxx: add helper to disable ports

On Wed, Nov 30, 2016 at 05:59:25PM -0500, Vivien Didelot wrote:
> Before resetting a switch, the ports should be set to the Disabled state
> and the transmit queues should be drained.
>
> Add an helper to explicit that.
>
> Signed-off-by: Vivien Didelot <[email protected]>

Reviewed-by: Andrew Lunn <[email protected]>

Andrew

2016-11-30 23:21:32

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 2/6] net: dsa: mv88e6xxx: add helper to hardware reset

On Wed, Nov 30, 2016 at 05:59:26PM -0500, Vivien Didelot wrote:
> Add an helper to toggle the eventual GPIO connected to the reset pin.
>
> Signed-off-by: Vivien Didelot <[email protected]>

Reviewed-by: Andrew Lunn <[email protected]>

Andrew

2016-11-30 23:26:36

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 3/6] net: dsa: mv88e6xxx: add a software reset op

> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
> index ab52c37..9e51405 100644
> --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
> @@ -765,6 +765,9 @@ struct mv88e6xxx_ops {
> int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
> u16 val);
>
> + /* Switch Software Reset */
> + int (*reset)(struct mv88e6xxx_chip *chip);
> +

Hi Vivien

In my huge patch series of 6390, i've been using a g1_ prefix for
functionality which is in global 1, g2_ for global 2, etc. This has
worked for everything so far with the exception of setting which
reserved MAC addresses should be sent to the CPU. Most devices have it
in g2, but 6390 has it in g1.

Please could you add the prefix.

Andrew

2016-11-30 23:38:15

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 5/6] net: dsa: mv88e6xxx: add helper for switch ready

> +static int mv88e6xxx_wait_switch_ready(struct mv88e6xxx_chip *chip)
> +{
> + const unsigned long timeout = jiffies + 1 * HZ;
> + bool ready;
> + int err;
> +
> + /* Wait up to 1 second for switch to be ready.
> + * The switch is ready when all units inside the device (ATU, VTU, etc.)
> + * have finished their initialization and are ready to accept frames.
> + */
> + while (time_before(jiffies, timeout)) {
> + err = mv88e6xxx_g1_init_ready(chip, &ready);
> + if (err)
> + return err;
> +
> + if (ready)
> + break;
> +
> + usleep_range(1000, 2000);
> + }
> +
> + if (time_after(jiffies, timeout))
> + return -ETIMEDOUT;

As we have seen in the past, this sort of loop is broken if we end up
sleeping for a long time. Please take the opportunity to replace it
with one of our _wait() helpers, e.g. mv88e6xxx_g1_wait()

> +int mv88e6xxx_g1_init_ready(struct mv88e6xxx_chip *chip, bool *ready)
> +{
> + u16 val;
> + int err;
> +
> + /* Check the value of the InitReady bit 11 */
> + err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
> + if (err)
> + return err;
> +
> + *ready = !!(val & GLOBAL_STATUS_INIT_READY);

I would actually do the wait here.

> +
> + return 0;
> +}
> +

Thanks

Andrew

2016-12-01 20:31:13

by Vivien Didelot

[permalink] [raw]
Subject: Re: [PATCH net-next 5/6] net: dsa: mv88e6xxx: add helper for switch ready

Hi Andrew,

Andrew Lunn <[email protected]> writes:

> As we have seen in the past, this sort of loop is broken if we end up
> sleeping for a long time. Please take the opportunity to replace it
> with one of our _wait() helpers, e.g. mv88e6xxx_g1_wait()

That won't work. the _wait() helpers are made to wait on self-clear (SC)
bits, i.e. looping until they are cleared to zero.

Here we want the opposite.

I will keep this existing wait loop for the moment and work soon on a
new patchset to rework the wait routines. We need a generic access to
test a given value against a given mask and wrappers for busy bits, etc.

>> +int mv88e6xxx_g1_init_ready(struct mv88e6xxx_chip *chip, bool *ready)
>> +{
>> + u16 val;
>> + int err;
>> +
>> + /* Check the value of the InitReady bit 11 */
>> + err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
>> + if (err)
>> + return err;
>> +
>> + *ready = !!(val & GLOBAL_STATUS_INIT_READY);
>
> I would actually do the wait here.

That is better indeed.

Thanks,

Vivien

2016-12-01 20:41:24

by Vivien Didelot

[permalink] [raw]
Subject: Re: [PATCH net-next 3/6] net: dsa: mv88e6xxx: add a software reset op

Hi Andrew,

Andrew Lunn <[email protected]> writes:

>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
>> index ab52c37..9e51405 100644
>> --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
>> @@ -765,6 +765,9 @@ struct mv88e6xxx_ops {
>> int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
>> u16 val);
>>
>> + /* Switch Software Reset */
>> + int (*reset)(struct mv88e6xxx_chip *chip);
>> +
>
> Hi Vivien
>
> In my huge patch series of 6390, i've been using a g1_ prefix for
> functionality which is in global 1, g2_ for global 2, etc. This has
> worked for everything so far with the exception of setting which
> reserved MAC addresses should be sent to the CPU. Most devices have it
> in g2, but 6390 has it in g1.
>
> Please could you add the prefix.

I don't understand. It looks like you are talking about the second part
of the comment I made on your RFC patchset, about the Rsvd2CPU feature:

https://www.mail-archive.com/[email protected]/msg139837.html

Switch reset routines are implemented in this patch in global1.c as
mv88e6185_g1_reset and mv88e6352_g1_reset.

6185 and 6352 are implementation references for other switches.

Thanks,

Vivien

2016-12-02 15:44:10

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 3/6] net: dsa: mv88e6xxx: add a software reset op

On Thu, Dec 01, 2016 at 03:41:20PM -0500, Vivien Didelot wrote:
> Hi Andrew,
>
> Andrew Lunn <[email protected]> writes:
>
> >> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
> >> index ab52c37..9e51405 100644
> >> --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
> >> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
> >> @@ -765,6 +765,9 @@ struct mv88e6xxx_ops {
> >> int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
> >> u16 val);
> >>
> >> + /* Switch Software Reset */
> >> + int (*reset)(struct mv88e6xxx_chip *chip);
> >> +
> >
> > Hi Vivien
> >
> > In my huge patch series of 6390, i've been using a g1_ prefix for
> > functionality which is in global 1, g2_ for global 2, etc. This has
> > worked for everything so far with the exception of setting which
> > reserved MAC addresses should be sent to the CPU. Most devices have it
> > in g2, but 6390 has it in g1.
> >
> > Please could you add the prefix.
>
> I don't understand. It looks like you are talking about the second part
> of the comment I made on your RFC patchset, about the Rsvd2CPU feature:

Hi Vivien

I mean

+ /* Switch Software Reset */
+ int (*g1_reset)(struct mv88e6xxx_chip *chip);
+

We have a collection of function pointers with port_ prefix, another
collection with stats_, and a third with ppu_, etc. And then we have
some which do not fit a specific category. Those i have prefixed with
g1_ or g2_. I think we should have some prefix, and that is my
suggestion.

Andrew

2016-12-02 17:23:16

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next 3/6] net: dsa: mv88e6xxx: add a software reset op

From: Vivien Didelot <[email protected]>
Date: Wed, 30 Nov 2016 17:59:27 -0500

> @@ -765,6 +765,9 @@ struct mv88e6xxx_ops {
> int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
> u16 val);
>
> + /* Switch Software Reset */
> + int (*reset)(struct mv88e6xxx_chip *chip);
> +

I think Andrew's request to name this method "g1_reset" is reasonable, please
respin with that change.

Thanks.

2016-12-02 17:36:57

by Vivien Didelot

[permalink] [raw]
Subject: Re: [PATCH net-next 3/6] net: dsa: mv88e6xxx: add a software reset op

Hi Andrew,

Andrew Lunn <[email protected]> writes:

> + /* Switch Software Reset */
> + int (*g1_reset)(struct mv88e6xxx_chip *chip);
> +
>
> We have a collection of function pointers with port_ prefix, another
> collection with stats_, and a third with ppu_, etc. And then we have
> some which do not fit a specific category. Those i have prefixed with
> g1_ or g2_. I think we should have some prefix, and that is my
> suggestion.

I disagree. There's only one entry point to issue a switch software
reset, so .reset is enough.

I use this opportunity to give a bit of details about mv88e6xxx/ so that
things get written down at least once somewhere:

global1.c implements accessors to "Global 1 Registers" features and are
prefixed with mv88e6xxx_g1_; port.c implements accessors to "Port
Registers" features and are prefixed with mv88e6xxx_port_, and so
on. (where xxx can be a model if there's conflict due to a redefinition
of the same register)

If a feature is not present or if there's more than one way to access
it, these accessors are bundled in the per-chip mv88e6xxx_ops structure
for disambiguation.

chip.c implements support for a single chip by aggregating and nicely
wrapping these operations. It provides a generic API for Marvell
switches, used to implement net/dsa routines.

Here's a couple of example. Setting a switch MAC can be done in Global
1, or Global 2 depending on the model. Thus .set_switch_mac can be
mv88e6xxx_g1_set_switch_mac or mv88e6xxx_g2_set_switch_mac.

Setting the port's speed is always in the same Port register, but its
layout varies with the model. Thus .port_set_speed can be
mv88e6185_port_set_speed or mv88e6352_port_set_speed.

Thanks,

Vivien