1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/net_tstamp.h>
11 struct ethnl_req_info base;
14 struct ts_reply_data {
15 struct ethnl_reply_data base;
16 enum timestamping_layer ts_layer;
19 #define TS_REPDATA(__reply_base) \
20 container_of(__reply_base, struct ts_reply_data, base)
23 const struct nla_policy ethnl_ts_get_policy[] = {
24 [ETHTOOL_A_TS_HEADER] =
25 NLA_POLICY_NESTED(ethnl_header_policy),
28 static int ts_prepare_data(const struct ethnl_req_info *req_base,
29 struct ethnl_reply_data *reply_base,
30 const struct genl_info *info)
32 struct ts_reply_data *data = TS_REPDATA(reply_base);
33 struct net_device *dev = reply_base->dev;
36 ret = ethnl_ops_begin(dev);
40 data->ts_layer = dev->ts_layer;
42 ethnl_ops_complete(dev);
47 static int ts_reply_size(const struct ethnl_req_info *req_base,
48 const struct ethnl_reply_data *reply_base)
50 return nla_total_size(sizeof(u32));
53 static int ts_fill_reply(struct sk_buff *skb,
54 const struct ethnl_req_info *req_base,
55 const struct ethnl_reply_data *reply_base)
57 struct ts_reply_data *data = TS_REPDATA(reply_base);
59 return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer);
63 const struct nla_policy ethnl_ts_set_policy[] = {
64 [ETHTOOL_A_TS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
65 [ETHTOOL_A_TS_LAYER] = NLA_POLICY_RANGE(NLA_U32, 0,
66 __TIMESTAMPING_COUNT - 1)
69 static int ethnl_set_ts_validate(struct ethnl_req_info *req_info,
70 struct genl_info *info)
72 struct nlattr **tb = info->attrs;
73 const struct net_device_ops *ops = req_info->dev->netdev_ops;
75 if (!ops->ndo_hwtstamp_set)
78 if (!tb[ETHTOOL_A_TS_LAYER])
84 static int ethnl_set_ts(struct ethnl_req_info *req_info, struct genl_info *info)
86 struct net_device *dev = req_info->dev;
87 const struct ethtool_ops *ops = dev->ethtool_ops;
88 struct kernel_hwtstamp_config config = {0};
89 struct nlattr **tb = info->attrs;
90 enum timestamping_layer ts_layer;
94 ts_layer = dev->ts_layer;
95 ethnl_update_u32(&ts_layer, tb[ETHTOOL_A_TS_LAYER], &mod);
100 if (ts_layer == SOFTWARE_TIMESTAMPING) {
101 struct ethtool_ts_info ts_info = {0};
103 if (!ops->get_ts_info) {
104 NL_SET_ERR_MSG_ATTR(info->extack,
105 tb[ETHTOOL_A_TS_LAYER],
106 "this net device cannot support timestamping");
110 ops->get_ts_info(dev, &ts_info);
111 if ((ts_info.so_timestamping &
112 SOF_TIMESTAMPING_SOFTWARE_MASK) !=
113 SOF_TIMESTAMPING_SOFTWARE_MASK) {
114 NL_SET_ERR_MSG_ATTR(info->extack,
115 tb[ETHTOOL_A_TS_LAYER],
116 "this net device cannot support software timestamping");
119 } else if (ts_layer == MAC_TIMESTAMPING) {
120 struct ethtool_ts_info ts_info = {0};
122 if (!ops->get_ts_info) {
123 NL_SET_ERR_MSG_ATTR(info->extack,
124 tb[ETHTOOL_A_TS_LAYER],
125 "this net device cannot support timestamping");
129 ops->get_ts_info(dev, &ts_info);
130 if ((ts_info.so_timestamping &
131 SOF_TIMESTAMPING_HARDWARE_MASK) !=
132 SOF_TIMESTAMPING_HARDWARE_MASK) {
133 NL_SET_ERR_MSG_ATTR(info->extack,
134 tb[ETHTOOL_A_TS_LAYER],
135 "this net device cannot support hardware timestamping");
138 } else if (ts_layer == PHY_TIMESTAMPING && !phy_has_tsinfo(dev->phydev)) {
139 NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_TS_LAYER],
140 "this phy device cannot support timestamping");
144 /* Disable time stamping in the current layer. */
145 if (netif_device_present(dev) &&
146 (dev->ts_layer == PHY_TIMESTAMPING ||
147 dev->ts_layer == MAC_TIMESTAMPING)) {
148 ret = dev_set_hwtstamp_phylib(dev, &config, info->extack);
153 dev->ts_layer = ts_layer;
158 const struct ethnl_request_ops ethnl_ts_request_ops = {
159 .request_cmd = ETHTOOL_MSG_TS_GET,
160 .reply_cmd = ETHTOOL_MSG_TS_GET_REPLY,
161 .hdr_attr = ETHTOOL_A_TS_HEADER,
162 .req_info_size = sizeof(struct ts_req_info),
163 .reply_data_size = sizeof(struct ts_reply_data),
165 .prepare_data = ts_prepare_data,
166 .reply_size = ts_reply_size,
167 .fill_reply = ts_fill_reply,
169 .set_validate = ethnl_set_ts_validate,
174 struct ts_list_reply_data {
175 struct ethnl_reply_data base;
176 enum timestamping_layer ts_layer[__TIMESTAMPING_COUNT];
180 #define TS_LIST_REPDATA(__reply_base) \
181 container_of(__reply_base, struct ts_list_reply_data, base)
183 static int ts_list_prepare_data(const struct ethnl_req_info *req_base,
184 struct ethnl_reply_data *reply_base,
185 const struct genl_info *info)
187 struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base);
188 struct net_device *dev = reply_base->dev;
189 const struct ethtool_ops *ops = dev->ethtool_ops;
192 ret = ethnl_ops_begin(dev);
196 if (phy_has_tsinfo(dev->phydev))
197 data->ts_layer[i++] = PHY_TIMESTAMPING;
198 if (ops->get_ts_info) {
199 struct ethtool_ts_info ts_info = {0};
201 ops->get_ts_info(dev, &ts_info);
202 if (ts_info.so_timestamping &
203 SOF_TIMESTAMPING_HARDWARE_MASK)
204 data->ts_layer[i++] = MAC_TIMESTAMPING;
206 if (ts_info.so_timestamping &
207 SOF_TIMESTAMPING_SOFTWARE_MASK)
208 data->ts_layer[i++] = SOFTWARE_TIMESTAMPING;
212 ethnl_ops_complete(dev);
217 static int ts_list_reply_size(const struct ethnl_req_info *req_base,
218 const struct ethnl_reply_data *reply_base)
220 struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base);
222 return nla_total_size(sizeof(u32)) * data->num_ts;
225 static int ts_list_fill_reply(struct sk_buff *skb,
226 const struct ethnl_req_info *req_base,
227 const struct ethnl_reply_data *reply_base)
229 struct ts_list_reply_data *data = TS_LIST_REPDATA(reply_base);
231 return nla_put(skb, ETHTOOL_A_TS_LIST_LAYER, sizeof(u32) * data->num_ts, data->ts_layer);
234 const struct ethnl_request_ops ethnl_ts_list_request_ops = {
235 .request_cmd = ETHTOOL_MSG_TS_LIST_GET,
236 .reply_cmd = ETHTOOL_MSG_TS_LIST_GET_REPLY,
237 .hdr_attr = ETHTOOL_A_TS_HEADER,
238 .req_info_size = sizeof(struct ts_req_info),
239 .reply_data_size = sizeof(struct ts_list_reply_data),
241 .prepare_data = ts_list_prepare_data,
242 .reply_size = ts_list_reply_size,
243 .fill_reply = ts_list_fill_reply,