Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a199d8b6 authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller
Browse files

net: dsa: mv88e6xxx: add PPU operations



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: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 17e708ba
Loading
Loading
Loading
Loading
+17 −59
Original line number Diff line number Diff line
@@ -527,58 +527,18 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)

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

	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
	if (err)
		return err;

	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL,
				 val & ~GLOBAL_CONTROL_PPU_ENABLE);
	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);
		val &= GLOBAL_STATUS_PPU_STATE_MASK;
		if (val != GLOBAL_STATUS_PPU_STATE_POLLING)
	if (!chip->info->ops->ppu_disable)
		return 0;
	}

	return -ETIMEDOUT;
	return chip->info->ops->ppu_disable(chip);
}

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

	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
	if (err)
		return err;

	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL,
				 val | GLOBAL_CONTROL_PPU_ENABLE);
	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);
		val &= GLOBAL_STATUS_PPU_STATE_MASK;
		if (val == GLOBAL_STATUS_PPU_STATE_POLLING)
	if (!chip->info->ops->ppu_enable)
		return 0;
	}

	return -ETIMEDOUT;
	return chip->info->ops->ppu_enable(chip);
}

static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
@@ -2746,22 +2706,12 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
{
	struct dsa_switch *ds = chip->ds;
	u32 upstream_port = dsa_upstream_port(ds);
	u16 reg;
	int err;

	/* 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);
	err = mv88e6xxx_ppu_enable(chip);
	if (err)
		return err;

@@ -3223,6 +3173,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
	.reset = mv88e6185_g1_reset,
};

@@ -3241,6 +3193,8 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
	.stats_get_strings = mv88e6095_stats_get_strings,
	.stats_get_stats = mv88e6095_stats_get_stats,
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
	.reset = mv88e6185_g1_reset,
};

@@ -3311,6 +3265,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
	.reset = mv88e6185_g1_reset,
};

@@ -3483,6 +3439,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
	.reset = mv88e6185_g1_reset,
};

@@ -4263,13 +4221,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);
}

+57 −0
Original line number Diff line number Diff line
@@ -35,6 +35,27 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)

/* Offset 0x00: Switch Global Status Register */

static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip)
{
	u16 state;
	int i, err;

	for (i = 0; i < 16; i++) {
		err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
		if (err)
			return err;

		/* Check the value of the PPUState bits 15:14 */
		state &= GLOBAL_STATUS_PPU_STATE_MASK;
		if (state != GLOBAL_STATUS_PPU_STATE_POLLING)
			return 0;

		usleep_range(1000, 2000);
	}

	return -ETIMEDOUT;
}

static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
{
	u16 state;
@@ -154,6 +175,42 @@ int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
	return mv88e6352_g1_wait_ppu_polling(chip);
}

int mv88e6185_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;

	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
	if (err)
		return err;

	return mv88e6185_g1_wait_ppu_polling(chip);
}

int mv88e6185_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;

	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
	if (err)
		return err;

	return mv88e6185_g1_wait_ppu_disabled(chip);
}

/* Offset 0x1a: Monitor Control */
/* Offset 0x1a: Monitor & MGMT Control on some devices */

+3 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ 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 mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip);
int mv88e6185_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);
int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
+4 −15
Original line number Diff line number Diff line
@@ -490,12 +490,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.
@@ -537,8 +531,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)
@@ -567,7 +559,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)

@@ -578,7 +569,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 |		\
@@ -605,7 +595,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	\
@@ -614,7 +603,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 |		\
@@ -630,7 +618,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 |		\
@@ -647,7 +634,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 |	\
@@ -662,7 +648,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 |	\
@@ -792,6 +777,10 @@ struct mv88e6xxx_ops {
	int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
			 u16 val);

	/* PHY Polling Unit (PPU) operations */
	int (*ppu_enable)(struct mv88e6xxx_chip *chip);
	int (*ppu_disable)(struct mv88e6xxx_chip *chip);

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