Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ethtool: provide EEE settings with EEE_GET request

Implement EEE_GET request to get EEE settings of a network device. These
are traditionally available via ETHTOOL_GEEE ioctl request.

The netlink interface allows reporting EEE status for all link modes
supported by kernel but only first 32 link modes are provided at the moment
as only those are reported by the ethtool_ops callback and drivers.

v2: fix alignment (whitespace only)

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michal Kubecek and committed by
David S. Miller
b7eeefe7 bf37faa3

+192 -2
+33 -1
Documentation/networking/ethtool-netlink.rst
··· 201 201 ``ETHTOOL_MSG_COALESCE_SET`` set coalescing parameters 202 202 ``ETHTOOL_MSG_PAUSE_GET`` get pause parameters 203 203 ``ETHTOOL_MSG_PAUSE_SET`` set pause parameters 204 + ``ETHTOOL_MSG_EEE_GET`` get EEE settings 204 205 ===================================== ================================ 205 206 206 207 Kernel to userspace: ··· 230 229 ``ETHTOOL_MSG_COALESCE_NTF`` coalescing parameters 231 230 ``ETHTOOL_MSG_PAUSE_GET_REPLY`` pause parameters 232 231 ``ETHTOOL_MSG_PAUSE_NTF`` pause parameters 232 + ``ETHTOOL_MSG_EEE_GET_REPLY`` EEE settings 233 233 ===================================== ================================= 234 234 235 235 ``GET`` requests are sent by userspace applications to retrieve device ··· 874 872 ===================================== ====== ========================== 875 873 876 874 875 + EEE_GET 876 + ======= 877 + 878 + Gets channel counts like ``ETHTOOL_GEEE`` ioctl request. 879 + 880 + Request contents: 881 + 882 + ===================================== ====== ========================== 883 + ``ETHTOOL_A_EEE_HEADER`` nested request header 884 + ===================================== ====== ========================== 885 + 886 + Kernel response contents: 887 + 888 + ===================================== ====== ========================== 889 + ``ETHTOOL_A_EEE_HEADER`` nested request header 890 + ``ETHTOOL_A_EEE_MODES_OURS`` bool supported/advertised modes 891 + ``ETHTOOL_A_EEE_MODES_PEER`` bool peer advertised link modes 892 + ``ETHTOOL_A_EEE_ACTIVE`` bool EEE is actively used 893 + ``ETHTOOL_A_EEE_ENABLED`` bool EEE is enabled 894 + ``ETHTOOL_A_EEE_TX_LPI_ENABLED`` bool Tx lpi enabled 895 + ``ETHTOOL_A_EEE_TX_LPI_TIMER`` u32 Tx lpi timeout (in us) 896 + ===================================== ====== ========================== 897 + 898 + In ``ETHTOOL_A_EEE_MODES_OURS``, mask consists of link modes for which EEE is 899 + enabled, value of link modes for which EEE is advertised. Link modes for which 900 + peer advertises EEE are listed in ``ETHTOOL_A_EEE_MODES_PEER`` (no mask). The 901 + netlink interface allows reporting EEE status for all link modes but only 902 + first 32 are provided by the ``ethtool_ops`` callback. 903 + 904 + 877 905 Request translation 878 906 =================== 879 907 ··· 982 950 ``ETHTOOL_GET_TS_INFO`` n/a 983 951 ``ETHTOOL_GMODULEINFO`` n/a 984 952 ``ETHTOOL_GMODULEEEPROM`` n/a 985 - ``ETHTOOL_GEEE`` n/a 953 + ``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET`` 986 954 ``ETHTOOL_SEEE`` n/a 987 955 ``ETHTOOL_GRSSH`` n/a 988 956 ``ETHTOOL_SRSSH`` n/a
+19
include/uapi/linux/ethtool_netlink.h
··· 36 36 ETHTOOL_MSG_COALESCE_SET, 37 37 ETHTOOL_MSG_PAUSE_GET, 38 38 ETHTOOL_MSG_PAUSE_SET, 39 + ETHTOOL_MSG_EEE_GET, 39 40 40 41 /* add new constants above here */ 41 42 __ETHTOOL_MSG_USER_CNT, ··· 69 68 ETHTOOL_MSG_COALESCE_NTF, 70 69 ETHTOOL_MSG_PAUSE_GET_REPLY, 71 70 ETHTOOL_MSG_PAUSE_NTF, 71 + ETHTOOL_MSG_EEE_GET_REPLY, 72 72 73 73 /* add new constants above here */ 74 74 __ETHTOOL_MSG_KERNEL_CNT, ··· 365 363 /* add new constants above here */ 366 364 __ETHTOOL_A_PAUSE_CNT, 367 365 ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1) 366 + }; 367 + 368 + /* EEE */ 369 + 370 + enum { 371 + ETHTOOL_A_EEE_UNSPEC, 372 + ETHTOOL_A_EEE_HEADER, /* nest - _A_HEADER_* */ 373 + ETHTOOL_A_EEE_MODES_OURS, /* bitset */ 374 + ETHTOOL_A_EEE_MODES_PEER, /* bitset */ 375 + ETHTOOL_A_EEE_ACTIVE, /* u8 */ 376 + ETHTOOL_A_EEE_ENABLED, /* u8 */ 377 + ETHTOOL_A_EEE_TX_LPI_ENABLED, /* u8 */ 378 + ETHTOOL_A_EEE_TX_LPI_TIMER, /* u32 */ 379 + 380 + /* add new constants above here */ 381 + __ETHTOOL_A_EEE_CNT, 382 + ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1) 368 383 }; 369 384 370 385 /* generic netlink info */
+1 -1
net/ethtool/Makefile
··· 6 6 7 7 ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ 8 8 linkstate.o debug.o wol.o features.o privflags.o rings.o \ 9 - channels.o coalesce.o pause.o 9 + channels.o coalesce.o pause.o eee.o
+130
net/ethtool/eee.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include "netlink.h" 4 + #include "common.h" 5 + #include "bitset.h" 6 + 7 + #define EEE_MODES_COUNT \ 8 + (sizeof_field(struct ethtool_eee, supported) * BITS_PER_BYTE) 9 + 10 + struct eee_req_info { 11 + struct ethnl_req_info base; 12 + }; 13 + 14 + struct eee_reply_data { 15 + struct ethnl_reply_data base; 16 + struct ethtool_eee eee; 17 + }; 18 + 19 + #define EEE_REPDATA(__reply_base) \ 20 + container_of(__reply_base, struct eee_reply_data, base) 21 + 22 + static const struct nla_policy 23 + eee_get_policy[ETHTOOL_A_EEE_MAX + 1] = { 24 + [ETHTOOL_A_EEE_UNSPEC] = { .type = NLA_REJECT }, 25 + [ETHTOOL_A_EEE_HEADER] = { .type = NLA_NESTED }, 26 + [ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_REJECT }, 27 + [ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT }, 28 + [ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT }, 29 + [ETHTOOL_A_EEE_ENABLED] = { .type = NLA_REJECT }, 30 + [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_REJECT }, 31 + [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_REJECT }, 32 + }; 33 + 34 + static int eee_prepare_data(const struct ethnl_req_info *req_base, 35 + struct ethnl_reply_data *reply_base, 36 + struct genl_info *info) 37 + { 38 + struct eee_reply_data *data = EEE_REPDATA(reply_base); 39 + struct net_device *dev = reply_base->dev; 40 + int ret; 41 + 42 + if (!dev->ethtool_ops->get_eee) 43 + return -EOPNOTSUPP; 44 + ret = ethnl_ops_begin(dev); 45 + if (ret < 0) 46 + return ret; 47 + ret = dev->ethtool_ops->get_eee(dev, &data->eee); 48 + ethnl_ops_complete(dev); 49 + 50 + return ret; 51 + } 52 + 53 + static int eee_reply_size(const struct ethnl_req_info *req_base, 54 + const struct ethnl_reply_data *reply_base) 55 + { 56 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 57 + const struct eee_reply_data *data = EEE_REPDATA(reply_base); 58 + const struct ethtool_eee *eee = &data->eee; 59 + int len = 0; 60 + int ret; 61 + 62 + BUILD_BUG_ON(sizeof(eee->advertised) * BITS_PER_BYTE != 63 + EEE_MODES_COUNT); 64 + BUILD_BUG_ON(sizeof(eee->lp_advertised) * BITS_PER_BYTE != 65 + EEE_MODES_COUNT); 66 + 67 + /* MODES_OURS */ 68 + ret = ethnl_bitset32_size(&eee->advertised, &eee->supported, 69 + EEE_MODES_COUNT, link_mode_names, compact); 70 + if (ret < 0) 71 + return ret; 72 + len += ret; 73 + /* MODES_PEERS */ 74 + ret = ethnl_bitset32_size(&eee->lp_advertised, NULL, 75 + EEE_MODES_COUNT, link_mode_names, compact); 76 + if (ret < 0) 77 + return ret; 78 + len += ret; 79 + 80 + len += nla_total_size(sizeof(u8)) + /* _EEE_ACTIVE */ 81 + nla_total_size(sizeof(u8)) + /* _EEE_ENABLED */ 82 + nla_total_size(sizeof(u8)) + /* _EEE_TX_LPI_ENABLED */ 83 + nla_total_size(sizeof(u32)); /* _EEE_TX_LPI_TIMER */ 84 + 85 + return len; 86 + } 87 + 88 + static int eee_fill_reply(struct sk_buff *skb, 89 + const struct ethnl_req_info *req_base, 90 + const struct ethnl_reply_data *reply_base) 91 + { 92 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 93 + const struct eee_reply_data *data = EEE_REPDATA(reply_base); 94 + const struct ethtool_eee *eee = &data->eee; 95 + int ret; 96 + 97 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_OURS, 98 + &eee->advertised, &eee->supported, 99 + EEE_MODES_COUNT, link_mode_names, compact); 100 + if (ret < 0) 101 + return ret; 102 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_PEER, 103 + &eee->lp_advertised, NULL, EEE_MODES_COUNT, 104 + link_mode_names, compact); 105 + if (ret < 0) 106 + return ret; 107 + 108 + if (nla_put_u8(skb, ETHTOOL_A_EEE_ACTIVE, !!eee->eee_active) || 109 + nla_put_u8(skb, ETHTOOL_A_EEE_ENABLED, !!eee->eee_enabled) || 110 + nla_put_u8(skb, ETHTOOL_A_EEE_TX_LPI_ENABLED, 111 + !!eee->tx_lpi_enabled) || 112 + nla_put_u32(skb, ETHTOOL_A_EEE_TX_LPI_TIMER, eee->tx_lpi_timer)) 113 + return -EMSGSIZE; 114 + 115 + return 0; 116 + } 117 + 118 + const struct ethnl_request_ops ethnl_eee_request_ops = { 119 + .request_cmd = ETHTOOL_MSG_EEE_GET, 120 + .reply_cmd = ETHTOOL_MSG_EEE_GET_REPLY, 121 + .hdr_attr = ETHTOOL_A_EEE_HEADER, 122 + .max_attr = ETHTOOL_A_EEE_MAX, 123 + .req_info_size = sizeof(struct eee_req_info), 124 + .reply_data_size = sizeof(struct eee_reply_data), 125 + .request_policy = eee_get_policy, 126 + 127 + .prepare_data = eee_prepare_data, 128 + .reply_size = eee_reply_size, 129 + .fill_reply = eee_fill_reply, 130 + };
+8
net/ethtool/netlink.c
··· 229 229 [ETHTOOL_MSG_CHANNELS_GET] = &ethnl_channels_request_ops, 230 230 [ETHTOOL_MSG_COALESCE_GET] = &ethnl_coalesce_request_ops, 231 231 [ETHTOOL_MSG_PAUSE_GET] = &ethnl_pause_request_ops, 232 + [ETHTOOL_MSG_EEE_GET] = &ethnl_eee_request_ops, 232 233 }; 233 234 234 235 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) ··· 816 815 .cmd = ETHTOOL_MSG_PAUSE_SET, 817 816 .flags = GENL_UNS_ADMIN_PERM, 818 817 .doit = ethnl_set_pause, 818 + }, 819 + { 820 + .cmd = ETHTOOL_MSG_EEE_GET, 821 + .doit = ethnl_default_doit, 822 + .start = ethnl_default_start, 823 + .dumpit = ethnl_default_dumpit, 824 + .done = ethnl_default_done, 819 825 }, 820 826 }; 821 827
+1
net/ethtool/netlink.h
··· 343 343 extern const struct ethnl_request_ops ethnl_channels_request_ops; 344 344 extern const struct ethnl_request_ops ethnl_coalesce_request_ops; 345 345 extern const struct ethnl_request_ops ethnl_pause_request_ops; 346 + extern const struct ethnl_request_ops ethnl_eee_request_ops; 346 347 347 348 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); 348 349 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);