On Wed, 20 Jan 2021 11:37:07 +0200 Danielle Ratson wrote:
> Currently, when auto negotiation is on, the user can advertise all the
> linkmodes which correspond to a specific speed, but does not have a
> similar selector for the number of lanes. This is significant when a
> specific speed can be achieved using different number of lanes.  For
> example, 2x50 or 4x25.
> 
> Add 'ETHTOOL_A_LINKMODES_LANES' attribute and expand 'struct
> ethtool_link_settings' with lanes field in order to implement a new
> lanes-selector that will enable the user to advertise a specific number
> of lanes as well.
> 
> When auto negotiation is off, lanes parameter can be forced only if the
> driver supports it. Add a capability bit in 'struct ethtool_ops' that
> allows ethtool know if the driver can handle the lanes parameter when
> auto negotiation is off, so if it does not, an error message will be
> returned when trying to set lanes.

> Signed-off-by: Danielle Ratson <daniel...@nvidia.com>

> diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
> index cde753bb2093..80edae2c24f7 100644
> --- a/include/uapi/linux/ethtool.h
> +++ b/include/uapi/linux/ethtool.h
> @@ -1738,6 +1738,8 @@ static inline int ethtool_validate_speed(__u32 speed)
>       return speed <= INT_MAX || speed == (__u32)SPEED_UNKNOWN;
>  }
>  
> +#define ETHTOOL_LANES_UNKNOWN                0

I already complained about these unnecessary uAPI constants, did you
reply to that and I missed it?

Don't report the nlattr if it's unknown, we have netlink now, those
constants are from times when we returned structures and all fields 
had to have a value.

>  /* Duplex, half or full. */
>  #define DUPLEX_HALF          0x00
>  #define DUPLEX_FULL          0x01
> diff --git a/include/uapi/linux/ethtool_netlink.h 
> b/include/uapi/linux/ethtool_netlink.h
> index e2bf36e6964b..a286635ac9b8 100644
> --- a/include/uapi/linux/ethtool_netlink.h
> +++ b/include/uapi/linux/ethtool_netlink.h
> @@ -227,6 +227,7 @@ enum {
>       ETHTOOL_A_LINKMODES_DUPLEX,             /* u8 */
>       ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG,   /* u8 */
>       ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, /* u8 */
> +     ETHTOOL_A_LINKMODES_LANES,              /* u32 */
>  
>       /* add new constants above here */
>       __ETHTOOL_A_LINKMODES_CNT,
> diff --git a/net/ethtool/linkmodes.c b/net/ethtool/linkmodes.c
> index c5bcb9abc8b9..fb7d73250864 100644
> --- a/net/ethtool/linkmodes.c
> +++ b/net/ethtool/linkmodes.c
> @@ -152,12 +152,14 @@ const struct ethnl_request_ops 
> ethnl_linkmodes_request_ops = {
>  
>  struct link_mode_info {
>       int                             speed;
> +     u32                             lanes;

This is not uapi, we can make it u8 now, save a few (hundred?) bytes 
of memory and bump it to u16 later.

>       u8                              duplex;
>  };

> @@ -353,10 +358,39 @@ static int ethnl_update_linkmodes(struct genl_info 
> *info, struct nlattr **tb,
>  
>       *mod = false;
>       req_speed = tb[ETHTOOL_A_LINKMODES_SPEED];
> +     req_lanes = tb[ETHTOOL_A_LINKMODES_LANES];
>       req_duplex = tb[ETHTOOL_A_LINKMODES_DUPLEX];
>  
>       ethnl_update_u8(&lsettings->autoneg, tb[ETHTOOL_A_LINKMODES_AUTONEG],
>                       mod);
> +
> +     if (req_lanes) {
> +             u32 lanes_cfg = nla_get_u32(tb[ETHTOOL_A_LINKMODES_LANES]);

req_lanes == tb[ETHTOOL_A_LINKMODES_LANES], right?

Please use req_lanes variable where possible.

> +
> +             if (!is_power_of_2(lanes_cfg)) {
> +                     NL_SET_ERR_MSG_ATTR(info->extack,
> +                                         tb[ETHTOOL_A_LINKMODES_LANES],
> +                                         "lanes value is invalid");
> +                     return -EINVAL;
> +             }
> +
> +             /* If autoneg is off and lanes parameter is not supported by the
> +              * driver, return an error.
> +              */
> +             if (!lsettings->autoneg &&
> +                 !dev->ethtool_ops->cap_link_lanes_supported) {
> +                     NL_SET_ERR_MSG_ATTR(info->extack,
> +                                         tb[ETHTOOL_A_LINKMODES_LANES],
> +                                         "lanes configuration not supported 
> by device");
> +                     return -EOPNOTSUPP;
> +             }

This validation does not depend on the current settings at all, it's
just input validation, it can be done before rtnl_lock is taken (in a
new function).

You can move ethnl_validate_master_slave_cfg() to that function as well
(as a cleanup before this patch).

> +     } else if (!lsettings->autoneg) {
> +             /* If autoneg is off and lanes parameter is not passed from 
> user,
> +              * set the lanes parameter to UNKNOWN.
> +              */
> +             ksettings->lanes = ETHTOOL_LANES_UNKNOWN;
> +     }
> +
>       ret = ethnl_update_bitset(ksettings->link_modes.advertising,
>                                 __ETHTOOL_LINK_MODE_MASK_NBITS,
>                                 tb[ETHTOOL_A_LINKMODES_OURS], link_mode_names,

Reply via email to