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

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

net: dsa: mv88e6xxx: setup port's MAC



Now that we have setters to configure the port's MAC, use them to
refactor the port setup and adjust_link code.

Note that port's MAC speed, duplex or RGMII delay must not be changed
unless the port's link is forced down. So wrap all that in a
mv88e6xxx_port_setup_mac function.

Signed-off-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 96a2b40c
Loading
Loading
Loading
Loading
+60 −80
Original line number Original line Diff line number Diff line
@@ -701,6 +701,47 @@ static bool mv88e6xxx_6352_family(struct mv88e6xxx_chip *chip)
	return chip->info->family == MV88E6XXX_FAMILY_6352;
	return chip->info->family == MV88E6XXX_FAMILY_6352;
}
}


static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
				    int link, int speed, int duplex,
				    phy_interface_t mode)
{
	int err;

	if (!chip->info->ops->port_set_link)
		return 0;

	/* Port's MAC control must not be changed unless the link is down */
	err = chip->info->ops->port_set_link(chip, port, 0);
	if (err)
		return err;

	if (chip->info->ops->port_set_speed) {
		err = chip->info->ops->port_set_speed(chip, port, speed);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

	if (chip->info->ops->port_set_duplex) {
		err = chip->info->ops->port_set_duplex(chip, port, duplex);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

	if (chip->info->ops->port_set_rgmii_delay) {
		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

	err = 0;
restore_link:
	if (chip->info->ops->port_set_link(chip, port, link))
		netdev_err(chip->ds->ports[port].netdev,
			   "failed to restore MAC's link\n");

	return err;
}

/* We expect the switch to perform auto negotiation if there is a real
/* We expect the switch to perform auto negotiation if there is a real
 * phy. However, in the case of a fixed link phy, we force the port
 * phy. However, in the case of a fixed link phy, we force the port
 * settings from the fixed link settings.
 * settings from the fixed link settings.
@@ -709,64 +750,18 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
				  struct phy_device *phydev)
				  struct phy_device *phydev)
{
{
	struct mv88e6xxx_chip *chip = ds->priv;
	struct mv88e6xxx_chip *chip = ds->priv;
	u16 reg;
	int err;
	int err;


	if (!phy_is_pseudo_fixed_link(phydev))
	if (!phy_is_pseudo_fixed_link(phydev))
		return;
		return;


	mutex_lock(&chip->reg_lock);
	mutex_lock(&chip->reg_lock);

	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
	err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
				       phydev->duplex, phydev->interface);
	if (err)
		goto out;

	reg &= ~(PORT_PCS_CTRL_LINK_UP |
		 PORT_PCS_CTRL_FORCE_LINK |
		 PORT_PCS_CTRL_DUPLEX_FULL |
		 PORT_PCS_CTRL_FORCE_DUPLEX |
		 PORT_PCS_CTRL_SPEED_UNFORCED);

	reg |= PORT_PCS_CTRL_FORCE_LINK;
	if (phydev->link)
		reg |= PORT_PCS_CTRL_LINK_UP;

	if (mv88e6xxx_6065_family(chip) && phydev->speed > SPEED_100)
		goto out;

	switch (phydev->speed) {
	case SPEED_1000:
		reg |= PORT_PCS_CTRL_SPEED_1000;
		break;
	case SPEED_100:
		reg |= PORT_PCS_CTRL_SPEED_100;
		break;
	case SPEED_10:
		reg |= PORT_PCS_CTRL_SPEED_10;
		break;
	default:
		pr_info("Unknown speed");
		goto out;
	}

	reg |= PORT_PCS_CTRL_FORCE_DUPLEX;
	if (phydev->duplex == DUPLEX_FULL)
		reg |= PORT_PCS_CTRL_DUPLEX_FULL;

	if ((mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip)) &&
	    (port >= mv88e6xxx_num_ports(chip) - 2)) {
		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
			reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK;
		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
			reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK;
		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
			reg |= (PORT_PCS_CTRL_RGMII_DELAY_RXCLK |
				PORT_PCS_CTRL_RGMII_DELAY_TXCLK);
	}
	mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);

out:
	mutex_unlock(&chip->reg_lock);
	mutex_unlock(&chip->reg_lock);

	if (err && err != -EOPNOTSUPP)
		netdev_err(ds->ports[port].netdev, "failed to configure MAC\n");
}
}


static int _mv88e6xxx_stats_wait(struct mv88e6xxx_chip *chip)
static int _mv88e6xxx_stats_wait(struct mv88e6xxx_chip *chip)
@@ -2409,35 +2404,20 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
	int err;
	int err;
	u16 reg;
	u16 reg;


	if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) ||
	/* MAC Forcing register: don't force link, speed, duplex or flow control
	    mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) ||
	 * state to any particular values on physical ports, but force the CPU
	    mv88e6xxx_6185_family(chip) || mv88e6xxx_6095_family(chip) ||
	 * port and all DSA ports to their maximum bandwidth and full duplex.
	    mv88e6xxx_6065_family(chip) || mv88e6xxx_6320_family(chip)) {
		/* MAC Forcing register: don't force link, speed,
		 * duplex or flow control state to any particular
		 * values on physical ports, but force the CPU port
		 * and all DSA ports to their maximum bandwidth and
		 * full duplex.
	 */
	 */
		err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
		if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
			reg &= ~PORT_PCS_CTRL_SPEED_UNFORCED;
					       SPEED_MAX, DUPLEX_FULL,
			reg |= PORT_PCS_CTRL_FORCE_LINK |
					       PHY_INTERFACE_MODE_NA);
				PORT_PCS_CTRL_LINK_UP |
				PORT_PCS_CTRL_DUPLEX_FULL |
				PORT_PCS_CTRL_FORCE_DUPLEX;
			if (mv88e6xxx_6065_family(chip))
				reg |= PORT_PCS_CTRL_SPEED_100;
	else
	else
				reg |= PORT_PCS_CTRL_SPEED_1000;
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
		} else {
					       SPEED_UNFORCED, DUPLEX_UNFORCED,
			reg |= PORT_PCS_CTRL_SPEED_UNFORCED;
					       PHY_INTERFACE_MODE_NA);
		}

		err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);
	if (err)
	if (err)
		return err;
		return err;
	}


	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN