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 ethtool_ts_info ts_info
;
18 #define TSINFO_REPDATA(__reply_base) \
19 container_of(__reply_base, struct tsinfo_reply_data, base)
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
},
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
)
35 struct tsinfo_reply_data
*data
= TSINFO_REPDATA(reply_base
);
36 struct net_device
*dev
= reply_base
->dev
;
39 ret
= ethnl_ops_begin(dev
);
42 ret
= __ethtool_get_ts_info(dev
, &data
->ts_info
);
43 ethnl_ops_complete(dev
);
48 static int tsinfo_reply_size(const struct ethnl_req_info
*req_base
,
49 const struct ethnl_reply_data
*reply_base
)
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
;
57 BUILD_BUG_ON(__SOF_TIMESTAMPING_CNT
> 32);
58 BUILD_BUG_ON(__HWTSTAMP_TX_CNT
> 32);
59 BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT
> 32);
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
);
67 len
+= ret
; /* _TSINFO_TIMESTAMPING */
69 if (ts_info
->tx_types
) {
70 ret
= ethnl_bitset32_size(&ts_info
->tx_types
, NULL
,
72 ts_tx_type_names
, compact
);
75 len
+= ret
; /* _TSINFO_TX_TYPES */
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
);
83 len
+= ret
; /* _TSINFO_RX_FILTERS */
85 if (ts_info
->phc_index
>= 0)
86 len
+= nla_total_size(sizeof(u32
)); /* _TSINFO_PHC_INDEX */
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
)
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
;
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
);
108 if (ts_info
->tx_types
) {
109 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_TSINFO_TX_TYPES
,
110 &ts_info
->tx_types
, NULL
,
112 ts_tx_type_names
, compact
);
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
);
124 if (ts_info
->phc_index
>= 0 &&
125 nla_put_u32(skb
, ETHTOOL_A_TSINFO_PHC_INDEX
, ts_info
->phc_index
))
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
,
140 .prepare_data
= tsinfo_prepare_data
,
141 .reply_size
= tsinfo_reply_size
,
142 .fill_reply
= tsinfo_fill_reply
,