Commit fd77be7b authored by Michal Kubecek's avatar Michal Kubecek Committed by David S. Miller

ethtool: set EEE settings with EEE_SET request

Implement EEE_SET netlink request to set EEE settings of a network device.
These are traditionally set with ETHTOOL_SEEE ioctl request.

The netlink interface allows setting the EEE status for all link modes
supported by kernel but only first 32 link modes can be set at the moment
as only those are supported by the ethtool_ops callback.
Signed-off-by: default avatarMichal Kubecek <mkubecek@suse.cz>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b7eeefe7
...@@ -202,6 +202,7 @@ Userspace to kernel: ...@@ -202,6 +202,7 @@ Userspace to kernel:
``ETHTOOL_MSG_PAUSE_GET`` get pause parameters ``ETHTOOL_MSG_PAUSE_GET`` get pause parameters
``ETHTOOL_MSG_PAUSE_SET`` set pause parameters ``ETHTOOL_MSG_PAUSE_SET`` set pause parameters
``ETHTOOL_MSG_EEE_GET`` get EEE settings ``ETHTOOL_MSG_EEE_GET`` get EEE settings
``ETHTOOL_MSG_EEE_SET`` set EEE settings
===================================== ================================ ===================================== ================================
Kernel to userspace: Kernel to userspace:
...@@ -904,6 +905,28 @@ netlink interface allows reporting EEE status for all link modes but only ...@@ -904,6 +905,28 @@ netlink interface allows reporting EEE status for all link modes but only
first 32 are provided by the ``ethtool_ops`` callback. first 32 are provided by the ``ethtool_ops`` callback.
EEE_SET
=======
Sets pause parameters like ``ETHTOOL_GEEEPARAM`` ioctl request.
Request contents:
===================================== ====== ==========================
``ETHTOOL_A_EEE_HEADER`` nested request header
``ETHTOOL_A_EEE_MODES_OURS`` bool advertised modes
``ETHTOOL_A_EEE_ENABLED`` bool EEE is enabled
``ETHTOOL_A_EEE_TX_LPI_ENABLED`` bool Tx lpi enabled
``ETHTOOL_A_EEE_TX_LPI_TIMER`` u32 Tx lpi timeout (in us)
===================================== ====== ==========================
``ETHTOOL_A_EEE_MODES_OURS`` is used to either list link modes to advertise
EEE for (if there is no mask) or specify changes to the list (if there is
a mask). The netlink interface allows reporting EEE status for all link modes
but only first 32 can be set at the moment as that is what the ``ethtool_ops``
callback supports.
Request translation Request translation
=================== ===================
...@@ -983,7 +1006,7 @@ have their netlink replacement yet. ...@@ -983,7 +1006,7 @@ have their netlink replacement yet.
``ETHTOOL_GMODULEINFO`` n/a ``ETHTOOL_GMODULEINFO`` n/a
``ETHTOOL_GMODULEEEPROM`` n/a ``ETHTOOL_GMODULEEEPROM`` n/a
``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET`` ``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET``
``ETHTOOL_SEEE`` n/a ``ETHTOOL_SEEE`` ``ETHTOOL_MSG_EEE_SET``
``ETHTOOL_GRSSH`` n/a ``ETHTOOL_GRSSH`` n/a
``ETHTOOL_SRSSH`` n/a ``ETHTOOL_SRSSH`` n/a
``ETHTOOL_GTUNABLE`` n/a ``ETHTOOL_GTUNABLE`` n/a
......
...@@ -37,6 +37,7 @@ enum { ...@@ -37,6 +37,7 @@ enum {
ETHTOOL_MSG_PAUSE_GET, ETHTOOL_MSG_PAUSE_GET,
ETHTOOL_MSG_PAUSE_SET, ETHTOOL_MSG_PAUSE_SET,
ETHTOOL_MSG_EEE_GET, ETHTOOL_MSG_EEE_GET,
ETHTOOL_MSG_EEE_SET,
/* add new constants above here */ /* add new constants above here */
__ETHTOOL_MSG_USER_CNT, __ETHTOOL_MSG_USER_CNT,
......
...@@ -128,3 +128,76 @@ const struct ethnl_request_ops ethnl_eee_request_ops = { ...@@ -128,3 +128,76 @@ const struct ethnl_request_ops ethnl_eee_request_ops = {
.reply_size = eee_reply_size, .reply_size = eee_reply_size,
.fill_reply = eee_fill_reply, .fill_reply = eee_fill_reply,
}; };
/* EEE_SET */
static const struct nla_policy
eee_set_policy[ETHTOOL_A_EEE_MAX + 1] = {
[ETHTOOL_A_EEE_UNSPEC] = { .type = NLA_REJECT },
[ETHTOOL_A_EEE_HEADER] = { .type = NLA_NESTED },
[ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_NESTED },
[ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT },
[ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT },
[ETHTOOL_A_EEE_ENABLED] = { .type = NLA_U8 },
[ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_U8 },
[ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_U32 },
};
int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *tb[ETHTOOL_A_EEE_MAX + 1];
struct ethtool_eee eee = {};
struct ethnl_req_info req_info = {};
const struct ethtool_ops *ops;
struct net_device *dev;
bool mod = false;
int ret;
ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_EEE_MAX,
eee_set_policy, info->extack);
if (ret < 0)
return ret;
ret = ethnl_parse_header_dev_get(&req_info,
tb[ETHTOOL_A_EEE_HEADER],
genl_info_net(info), info->extack,
true);
if (ret < 0)
return ret;
dev = req_info.dev;
ops = dev->ethtool_ops;
ret = -EOPNOTSUPP;
if (!ops->get_eee || !ops->set_eee)
goto out_dev;
rtnl_lock();
ret = ethnl_ops_begin(dev);
if (ret < 0)
goto out_rtnl;
ret = ops->get_eee(dev, &eee);
if (ret < 0)
goto out_ops;
ret = ethnl_update_bitset32(&eee.advertised, EEE_MODES_COUNT,
tb[ETHTOOL_A_EEE_MODES_OURS],
link_mode_names, info->extack, &mod);
if (ret < 0)
goto out_ops;
ethnl_update_bool32(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod);
ethnl_update_bool32(&eee.tx_lpi_enabled,
tb[ETHTOOL_A_EEE_TX_LPI_ENABLED], &mod);
ethnl_update_bool32(&eee.tx_lpi_timer, tb[ETHTOOL_A_EEE_TX_LPI_TIMER],
&mod);
ret = 0;
if (!mod)
goto out_ops;
ret = dev->ethtool_ops->set_eee(dev, &eee);
out_ops:
ethnl_ops_complete(dev);
out_rtnl:
rtnl_unlock();
out_dev:
dev_put(dev);
return ret;
}
...@@ -824,6 +824,11 @@ static const struct genl_ops ethtool_genl_ops[] = { ...@@ -824,6 +824,11 @@ static const struct genl_ops ethtool_genl_ops[] = {
.dumpit = ethnl_default_dumpit, .dumpit = ethnl_default_dumpit,
.done = ethnl_default_done, .done = ethnl_default_done,
}, },
{
.cmd = ETHTOOL_MSG_EEE_SET,
.flags = GENL_UNS_ADMIN_PERM,
.doit = ethnl_set_eee,
},
}; };
static const struct genl_multicast_group ethtool_nl_mcgrps[] = { static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
......
...@@ -355,5 +355,6 @@ int ethnl_set_rings(struct sk_buff *skb, struct genl_info *info); ...@@ -355,5 +355,6 @@ int ethnl_set_rings(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info); int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info); int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info); int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info);
#endif /* _NET_ETHTOOL_NETLINK_H */ #endif /* _NET_ETHTOOL_NETLINK_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment