Merge branch 'net-dsa-enable-and-disable-all-ports'

Vivien Didelot says:

====================
net: dsa: enable and disable all ports

The DSA stack currently calls the .port_enable and .port_disable switch
callbacks for slave ports only. However, it is useful to call them for all
port types. For example this allows some drivers to delay the optimization
of power consumption after the switch is setup. This can also help reducing
the setup code of drivers a bit.

The first DSA core patches enable and disable all ports of a switch, regardless
their type. The last mv88e6xxx patches remove redundant code from the driver
setup and the said callbacks, now that they handle SERDES power for all ports.

Changes in v2: do not guard .port_disable for broadcom switches.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-08-20 12:33:49 -07:00
Родитель d2187f8e44 fc0bc0190b
Коммит b1b5133db1
8 изменённых файлов: 106 добавлений и 90 удалений

Просмотреть файл

@ -510,10 +510,15 @@ EXPORT_SYMBOL(b53_imp_vlan_setup);
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
{
struct b53_device *dev = ds->priv;
unsigned int cpu_port = ds->ports[port].cpu_dp->index;
unsigned int cpu_port;
int ret = 0;
u16 pvlan;
if (!dsa_is_user_port(ds, port))
return 0;
cpu_port = ds->ports[port].cpu_dp->index;
if (dev->ops->irq_enable)
ret = dev->ops->irq_enable(dev, port);
if (ret)

Просмотреть файл

@ -157,6 +157,9 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
unsigned int i;
u32 reg;
if (!dsa_is_user_port(ds, port))
return 0;
/* Clear the memory power down */
reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
reg &= ~P_TXQ_PSM_VDD(port);

Просмотреть файл

@ -1079,6 +1079,9 @@ static int lan9303_port_enable(struct dsa_switch *ds, int port,
{
struct lan9303 *chip = ds->priv;
if (!dsa_is_user_port(ds, port))
return 0;
return lan9303_enable_processing_port(chip, port);
}
@ -1086,6 +1089,9 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port)
{
struct lan9303 *chip = ds->priv;
if (!dsa_is_user_port(ds, port))
return;
lan9303_disable_processing_port(chip, port);
lan9303_phy_write(ds, chip->phy_addr_base + port, MII_BMCR, BMCR_PDOWN);
}

Просмотреть файл

@ -642,6 +642,9 @@ static int gswip_port_enable(struct dsa_switch *ds, int port,
struct gswip_priv *priv = ds->priv;
int err;
if (!dsa_is_user_port(ds, port))
return 0;
if (!dsa_is_cpu_port(ds, port)) {
err = gswip_add_single_port_br(priv, port, true);
if (err)
@ -678,6 +681,9 @@ static void gswip_port_disable(struct dsa_switch *ds, int port)
{
struct gswip_priv *priv = ds->priv;
if (!dsa_is_user_port(ds, port))
return;
if (!dsa_is_cpu_port(ds, port)) {
gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_DOWN,
GSWIP_MDIO_PHY_LINK_MASK,

Просмотреть файл

@ -361,6 +361,9 @@ int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
{
struct ksz_device *dev = ds->priv;
if (!dsa_is_user_port(ds, port))
return 0;
/* setup slave port */
dev->dev_ops->port_setup(dev, port, false);
if (dev->dev_ops->phy_setup)
@ -378,6 +381,9 @@ void ksz_disable_port(struct dsa_switch *ds, int port)
{
struct ksz_device *dev = ds->priv;
if (!dsa_is_user_port(ds, port))
return;
dev->on_ports &= ~(1 << port);
dev->live_ports &= ~(1 << port);

Просмотреть файл

@ -726,6 +726,9 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
{
struct mt7530_priv *priv = ds->priv;
if (!dsa_is_user_port(ds, port))
return 0;
mutex_lock(&priv->reg_mutex);
/* Setup the MAC for the user port */
@ -751,6 +754,9 @@ mt7530_port_disable(struct dsa_switch *ds, int port)
{
struct mt7530_priv *priv = ds->priv;
if (!dsa_is_user_port(ds, port))
return;
mutex_lock(&priv->reg_mutex);
/* Clear up all port matrix which could be restored in the next

Просмотреть файл

@ -2057,10 +2057,26 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
bool on)
{
if (chip->info->ops->serdes_power)
return chip->info->ops->serdes_power(chip, port, on);
int err;
return 0;
if (!chip->info->ops->serdes_power)
return 0;
if (on) {
err = chip->info->ops->serdes_power(chip, port, true);
if (err)
return err;
if (chip->info->ops->serdes_irq_setup)
err = chip->info->ops->serdes_irq_setup(chip, port);
} else {
if (chip->info->ops->serdes_irq_free)
chip->info->ops->serdes_irq_free(chip, port);
err = chip->info->ops->serdes_power(chip, port, false);
}
return err;
}
static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
@ -2151,16 +2167,6 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
if (err)
return err;
/* Enable the SERDES interface for DSA and CPU ports. Normal
* ports SERDES are enabled when the port is enabled, thus
* saving a bit of power.
*/
if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) {
err = mv88e6xxx_serdes_power(chip, port, true);
if (err)
return err;
}
/* Port Control 2: don't force a good FCS, set the maximum frame size to
* 10240 bytes, disable 802.1q tags checking, don't discard tagged or
* untagged frames on this port, do a destination address lookup on all
@ -2268,12 +2274,7 @@ static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
int err;
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_serdes_power(chip, port, true);
if (!err && chip->info->ops->serdes_irq_setup)
err = chip->info->ops->serdes_irq_setup(chip, port);
mv88e6xxx_reg_unlock(chip);
return err;
@ -2284,16 +2285,8 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED))
dev_err(chip->dev, "failed to disable port\n");
if (chip->info->ops->serdes_irq_free)
chip->info->ops->serdes_irq_free(chip, port);
if (mv88e6xxx_serdes_power(chip, port, false))
dev_err(chip->dev, "failed to power off SERDES\n");
mv88e6xxx_reg_unlock(chip);
}
@ -2458,27 +2451,16 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
/* Setup Switch Port Registers */
for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
if (dsa_is_unused_port(ds, i))
continue;
/* Prevent the use of an invalid port. */
if (mv88e6xxx_is_invalid_port(chip, i) &&
!dsa_is_unused_port(ds, i)) {
if (mv88e6xxx_is_invalid_port(chip, i)) {
dev_err(chip->dev, "port %d is invalid\n", i);
err = -EINVAL;
goto unlock;
}
if (dsa_is_unused_port(ds, i)) {
err = mv88e6xxx_port_set_state(chip, i,
BR_STATE_DISABLED);
if (err)
goto unlock;
err = mv88e6xxx_serdes_power(chip, i, false);
if (err)
goto unlock;
continue;
}
err = mv88e6xxx_setup_port(chip, i);
if (err)
goto unlock;

Просмотреть файл

@ -254,88 +254,90 @@ static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst)
static int dsa_port_setup(struct dsa_port *dp)
{
enum devlink_port_flavour flavour;
struct dsa_switch *ds = dp->ds;
struct dsa_switch_tree *dst = ds->dst;
int err = 0;
if (dp->type == DSA_PORT_TYPE_UNUSED)
return 0;
memset(&dp->devlink_port, 0, sizeof(dp->devlink_port));
dp->mac = of_get_mac_address(dp->dn);
switch (dp->type) {
case DSA_PORT_TYPE_CPU:
flavour = DEVLINK_PORT_FLAVOUR_CPU;
break;
case DSA_PORT_TYPE_DSA:
flavour = DEVLINK_PORT_FLAVOUR_DSA;
break;
case DSA_PORT_TYPE_USER: /* fall-through */
default:
flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
break;
}
/* dp->index is used now as port_number. However
* CPU and DSA ports should have separate numbering
* independent from front panel port numbers.
*/
devlink_port_attrs_set(&dp->devlink_port, flavour,
dp->index, false, 0,
(const char *) &dst->index, sizeof(dst->index));
err = devlink_port_register(ds->devlink, &dp->devlink_port,
dp->index);
if (err)
return err;
const unsigned char *id = (const unsigned char *)&dst->index;
const unsigned char len = sizeof(dst->index);
struct devlink_port *dlp = &dp->devlink_port;
struct devlink *dl = ds->devlink;
int err;
switch (dp->type) {
case DSA_PORT_TYPE_UNUSED:
dsa_port_disable(dp);
break;
case DSA_PORT_TYPE_CPU:
memset(dlp, 0, sizeof(*dlp));
devlink_port_attrs_set(dlp, DEVLINK_PORT_FLAVOUR_CPU,
dp->index, false, 0, id, len);
err = devlink_port_register(dl, dlp, dp->index);
if (err)
return err;
err = dsa_port_link_register_of(dp);
if (err)
dev_err(ds->dev, "failed to setup link for port %d.%d\n",
ds->index, dp->index);
return err;
err = dsa_port_enable(dp, NULL);
if (err)
return err;
break;
case DSA_PORT_TYPE_DSA:
memset(dlp, 0, sizeof(*dlp));
devlink_port_attrs_set(dlp, DEVLINK_PORT_FLAVOUR_DSA,
dp->index, false, 0, id, len);
err = devlink_port_register(dl, dlp, dp->index);
if (err)
return err;
err = dsa_port_link_register_of(dp);
if (err)
dev_err(ds->dev, "failed to setup link for port %d.%d\n",
ds->index, dp->index);
return err;
err = dsa_port_enable(dp, NULL);
if (err)
return err;
break;
case DSA_PORT_TYPE_USER:
memset(dlp, 0, sizeof(*dlp));
devlink_port_attrs_set(dlp, DEVLINK_PORT_FLAVOUR_PHYSICAL,
dp->index, false, 0, id, len);
err = devlink_port_register(dl, dlp, dp->index);
if (err)
return err;
dp->mac = of_get_mac_address(dp->dn);
err = dsa_slave_create(dp);
if (err)
dev_err(ds->dev, "failed to create slave for port %d.%d\n",
ds->index, dp->index);
else
devlink_port_type_eth_set(&dp->devlink_port, dp->slave);
return err;
devlink_port_type_eth_set(dlp, dp->slave);
break;
}
if (err)
devlink_port_unregister(&dp->devlink_port);
return err;
return 0;
}
static void dsa_port_teardown(struct dsa_port *dp)
{
if (dp->type != DSA_PORT_TYPE_UNUSED)
devlink_port_unregister(&dp->devlink_port);
struct devlink_port *dlp = &dp->devlink_port;
switch (dp->type) {
case DSA_PORT_TYPE_UNUSED:
break;
case DSA_PORT_TYPE_CPU:
dsa_port_disable(dp);
dsa_tag_driver_put(dp->tag_ops);
/* fall-through */
devlink_port_unregister(dlp);
dsa_port_link_unregister_of(dp);
break;
case DSA_PORT_TYPE_DSA:
dsa_port_disable(dp);
devlink_port_unregister(dlp);
dsa_port_link_unregister_of(dp);
break;
case DSA_PORT_TYPE_USER:
devlink_port_unregister(dlp);
if (dp->slave) {
dsa_slave_destroy(dp->slave);
dp->slave = NULL;