162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2021 NXP
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include "netlink.h"
662306a36Sopenharmony_ci#include "common.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistruct phc_vclocks_req_info {
962306a36Sopenharmony_ci	struct ethnl_req_info		base;
1062306a36Sopenharmony_ci};
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistruct phc_vclocks_reply_data {
1362306a36Sopenharmony_ci	struct ethnl_reply_data		base;
1462306a36Sopenharmony_ci	int				num;
1562306a36Sopenharmony_ci	int				*index;
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define PHC_VCLOCKS_REPDATA(__reply_base) \
1962306a36Sopenharmony_ci	container_of(__reply_base, struct phc_vclocks_reply_data, base)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciconst struct nla_policy ethnl_phc_vclocks_get_policy[] = {
2262306a36Sopenharmony_ci	[ETHTOOL_A_PHC_VCLOCKS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic int phc_vclocks_prepare_data(const struct ethnl_req_info *req_base,
2662306a36Sopenharmony_ci				    struct ethnl_reply_data *reply_base,
2762306a36Sopenharmony_ci				    const struct genl_info *info)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct phc_vclocks_reply_data *data = PHC_VCLOCKS_REPDATA(reply_base);
3062306a36Sopenharmony_ci	struct net_device *dev = reply_base->dev;
3162306a36Sopenharmony_ci	int ret;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	ret = ethnl_ops_begin(dev);
3462306a36Sopenharmony_ci	if (ret < 0)
3562306a36Sopenharmony_ci		return ret;
3662306a36Sopenharmony_ci	data->num = ethtool_get_phc_vclocks(dev, &data->index);
3762306a36Sopenharmony_ci	ethnl_ops_complete(dev);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return ret;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int phc_vclocks_reply_size(const struct ethnl_req_info *req_base,
4362306a36Sopenharmony_ci				  const struct ethnl_reply_data *reply_base)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	const struct phc_vclocks_reply_data *data =
4662306a36Sopenharmony_ci		PHC_VCLOCKS_REPDATA(reply_base);
4762306a36Sopenharmony_ci	int len = 0;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (data->num > 0) {
5062306a36Sopenharmony_ci		len += nla_total_size(sizeof(u32));
5162306a36Sopenharmony_ci		len += nla_total_size(sizeof(s32) * data->num);
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return len;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic int phc_vclocks_fill_reply(struct sk_buff *skb,
5862306a36Sopenharmony_ci				  const struct ethnl_req_info *req_base,
5962306a36Sopenharmony_ci				  const struct ethnl_reply_data *reply_base)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	const struct phc_vclocks_reply_data *data =
6262306a36Sopenharmony_ci		PHC_VCLOCKS_REPDATA(reply_base);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (data->num <= 0)
6562306a36Sopenharmony_ci		return 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (nla_put_u32(skb, ETHTOOL_A_PHC_VCLOCKS_NUM, data->num) ||
6862306a36Sopenharmony_ci	    nla_put(skb, ETHTOOL_A_PHC_VCLOCKS_INDEX,
6962306a36Sopenharmony_ci		    sizeof(s32) * data->num, data->index))
7062306a36Sopenharmony_ci		return -EMSGSIZE;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void phc_vclocks_cleanup_data(struct ethnl_reply_data *reply_base)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	const struct phc_vclocks_reply_data *data =
7862306a36Sopenharmony_ci		PHC_VCLOCKS_REPDATA(reply_base);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	kfree(data->index);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciconst struct ethnl_request_ops ethnl_phc_vclocks_request_ops = {
8462306a36Sopenharmony_ci	.request_cmd		= ETHTOOL_MSG_PHC_VCLOCKS_GET,
8562306a36Sopenharmony_ci	.reply_cmd		= ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
8662306a36Sopenharmony_ci	.hdr_attr		= ETHTOOL_A_PHC_VCLOCKS_HEADER,
8762306a36Sopenharmony_ci	.req_info_size		= sizeof(struct phc_vclocks_req_info),
8862306a36Sopenharmony_ci	.reply_data_size	= sizeof(struct phc_vclocks_reply_data),
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	.prepare_data		= phc_vclocks_prepare_data,
9162306a36Sopenharmony_ci	.reply_size		= phc_vclocks_reply_size,
9262306a36Sopenharmony_ci	.fill_reply		= phc_vclocks_fill_reply,
9362306a36Sopenharmony_ci	.cleanup_data		= phc_vclocks_cleanup_data,
9462306a36Sopenharmony_ci};
95