Commit 4bc61b0b authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-dsa-mv88e6xxx-centralize-SERDES-IRQ-handling'



Vivien Didelot says:

====================
net: dsa: mv88e6xxx: centralize SERDES IRQ handling

Following Marek's work on the abstraction of the SERDES lanes mapping, this
series trades the .serdes_irq_setup and .serdes_irq_free callbacks for new
.serdes_irq_mapping, .serdes_irq_enable and .serdes_irq_status operations.

This has the benefit to limit the various SERDES implementations to simple
register accesses only; centralize the IRQ handling and mutex locking logic;
as well as reducing boilerplate in the driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b943e033 45de77ff
Loading
Loading
Loading
Loading
+111 −30
Original line number Diff line number Diff line
@@ -2054,27 +2054,93 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
	return 0;
}

static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
{
	struct mv88e6xxx_port *mvp = dev_id;
	struct mv88e6xxx_chip *chip = mvp->chip;
	irqreturn_t ret = IRQ_NONE;
	int port = mvp->port;
	u8 lane;

	mv88e6xxx_reg_lock(chip);
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (lane)
		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
	mv88e6xxx_reg_unlock(chip);

	return ret;
}

static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
					u8 lane)
{
	struct mv88e6xxx_port *dev_id = &chip->ports[port];
	unsigned int irq;
	int err;

	/* Nothing to request if this SERDES port has no IRQ */
	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
	if (!irq)
		return 0;

	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
	mv88e6xxx_reg_unlock(chip);
	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
				   IRQF_ONESHOT, "mv88e6xxx-serdes", dev_id);
	mv88e6xxx_reg_lock(chip);
	if (err)
		return err;

	dev_id->serdes_irq = irq;

	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
}

static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
				     u8 lane)
{
	struct mv88e6xxx_port *dev_id = &chip->ports[port];
	unsigned int irq = dev_id->serdes_irq;
	int err;

	/* Nothing to free if no IRQ has been requested */
	if (!irq)
		return 0;

	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);

	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
	mv88e6xxx_reg_unlock(chip);
	free_irq(irq, dev_id);
	mv88e6xxx_reg_lock(chip);

	dev_id->serdes_irq = 0;

	return err;
}

static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
				  bool on)
{
	u8 lane;
	int err;

	if (!chip->info->ops->serdes_power)
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
		return 0;

	if (on) {
		err = chip->info->ops->serdes_power(chip, port, true);
		err = mv88e6xxx_serdes_power_up(chip, port, lane);
		if (err)
			return err;

		if (chip->info->ops->serdes_irq_setup)
			err = chip->info->ops->serdes_irq_setup(chip, port);
		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
	} else {
		if (chip->info->ops->serdes_irq_free &&
		    chip->ports[port].serdes_irq)
			chip->info->ops->serdes_irq_free(chip, port);
		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
		if (err)
			return err;

		err = chip->info->ops->serdes_power(chip, port, false);
		err = mv88e6xxx_serdes_power_down(chip, port, lane);
	}

	return err;
@@ -2931,8 +2997,9 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6341_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6341_phylink_validate,
};
@@ -3092,6 +3159,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
	.rmu_disable = mv88e6352_g1_rmu_disable,
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_get_lane = mv88e6352_serdes_get_lane,
	.serdes_power = mv88e6352_serdes_power,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6352_phylink_validate,
@@ -3177,9 +3245,11 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
	.rmu_disable = mv88e6352_g1_rmu_disable,
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_get_lane = mv88e6352_serdes_get_lane,
	.serdes_power = mv88e6352_serdes_power,
	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
	.serdes_irq_free = mv88e6352_serdes_irq_free,
	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
	.serdes_irq_status = mv88e6352_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6352_phylink_validate,
};
@@ -3261,8 +3331,9 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6390_phylink_validate,
};
@@ -3308,8 +3379,9 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390x_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6390x_phylink_validate,
};
@@ -3355,8 +3427,9 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
	.phylink_validate = mv88e6390_phylink_validate,
@@ -3402,9 +3475,11 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
	.rmu_disable = mv88e6352_g1_rmu_disable,
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_get_lane = mv88e6352_serdes_get_lane,
	.serdes_power = mv88e6352_serdes_power,
	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
	.serdes_irq_free = mv88e6352_serdes_irq_free,
	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
	.serdes_irq_status = mv88e6352_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6352_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
@@ -3492,8 +3567,9 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
@@ -3629,8 +3705,9 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6341_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
@@ -3759,9 +3836,11 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
	.rmu_disable = mv88e6352_g1_rmu_disable,
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_get_lane = mv88e6352_serdes_get_lane,
	.serdes_power = mv88e6352_serdes_power,
	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
	.serdes_irq_free = mv88e6352_serdes_irq_free,
	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
	.serdes_irq_status = mv88e6352_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6352_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
@@ -3814,8 +3893,9 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
@@ -3865,8 +3945,9 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390x_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
	.serdes_irq_status = mv88e6390_serdes_irq_status,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
+10 −5
Original line number Diff line number Diff line
@@ -199,7 +199,7 @@ struct mv88e6xxx_port {
	u64 vtu_member_violation;
	u64 vtu_miss_violation;
	u8 cmode;
	int serdes_irq;
	unsigned int serdes_irq;
};

struct mv88e6xxx_chip {
@@ -441,14 +441,19 @@ struct mv88e6xxx_ops {
	int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);

	/* Power on/off a SERDES interface */
	int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on);
	int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, u8 lane,
			    bool up);

	/* SERDES lane mapping */
	int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port, u8 *lane);
	u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);

	/* SERDES interrupt handling */
	int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port);
	void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port);
	unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip,
					   int port);
	int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, u8 lane,
				 bool enable);
	irqreturn_t (*serdes_irq_status)(struct mv88e6xxx_chip *chip, int port,
					 u8 lane);

	/* Statistics from the SERDES interface */
	int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
+9 −12
Original line number Diff line number Diff line
@@ -431,18 +431,15 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
	if (cmode == chip->ports[port].cmode)
		return 0;

	err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
	if (err && err != -ENODEV)
		return err;

	if (err != -ENODEV) {
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (lane) {
		if (chip->ports[port].serdes_irq) {
			err = mv88e6390_serdes_irq_disable(chip, port, lane);
			err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
			if (err)
				return err;
		}

		err = mv88e6390_serdes_power(chip, port, false);
		err = mv88e6xxx_serdes_power_down(chip, port, lane);
		if (err)
			return err;
	}
@@ -463,16 +460,16 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,

		chip->ports[port].cmode = cmode;

		err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
		if (err)
			return err;
		lane = mv88e6xxx_serdes_get_lane(chip, port);
		if (!lane)
			return -ENODEV;

		err = mv88e6390_serdes_power(chip, port, true);
		err = mv88e6xxx_serdes_power_up(chip, port, lane);
		if (err)
			return err;

		if (chip->ports[port].serdes_irq) {
			err = mv88e6390_serdes_irq_enable(chip, port, lane);
			err = mv88e6xxx_serdes_irq_enable(chip, port, lane);
			if (err)
				return err;
		}
+103 −279

File changed.

Preview size limit exceeded, changes collapsed.

+82 −25
Original line number Diff line number Diff line
@@ -74,37 +74,94 @@
#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11)
#define MV88E6390_SGMII_PHY_STATUS_LINK		BIT(10)

/* Put the SERDES lane address a port is using into *lane. If a port has
 * multiple lanes, should put the first lane the port is using. If a port does
 * not have a lane, return -ENODEV.
 */
static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
					    int port, u8 *lane)
u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
					  int port);
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
					  int port);
int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
			   bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
			   bool on);
int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
				bool enable);
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
				bool enable);
irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
					u8 lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
					u8 lane);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
				 int port, uint8_t *data);
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
			       uint64_t *data);

/* Return the (first) SERDES lane address a port is using, 0 otherwise. */
static inline u8 mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
					   int port)
{
	if (!chip->info->ops->serdes_get_lane)
		return 0;

	return chip->info->ops->serdes_get_lane(chip, port);
}

static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
					    int port, u8 lane)
{
	if (!chip->info->ops->serdes_power)
		return -EOPNOTSUPP;

	return chip->info->ops->serdes_get_lane(chip, port, lane);
	return chip->info->ops->serdes_power(chip, port, lane, true);
}

int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
				 int port, uint8_t *data);
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
			       uint64_t *data);
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
				u8 lane);
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
				 u8 lane);
int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
static inline int mv88e6xxx_serdes_power_down(struct mv88e6xxx_chip *chip,
					      int port, u8 lane)
{
	if (!chip->info->ops->serdes_power)
		return -EOPNOTSUPP;

	return chip->info->ops->serdes_power(chip, port, lane, false);
}

static inline unsigned int
mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
	if (!chip->info->ops->serdes_irq_mapping)
		return 0;

	return chip->info->ops->serdes_irq_mapping(chip, port);
}

static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
					      int port, u8 lane)
{
	if (!chip->info->ops->serdes_irq_enable)
		return -EOPNOTSUPP;

	return chip->info->ops->serdes_irq_enable(chip, port, lane, true);
}

static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
					       int port, u8 lane)
{
	if (!chip->info->ops->serdes_irq_enable)
		return -EOPNOTSUPP;

	return chip->info->ops->serdes_irq_enable(chip, port, lane, false);
}

static inline irqreturn_t
mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane)
{
	if (!chip->info->ops->serdes_irq_status)
		return IRQ_NONE;

	return chip->info->ops->serdes_irq_status(chip, port, lane);
}

#endif