0001
0002
0003 #include <linux/ethtool.h>
0004
0005 #include "netlink.h"
0006 #include "common.h"
0007 #include "bitset.h"
0008
0009 struct module_req_info {
0010 struct ethnl_req_info base;
0011 };
0012
0013 struct module_reply_data {
0014 struct ethnl_reply_data base;
0015 struct ethtool_module_power_mode_params power;
0016 };
0017
0018 #define MODULE_REPDATA(__reply_base) \
0019 container_of(__reply_base, struct module_reply_data, base)
0020
0021
0022
0023 const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER + 1] = {
0024 [ETHTOOL_A_MODULE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
0025 };
0026
0027 static int module_get_power_mode(struct net_device *dev,
0028 struct module_reply_data *data,
0029 struct netlink_ext_ack *extack)
0030 {
0031 const struct ethtool_ops *ops = dev->ethtool_ops;
0032
0033 if (!ops->get_module_power_mode)
0034 return 0;
0035
0036 return ops->get_module_power_mode(dev, &data->power, extack);
0037 }
0038
0039 static int module_prepare_data(const struct ethnl_req_info *req_base,
0040 struct ethnl_reply_data *reply_base,
0041 struct genl_info *info)
0042 {
0043 struct module_reply_data *data = MODULE_REPDATA(reply_base);
0044 struct netlink_ext_ack *extack = info ? info->extack : NULL;
0045 struct net_device *dev = reply_base->dev;
0046 int ret;
0047
0048 ret = ethnl_ops_begin(dev);
0049 if (ret < 0)
0050 return ret;
0051
0052 ret = module_get_power_mode(dev, data, extack);
0053 if (ret < 0)
0054 goto out_complete;
0055
0056 out_complete:
0057 ethnl_ops_complete(dev);
0058 return ret;
0059 }
0060
0061 static int module_reply_size(const struct ethnl_req_info *req_base,
0062 const struct ethnl_reply_data *reply_base)
0063 {
0064 struct module_reply_data *data = MODULE_REPDATA(reply_base);
0065 int len = 0;
0066
0067 if (data->power.policy)
0068 len += nla_total_size(sizeof(u8));
0069
0070 if (data->power.mode)
0071 len += nla_total_size(sizeof(u8));
0072
0073 return len;
0074 }
0075
0076 static int module_fill_reply(struct sk_buff *skb,
0077 const struct ethnl_req_info *req_base,
0078 const struct ethnl_reply_data *reply_base)
0079 {
0080 const struct module_reply_data *data = MODULE_REPDATA(reply_base);
0081
0082 if (data->power.policy &&
0083 nla_put_u8(skb, ETHTOOL_A_MODULE_POWER_MODE_POLICY,
0084 data->power.policy))
0085 return -EMSGSIZE;
0086
0087 if (data->power.mode &&
0088 nla_put_u8(skb, ETHTOOL_A_MODULE_POWER_MODE, data->power.mode))
0089 return -EMSGSIZE;
0090
0091 return 0;
0092 }
0093
0094 const struct ethnl_request_ops ethnl_module_request_ops = {
0095 .request_cmd = ETHTOOL_MSG_MODULE_GET,
0096 .reply_cmd = ETHTOOL_MSG_MODULE_GET_REPLY,
0097 .hdr_attr = ETHTOOL_A_MODULE_HEADER,
0098 .req_info_size = sizeof(struct module_req_info),
0099 .reply_data_size = sizeof(struct module_reply_data),
0100
0101 .prepare_data = module_prepare_data,
0102 .reply_size = module_reply_size,
0103 .fill_reply = module_fill_reply,
0104 };
0105
0106
0107
0108 const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1] = {
0109 [ETHTOOL_A_MODULE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
0110 [ETHTOOL_A_MODULE_POWER_MODE_POLICY] =
0111 NLA_POLICY_RANGE(NLA_U8, ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH,
0112 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO),
0113 };
0114
0115 static int module_set_power_mode(struct net_device *dev, struct nlattr **tb,
0116 bool *p_mod, struct netlink_ext_ack *extack)
0117 {
0118 struct ethtool_module_power_mode_params power = {};
0119 struct ethtool_module_power_mode_params power_new;
0120 const struct ethtool_ops *ops = dev->ethtool_ops;
0121 int ret;
0122
0123 if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY])
0124 return 0;
0125
0126 if (!ops->get_module_power_mode || !ops->set_module_power_mode) {
0127 NL_SET_ERR_MSG_ATTR(extack,
0128 tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY],
0129 "Setting power mode policy is not supported by this device");
0130 return -EOPNOTSUPP;
0131 }
0132
0133 power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]);
0134 ret = ops->get_module_power_mode(dev, &power, extack);
0135 if (ret < 0)
0136 return ret;
0137
0138 if (power_new.policy == power.policy)
0139 return 0;
0140 *p_mod = true;
0141
0142 return ops->set_module_power_mode(dev, &power_new, extack);
0143 }
0144
0145 int ethnl_set_module(struct sk_buff *skb, struct genl_info *info)
0146 {
0147 struct ethnl_req_info req_info = {};
0148 struct nlattr **tb = info->attrs;
0149 struct net_device *dev;
0150 bool mod = false;
0151 int ret;
0152
0153 ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_MODULE_HEADER],
0154 genl_info_net(info), info->extack,
0155 true);
0156 if (ret < 0)
0157 return ret;
0158 dev = req_info.dev;
0159
0160 rtnl_lock();
0161 ret = ethnl_ops_begin(dev);
0162 if (ret < 0)
0163 goto out_rtnl;
0164
0165 ret = module_set_power_mode(dev, tb, &mod, info->extack);
0166 if (ret < 0)
0167 goto out_ops;
0168
0169 if (!mod)
0170 goto out_ops;
0171
0172 ethtool_notify(dev, ETHTOOL_MSG_MODULE_NTF, NULL);
0173
0174 out_ops:
0175 ethnl_ops_complete(dev);
0176 out_rtnl:
0177 rtnl_unlock();
0178 ethnl_parse_header_dev_put(&req_info);
0179 return ret;
0180 }