1 // SPDX-License-Identifier: GPL-2.0-only
6 struct pause_req_info
{
7 struct ethnl_req_info base
;
10 struct pause_reply_data
{
11 struct ethnl_reply_data base
;
12 struct ethtool_pauseparam pauseparam
;
13 struct ethtool_pause_stats pausestat
;
16 #define PAUSE_REPDATA(__reply_base) \
17 container_of(__reply_base, struct pause_reply_data, base)
19 const struct nla_policy ethnl_pause_get_policy
[] = {
20 [ETHTOOL_A_PAUSE_HEADER
] =
21 NLA_POLICY_NESTED(ethnl_header_policy_stats
),
24 static int pause_prepare_data(const struct ethnl_req_info
*req_base
,
25 struct ethnl_reply_data
*reply_base
,
26 struct genl_info
*info
)
28 struct pause_reply_data
*data
= PAUSE_REPDATA(reply_base
);
29 struct net_device
*dev
= reply_base
->dev
;
32 if (!dev
->ethtool_ops
->get_pauseparam
)
35 ethtool_stats_init((u64
*)&data
->pausestat
,
36 sizeof(data
->pausestat
) / 8);
38 ret
= ethnl_ops_begin(dev
);
41 dev
->ethtool_ops
->get_pauseparam(dev
, &data
->pauseparam
);
42 if (req_base
->flags
& ETHTOOL_FLAG_STATS
&&
43 dev
->ethtool_ops
->get_pause_stats
)
44 dev
->ethtool_ops
->get_pause_stats(dev
, &data
->pausestat
);
45 ethnl_ops_complete(dev
);
50 static int pause_reply_size(const struct ethnl_req_info
*req_base
,
51 const struct ethnl_reply_data
*reply_base
)
53 int n
= nla_total_size(sizeof(u8
)) + /* _PAUSE_AUTONEG */
54 nla_total_size(sizeof(u8
)) + /* _PAUSE_RX */
55 nla_total_size(sizeof(u8
)); /* _PAUSE_TX */
57 if (req_base
->flags
& ETHTOOL_FLAG_STATS
)
58 n
+= nla_total_size(0) + /* _PAUSE_STATS */
59 nla_total_size_64bit(sizeof(u64
)) * ETHTOOL_PAUSE_STAT_CNT
;
63 static int ethtool_put_stat(struct sk_buff
*skb
, u64 val
, u16 attrtype
,
66 if (val
== ETHTOOL_STAT_NOT_SET
)
68 if (nla_put_u64_64bit(skb
, attrtype
, val
, padtype
))
74 static int pause_put_stats(struct sk_buff
*skb
,
75 const struct ethtool_pause_stats
*pause_stats
)
77 const u16 pad
= ETHTOOL_A_PAUSE_STAT_PAD
;
80 nest
= nla_nest_start(skb
, ETHTOOL_A_PAUSE_STATS
);
84 if (ethtool_put_stat(skb
, pause_stats
->tx_pause_frames
,
85 ETHTOOL_A_PAUSE_STAT_TX_FRAMES
, pad
) ||
86 ethtool_put_stat(skb
, pause_stats
->rx_pause_frames
,
87 ETHTOOL_A_PAUSE_STAT_RX_FRAMES
, pad
))
90 nla_nest_end(skb
, nest
);
94 nla_nest_cancel(skb
, nest
);
98 static int pause_fill_reply(struct sk_buff
*skb
,
99 const struct ethnl_req_info
*req_base
,
100 const struct ethnl_reply_data
*reply_base
)
102 const struct pause_reply_data
*data
= PAUSE_REPDATA(reply_base
);
103 const struct ethtool_pauseparam
*pauseparam
= &data
->pauseparam
;
105 if (nla_put_u8(skb
, ETHTOOL_A_PAUSE_AUTONEG
, !!pauseparam
->autoneg
) ||
106 nla_put_u8(skb
, ETHTOOL_A_PAUSE_RX
, !!pauseparam
->rx_pause
) ||
107 nla_put_u8(skb
, ETHTOOL_A_PAUSE_TX
, !!pauseparam
->tx_pause
))
110 if (req_base
->flags
& ETHTOOL_FLAG_STATS
&&
111 pause_put_stats(skb
, &data
->pausestat
))
117 const struct ethnl_request_ops ethnl_pause_request_ops
= {
118 .request_cmd
= ETHTOOL_MSG_PAUSE_GET
,
119 .reply_cmd
= ETHTOOL_MSG_PAUSE_GET_REPLY
,
120 .hdr_attr
= ETHTOOL_A_PAUSE_HEADER
,
121 .req_info_size
= sizeof(struct pause_req_info
),
122 .reply_data_size
= sizeof(struct pause_reply_data
),
124 .prepare_data
= pause_prepare_data
,
125 .reply_size
= pause_reply_size
,
126 .fill_reply
= pause_fill_reply
,
131 const struct nla_policy ethnl_pause_set_policy
[] = {
132 [ETHTOOL_A_PAUSE_HEADER
] =
133 NLA_POLICY_NESTED(ethnl_header_policy
),
134 [ETHTOOL_A_PAUSE_AUTONEG
] = { .type
= NLA_U8
},
135 [ETHTOOL_A_PAUSE_RX
] = { .type
= NLA_U8
},
136 [ETHTOOL_A_PAUSE_TX
] = { .type
= NLA_U8
},
139 int ethnl_set_pause(struct sk_buff
*skb
, struct genl_info
*info
)
141 struct ethtool_pauseparam params
= {};
142 struct ethnl_req_info req_info
= {};
143 struct nlattr
**tb
= info
->attrs
;
144 const struct ethtool_ops
*ops
;
145 struct net_device
*dev
;
149 ret
= ethnl_parse_header_dev_get(&req_info
,
150 tb
[ETHTOOL_A_PAUSE_HEADER
],
151 genl_info_net(info
), info
->extack
,
156 ops
= dev
->ethtool_ops
;
158 if (!ops
->get_pauseparam
|| !ops
->set_pauseparam
)
162 ret
= ethnl_ops_begin(dev
);
165 ops
->get_pauseparam(dev
, ¶ms
);
167 ethnl_update_bool32(¶ms
.autoneg
, tb
[ETHTOOL_A_PAUSE_AUTONEG
], &mod
);
168 ethnl_update_bool32(¶ms
.rx_pause
, tb
[ETHTOOL_A_PAUSE_RX
], &mod
);
169 ethnl_update_bool32(¶ms
.tx_pause
, tb
[ETHTOOL_A_PAUSE_TX
], &mod
);
174 ret
= dev
->ethtool_ops
->set_pauseparam(dev
, ¶ms
);
177 ethtool_notify(dev
, ETHTOOL_MSG_PAUSE_NTF
, NULL
);
180 ethnl_ops_complete(dev
);