Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include "netlink.h"
0004 #include "common.h"
0005 
0006 struct coalesce_req_info {
0007     struct ethnl_req_info       base;
0008 };
0009 
0010 struct coalesce_reply_data {
0011     struct ethnl_reply_data     base;
0012     struct ethtool_coalesce     coalesce;
0013     struct kernel_ethtool_coalesce  kernel_coalesce;
0014     u32             supported_params;
0015 };
0016 
0017 #define COALESCE_REPDATA(__reply_base) \
0018     container_of(__reply_base, struct coalesce_reply_data, base)
0019 
0020 #define __SUPPORTED_OFFSET ETHTOOL_A_COALESCE_RX_USECS
0021 static u32 attr_to_mask(unsigned int attr_type)
0022 {
0023     return BIT(attr_type - __SUPPORTED_OFFSET);
0024 }
0025 
0026 /* build time check that indices in ethtool_ops::supported_coalesce_params
0027  * match corresponding attribute types with an offset
0028  */
0029 #define __CHECK_SUPPORTED_OFFSET(x) \
0030     static_assert((ETHTOOL_ ## x) == \
0031               BIT((ETHTOOL_A_ ## x) - __SUPPORTED_OFFSET))
0032 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS);
0033 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES);
0034 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_IRQ);
0035 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_IRQ);
0036 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS);
0037 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES);
0038 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_IRQ);
0039 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_IRQ);
0040 __CHECK_SUPPORTED_OFFSET(COALESCE_STATS_BLOCK_USECS);
0041 __CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_RX);
0042 __CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_TX);
0043 __CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_LOW);
0044 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_LOW);
0045 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_LOW);
0046 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_LOW);
0047 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_LOW);
0048 __CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_HIGH);
0049 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_HIGH);
0050 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_HIGH);
0051 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH);
0052 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH);
0053 __CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL);
0054 
0055 const struct nla_policy ethnl_coalesce_get_policy[] = {
0056     [ETHTOOL_A_COALESCE_HEADER]     =
0057         NLA_POLICY_NESTED(ethnl_header_policy),
0058 };
0059 
0060 static int coalesce_prepare_data(const struct ethnl_req_info *req_base,
0061                  struct ethnl_reply_data *reply_base,
0062                  struct genl_info *info)
0063 {
0064     struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
0065     struct netlink_ext_ack *extack = info ? info->extack : NULL;
0066     struct net_device *dev = reply_base->dev;
0067     int ret;
0068 
0069     if (!dev->ethtool_ops->get_coalesce)
0070         return -EOPNOTSUPP;
0071     data->supported_params = dev->ethtool_ops->supported_coalesce_params;
0072     ret = ethnl_ops_begin(dev);
0073     if (ret < 0)
0074         return ret;
0075     ret = dev->ethtool_ops->get_coalesce(dev, &data->coalesce,
0076                          &data->kernel_coalesce, extack);
0077     ethnl_ops_complete(dev);
0078 
0079     return ret;
0080 }
0081 
0082 static int coalesce_reply_size(const struct ethnl_req_info *req_base,
0083                    const struct ethnl_reply_data *reply_base)
0084 {
0085     return nla_total_size(sizeof(u32)) +    /* _RX_USECS */
0086            nla_total_size(sizeof(u32)) +    /* _RX_MAX_FRAMES */
0087            nla_total_size(sizeof(u32)) +    /* _RX_USECS_IRQ */
0088            nla_total_size(sizeof(u32)) +    /* _RX_MAX_FRAMES_IRQ */
0089            nla_total_size(sizeof(u32)) +    /* _TX_USECS */
0090            nla_total_size(sizeof(u32)) +    /* _TX_MAX_FRAMES */
0091            nla_total_size(sizeof(u32)) +    /* _TX_USECS_IRQ */
0092            nla_total_size(sizeof(u32)) +    /* _TX_MAX_FRAMES_IRQ */
0093            nla_total_size(sizeof(u32)) +    /* _STATS_BLOCK_USECS */
0094            nla_total_size(sizeof(u8)) + /* _USE_ADAPTIVE_RX */
0095            nla_total_size(sizeof(u8)) + /* _USE_ADAPTIVE_TX */
0096            nla_total_size(sizeof(u32)) +    /* _PKT_RATE_LOW */
0097            nla_total_size(sizeof(u32)) +    /* _RX_USECS_LOW */
0098            nla_total_size(sizeof(u32)) +    /* _RX_MAX_FRAMES_LOW */
0099            nla_total_size(sizeof(u32)) +    /* _TX_USECS_LOW */
0100            nla_total_size(sizeof(u32)) +    /* _TX_MAX_FRAMES_LOW */
0101            nla_total_size(sizeof(u32)) +    /* _PKT_RATE_HIGH */
0102            nla_total_size(sizeof(u32)) +    /* _RX_USECS_HIGH */
0103            nla_total_size(sizeof(u32)) +    /* _RX_MAX_FRAMES_HIGH */
0104            nla_total_size(sizeof(u32)) +    /* _TX_USECS_HIGH */
0105            nla_total_size(sizeof(u32)) +    /* _TX_MAX_FRAMES_HIGH */
0106            nla_total_size(sizeof(u32)) +    /* _RATE_SAMPLE_INTERVAL */
0107            nla_total_size(sizeof(u8)) + /* _USE_CQE_MODE_TX */
0108            nla_total_size(sizeof(u8));  /* _USE_CQE_MODE_RX */
0109 }
0110 
0111 static bool coalesce_put_u32(struct sk_buff *skb, u16 attr_type, u32 val,
0112                  u32 supported_params)
0113 {
0114     if (!val && !(supported_params & attr_to_mask(attr_type)))
0115         return false;
0116     return nla_put_u32(skb, attr_type, val);
0117 }
0118 
0119 static bool coalesce_put_bool(struct sk_buff *skb, u16 attr_type, u32 val,
0120                   u32 supported_params)
0121 {
0122     if (!val && !(supported_params & attr_to_mask(attr_type)))
0123         return false;
0124     return nla_put_u8(skb, attr_type, !!val);
0125 }
0126 
0127 static int coalesce_fill_reply(struct sk_buff *skb,
0128                    const struct ethnl_req_info *req_base,
0129                    const struct ethnl_reply_data *reply_base)
0130 {
0131     const struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
0132     const struct kernel_ethtool_coalesce *kcoal = &data->kernel_coalesce;
0133     const struct ethtool_coalesce *coal = &data->coalesce;
0134     u32 supported = data->supported_params;
0135 
0136     if (coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS,
0137                  coal->rx_coalesce_usecs, supported) ||
0138         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES,
0139                  coal->rx_max_coalesced_frames, supported) ||
0140         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_IRQ,
0141                  coal->rx_coalesce_usecs_irq, supported) ||
0142         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,
0143                  coal->rx_max_coalesced_frames_irq, supported) ||
0144         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS,
0145                  coal->tx_coalesce_usecs, supported) ||
0146         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES,
0147                  coal->tx_max_coalesced_frames, supported) ||
0148         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_IRQ,
0149                  coal->tx_coalesce_usecs_irq, supported) ||
0150         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,
0151                  coal->tx_max_coalesced_frames_irq, supported) ||
0152         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,
0153                  coal->stats_block_coalesce_usecs, supported) ||
0154         coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,
0155                   coal->use_adaptive_rx_coalesce, supported) ||
0156         coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,
0157                   coal->use_adaptive_tx_coalesce, supported) ||
0158         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_PKT_RATE_LOW,
0159                  coal->pkt_rate_low, supported) ||
0160         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_LOW,
0161                  coal->rx_coalesce_usecs_low, supported) ||
0162         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,
0163                  coal->rx_max_coalesced_frames_low, supported) ||
0164         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_LOW,
0165                  coal->tx_coalesce_usecs_low, supported) ||
0166         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,
0167                  coal->tx_max_coalesced_frames_low, supported) ||
0168         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_PKT_RATE_HIGH,
0169                  coal->pkt_rate_high, supported) ||
0170         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_HIGH,
0171                  coal->rx_coalesce_usecs_high, supported) ||
0172         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,
0173                  coal->rx_max_coalesced_frames_high, supported) ||
0174         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_HIGH,
0175                  coal->tx_coalesce_usecs_high, supported) ||
0176         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
0177                  coal->tx_max_coalesced_frames_high, supported) ||
0178         coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
0179                  coal->rate_sample_interval, supported) ||
0180         coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX,
0181                   kcoal->use_cqe_mode_tx, supported) ||
0182         coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX,
0183                   kcoal->use_cqe_mode_rx, supported))
0184         return -EMSGSIZE;
0185 
0186     return 0;
0187 }
0188 
0189 const struct ethnl_request_ops ethnl_coalesce_request_ops = {
0190     .request_cmd        = ETHTOOL_MSG_COALESCE_GET,
0191     .reply_cmd      = ETHTOOL_MSG_COALESCE_GET_REPLY,
0192     .hdr_attr       = ETHTOOL_A_COALESCE_HEADER,
0193     .req_info_size      = sizeof(struct coalesce_req_info),
0194     .reply_data_size    = sizeof(struct coalesce_reply_data),
0195 
0196     .prepare_data       = coalesce_prepare_data,
0197     .reply_size     = coalesce_reply_size,
0198     .fill_reply     = coalesce_fill_reply,
0199 };
0200 
0201 /* COALESCE_SET */
0202 
0203 const struct nla_policy ethnl_coalesce_set_policy[] = {
0204     [ETHTOOL_A_COALESCE_HEADER]     =
0205         NLA_POLICY_NESTED(ethnl_header_policy),
0206     [ETHTOOL_A_COALESCE_RX_USECS]       = { .type = NLA_U32 },
0207     [ETHTOOL_A_COALESCE_RX_MAX_FRAMES]  = { .type = NLA_U32 },
0208     [ETHTOOL_A_COALESCE_RX_USECS_IRQ]   = { .type = NLA_U32 },
0209     [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ]  = { .type = NLA_U32 },
0210     [ETHTOOL_A_COALESCE_TX_USECS]       = { .type = NLA_U32 },
0211     [ETHTOOL_A_COALESCE_TX_MAX_FRAMES]  = { .type = NLA_U32 },
0212     [ETHTOOL_A_COALESCE_TX_USECS_IRQ]   = { .type = NLA_U32 },
0213     [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ]  = { .type = NLA_U32 },
0214     [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS]  = { .type = NLA_U32 },
0215     [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX]    = { .type = NLA_U8 },
0216     [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX]    = { .type = NLA_U8 },
0217     [ETHTOOL_A_COALESCE_PKT_RATE_LOW]   = { .type = NLA_U32 },
0218     [ETHTOOL_A_COALESCE_RX_USECS_LOW]   = { .type = NLA_U32 },
0219     [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW]  = { .type = NLA_U32 },
0220     [ETHTOOL_A_COALESCE_TX_USECS_LOW]   = { .type = NLA_U32 },
0221     [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW]  = { .type = NLA_U32 },
0222     [ETHTOOL_A_COALESCE_PKT_RATE_HIGH]  = { .type = NLA_U32 },
0223     [ETHTOOL_A_COALESCE_RX_USECS_HIGH]  = { .type = NLA_U32 },
0224     [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .type = NLA_U32 },
0225     [ETHTOOL_A_COALESCE_TX_USECS_HIGH]  = { .type = NLA_U32 },
0226     [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .type = NLA_U32 },
0227     [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_U32 },
0228     [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX]    = NLA_POLICY_MAX(NLA_U8, 1),
0229     [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX]    = NLA_POLICY_MAX(NLA_U8, 1),
0230 };
0231 
0232 int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info)
0233 {
0234     struct kernel_ethtool_coalesce kernel_coalesce = {};
0235     struct ethtool_coalesce coalesce = {};
0236     struct ethnl_req_info req_info = {};
0237     struct nlattr **tb = info->attrs;
0238     const struct ethtool_ops *ops;
0239     struct net_device *dev;
0240     u32 supported_params;
0241     bool mod = false;
0242     int ret;
0243     u16 a;
0244 
0245     ret = ethnl_parse_header_dev_get(&req_info,
0246                      tb[ETHTOOL_A_COALESCE_HEADER],
0247                      genl_info_net(info), info->extack,
0248                      true);
0249     if (ret < 0)
0250         return ret;
0251     dev = req_info.dev;
0252     ops = dev->ethtool_ops;
0253     ret = -EOPNOTSUPP;
0254     if (!ops->get_coalesce || !ops->set_coalesce)
0255         goto out_dev;
0256 
0257     /* make sure that only supported parameters are present */
0258     supported_params = ops->supported_coalesce_params;
0259     for (a = ETHTOOL_A_COALESCE_RX_USECS; a < __ETHTOOL_A_COALESCE_CNT; a++)
0260         if (tb[a] && !(supported_params & attr_to_mask(a))) {
0261             ret = -EINVAL;
0262             NL_SET_ERR_MSG_ATTR(info->extack, tb[a],
0263                         "cannot modify an unsupported parameter");
0264             goto out_dev;
0265         }
0266 
0267     rtnl_lock();
0268     ret = ethnl_ops_begin(dev);
0269     if (ret < 0)
0270         goto out_rtnl;
0271     ret = ops->get_coalesce(dev, &coalesce, &kernel_coalesce,
0272                 info->extack);
0273     if (ret < 0)
0274         goto out_ops;
0275 
0276     ethnl_update_u32(&coalesce.rx_coalesce_usecs,
0277              tb[ETHTOOL_A_COALESCE_RX_USECS], &mod);
0278     ethnl_update_u32(&coalesce.rx_max_coalesced_frames,
0279              tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES], &mod);
0280     ethnl_update_u32(&coalesce.rx_coalesce_usecs_irq,
0281              tb[ETHTOOL_A_COALESCE_RX_USECS_IRQ], &mod);
0282     ethnl_update_u32(&coalesce.rx_max_coalesced_frames_irq,
0283              tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ], &mod);
0284     ethnl_update_u32(&coalesce.tx_coalesce_usecs,
0285              tb[ETHTOOL_A_COALESCE_TX_USECS], &mod);
0286     ethnl_update_u32(&coalesce.tx_max_coalesced_frames,
0287              tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES], &mod);
0288     ethnl_update_u32(&coalesce.tx_coalesce_usecs_irq,
0289              tb[ETHTOOL_A_COALESCE_TX_USECS_IRQ], &mod);
0290     ethnl_update_u32(&coalesce.tx_max_coalesced_frames_irq,
0291              tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ], &mod);
0292     ethnl_update_u32(&coalesce.stats_block_coalesce_usecs,
0293              tb[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS], &mod);
0294     ethnl_update_bool32(&coalesce.use_adaptive_rx_coalesce,
0295                 tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX], &mod);
0296     ethnl_update_bool32(&coalesce.use_adaptive_tx_coalesce,
0297                 tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX], &mod);
0298     ethnl_update_u32(&coalesce.pkt_rate_low,
0299              tb[ETHTOOL_A_COALESCE_PKT_RATE_LOW], &mod);
0300     ethnl_update_u32(&coalesce.rx_coalesce_usecs_low,
0301              tb[ETHTOOL_A_COALESCE_RX_USECS_LOW], &mod);
0302     ethnl_update_u32(&coalesce.rx_max_coalesced_frames_low,
0303              tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW], &mod);
0304     ethnl_update_u32(&coalesce.tx_coalesce_usecs_low,
0305              tb[ETHTOOL_A_COALESCE_TX_USECS_LOW], &mod);
0306     ethnl_update_u32(&coalesce.tx_max_coalesced_frames_low,
0307              tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW], &mod);
0308     ethnl_update_u32(&coalesce.pkt_rate_high,
0309              tb[ETHTOOL_A_COALESCE_PKT_RATE_HIGH], &mod);
0310     ethnl_update_u32(&coalesce.rx_coalesce_usecs_high,
0311              tb[ETHTOOL_A_COALESCE_RX_USECS_HIGH], &mod);
0312     ethnl_update_u32(&coalesce.rx_max_coalesced_frames_high,
0313              tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH], &mod);
0314     ethnl_update_u32(&coalesce.tx_coalesce_usecs_high,
0315              tb[ETHTOOL_A_COALESCE_TX_USECS_HIGH], &mod);
0316     ethnl_update_u32(&coalesce.tx_max_coalesced_frames_high,
0317              tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH], &mod);
0318     ethnl_update_u32(&coalesce.rate_sample_interval,
0319              tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL], &mod);
0320     ethnl_update_u8(&kernel_coalesce.use_cqe_mode_tx,
0321             tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX], &mod);
0322     ethnl_update_u8(&kernel_coalesce.use_cqe_mode_rx,
0323             tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX], &mod);
0324     ret = 0;
0325     if (!mod)
0326         goto out_ops;
0327 
0328     ret = dev->ethtool_ops->set_coalesce(dev, &coalesce, &kernel_coalesce,
0329                          info->extack);
0330     if (ret < 0)
0331         goto out_ops;
0332     ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);
0333 
0334 out_ops:
0335     ethnl_ops_complete(dev);
0336 out_rtnl:
0337     rtnl_unlock();
0338 out_dev:
0339     ethnl_parse_header_dev_put(&req_info);
0340     return ret;
0341 }