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

Reply via email to