1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/net_tstamp.h>
9 struct tsinfo_req_info
{
10 struct ethnl_req_info base
;
13 struct tsinfo_reply_data
{
14 struct ethnl_reply_data base
;
15 struct kernel_ethtool_ts_info ts_info
;
16 struct ethtool_ts_stats stats
;
19 #define TSINFO_REPDATA(__reply_base) \
20 container_of(__reply_base, struct tsinfo_reply_data, base)
22 #define ETHTOOL_TS_STAT_CNT \
23 (__ETHTOOL_A_TS_STAT_CNT - (ETHTOOL_A_TS_STAT_UNSPEC + 1))
25 const struct nla_policy ethnl_tsinfo_get_policy
[] = {
26 [ETHTOOL_A_TSINFO_HEADER
] =
27 NLA_POLICY_NESTED(ethnl_header_policy_stats
),
30 static int tsinfo_prepare_data(const struct ethnl_req_info
*req_base
,
31 struct ethnl_reply_data
*reply_base
,
32 const struct genl_info
*info
)
34 struct tsinfo_reply_data
*data
= TSINFO_REPDATA(reply_base
);
35 struct net_device
*dev
= reply_base
->dev
;
38 ret
= ethnl_ops_begin(dev
);
41 if (req_base
->flags
& ETHTOOL_FLAG_STATS
) {
42 ethtool_stats_init((u64
*)&data
->stats
,
43 sizeof(data
->stats
) / sizeof(u64
));
44 if (dev
->ethtool_ops
->get_ts_stats
)
45 dev
->ethtool_ops
->get_ts_stats(dev
, &data
->stats
);
47 ret
= __ethtool_get_ts_info(dev
, &data
->ts_info
);
48 ethnl_ops_complete(dev
);
53 static int tsinfo_reply_size(const struct ethnl_req_info
*req_base
,
54 const struct ethnl_reply_data
*reply_base
)
56 const struct tsinfo_reply_data
*data
= TSINFO_REPDATA(reply_base
);
57 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
58 const struct kernel_ethtool_ts_info
*ts_info
= &data
->ts_info
;
62 BUILD_BUG_ON(__SOF_TIMESTAMPING_CNT
> 32);
63 BUILD_BUG_ON(__HWTSTAMP_TX_CNT
> 32);
64 BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT
> 32);
66 if (ts_info
->so_timestamping
) {
67 ret
= ethnl_bitset32_size(&ts_info
->so_timestamping
, NULL
,
68 __SOF_TIMESTAMPING_CNT
,
69 sof_timestamping_names
, compact
);
72 len
+= ret
; /* _TSINFO_TIMESTAMPING */
74 if (ts_info
->tx_types
) {
75 ret
= ethnl_bitset32_size(&ts_info
->tx_types
, NULL
,
77 ts_tx_type_names
, compact
);
80 len
+= ret
; /* _TSINFO_TX_TYPES */
82 if (ts_info
->rx_filters
) {
83 ret
= ethnl_bitset32_size(&ts_info
->rx_filters
, NULL
,
84 __HWTSTAMP_FILTER_CNT
,
85 ts_rx_filter_names
, compact
);
88 len
+= ret
; /* _TSINFO_RX_FILTERS */
90 if (ts_info
->phc_index
>= 0)
91 len
+= nla_total_size(sizeof(u32
)); /* _TSINFO_PHC_INDEX */
92 if (req_base
->flags
& ETHTOOL_FLAG_STATS
)
93 len
+= nla_total_size(0) + /* _TSINFO_STATS */
94 nla_total_size_64bit(sizeof(u64
)) * ETHTOOL_TS_STAT_CNT
;
99 static int tsinfo_put_stat(struct sk_buff
*skb
, u64 val
, u16 attrtype
)
101 if (val
== ETHTOOL_STAT_NOT_SET
)
103 if (nla_put_uint(skb
, attrtype
, val
))
108 static int tsinfo_put_stats(struct sk_buff
*skb
,
109 const struct ethtool_ts_stats
*stats
)
113 nest
= nla_nest_start(skb
, ETHTOOL_A_TSINFO_STATS
);
117 if (tsinfo_put_stat(skb
, stats
->tx_stats
.pkts
,
118 ETHTOOL_A_TS_STAT_TX_PKTS
) ||
119 tsinfo_put_stat(skb
, stats
->tx_stats
.lost
,
120 ETHTOOL_A_TS_STAT_TX_LOST
) ||
121 tsinfo_put_stat(skb
, stats
->tx_stats
.err
,
122 ETHTOOL_A_TS_STAT_TX_ERR
))
125 nla_nest_end(skb
, nest
);
129 nla_nest_cancel(skb
, nest
);
133 static int tsinfo_fill_reply(struct sk_buff
*skb
,
134 const struct ethnl_req_info
*req_base
,
135 const struct ethnl_reply_data
*reply_base
)
137 const struct tsinfo_reply_data
*data
= TSINFO_REPDATA(reply_base
);
138 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
139 const struct kernel_ethtool_ts_info
*ts_info
= &data
->ts_info
;
142 if (ts_info
->so_timestamping
) {
143 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_TSINFO_TIMESTAMPING
,
144 &ts_info
->so_timestamping
, NULL
,
145 __SOF_TIMESTAMPING_CNT
,
146 sof_timestamping_names
, compact
);
150 if (ts_info
->tx_types
) {
151 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_TSINFO_TX_TYPES
,
152 &ts_info
->tx_types
, NULL
,
154 ts_tx_type_names
, compact
);
158 if (ts_info
->rx_filters
) {
159 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_TSINFO_RX_FILTERS
,
160 &ts_info
->rx_filters
, NULL
,
161 __HWTSTAMP_FILTER_CNT
,
162 ts_rx_filter_names
, compact
);
166 if (ts_info
->phc_index
>= 0 &&
167 nla_put_u32(skb
, ETHTOOL_A_TSINFO_PHC_INDEX
, ts_info
->phc_index
))
169 if (req_base
->flags
& ETHTOOL_FLAG_STATS
&&
170 tsinfo_put_stats(skb
, &data
->stats
))
176 const struct ethnl_request_ops ethnl_tsinfo_request_ops
= {
177 .request_cmd
= ETHTOOL_MSG_TSINFO_GET
,
178 .reply_cmd
= ETHTOOL_MSG_TSINFO_GET_REPLY
,
179 .hdr_attr
= ETHTOOL_A_TSINFO_HEADER
,
180 .req_info_size
= sizeof(struct tsinfo_req_info
),
181 .reply_data_size
= sizeof(struct tsinfo_reply_data
),
183 .prepare_data
= tsinfo_prepare_data
,
184 .reply_size
= tsinfo_reply_size
,
185 .fill_reply
= tsinfo_fill_reply
,