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:
Коммит
b1b5133db1
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче