aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/net/ethtool/linkmodes.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-05-06 17:45:45 -0700
committerDavid S. Miller <davem@davemloft.net>2020-05-06 17:45:45 -0700
commit9e330bf469e02e64d46cb150a2ec65310b9412ea (patch)
treefc04060f03d67fca8157b07d648bd7113e6d914b /net/ethtool/linkmodes.c
parentMerge branch 'chcr-next' (diff)
parentnet: phy: tja11xx: add support for master-slave configuration (diff)
downloadwireguard-linux-9e330bf469e02e64d46cb150a2ec65310b9412ea.tar.xz
wireguard-linux-9e330bf469e02e64d46cb150a2ec65310b9412ea.zip
Merge branch 'ethtool-master-slave'
Oleksij Rempel says: ==================== provide support for PHY master/slave configuration changes v6: - use NL_SET_ERR_MSG_ATTR in ethnl_update_linkmodes - add sanity checks in the ioctl interface - use bool for ethnl_validate_master_slave_cfg() changes v5: - set MASTER_SLAVE_CFG_UNSUPPORTED as default value - send a netlink error message on validation error - more code fixes changes v4: - rename port_mode to master_slave - move validation code to net/ethtool/linkmodes.c - add UNSUPPORTED state and avoid sending unsupported fields - more formatting and naming fixes - tja11xx: support only force mode - tja11xx: mark state as unsupported changes v3: - provide separate field for config and state. - make state rejected on set - add validation changes v2: - change names. Use MASTER_PREFERRED instead of MULTIPORT - configure master/slave only on request. Default configuration can be provided by PHY or eeprom - status and configuration to the user space. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ethtool/linkmodes.c')
-rw-r--r--net/ethtool/linkmodes.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/net/ethtool/linkmodes.c b/net/ethtool/linkmodes.c
index 452608c6d856..fd4f3e58c6f6 100644
--- a/net/ethtool/linkmodes.c
+++ b/net/ethtool/linkmodes.c
@@ -27,6 +27,8 @@ linkmodes_get_policy[ETHTOOL_A_LINKMODES_MAX + 1] = {
[ETHTOOL_A_LINKMODES_PEER] = { .type = NLA_REJECT },
[ETHTOOL_A_LINKMODES_SPEED] = { .type = NLA_REJECT },
[ETHTOOL_A_LINKMODES_DUPLEX] = { .type = NLA_REJECT },
+ [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .type = NLA_REJECT },
+ [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .type = NLA_REJECT },
};
static int linkmodes_prepare_data(const struct ethnl_req_info *req_base,
@@ -63,6 +65,7 @@ static int linkmodes_reply_size(const struct ethnl_req_info *req_base,
{
const struct linkmodes_reply_data *data = LINKMODES_REPDATA(reply_base);
const struct ethtool_link_ksettings *ksettings = &data->ksettings;
+ const struct ethtool_link_settings *lsettings = &ksettings->base;
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
int len, ret;
@@ -86,6 +89,12 @@ static int linkmodes_reply_size(const struct ethnl_req_info *req_base,
len += ret;
}
+ if (lsettings->master_slave_cfg != MASTER_SLAVE_CFG_UNSUPPORTED)
+ len += nla_total_size(sizeof(u8));
+
+ if (lsettings->master_slave_state != MASTER_SLAVE_STATE_UNSUPPORTED)
+ len += nla_total_size(sizeof(u8));
+
return len;
}
@@ -122,6 +131,16 @@ static int linkmodes_fill_reply(struct sk_buff *skb,
nla_put_u8(skb, ETHTOOL_A_LINKMODES_DUPLEX, lsettings->duplex))
return -EMSGSIZE;
+ if (lsettings->master_slave_cfg != MASTER_SLAVE_CFG_UNSUPPORTED &&
+ nla_put_u8(skb, ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG,
+ lsettings->master_slave_cfg))
+ return -EMSGSIZE;
+
+ if (lsettings->master_slave_state != MASTER_SLAVE_STATE_UNSUPPORTED &&
+ nla_put_u8(skb, ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE,
+ lsettings->master_slave_state))
+ return -EMSGSIZE;
+
return 0;
}
@@ -249,6 +268,8 @@ linkmodes_set_policy[ETHTOOL_A_LINKMODES_MAX + 1] = {
[ETHTOOL_A_LINKMODES_PEER] = { .type = NLA_REJECT },
[ETHTOOL_A_LINKMODES_SPEED] = { .type = NLA_U32 },
[ETHTOOL_A_LINKMODES_DUPLEX] = { .type = NLA_U8 },
+ [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .type = NLA_U8 },
+ [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .type = NLA_REJECT },
};
/* Set advertised link modes to all supported modes matching requested speed
@@ -287,14 +308,45 @@ static bool ethnl_auto_linkmodes(struct ethtool_link_ksettings *ksettings,
__ETHTOOL_LINK_MODE_MASK_NBITS);
}
+static bool ethnl_validate_master_slave_cfg(u8 cfg)
+{
+ switch (cfg) {
+ case MASTER_SLAVE_CFG_MASTER_PREFERRED:
+ case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
+ case MASTER_SLAVE_CFG_MASTER_FORCE:
+ case MASTER_SLAVE_CFG_SLAVE_FORCE:
+ return true;
+ }
+
+ return false;
+}
+
static int ethnl_update_linkmodes(struct genl_info *info, struct nlattr **tb,
struct ethtool_link_ksettings *ksettings,
bool *mod)
{
struct ethtool_link_settings *lsettings = &ksettings->base;
bool req_speed, req_duplex;
+ const struct nlattr *master_slave_cfg;
int ret;
+ master_slave_cfg = tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG];
+ if (master_slave_cfg) {
+ u8 cfg = nla_get_u8(master_slave_cfg);
+
+ if (lsettings->master_slave_cfg == MASTER_SLAVE_CFG_UNSUPPORTED) {
+ NL_SET_ERR_MSG_ATTR(info->extack, master_slave_cfg,
+ "master/slave configuration not supported by device");
+ return -EOPNOTSUPP;
+ }
+
+ if (!ethnl_validate_master_slave_cfg(cfg)) {
+ NL_SET_ERR_MSG_ATTR(info->extack, master_slave_cfg,
+ "master/slave value is invalid");
+ return -EOPNOTSUPP;
+ }
+ }
+
*mod = false;
req_speed = tb[ETHTOOL_A_LINKMODES_SPEED];
req_duplex = tb[ETHTOOL_A_LINKMODES_DUPLEX];
@@ -311,6 +363,7 @@ static int ethnl_update_linkmodes(struct genl_info *info, struct nlattr **tb,
mod);
ethnl_update_u8(&lsettings->duplex, tb[ETHTOOL_A_LINKMODES_DUPLEX],
mod);
+ ethnl_update_u8(&lsettings->master_slave_cfg, master_slave_cfg, mod);
if (!tb[ETHTOOL_A_LINKMODES_OURS] && lsettings->autoneg &&
(req_speed || req_duplex) &&