Now that the current timestamp is saved in a variable lets add the ETHTOOL_MSG_TS_SET ethtool netlink socket to make it selectable.
Unified · Split
| @@ -227,6 +227,7 @@ Userspace to kernel: · 226 unmodified lines | |||
| 227 | ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters | 227 | ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters |
| 228 | ``ETHTOOL_MSG_TS_GET`` get current timestamping | 228 | ``ETHTOOL_MSG_TS_GET`` get current timestamping |
| 229 | ``ETHTOOL_MSG_TS_LIST_GET`` list available timestampings | 229 | ``ETHTOOL_MSG_TS_LIST_GET`` list available timestampings |
| 230 | ``ETHTOOL_MSG_TS_SET`` set current timestamping | ||
| 230 | ===================================== ================================= | 231 | ===================================== ================================= |
| 231 | 232 | ||
| 232 | Kernel to userspace: | 233 | Kernel to userspace: |
| @@ -2038,6 +2039,21 @@ Kernel response contents: · 1805 unmodified lines | |||
| 2038 | 2039 | ||
| 2039 | This command lists all the possible timestamp layer available. | 2040 | This command lists all the possible timestamp layer available. |
| 2040 | 2041 | ||
| 2042 | TS_SET | ||
| 2043 | ====== | ||
| 2044 | |||
| 2045 | Modify the selected timestamping. | ||
| 2046 | |||
| 2047 | Request contents: | ||
| 2048 | |||
| 2049 | ======================= ====== =================== | ||
| 2050 | ``ETHTOOL_A_TS_HEADER`` nested reply header | ||
| 2051 | ``ETHTOOL_A_TS_LAYER`` u32 timestamping | ||
| 2052 | ======================= ====== =================== | ||
| 2053 | |||
| 2054 | This command set the timestamping with one that should be listed by the | ||
| 2055 | TSLIST_GET command. | ||
| 2056 | |||
| 2041 | Request translation | 2057 | Request translation |
| 2042 | =================== | 2058 | =================== |
| 2043 | 2059 | ||
| @@ -2146,4 +2162,5 @@ are netlink only. · 102 unmodified lines | |||
| 2146 | n/a ``ETHTOOL_MSG_MM_SET`` | 2162 | n/a ``ETHTOOL_MSG_MM_SET`` |
| 2147 | n/a ``ETHTOOL_MSG_TS_GET`` | 2163 | n/a ``ETHTOOL_MSG_TS_GET`` |
| 2148 | n/a ``ETHTOOL_MSG_TS_LIST_GET`` | 2164 | n/a ``ETHTOOL_MSG_TS_LIST_GET`` |
| 2165 | n/a ``ETHTOOL_MSG_TS_SET`` | ||
| 2149 | =================================== ===================================== | 2166 | =================================== ===================================== |
| @@ -59,6 +59,7 @@ enum { · 58 unmodified lines | |||
| 59 | ETHTOOL_MSG_MM_SET, | 59 | ETHTOOL_MSG_MM_SET, |
| 60 | ETHTOOL_MSG_TS_GET, | 60 | ETHTOOL_MSG_TS_GET, |
| 61 | ETHTOOL_MSG_TS_LIST_GET, | 61 | ETHTOOL_MSG_TS_LIST_GET, |
| 62 | ETHTOOL_MSG_TS_SET, | ||
| 62 | 63 | ||
| 63 | /* add new constants above here */ | 64 | /* add new constants above here */ |
| 64 | __ETHTOOL_MSG_USER_CNT, | 65 | __ETHTOOL_MSG_USER_CNT, |
| @@ -308,6 +308,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { · 307 unmodified lines | |||
| 308 | [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, | 308 | [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, |
| 309 | [ETHTOOL_MSG_TS_GET] = ðnl_ts_request_ops, | 309 | [ETHTOOL_MSG_TS_GET] = ðnl_ts_request_ops, |
| 310 | [ETHTOOL_MSG_TS_LIST_GET] = ðnl_ts_list_request_ops, | 310 | [ETHTOOL_MSG_TS_LIST_GET] = ðnl_ts_list_request_ops, |
| 311 | [ETHTOOL_MSG_TS_SET] = ðnl_ts_request_ops, | ||
| 311 | }; | 312 | }; |
| 312 | 313 | ||
| 313 | static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) | 314 | static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) |
| @@ -1148,6 +1149,13 @@ static const struct genl_ops ethtool_genl_ops[] = { · 834 unmodified lines | |||
| 1148 | .policy = ethnl_ts_get_policy, | 1149 | .policy = ethnl_ts_get_policy, |
| 1149 | .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, | 1150 | .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1, |
| 1150 | }, | 1151 | }, |
| 1152 | { | ||
| 1153 | .cmd = ETHTOOL_MSG_TS_SET, | ||
| 1154 | .flags = GENL_UNS_ADMIN_PERM, | ||
| 1155 | .doit = ethnl_default_set_doit, | ||
| 1156 | .policy = ethnl_ts_set_policy, | ||
| 1157 | .maxattr = ARRAY_SIZE(ethnl_ts_set_policy) - 1, | ||
| 1158 | }, | ||
| 1151 | }; | 1159 | }; |
| 1152 | 1160 | ||
| 1153 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { | 1161 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { |
| @@ -444,6 +444,7 @@ extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADE · 443 unmodified lines | |||
| 444 | extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; | 444 | extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; |
| 445 | extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; | 445 | extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; |
| 446 | extern const struct nla_policy ethnl_ts_get_policy[ETHTOOL_A_TS_HEADER + 1]; | 446 | extern const struct nla_policy ethnl_ts_get_policy[ETHTOOL_A_TS_HEADER + 1]; |
| 447 | extern const struct nla_policy ethnl_ts_set_policy[ETHTOOL_A_TS_MAX + 1]; | ||
| 447 | 448 | ||
| 448 | int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); | 449 | int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); |
| 449 | int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); | 450 | int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); |
| @@ -59,6 +59,102 @@ static int ts_fill_reply(struct sk_buff *skb, · 58 unmodified lines | |||
| 59 | return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer); | 59 | return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | /* TS_SET */ | ||
| 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) | ||
| 67 | }; | ||
| 68 | |||
| 69 | static int ethnl_set_ts_validate(struct ethnl_req_info *req_info, | ||
| 70 | struct genl_info *info) | ||
| 71 | { | ||
| 72 | struct nlattr **tb = info->attrs; | ||
| 73 | const struct net_device_ops *ops = req_info->dev->netdev_ops; | ||
| 74 | |||
| 75 | if (!ops->ndo_hwtstamp_set) | ||
| 76 | return -EOPNOTSUPP; | ||
| 77 | |||
| 78 | if (!tb[ETHTOOL_A_TS_LAYER]) | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | return 1; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int ethnl_set_ts(struct ethnl_req_info *req_info, struct genl_info *info) | ||
| 85 | { | ||
| 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; | ||
| 91 | bool mod = false; | ||
| 92 | int ret; | ||
| 93 | |||
| 94 | ts_layer = dev->ts_layer; | ||
| 95 | ethnl_update_u32(&ts_layer, tb[ETHTOOL_A_TS_LAYER], &mod); | ||
| 96 | |||
| 97 | if (!mod) | ||
| 98 | return 0; | ||
| 99 | |||
| 100 | if (ts_layer == SOFTWARE_TIMESTAMPING) { | ||
| 101 | struct ethtool_ts_info ts_info = {0}; | ||
| 102 | |||
| 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"); | ||
| 107 | return -EINVAL; | ||
| 108 | } | ||
| 109 | |||
| 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"); | ||
| 117 | return -EINVAL; | ||
| 118 | } | ||
| 119 | } else if (ts_layer == MAC_TIMESTAMPING) { | ||
| 120 | struct ethtool_ts_info ts_info = {0}; | ||
| 121 | |||
| 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"); | ||
| 126 | return -EINVAL; | ||
| 127 | } | ||
| 128 | |||
| 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"); | ||
| 136 | return -EINVAL; | ||
| 137 | } | ||
| 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"); | ||
| 141 | return -EINVAL; | ||
| 142 | } | ||
| 143 | |||
| 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); | ||
| 149 | if (ret < 0) | ||
| 150 | return ret; | ||
| 151 | } | ||
| 152 | |||
| 153 | dev->ts_layer = ts_layer; | ||
| 154 | |||
| 155 | return 1; | ||
| 156 | } | ||
| 157 | |||
| 62 | const struct ethnl_request_ops ethnl_ts_request_ops = { | 158 | const struct ethnl_request_ops ethnl_ts_request_ops = { |
| 63 | .request_cmd = ETHTOOL_MSG_TS_GET, | 159 | .request_cmd = ETHTOOL_MSG_TS_GET, |
| 64 | .reply_cmd = ETHTOOL_MSG_TS_GET_REPLY, | 160 | .reply_cmd = ETHTOOL_MSG_TS_GET_REPLY, |
| @@ -69,6 +165,9 @@ const struct ethnl_request_ops ethnl_ts_request_ops = { · 4 unmodified lines | |||
| 69 | .prepare_data = ts_prepare_data, | 165 | .prepare_data = ts_prepare_data, |
| 70 | .reply_size = ts_reply_size, | 166 | .reply_size = ts_reply_size, |
| 71 | .fill_reply = ts_fill_reply, | 167 | .fill_reply = ts_fill_reply, |
| 168 | |||
| 169 | .set_validate = ethnl_set_ts_validate, | ||
| 170 | .set = ethnl_set_ts, | ||
| 72 | }; | 171 | }; |
| 73 | 172 | ||
| 74 | /* TS_LIST_GET */ | 173 | /* TS_LIST_GET */ |