Since the information whether the adaptive behavior is implemented
by DIM or driver custom is useful, so add new attribute to
ETHTOOL_MSG_COALESCE_GET/ETHTOOL_MSG_COALESCE_SET commands to control
the type of adaptive coalescing.

In order to compatible with ioctl code, add a extended coalescing
handler to deal with it in the netlink API, then other new extended
coalescing parameters can utiliaze it as well.

Suggested-by: Jakub Kicinski <k...@kernel.org>
Signed-off-by: Huazhong Tan <tanhuazh...@huawei.com>
---
 Documentation/networking/ethtool-netlink.rst |  1 +
 include/linux/ethtool.h                      | 14 +++++++++++
 include/uapi/linux/ethtool_netlink.h         |  1 +
 net/ethtool/coalesce.c                       | 35 ++++++++++++++++++++++++++--
 net/ethtool/netlink.h                        |  2 +-
 5 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.rst 
b/Documentation/networking/ethtool-netlink.rst
index 30b9824..dae7145 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -928,6 +928,7 @@ Kernel response contents:
   ``ETHTOOL_A_COALESCE_TX_USECS_HIGH``         u32     delay (us), high Tx
   ``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH``    u32     max packets, high Tx
   ``ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL``  u32     rate sampling interval
+  ``ETHTOOL_A_COALESCE_USE_DIM``               bool    using DIM adaptive
   ===========================================  ======  =======================
 
 Attributes are only included in reply if their value is not zero or the
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 6408b44..4426d65 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -215,6 +215,7 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
 #define ETHTOOL_COALESCE_TX_USECS_HIGH         BIT(19)
 #define ETHTOOL_COALESCE_TX_MAX_FRAMES_HIGH    BIT(20)
 #define ETHTOOL_COALESCE_RATE_SAMPLE_INTERVAL  BIT(21)
+#define ETHTOOL_COALESCE_USE_DIM               BIT(22)
 
 #define ETHTOOL_COALESCE_USECS                                         \
        (ETHTOOL_COALESCE_RX_USECS | ETHTOOL_COALESCE_TX_USECS)
@@ -241,6 +242,10 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
         ETHTOOL_COALESCE_PKT_RATE_LOW | ETHTOOL_COALESCE_PKT_RATE_HIGH | \
         ETHTOOL_COALESCE_RATE_SAMPLE_INTERVAL)
 
+struct ethtool_ext_coalesce {
+       __u32 use_dim;
+};
+
 #define ETHTOOL_STAT_NOT_SET   (~0ULL)
 
 /**
@@ -298,9 +303,14 @@ struct ethtool_pause_stats {
  *     or zero.
  * @get_coalesce: Get interrupt coalescing parameters.  Returns a negative
  *     error code or zero.
+ * @get_ext_coalesce: Get extended interrupt coalescing parameters.
+ *     Returns a negative error code or zero.
  * @set_coalesce: Set interrupt coalescing parameters.  Supported coalescing
  *     types should be set in @supported_coalesce_params.
  *     Returns a negative error code or zero.
+ * @set_ext_coalesce: Set extended interrupt coalescing parameters.  Supported
+ *     extended coalescing types should be set in @supported_coalesce_params.
+ *     Returns a negative error code or zero.
  * @get_ringparam: Report ring sizes
  * @set_ringparam: Set ring sizes.  Returns a negative error code or zero.
  * @get_pause_stats: Report pause frame statistics. Drivers must not zero
@@ -437,7 +447,11 @@ struct ethtool_ops {
        int     (*set_eeprom)(struct net_device *,
                              struct ethtool_eeprom *, u8 *);
        int     (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
+       int     (*get_ext_coalesce)(struct net_device *,
+                                   struct ethtool_ext_coalesce *);
        int     (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
+       int     (*set_ext_coalesce)(struct net_device *,
+                                   struct ethtool_ext_coalesce *);
        void    (*get_ringparam)(struct net_device *,
                                 struct ethtool_ringparam *);
        int     (*set_ringparam)(struct net_device *,
diff --git a/include/uapi/linux/ethtool_netlink.h 
b/include/uapi/linux/ethtool_netlink.h
index e2bf36e..e3458d9 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -366,6 +366,7 @@ enum {
        ETHTOOL_A_COALESCE_TX_USECS_HIGH,               /* u32 */
        ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,          /* u32 */
        ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,        /* u32 */
+       ETHTOOL_A_COALESCE_USE_DIM,                     /* u8 */
 
        /* add new constants above here */
        __ETHTOOL_A_COALESCE_CNT,
diff --git a/net/ethtool/coalesce.c b/net/ethtool/coalesce.c
index 1d6bc13..d4d8901 100644
--- a/net/ethtool/coalesce.c
+++ b/net/ethtool/coalesce.c
@@ -11,6 +11,7 @@ struct coalesce_reply_data {
        struct ethnl_reply_data         base;
        struct ethtool_coalesce         coalesce;
        u32                             supported_params;
+       struct ethtool_ext_coalesce     ext_coalesce;
 };
 
 #define COALESCE_REPDATA(__reply_base) \
@@ -50,6 +51,7 @@ __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_HIGH);
 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH);
 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH);
 __CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL);
+__CHECK_SUPPORTED_OFFSET(COALESCE_USE_DIM);
 
 const struct nla_policy ethnl_coalesce_get_policy[] = {
        [ETHTOOL_A_COALESCE_HEADER]             =
@@ -71,6 +73,14 @@ static int coalesce_prepare_data(const struct ethnl_req_info 
*req_base,
        if (ret < 0)
                return ret;
        ret = dev->ethtool_ops->get_coalesce(dev, &data->coalesce);
+
+       if (dev->ethtool_ops->get_ext_coalesce) {
+               ret = dev->ethtool_ops->get_ext_coalesce(dev,
+                       &data->ext_coalesce);
+               if (ret < 0)
+                       return ret;
+       }
+
        ethnl_ops_complete(dev);
 
        return ret;
@@ -100,7 +110,8 @@ static int coalesce_reply_size(const struct ethnl_req_info 
*req_base,
               nla_total_size(sizeof(u32)) +    /* _RX_MAX_FRAMES_HIGH */
               nla_total_size(sizeof(u32)) +    /* _TX_USECS_HIGH */
               nla_total_size(sizeof(u32)) +    /* _TX_MAX_FRAMES_HIGH */
-              nla_total_size(sizeof(u32));     /* _RATE_SAMPLE_INTERVAL */
+              nla_total_size(sizeof(u32)) +    /* _RATE_SAMPLE_INTERVAL */
+              nla_total_size(sizeof(u8));      /* _USE_DIM */
 }
 
 static bool coalesce_put_u32(struct sk_buff *skb, u16 attr_type, u32 val,
@@ -124,6 +135,7 @@ static int coalesce_fill_reply(struct sk_buff *skb,
                               const struct ethnl_reply_data *reply_base)
 {
        const struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
+       const struct ethtool_ext_coalesce *ext_coal = &data->ext_coalesce;
        const struct ethtool_coalesce *coal = &data->coalesce;
        u32 supported = data->supported_params;
 
@@ -170,7 +182,9 @@ static int coalesce_fill_reply(struct sk_buff *skb,
            coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
                             coal->tx_max_coalesced_frames_high, supported) ||
            coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
-                            coal->rate_sample_interval, supported))
+                            coal->rate_sample_interval, supported) ||
+           coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_DIM,
+                             ext_coal->use_dim, supported))
                return -EMSGSIZE;
 
        return 0;
@@ -215,10 +229,12 @@ const struct nla_policy ethnl_coalesce_set_policy[] = {
        [ETHTOOL_A_COALESCE_TX_USECS_HIGH]      = { .type = NLA_U32 },
        [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .type = NLA_U32 },
        [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_U32 },
+       [ETHTOOL_A_COALESCE_USE_DIM]            = { .type = NLA_U8 },
 };
 
 int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info)
 {
+       struct ethtool_ext_coalesce ext_coalesce = {};
        struct ethtool_coalesce coalesce = {};
        struct ethnl_req_info req_info = {};
        struct nlattr **tb = info->attrs;
@@ -259,6 +275,12 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct 
genl_info *info)
        if (ret < 0)
                goto out_ops;
 
+       if (ops->get_ext_coalesce) {
+               ret = ops->get_ext_coalesce(dev, &ext_coalesce);
+               if (ret < 0)
+                       goto out_ops;
+       }
+
        ethnl_update_u32(&coalesce.rx_coalesce_usecs,
                         tb[ETHTOOL_A_COALESCE_RX_USECS], &mod);
        ethnl_update_u32(&coalesce.rx_max_coalesced_frames,
@@ -303,6 +325,8 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct 
genl_info *info)
                         tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH], &mod);
        ethnl_update_u32(&coalesce.rate_sample_interval,
                         tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL], &mod);
+       ethnl_update_bool32(&ext_coalesce.use_dim,
+                           tb[ETHTOOL_A_COALESCE_USE_DIM], &mod);
        ret = 0;
        if (!mod)
                goto out_ops;
@@ -310,6 +334,13 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct 
genl_info *info)
        ret = dev->ethtool_ops->set_coalesce(dev, &coalesce);
        if (ret < 0)
                goto out_ops;
+
+       if (ops->set_ext_coalesce) {
+               ret = ops->set_ext_coalesce(dev, &ext_coalesce);
+               if (ret < 0)
+                       goto out_ops;
+       }
+
        ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);
 
 out_ops:
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index d8efec5..e63f44a 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -366,7 +366,7 @@ extern const struct nla_policy 
ethnl_rings_set_policy[ETHTOOL_A_RINGS_TX + 1];
 extern const struct nla_policy 
ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1];
 extern const struct nla_policy 
ethnl_channels_set_policy[ETHTOOL_A_CHANNELS_COMBINED_COUNT + 1];
 extern const struct nla_policy 
ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_HEADER + 1];
-extern const struct nla_policy 
ethnl_coalesce_set_policy[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL + 1];
+extern const struct nla_policy 
ethnl_coalesce_set_policy[ETHTOOL_A_COALESCE_USE_DIM + 1];
 extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_HEADER + 
1];
 extern const struct nla_policy ethnl_pause_set_policy[ETHTOOL_A_PAUSE_TX + 1];
 extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_HEADER + 1];
-- 
2.7.4

Reply via email to