eee.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include "netlink.h"
  3. #include "common.h"
  4. #include "bitset.h"
  5. struct eee_req_info {
  6. struct ethnl_req_info base;
  7. };
  8. struct eee_reply_data {
  9. struct ethnl_reply_data base;
  10. struct ethtool_keee eee;
  11. };
  12. #define EEE_REPDATA(__reply_base) \
  13. container_of(__reply_base, struct eee_reply_data, base)
  14. const struct nla_policy ethnl_eee_get_policy[] = {
  15. [ETHTOOL_A_EEE_HEADER] =
  16. NLA_POLICY_NESTED(ethnl_header_policy),
  17. };
  18. static int eee_prepare_data(const struct ethnl_req_info *req_base,
  19. struct ethnl_reply_data *reply_base,
  20. const struct genl_info *info)
  21. {
  22. struct eee_reply_data *data = EEE_REPDATA(reply_base);
  23. struct net_device *dev = reply_base->dev;
  24. struct ethtool_keee *eee = &data->eee;
  25. int ret;
  26. if (!dev->ethtool_ops->get_eee)
  27. return -EOPNOTSUPP;
  28. ret = ethnl_ops_begin(dev);
  29. if (ret < 0)
  30. return ret;
  31. ret = dev->ethtool_ops->get_eee(dev, eee);
  32. ethnl_ops_complete(dev);
  33. return ret;
  34. }
  35. static int eee_reply_size(const struct ethnl_req_info *req_base,
  36. const struct ethnl_reply_data *reply_base)
  37. {
  38. bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
  39. const struct eee_reply_data *data = EEE_REPDATA(reply_base);
  40. const struct ethtool_keee *eee = &data->eee;
  41. int len = 0;
  42. int ret;
  43. /* MODES_OURS */
  44. ret = ethnl_bitset_size(eee->advertised, eee->supported,
  45. __ETHTOOL_LINK_MODE_MASK_NBITS,
  46. link_mode_names, compact);
  47. if (ret < 0)
  48. return ret;
  49. len += ret;
  50. /* MODES_PEERS */
  51. ret = ethnl_bitset_size(eee->lp_advertised, NULL,
  52. __ETHTOOL_LINK_MODE_MASK_NBITS,
  53. link_mode_names, compact);
  54. if (ret < 0)
  55. return ret;
  56. len += ret;
  57. len += nla_total_size(sizeof(u8)) + /* _EEE_ACTIVE */
  58. nla_total_size(sizeof(u8)) + /* _EEE_ENABLED */
  59. nla_total_size(sizeof(u8)) + /* _EEE_TX_LPI_ENABLED */
  60. nla_total_size(sizeof(u32)); /* _EEE_TX_LPI_TIMER */
  61. return len;
  62. }
  63. static int eee_fill_reply(struct sk_buff *skb,
  64. const struct ethnl_req_info *req_base,
  65. const struct ethnl_reply_data *reply_base)
  66. {
  67. bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
  68. const struct eee_reply_data *data = EEE_REPDATA(reply_base);
  69. const struct ethtool_keee *eee = &data->eee;
  70. int ret;
  71. ret = ethnl_put_bitset(skb, ETHTOOL_A_EEE_MODES_OURS,
  72. eee->advertised, eee->supported,
  73. __ETHTOOL_LINK_MODE_MASK_NBITS,
  74. link_mode_names, compact);
  75. if (ret < 0)
  76. return ret;
  77. ret = ethnl_put_bitset(skb, ETHTOOL_A_EEE_MODES_PEER,
  78. eee->lp_advertised, NULL,
  79. __ETHTOOL_LINK_MODE_MASK_NBITS,
  80. link_mode_names, compact);
  81. if (ret < 0)
  82. return ret;
  83. if (nla_put_u8(skb, ETHTOOL_A_EEE_ACTIVE, eee->eee_active) ||
  84. nla_put_u8(skb, ETHTOOL_A_EEE_ENABLED, eee->eee_enabled) ||
  85. nla_put_u8(skb, ETHTOOL_A_EEE_TX_LPI_ENABLED,
  86. eee->tx_lpi_enabled) ||
  87. nla_put_u32(skb, ETHTOOL_A_EEE_TX_LPI_TIMER, eee->tx_lpi_timer))
  88. return -EMSGSIZE;
  89. return 0;
  90. }
  91. /* EEE_SET */
  92. const struct nla_policy ethnl_eee_set_policy[] = {
  93. [ETHTOOL_A_EEE_HEADER] =
  94. NLA_POLICY_NESTED(ethnl_header_policy),
  95. [ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_NESTED },
  96. [ETHTOOL_A_EEE_ENABLED] = { .type = NLA_U8 },
  97. [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_U8 },
  98. [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_U32 },
  99. };
  100. static int
  101. ethnl_set_eee_validate(struct ethnl_req_info *req_info, struct genl_info *info)
  102. {
  103. const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
  104. return ops->get_eee && ops->set_eee ? 1 : -EOPNOTSUPP;
  105. }
  106. static int
  107. ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info)
  108. {
  109. struct net_device *dev = req_info->dev;
  110. struct nlattr **tb = info->attrs;
  111. struct ethtool_keee eee = {};
  112. bool mod = false;
  113. int ret;
  114. ret = dev->ethtool_ops->get_eee(dev, &eee);
  115. if (ret < 0)
  116. return ret;
  117. ret = ethnl_update_bitset(eee.advertised,
  118. __ETHTOOL_LINK_MODE_MASK_NBITS,
  119. tb[ETHTOOL_A_EEE_MODES_OURS],
  120. link_mode_names, info->extack, &mod);
  121. if (ret < 0)
  122. return ret;
  123. ethnl_update_bool(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod);
  124. ethnl_update_bool(&eee.tx_lpi_enabled, tb[ETHTOOL_A_EEE_TX_LPI_ENABLED],
  125. &mod);
  126. ethnl_update_u32(&eee.tx_lpi_timer, tb[ETHTOOL_A_EEE_TX_LPI_TIMER],
  127. &mod);
  128. if (!mod)
  129. return 0;
  130. ret = dev->ethtool_ops->set_eee(dev, &eee);
  131. return ret < 0 ? ret : 1;
  132. }
  133. const struct ethnl_request_ops ethnl_eee_request_ops = {
  134. .request_cmd = ETHTOOL_MSG_EEE_GET,
  135. .reply_cmd = ETHTOOL_MSG_EEE_GET_REPLY,
  136. .hdr_attr = ETHTOOL_A_EEE_HEADER,
  137. .req_info_size = sizeof(struct eee_req_info),
  138. .reply_data_size = sizeof(struct eee_reply_data),
  139. .prepare_data = eee_prepare_data,
  140. .reply_size = eee_reply_size,
  141. .fill_reply = eee_fill_reply,
  142. .set_validate = ethnl_set_eee_validate,
  143. .set = ethnl_set_eee,
  144. .set_ntf_cmd = ETHTOOL_MSG_EEE_NTF,
  145. };