From: Inbar Karmy <inb...@mellanox.com> In the event where the device unexpectedly becomes unresponsive for a long period of time, flow control mechanism may propagate pause frames which will cause congestion spreading to the entire network. To prevent this scenario, when the device is stalled for a period longer than a pre-configured timeout, flow control mechanisms are automatically disabled. This patch defines a new ETHTOOL_GPFCPREVENTION/ETHTOOL_SPFCPREVENTION API, handled by the new get_pfc_prevention_mode/set_pfc_prevention_mode callbacks. This API provides support for configuring flow control protection mechanism into two deferent modes: default/auto.
Signed-off-by: Inbar Karmy <inb...@mellanox.com> Reviewed-by: Eran Ben Elisha <era...@mellanox.com> --- include/linux/ethtool.h | 8 ++++++++ include/uapi/linux/ethtool.h | 20 ++++++++++++++++++++ net/core/ethtool.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 2ec41a7..f6d5e26 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -310,6 +310,10 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, * fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS * instead of the latter), any change to them will be overwritten * by kernel. Returns a negative error code or zero. + * @get_pfc_prevention_mode: Report pfc storm prevention mode- + * default/auto. + * @set_pfc_prevention_mode: Set pfc storm prevention mode. Returns + * a negative error code or zero. * * All operations are optional (i.e. the function pointer may be set * to %NULL) and callers must take this into account. Callers must @@ -400,5 +404,9 @@ struct ethtool_ops { struct ethtool_fecparam *); int (*set_fecparam)(struct net_device *, struct ethtool_fecparam *); + int (*get_pfc_prevention_mode)(struct net_device *, + struct ethtool_pfc_prevention *); + int (*set_pfc_prevention_mode)(struct net_device *, + struct ethtool_pfc_prevention *); }; #endif /* _LINUX_ETHTOOL_H */ diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index ac71559..6ba0d43 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -552,6 +552,24 @@ struct ethtool_pauseparam { #define ETH_GSTRING_LEN 32 /** + * struct ethtool_pfc_prevention - flow control stall prevention mode + * @cmd: Command number = %ETHTOOL_GPFCPREVENTION or %ETHTOOL_SPFCPREVENTION + * @mode: Flag to define the time till activate pfc stall prevention: + * auto, default. + */ + +enum pfc_prevention_type { + ETH_PFC_PREVENTION_DEFAULT = 0, + ETH_PFC_PREVENTION_AUTO, +}; + +struct ethtool_pfc_prevention { + __u32 cmd; + __u32 mode; + __u32 reserved; +}; + +/** * enum ethtool_stringset - string set ID * @ETH_SS_TEST: Self-test result names, for use with %ETHTOOL_TEST * @ETH_SS_STATS: Statistic names, for use with %ETHTOOL_GSTATS @@ -1374,6 +1392,8 @@ enum ethtool_fec_config_bits { #define ETHTOOL_PHY_STUNABLE 0x0000004f /* Set PHY tunable configuration */ #define ETHTOOL_GFECPARAM 0x00000050 /* Get FEC settings */ #define ETHTOOL_SFECPARAM 0x00000051 /* Set FEC settings */ +#define ETHTOOL_GPFCPREVENTION 0x00000052 /* Get PFC stall prevention configuration */ +#define ETHTOOL_SPFCPREVENTION 0x00000053 /* Set PFC stall prevention configuration*/ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index f8fcf45..a656ecc 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2556,6 +2556,38 @@ static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr) return dev->ethtool_ops->set_fecparam(dev, &fecparam); } +static int ethtool_get_pfc_prevention_mode(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_pfc_prevention preventionmod = { .cmd = ETHTOOL_GPFCPREVENTION }; + int ret; + + if (!dev->ethtool_ops->get_pfc_prevention_mode) + return -EOPNOTSUPP; + + ret = dev->ethtool_ops->get_pfc_prevention_mode(dev, &preventionmod); + + if (copy_to_user(useraddr, &preventionmod, sizeof(preventionmod))) + return -EFAULT; + + return ret; +} + +static int ethtool_set_pfc_prevention_mode(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_pfc_prevention preventionmod; + + if (!dev->ethtool_ops->set_pfc_prevention_mode) + return -EOPNOTSUPP; + + if (copy_from_user(&preventionmod, useraddr, sizeof(preventionmod))) + return -EFAULT; + + if (preventionmod.reserved) + return -EINVAL; + + return dev->ethtool_ops->set_pfc_prevention_mode(dev, &preventionmod); +} + /* The main entry point in this file. Called from net/core/dev_ioctl.c */ int dev_ethtool(struct net *net, struct ifreq *ifr) @@ -2615,6 +2647,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_PHY_GTUNABLE: case ETHTOOL_GLINKSETTINGS: case ETHTOOL_GFECPARAM: + case ETHTOOL_GPFCPREVENTION: break; default: if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) @@ -2830,6 +2863,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_SFECPARAM: rc = ethtool_set_fecparam(dev, useraddr); break; + case ETHTOOL_GPFCPREVENTION: + rc = ethtool_get_pfc_prevention_mode(dev, useraddr); + break; + case ETHTOOL_SPFCPREVENTION: + rc = ethtool_set_pfc_prevention_mode(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- 1.8.3.1