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