Commit af74be9f authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-dsa-allow-phylink_mac_ops-in-dsa-drivers'

Russell King says:

====================
net: dsa: allow phylink_mac_ops in DSA drivers

This series showcases my idea of moving the phylink_mac_ops into DSA
drivers, using mv88e6xxx as an example. Since I'm only changing one
driver, providing the mac_ops has to be optional and the existing shims
need to be kept for unconverted drivers.

The first patch introduces a new helper that converts from the
phylink_config structure that phylink uses to communicate with MAC
drivers to the dsa_port structure. From this, DSA drivers can get
the dsa_switch structure and thus their implementation specific
data structure, and they can also retrieve the port index.

The second patch adds the support to the core DSA layer to allow
DSA drivers to provide phylink_mac_ops.

The third patch converts mv88e6xxx to use this.

I initially made this change after adding yet more phylink to DSA
driver shims for my work with phylink-based EEE support, and decided
that it was getting silly to keep implementing more and more shims.
There are cases where shims don't work well - we had already tripped
over a case a few years ago when the phylink mac_select_pcs operation
was introduced. Phylink tested for the presence of this in the ops
structure, but with DSA shims, this doesn't necessarily mean that
the sub-driver supports this method. The only way to find that out
is to call the method with dummy values and check the return code.

The same thing was partly true when adding EEE support, and I ended
up with this in phylink to determine whether the MAC supported EEE:

+static bool phylink_mac_supports_eee(struct phylink *pl)
+{
+       return pl->mac_ops->mac_disable_tx_lpi &&
+              pl->mac_ops->mac_enable_tx_lpi &&
+              pl->config->lpi_capabilities;
+}

because merely testing for the presence of the operations is
insufficient when shims are involved - and it wasn't possible to call
these functions in the way that mac_select_pcs could be called.

So, I think it's time to get away from this shimming model and instead
have drivers directly interface to the various subsystems.

This converts mv88e6xxx. I have similar patches for other DSA drivers
that will be sent once this has been reviewed.
====================

Link: https://lore.kernel.org/r/ZhbrbM+d5UfgafGp@shell.armlinux.org.ukSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents f7ac8fbd 0cb6da0c
......@@ -790,24 +790,27 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
}
}
static struct phylink_pcs *mv88e6xxx_mac_select_pcs(struct dsa_switch *ds,
int port,
phy_interface_t interface)
static struct phylink_pcs *
mv88e6xxx_mac_select_pcs(struct phylink_config *config,
phy_interface_t interface)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mv88e6xxx_chip *chip = dp->ds->priv;
struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
if (chip->info->ops->pcs_ops)
pcs = chip->info->ops->pcs_ops->pcs_select(chip, port,
pcs = chip->info->ops->pcs_ops->pcs_select(chip, dp->index,
interface);
return pcs;
}
static int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port,
static int mv88e6xxx_mac_prepare(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mv88e6xxx_chip *chip = dp->ds->priv;
int port = dp->index;
int err = 0;
/* In inband mode, the link may come up at any time while the link
......@@ -826,11 +829,13 @@ static int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port,
return err;
}
static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
static void mv88e6xxx_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mv88e6xxx_chip *chip = dp->ds->priv;
int port = dp->index;
int err = 0;
mv88e6xxx_reg_lock(chip);
......@@ -846,13 +851,15 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
mv88e6xxx_reg_unlock(chip);
if (err && err != -EOPNOTSUPP)
dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
dev_err(chip->dev, "p%d: failed to configure MAC/PCS\n", port);
}
static int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port,
static int mv88e6xxx_mac_finish(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mv88e6xxx_chip *chip = dp->ds->priv;
int port = dp->index;
int err = 0;
/* Undo the forced down state above after completing configuration
......@@ -876,12 +883,14 @@ static int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port,
return err;
}
static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
static void mv88e6xxx_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mv88e6xxx_chip *chip = dp->ds->priv;
const struct mv88e6xxx_ops *ops;
int port = dp->index;
int err = 0;
ops = chip->info->ops;
......@@ -904,14 +913,16 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
"p%d: failed to force MAC link down\n", port);
}
static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode, phy_interface_t interface,
static void mv88e6xxx_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode, phy_interface_t interface,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mv88e6xxx_chip *chip = dp->ds->priv;
const struct mv88e6xxx_ops *ops;
int port = dp->index;
int err = 0;
ops = chip->info->ops;
......@@ -937,7 +948,7 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
mv88e6xxx_reg_unlock(chip);
if (err && err != -EOPNOTSUPP)
dev_err(ds->dev,
dev_err(chip->dev,
"p%d: failed to configure MAC link up\n", port);
}
......@@ -6922,6 +6933,15 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
return err_sync ? : err_pvt;
}
static const struct phylink_mac_ops mv88e6xxx_phylink_mac_ops = {
.mac_select_pcs = mv88e6xxx_mac_select_pcs,
.mac_prepare = mv88e6xxx_mac_prepare,
.mac_config = mv88e6xxx_mac_config,
.mac_finish = mv88e6xxx_mac_finish,
.mac_link_down = mv88e6xxx_mac_link_down,
.mac_link_up = mv88e6xxx_mac_link_up,
};
static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.get_tag_protocol = mv88e6xxx_get_tag_protocol,
.change_tag_protocol = mv88e6xxx_change_tag_protocol,
......@@ -6930,12 +6950,6 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.port_setup = mv88e6xxx_port_setup,
.port_teardown = mv88e6xxx_port_teardown,
.phylink_get_caps = mv88e6xxx_get_caps,
.phylink_mac_select_pcs = mv88e6xxx_mac_select_pcs,
.phylink_mac_prepare = mv88e6xxx_mac_prepare,
.phylink_mac_config = mv88e6xxx_mac_config,
.phylink_mac_finish = mv88e6xxx_mac_finish,
.phylink_mac_link_down = mv88e6xxx_mac_link_down,
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
......@@ -7004,6 +7018,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
ds->priv = chip;
ds->dev = dev;
ds->ops = &mv88e6xxx_switch_ops;
ds->phylink_mac_ops = &mv88e6xxx_phylink_mac_ops;
ds->ageing_time_min = chip->info->age_time_coeff;
ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
......
......@@ -327,6 +327,12 @@ struct dsa_port {
};
};
static inline struct dsa_port *
dsa_phylink_to_port(struct phylink_config *config)
{
return container_of(config, struct dsa_port, pl_config);
}
/* TODO: ideally DSA ports would have a single dp->link_dp member,
* and no dst->rtable nor this struct dsa_link would be needed,
* but this would require some more complex tree walking,
......@@ -451,6 +457,11 @@ struct dsa_switch {
*/
const struct dsa_switch_ops *ops;
/*
* Allow a DSA switch driver to override the phylink MAC ops
*/
const struct phylink_mac_ops *phylink_mac_ops;
/*
* User mii_bus and devices for the individual ports.
*/
......
......@@ -1505,6 +1505,17 @@ static int dsa_switch_probe(struct dsa_switch *ds)
if (!ds->num_ports)
return -EINVAL;
if (ds->phylink_mac_ops) {
if (ds->ops->phylink_mac_select_pcs ||
ds->ops->phylink_mac_prepare ||
ds->ops->phylink_mac_config ||
ds->ops->phylink_mac_finish ||
ds->ops->phylink_mac_link_down ||
ds->ops->phylink_mac_link_up ||
ds->ops->adjust_link)
return -EINVAL;
}
if (np) {
err = dsa_switch_parse_of(ds, np);
if (err)
......
......@@ -1558,7 +1558,7 @@ static struct phylink_pcs *
dsa_port_phylink_mac_select_pcs(struct phylink_config *config,
phy_interface_t interface)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_port *dp = dsa_phylink_to_port(config);
struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
struct dsa_switch *ds = dp->ds;
......@@ -1572,7 +1572,7 @@ static int dsa_port_phylink_mac_prepare(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_port *dp = dsa_phylink_to_port(config);
struct dsa_switch *ds = dp->ds;
int err = 0;
......@@ -1587,7 +1587,7 @@ static void dsa_port_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_port *dp = dsa_phylink_to_port(config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_config)
......@@ -1600,7 +1600,7 @@ static int dsa_port_phylink_mac_finish(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_port *dp = dsa_phylink_to_port(config);
struct dsa_switch *ds = dp->ds;
int err = 0;
......@@ -1615,7 +1615,7 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_port *dp = dsa_phylink_to_port(config);
struct phy_device *phydev = NULL;
struct dsa_switch *ds = dp->ds;
......@@ -1638,7 +1638,7 @@ static void dsa_port_phylink_mac_link_up(struct phylink_config *config,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_port *dp = dsa_phylink_to_port(config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_link_up) {
......@@ -1662,6 +1662,7 @@ static const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
int dsa_port_phylink_create(struct dsa_port *dp)
{
const struct phylink_mac_ops *mac_ops;
struct dsa_switch *ds = dp->ds;
phy_interface_t mode;
struct phylink *pl;
......@@ -1685,8 +1686,12 @@ int dsa_port_phylink_create(struct dsa_port *dp)
}
}
pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
mode, &dsa_port_phylink_mac_ops);
mac_ops = &dsa_port_phylink_mac_ops;
if (ds->phylink_mac_ops)
mac_ops = ds->phylink_mac_ops;
pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode,
mac_ops);
if (IS_ERR(pl)) {
pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));
return PTR_ERR(pl);
......@@ -1952,12 +1957,23 @@ static void dsa_shared_port_validate_of(struct dsa_port *dp,
dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
}
static void dsa_shared_port_link_down(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down)
ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED,
PHY_INTERFACE_MODE_NA);
else if (ds->ops->phylink_mac_link_down)
ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED,
PHY_INTERFACE_MODE_NA);
}
int dsa_shared_port_link_register_of(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
bool missing_link_description;
bool missing_phy_mode;
int port = dp->index;
dsa_shared_port_validate_of(dp, &missing_phy_mode,
&missing_link_description);
......@@ -1973,9 +1989,7 @@ int dsa_shared_port_link_register_of(struct dsa_port *dp)
"Skipping phylink registration for %s port %d\n",
dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
} else {
if (ds->ops->phylink_mac_link_down)
ds->ops->phylink_mac_link_down(ds, port,
MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
dsa_shared_port_link_down(dp);
return dsa_shared_port_phylink_register(dp);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment