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

Commit 6ddb4fdf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-mv88e6xxx-cleanup-capabilities'



Vivien Didelot says:

====================
net: dsa: mv88e6xxx: cleanup capabilities

This patch series removes the remaining capabilities as well as the
flags bitmap in the info structures. Most of them are turned into ops,
or new info members.

There is no mv88e6xxx_cap enum or bitmap flags anymore, only
mv88e6xxx_info and mv88e6xxx_ops structures.

While reviewing and documenting the related G2 registers, fix a few
inconsistencies: 88E6185 has no interrupt in G2 and 88E6390 has a POT.

Except these two adjustments, there is no functional changes.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 46f55cff b3e05aa1
Loading
Loading
Loading
Loading
+195 −92

File changed.

Preview size limit exceeded, changes collapsed.

+17 −135
Original line number Diff line number Diff line
@@ -97,133 +97,6 @@ enum mv88e6xxx_family {
	MV88E6XXX_FAMILY_6390,  /* 6190 6190X 6191 6290 6390 6390X */
};

enum mv88e6xxx_cap {
	/* Energy Efficient Ethernet.
	 */
	MV88E6XXX_CAP_EEE,

	/* Multi-chip Addressing Mode.
	 * Some chips respond to only 2 registers of its own SMI device address
	 * when it is non-zero, and use indirect access to internal registers.
	 */
	MV88E6XXX_CAP_SMI_CMD,		/* (0x00) SMI Command */
	MV88E6XXX_CAP_SMI_DATA,		/* (0x01) SMI Data */

	/* Switch Global (1) Registers.
	 */
	MV88E6XXX_CAP_G1_ATU_FID,	/* (0x01) ATU FID Register */
	MV88E6XXX_CAP_G1_VTU_FID,	/* (0x02) VTU FID Register */

	/* Switch Global 2 Registers.
	 * The device contains a second set of global 16-bit registers.
	 */
	MV88E6XXX_CAP_GLOBAL2,
	MV88E6XXX_CAP_G2_INT,		/* (0x00) Interrupt Status */
	MV88E6XXX_CAP_G2_MGMT_EN_2X,	/* (0x02) MGMT Enable Register 2x */
	MV88E6XXX_CAP_G2_MGMT_EN_0X,	/* (0x03) MGMT Enable Register 0x */
	MV88E6XXX_CAP_G2_POT,		/* (0x0f) Priority Override Table */

	/* Per VLAN Spanning Tree Unit (STU).
	 * The Port State database, if present, is accessed through VTU
	 * operations and dedicated SID registers. See MV88E6352_G1_VTU_SID.
	 */
	MV88E6XXX_CAP_STU,

	/* VLAN Table Unit.
	 * The VTU is used to program 802.1Q VLANs. See MV88E6XXX_G1_VTU_OP.
	 */
	MV88E6XXX_CAP_VTU,
};

/* Bitmask of capabilities */
#define MV88E6XXX_FLAG_EEE		BIT_ULL(MV88E6XXX_CAP_EEE)

#define MV88E6XXX_FLAG_SMI_CMD		BIT_ULL(MV88E6XXX_CAP_SMI_CMD)
#define MV88E6XXX_FLAG_SMI_DATA		BIT_ULL(MV88E6XXX_CAP_SMI_DATA)

#define MV88E6XXX_FLAG_G1_VTU_FID	BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID)

#define MV88E6XXX_FLAG_GLOBAL2		BIT_ULL(MV88E6XXX_CAP_GLOBAL2)
#define MV88E6XXX_FLAG_G2_INT		BIT_ULL(MV88E6XXX_CAP_G2_INT)
#define MV88E6XXX_FLAG_G2_MGMT_EN_2X	BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_2X)
#define MV88E6XXX_FLAG_G2_MGMT_EN_0X	BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X)
#define MV88E6XXX_FLAG_G2_POT		BIT_ULL(MV88E6XXX_CAP_G2_POT)

/* Multi-chip Addressing Mode */
#define MV88E6XXX_FLAGS_MULTI_CHIP	\
	(MV88E6XXX_FLAG_SMI_CMD |	\
	 MV88E6XXX_FLAG_SMI_DATA)

#define MV88E6XXX_FLAGS_FAMILY_6095	\
	(MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6097	\
	(MV88E6XXX_FLAG_G1_VTU_FID |	\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |        \
	 MV88E6XXX_FLAG_G2_MGMT_EN_2X |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAG_G2_POT |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6165	\
	(MV88E6XXX_FLAG_G1_VTU_FID |	\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_2X |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAG_G2_POT |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6185	\
	(MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6320	\
	(MV88E6XXX_FLAG_EEE |		\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_2X |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAG_G2_POT |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6341	\
	(MV88E6XXX_FLAG_EEE |		\
	 MV88E6XXX_FLAG_G1_VTU_FID |	\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |	\
	 MV88E6XXX_FLAG_G2_POT |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6351	\
	(MV88E6XXX_FLAG_G1_VTU_FID |	\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_2X |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAG_G2_POT |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6352	\
	(MV88E6XXX_FLAG_EEE |		\
	 MV88E6XXX_FLAG_G1_VTU_FID |	\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_2X |	\
	 MV88E6XXX_FLAG_G2_MGMT_EN_0X |	\
	 MV88E6XXX_FLAG_G2_POT |	\
	 MV88E6XXX_FLAGS_MULTI_CHIP)

#define MV88E6XXX_FLAGS_FAMILY_6390	\
	(MV88E6XXX_FLAG_EEE |		\
	 MV88E6XXX_FLAG_GLOBAL2 |	\
	 MV88E6XXX_FLAG_G2_INT |        \
	 MV88E6XXX_FLAGS_MULTI_CHIP)

struct mv88e6xxx_ops;

struct mv88e6xxx_info {
@@ -235,11 +108,18 @@ struct mv88e6xxx_info {
	unsigned int max_vid;
	unsigned int port_base_addr;
	unsigned int global1_addr;
	unsigned int global2_addr;
	unsigned int age_time_coeff;
	unsigned int g1_irqs;
	unsigned int g2_irqs;
	bool pvt;

	/* Multi-chip Addressing Mode.
	 * Some chips respond to only 2 registers of its own SMI device address
	 * when it is non-zero, and use indirect access to internal registers.
	 */
	bool multi_chip;
	enum dsa_tag_protocol tag_protocol;
	unsigned long long flags;

	/* Mask for FromPort and ToPort value of PortVec used in ATU Move
	 * operation. 0 means that the ATU Move operation is not supported.
@@ -359,6 +239,15 @@ struct mv88e6xxx_ops {
			 struct mii_bus *bus,
			 int addr, int reg, u16 val);

	/* Copper Energy Detect operations */
	int (*phy_energy_detect_read)(struct mv88e6xxx_chip *chip, int phy,
				      struct ethtool_eee *eee);
	int (*phy_energy_detect_write)(struct mv88e6xxx_chip *chip, int phy,
				       struct ethtool_eee *eee);

	/* Priority Override Table operations */
	int (*pot_clear)(struct mv88e6xxx_chip *chip);

	/* PHY Polling Unit (PPU) operations */
	int (*ppu_enable)(struct mv88e6xxx_chip *chip);
	int (*ppu_disable)(struct mv88e6xxx_chip *chip);
@@ -449,7 +338,6 @@ struct mv88e6xxx_ops {
	int (*set_egress_port)(struct mv88e6xxx_chip *chip, int port);
	const struct mv88e6xxx_irq_ops *watchdog_ops;

	/* Can be either in g1 or g2, so don't use a prefix */
	int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);

	/* Power on/off a SERDES interface */
@@ -482,12 +370,6 @@ struct mv88e6xxx_hw_stat {
	int type;
};

static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip,
				 unsigned long flags)
{
	return (chip->info->flags & flags) == flags;
}

static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip)
{
	return chip->info->pvt;
+73 −29
Original line number Diff line number Diff line
@@ -22,48 +22,99 @@

static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
{
	return mv88e6xxx_read(chip, MV88E6XXX_G2, reg, val);
	return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
}

static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
{
	return mv88e6xxx_write(chip, MV88E6XXX_G2, reg, val);
	return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
}

static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
{
	return mv88e6xxx_update(chip, MV88E6XXX_G2, reg, update);
	return mv88e6xxx_update(chip, chip->info->global2_addr, reg, update);
}

static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
{
	return mv88e6xxx_wait(chip, MV88E6XXX_G2, reg, mask);
	return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask);
}

/* Offset 0x00: Interrupt Source Register */

static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
{
	/* Read (and clear most of) the Interrupt Source bits */
	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src);
}

/* Offset 0x01: Interrupt Mask Register */

static int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask)
{
	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask);
}

/* Offset 0x02: Management Enable 2x */

static int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x)
{
	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x);
}

/* Offset 0x03: Management Enable 0x */

int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
static int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x)
{
	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x);
}

/* Offset 0x05: Switch Management Register */

static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip,
					     bool enable)
{
	u16 val;
	int err;

	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val);
	if (err)
		return err;

	if (enable)
		val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
	else
		val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;

	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val);
}

int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
	int err;

	/* Consider the frames with reserved multicast destination
	 * addresses matching 01:80:c2:00:00:2x as MGMT.
	 * addresses matching 01:80:c2:00:00:0x as MGMT.
	 */
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) {
		err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, 0xffff);
	err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff);
	if (err)
		return err;

	return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true);
}

int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
	int err;

	/* Consider the frames with reserved multicast destination
	 * addresses matching 01:80:c2:00:00:0x as MGMT.
	 * addresses matching 01:80:c2:00:00:2x as MGMT.
	 */
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X))
		return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X,
					  0xffff);
	err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff);
	if (err)
		return err;

	return 0;
	return mv88e6185_g2_mgmt_rsvd2cpu(chip);
}

/* Offset 0x06: Device Mapping Table register */
@@ -260,7 +311,7 @@ static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_PRIO_OVERRIDE, val);
}

static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)
int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
{
	int i, err;

@@ -933,7 +984,7 @@ static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
	u16 reg;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SOURCE, &reg);
	err = mv88e6xxx_g2_int_source(chip, &reg);
	mutex_unlock(&chip->reg_lock);
	if (err)
		goto out;
@@ -959,8 +1010,11 @@ static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
	int err;

	mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, ~chip->g2_irq.masked);
	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
	if (err)
		dev_err(chip->dev, "failed to mask interrupts\n");

	mutex_unlock(&chip->reg_lock);
}
@@ -1063,9 +1117,6 @@ int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
	 * port at the highest priority.
	 */
	reg = MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI | (0x7 << 4);
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
	    mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
		reg |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU | 0x7;
	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, reg);
	if (err)
		return err;
@@ -1080,12 +1131,5 @@ int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
	if (err)
		return err;

	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
		/* Clear the priority override table. */
		err = mv88e6xxx_g2_clear_pot(chip);
		if (err)
			return err;
	}

	return 0;
}
+34 −7
Original line number Diff line number Diff line
@@ -17,14 +17,27 @@

#include "chip.h"

#define MV88E6XXX_G2	0x1c

/* Offset 0x00: Interrupt Source Register */
#define MV88E6XXX_G2_INT_SOURCE			0x00
#define MV88E6XXX_G2_INT_SRC			0x00
#define MV88E6XXX_G2_INT_SRC_WDOG		0x8000
#define MV88E6XXX_G2_INT_SRC_JAM_LIMIT		0x4000
#define MV88E6XXX_G2_INT_SRC_DUPLEX_MISMATCH	0x2000
#define MV88E6XXX_G2_INT_SRC_WAKE_EVENT		0x1000
#define MV88E6352_G2_INT_SRC_SERDES		0x0800
#define MV88E6352_G2_INT_SRC_PHY		0x001f
#define MV88E6390_G2_INT_SRC_PHY		0x07fe

#define MV88E6XXX_G2_INT_SOURCE_WATCHDOG	15

/* Offset 0x01: Interrupt Mask Register */
#define MV88E6XXX_G2_INT_MASK			0x01
#define MV88E6XXX_G2_INT_MASK_WDOG		0x8000
#define MV88E6XXX_G2_INT_MASK_JAM_LIMIT		0x4000
#define MV88E6XXX_G2_INT_MASK_DUPLEX_MISMATCH	0x2000
#define MV88E6XXX_G2_INT_MASK_WAKE_EVENT	0x1000
#define MV88E6352_G2_INT_MASK_SERDES		0x0800
#define MV88E6352_G2_INT_MASK_PHY		0x001f
#define MV88E6390_G2_INT_MASK_PHY		0x07fe

/* Offset 0x02: MGMT Enable Register 2x */
#define MV88E6XXX_G2_MGMT_EN_2X		0x02
@@ -245,7 +258,11 @@ int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip);
int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);

int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);

int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip);

extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
@@ -254,7 +271,7 @@ extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;

static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
{
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) {
	if (chip->info->global2_addr) {
		dev_err(chip->dev, "this chip requires CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 enabled\n");
		return -EOPNOTSUPP;
	}
@@ -347,7 +364,17 @@ static inline void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
{
}

static inline int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
static inline int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
	return -EOPNOTSUPP;
}

static inline int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
	return -EOPNOTSUPP;
}

static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
{
	return -EOPNOTSUPP;
}
+96 −1
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@

#include <linux/mdio.h>
#include <linux/module.h>
#include <net/dsa.h>

#include "chip.h"
#include "phy.h"
@@ -247,3 +246,99 @@ int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_phy_ppu_enable(chip);
}

/* Page 0, Register 16: Copper Specific Control Register 1 */

int mv88e6352_phy_energy_detect_read(struct mv88e6xxx_chip *chip, int phy,
				     struct ethtool_eee *eee)
{
	u16 val;
	int err;

	err = mv88e6xxx_phy_read(chip, phy, MV88E6XXX_PHY_CSCTL1, &val);
	if (err)
		return err;

	val &= MV88E6352_PHY_CSCTL1_ENERGY_DETECT_MASK;

	eee->eee_enabled = false;
	eee->tx_lpi_enabled = false;

	switch (val) {
	case MV88E6352_PHY_CSCTL1_ENERGY_DETECT_SENSE_NLP:
		eee->tx_lpi_enabled = true;
		/* fall through... */
	case MV88E6352_PHY_CSCTL1_ENERGY_DETECT_SENSE_RCV:
		eee->eee_enabled = true;
	}

	return 0;
}

int mv88e6352_phy_energy_detect_write(struct mv88e6xxx_chip *chip, int phy,
				      struct ethtool_eee *eee)
{
	u16 val;
	int err;

	err = mv88e6xxx_phy_read(chip, phy, MV88E6XXX_PHY_CSCTL1, &val);
	if (err)
		return err;

	val &= ~MV88E6352_PHY_CSCTL1_ENERGY_DETECT_MASK;

	if (eee->eee_enabled)
		val |= MV88E6352_PHY_CSCTL1_ENERGY_DETECT_SENSE_RCV;
	if (eee->tx_lpi_enabled)
		val |= MV88E6352_PHY_CSCTL1_ENERGY_DETECT_SENSE_NLP;

	return mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_CSCTL1, val);
}

int mv88e6390_phy_energy_detect_read(struct mv88e6xxx_chip *chip, int phy,
				     struct ethtool_eee *eee)
{
	u16 val;
	int err;

	err = mv88e6xxx_phy_read(chip, phy, MV88E6XXX_PHY_CSCTL1, &val);
	if (err)
		return err;

	val &= MV88E6390_PHY_CSCTL1_ENERGY_DETECT_MASK;

	eee->eee_enabled = false;
	eee->tx_lpi_enabled = false;

	switch (val) {
	case MV88E6390_PHY_CSCTL1_ENERGY_DETECT_SENSE_NLP_AUTO:
	case MV88E6390_PHY_CSCTL1_ENERGY_DETECT_SENSE_NLP_SW:
		eee->tx_lpi_enabled = true;
		/* fall through... */
	case MV88E6390_PHY_CSCTL1_ENERGY_DETECT_SENSE_RCV_AUTO:
	case MV88E6390_PHY_CSCTL1_ENERGY_DETECT_SENSE_RCV_SW:
		eee->eee_enabled = true;
	}

	return 0;
}

int mv88e6390_phy_energy_detect_write(struct mv88e6xxx_chip *chip, int phy,
				      struct ethtool_eee *eee)
{
	u16 val;
	int err;

	err = mv88e6xxx_phy_read(chip, phy, MV88E6XXX_PHY_CSCTL1, &val);
	if (err)
		return err;

	val &= ~MV88E6390_PHY_CSCTL1_ENERGY_DETECT_MASK;

	if (eee->eee_enabled)
		val |= MV88E6390_PHY_CSCTL1_ENERGY_DETECT_SENSE_RCV_AUTO;
	if (eee->tx_lpi_enabled)
		val |= MV88E6390_PHY_CSCTL1_ENERGY_DETECT_SENSE_NLP_AUTO;

	return mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_CSCTL1, val);
}
Loading