tsinfo.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/net_tstamp.h>
  3. #include "netlink.h"
  4. #include "common.h"
  5. #include "bitset.h"
  6. struct tsinfo_req_info {
  7. struct ethnl_req_info base;
  8. };
  9. struct tsinfo_reply_data {
  10. struct ethnl_reply_data base;
  11. struct ethtool_ts_info ts_info;
  12. };
  13. #define TSINFO_REPDATA(__reply_base) \
  14. container_of(__reply_base, struct tsinfo_reply_data, base)
  15. const struct nla_policy ethnl_tsinfo_get_policy[] = {
  16. [ETHTOOL_A_TSINFO_HEADER] =
  17. NLA_POLICY_NESTED(ethnl_header_policy),
  18. };
  19. static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
  20. struct ethnl_reply_data *reply_base,
  21. struct genl_info *info)
  22. {
  23. struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
  24. struct net_device *dev = reply_base->dev;
  25. int ret;
  26. ret = ethnl_ops_begin(dev);
  27. if (ret < 0)
  28. return ret;
  29. ret = __ethtool_get_ts_info(dev, &data->ts_info);
  30. ethnl_ops_complete(dev);
  31. return ret;
  32. }
  33. static int tsinfo_reply_size(const struct ethnl_req_info *req_base,
  34. const struct ethnl_reply_data *reply_base)
  35. {
  36. const struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
  37. bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
  38. const struct ethtool_ts_info *ts_info = &data->ts_info;
  39. int len = 0;
  40. int ret;
  41. BUILD_BUG_ON(__SOF_TIMESTAMPING_CNT > 32);
  42. BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32);
  43. BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32);
  44. if (ts_info->so_timestamping) {
  45. ret = ethnl_bitset32_size(&ts_info->so_timestamping, NULL,
  46. __SOF_TIMESTAMPING_CNT,
  47. sof_timestamping_names, compact);
  48. if (ret < 0)
  49. return ret;
  50. len += ret; /* _TSINFO_TIMESTAMPING */
  51. }
  52. if (ts_info->tx_types) {
  53. ret = ethnl_bitset32_size(&ts_info->tx_types, NULL,
  54. __HWTSTAMP_TX_CNT,
  55. ts_tx_type_names, compact);
  56. if (ret < 0)
  57. return ret;
  58. len += ret; /* _TSINFO_TX_TYPES */
  59. }
  60. if (ts_info->rx_filters) {
  61. ret = ethnl_bitset32_size(&ts_info->rx_filters, NULL,
  62. __HWTSTAMP_FILTER_CNT,
  63. ts_rx_filter_names, compact);
  64. if (ret < 0)
  65. return ret;
  66. len += ret; /* _TSINFO_RX_FILTERS */
  67. }
  68. if (ts_info->phc_index >= 0)
  69. len += nla_total_size(sizeof(u32)); /* _TSINFO_PHC_INDEX */
  70. return len;
  71. }
  72. static int tsinfo_fill_reply(struct sk_buff *skb,
  73. const struct ethnl_req_info *req_base,
  74. const struct ethnl_reply_data *reply_base)
  75. {
  76. const struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
  77. bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
  78. const struct ethtool_ts_info *ts_info = &data->ts_info;
  79. int ret;
  80. if (ts_info->so_timestamping) {
  81. ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_TIMESTAMPING,
  82. &ts_info->so_timestamping, NULL,
  83. __SOF_TIMESTAMPING_CNT,
  84. sof_timestamping_names, compact);
  85. if (ret < 0)
  86. return ret;
  87. }
  88. if (ts_info->tx_types) {
  89. ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_TX_TYPES,
  90. &ts_info->tx_types, NULL,
  91. __HWTSTAMP_TX_CNT,
  92. ts_tx_type_names, compact);
  93. if (ret < 0)
  94. return ret;
  95. }
  96. if (ts_info->rx_filters) {
  97. ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_RX_FILTERS,
  98. &ts_info->rx_filters, NULL,
  99. __HWTSTAMP_FILTER_CNT,
  100. ts_rx_filter_names, compact);
  101. if (ret < 0)
  102. return ret;
  103. }
  104. if (ts_info->phc_index >= 0 &&
  105. nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX, ts_info->phc_index))
  106. return -EMSGSIZE;
  107. return 0;
  108. }
  109. const struct ethnl_request_ops ethnl_tsinfo_request_ops = {
  110. .request_cmd = ETHTOOL_MSG_TSINFO_GET,
  111. .reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY,
  112. .hdr_attr = ETHTOOL_A_TSINFO_HEADER,
  113. .req_info_size = sizeof(struct tsinfo_req_info),
  114. .reply_data_size = sizeof(struct tsinfo_reply_data),
  115. .prepare_data = tsinfo_prepare_data,
  116. .reply_size = tsinfo_reply_size,
  117. .fill_reply = tsinfo_fill_reply,
  118. };