mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 05:13:18 +00:00
Merge branch 'ethtool-netlink-interface-part-4'
Michal Kubecek says:
====================
ethtool netlink interface, part 4
Implementation of more netlink request types:
- coalescing (ethtool -c/-C, patches 2-4)
- pause parameters (ethtool -a/-A, patches 5-7)
- EEE settings (--show-eee / --set-eee, patches 8-10)
- timestamping info (-T, patches 11-12)
Patch 1 is a fix for netdev reference leak similar to commit 2f599ec422
("ethtool: fix reference leak in some *_SET handlers") but fixing a code
Changes in v3
- change "one-step-*" Tx type names to "onestep-*", (patch 11, suggested
by Richard Cochran
- use "TSINFO" rather than "TIMESTAMP" for timestamping information
constants and adjust symbol names (patch 12, suggested by Richard
Cochran)
Changes in v2:
- fix compiler warning in net_hwtstamp_validate() (patch 11)
- fix follow-up lines alignment (whitespace only, patches 3 and 8)
which is only in net-next tree at the moment.
====================
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c13b5adb06
@ -197,6 +197,13 @@ Userspace to kernel:
|
||||
``ETHTOOL_MSG_RINGS_SET`` set ring sizes
|
||||
``ETHTOOL_MSG_CHANNELS_GET`` get channel counts
|
||||
``ETHTOOL_MSG_CHANNELS_SET`` set channel counts
|
||||
``ETHTOOL_MSG_COALESCE_GET`` get coalescing parameters
|
||||
``ETHTOOL_MSG_COALESCE_SET`` set coalescing parameters
|
||||
``ETHTOOL_MSG_PAUSE_GET`` get pause parameters
|
||||
``ETHTOOL_MSG_PAUSE_SET`` set pause parameters
|
||||
``ETHTOOL_MSG_EEE_GET`` get EEE settings
|
||||
``ETHTOOL_MSG_EEE_SET`` set EEE settings
|
||||
``ETHTOOL_MSG_TSINFO_GET`` get timestamping info
|
||||
===================================== ================================
|
||||
|
||||
Kernel to userspace:
|
||||
@ -221,6 +228,13 @@ Kernel to userspace:
|
||||
``ETHTOOL_MSG_RINGS_NTF`` ring sizes
|
||||
``ETHTOOL_MSG_CHANNELS_GET_REPLY`` channel counts
|
||||
``ETHTOOL_MSG_CHANNELS_NTF`` channel counts
|
||||
``ETHTOOL_MSG_COALESCE_GET_REPLY`` coalescing parameters
|
||||
``ETHTOOL_MSG_COALESCE_NTF`` coalescing parameters
|
||||
``ETHTOOL_MSG_PAUSE_GET_REPLY`` pause parameters
|
||||
``ETHTOOL_MSG_PAUSE_NTF`` pause parameters
|
||||
``ETHTOOL_MSG_EEE_GET_REPLY`` EEE settings
|
||||
``ETHTOOL_MSG_EEE_NTF`` EEE settings
|
||||
``ETHTOOL_MSG_TSINFO_GET_REPLY`` timestamping info
|
||||
===================================== =================================
|
||||
|
||||
``GET`` requests are sent by userspace applications to retrieve device
|
||||
@ -745,6 +759,203 @@ driver. Driver may impose additional constraints and may not suspport all
|
||||
attributes.
|
||||
|
||||
|
||||
COALESCE_GET
|
||||
============
|
||||
|
||||
Gets coalescing parameters like ``ETHTOOL_GCOALESCE`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
==================================== ====== ==========================
|
||||
``ETHTOOL_A_COALESCE_HEADER`` nested request header
|
||||
==================================== ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
=========================================== ====== =======================
|
||||
``ETHTOOL_A_COALESCE_HEADER`` nested reply header
|
||||
``ETHTOOL_A_COALESCE_RX_USECS`` u32 delay (us), normal Rx
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES`` u32 max packets, normal Rx
|
||||
``ETHTOOL_A_COALESCE_RX_USECS_IRQ`` u32 delay (us), Rx in IRQ
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ`` u32 max packets, Rx in IRQ
|
||||
``ETHTOOL_A_COALESCE_TX_USECS`` u32 delay (us), normal Tx
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES`` u32 max packets, normal Tx
|
||||
``ETHTOOL_A_COALESCE_TX_USECS_IRQ`` u32 delay (us), Tx in IRQ
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ`` u32 IRQ packets, Tx in IRQ
|
||||
``ETHTOOL_A_COALESCE_STATS_BLOCK_USECS`` u32 delay of stats update
|
||||
``ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX`` bool adaptive Rx coalesce
|
||||
``ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX`` bool adaptive Tx coalesce
|
||||
``ETHTOOL_A_COALESCE_PKT_RATE_LOW`` u32 threshold for low rate
|
||||
``ETHTOOL_A_COALESCE_RX_USECS_LOW`` u32 delay (us), low Rx
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW`` u32 max packets, low Rx
|
||||
``ETHTOOL_A_COALESCE_TX_USECS_LOW`` u32 delay (us), low Tx
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW`` u32 max packets, low Tx
|
||||
``ETHTOOL_A_COALESCE_PKT_RATE_HIGH`` u32 threshold for high rate
|
||||
``ETHTOOL_A_COALESCE_RX_USECS_HIGH`` u32 delay (us), high Rx
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH`` u32 max packets, high Rx
|
||||
``ETHTOOL_A_COALESCE_TX_USECS_HIGH`` u32 delay (us), high Tx
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH`` u32 max packets, high Tx
|
||||
``ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL`` u32 rate sampling interval
|
||||
=========================================== ====== =======================
|
||||
|
||||
Attributes are only included in reply if their value is not zero or the
|
||||
corresponding bit in ``ethtool_ops::supported_coalesce_params`` is set (i.e.
|
||||
they are declared as supported by driver).
|
||||
|
||||
|
||||
COALESCE_SET
|
||||
============
|
||||
|
||||
Sets coalescing parameters like ``ETHTOOL_SCOALESCE`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
=========================================== ====== =======================
|
||||
``ETHTOOL_A_COALESCE_HEADER`` nested request header
|
||||
``ETHTOOL_A_COALESCE_RX_USECS`` u32 delay (us), normal Rx
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES`` u32 max packets, normal Rx
|
||||
``ETHTOOL_A_COALESCE_RX_USECS_IRQ`` u32 delay (us), Rx in IRQ
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ`` u32 max packets, Rx in IRQ
|
||||
``ETHTOOL_A_COALESCE_TX_USECS`` u32 delay (us), normal Tx
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES`` u32 max packets, normal Tx
|
||||
``ETHTOOL_A_COALESCE_TX_USECS_IRQ`` u32 delay (us), Tx in IRQ
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ`` u32 IRQ packets, Tx in IRQ
|
||||
``ETHTOOL_A_COALESCE_STATS_BLOCK_USECS`` u32 delay of stats update
|
||||
``ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX`` bool adaptive Rx coalesce
|
||||
``ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX`` bool adaptive Tx coalesce
|
||||
``ETHTOOL_A_COALESCE_PKT_RATE_LOW`` u32 threshold for low rate
|
||||
``ETHTOOL_A_COALESCE_RX_USECS_LOW`` u32 delay (us), low Rx
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW`` u32 max packets, low Rx
|
||||
``ETHTOOL_A_COALESCE_TX_USECS_LOW`` u32 delay (us), low Tx
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW`` u32 max packets, low Tx
|
||||
``ETHTOOL_A_COALESCE_PKT_RATE_HIGH`` u32 threshold for high rate
|
||||
``ETHTOOL_A_COALESCE_RX_USECS_HIGH`` u32 delay (us), high Rx
|
||||
``ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH`` u32 max packets, high Rx
|
||||
``ETHTOOL_A_COALESCE_TX_USECS_HIGH`` u32 delay (us), high Tx
|
||||
``ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH`` u32 max packets, high Tx
|
||||
``ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL`` u32 rate sampling interval
|
||||
=========================================== ====== =======================
|
||||
|
||||
Request is rejected if it attributes declared as unsupported by driver (i.e.
|
||||
such that the corresponding bit in ``ethtool_ops::supported_coalesce_params``
|
||||
is not set), regardless of their values. Driver may impose additional
|
||||
constraints on coalescing parameters and their values.
|
||||
|
||||
|
||||
PAUSE_GET
|
||||
============
|
||||
|
||||
Gets channel counts like ``ETHTOOL_GPAUSE`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_PAUSE_HEADER`` nested request header
|
||||
===================================== ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_PAUSE_HEADER`` nested request header
|
||||
``ETHTOOL_A_PAUSE_AUTONEG`` bool pause autonegotiation
|
||||
``ETHTOOL_A_PAUSE_RX`` bool receive pause frames
|
||||
``ETHTOOL_A_PAUSE_TX`` bool transmit pause frames
|
||||
===================================== ====== ==========================
|
||||
|
||||
|
||||
PAUSE_SET
|
||||
============
|
||||
|
||||
Sets pause parameters like ``ETHTOOL_GPAUSEPARAM`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_PAUSE_HEADER`` nested request header
|
||||
``ETHTOOL_A_PAUSE_AUTONEG`` bool pause autonegotiation
|
||||
``ETHTOOL_A_PAUSE_RX`` bool receive pause frames
|
||||
``ETHTOOL_A_PAUSE_TX`` bool transmit pause frames
|
||||
===================================== ====== ==========================
|
||||
|
||||
|
||||
EEE_GET
|
||||
=======
|
||||
|
||||
Gets channel counts like ``ETHTOOL_GEEE`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_EEE_HEADER`` nested request header
|
||||
===================================== ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_EEE_HEADER`` nested request header
|
||||
``ETHTOOL_A_EEE_MODES_OURS`` bool supported/advertised modes
|
||||
``ETHTOOL_A_EEE_MODES_PEER`` bool peer advertised link modes
|
||||
``ETHTOOL_A_EEE_ACTIVE`` bool EEE is actively used
|
||||
``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)
|
||||
===================================== ====== ==========================
|
||||
|
||||
In ``ETHTOOL_A_EEE_MODES_OURS``, mask consists of link modes for which EEE is
|
||||
enabled, value of link modes for which EEE is advertised. Link modes for which
|
||||
peer advertises EEE are listed in ``ETHTOOL_A_EEE_MODES_PEER`` (no mask). The
|
||||
netlink interface allows reporting EEE status for all link modes but only
|
||||
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.
|
||||
|
||||
|
||||
TSINFO_GET
|
||||
==========
|
||||
|
||||
Gets timestamping information like ``ETHTOOL_GET_TS_INFO`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_TSINFO_HEADER`` nested request header
|
||||
===================================== ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_TSINFO_HEADER`` nested request header
|
||||
``ETHTOOL_A_TSINFO_TIMESTAMPING`` bitset SO_TIMESTAMPING flags
|
||||
``ETHTOOL_A_TSINFO_TX_TYPES`` bitset supported Tx types
|
||||
``ETHTOOL_A_TSINFO_RX_FILTERS`` bitset supported Rx filters
|
||||
``ETHTOOL_A_TSINFO_PHC_INDEX`` u32 PTP hw clock index
|
||||
===================================== ====== ==========================
|
||||
|
||||
``ETHTOOL_A_TSINFO_PHC_INDEX`` is absent if there is no associated PHC (there
|
||||
is no special value for this case). The bitset attributes are omitted if they
|
||||
would be empty (no bit set).
|
||||
|
||||
|
||||
Request translation
|
||||
===================
|
||||
|
||||
@ -769,12 +980,12 @@ have their netlink replacement yet.
|
||||
``ETHTOOL_GLINK`` ``ETHTOOL_MSG_LINKSTATE_GET``
|
||||
``ETHTOOL_GEEPROM`` n/a
|
||||
``ETHTOOL_SEEPROM`` n/a
|
||||
``ETHTOOL_GCOALESCE`` n/a
|
||||
``ETHTOOL_SCOALESCE`` n/a
|
||||
``ETHTOOL_GCOALESCE`` ``ETHTOOL_MSG_COALESCE_GET``
|
||||
``ETHTOOL_SCOALESCE`` ``ETHTOOL_MSG_COALESCE_SET``
|
||||
``ETHTOOL_GRINGPARAM`` ``ETHTOOL_MSG_RINGS_GET``
|
||||
``ETHTOOL_SRINGPARAM`` ``ETHTOOL_MSG_RINGS_SET``
|
||||
``ETHTOOL_GPAUSEPARAM`` n/a
|
||||
``ETHTOOL_SPAUSEPARAM`` n/a
|
||||
``ETHTOOL_GPAUSEPARAM`` ``ETHTOOL_MSG_PAUSE_GET``
|
||||
``ETHTOOL_SPAUSEPARAM`` ``ETHTOOL_MSG_PAUSE_SET``
|
||||
``ETHTOOL_GRXCSUM`` ``ETHTOOL_MSG_FEATURES_GET``
|
||||
``ETHTOOL_SRXCSUM`` ``ETHTOOL_MSG_FEATURES_SET``
|
||||
``ETHTOOL_GTXCSUM`` ``ETHTOOL_MSG_FEATURES_GET``
|
||||
@ -820,11 +1031,11 @@ have their netlink replacement yet.
|
||||
``ETHTOOL_SET_DUMP`` n/a
|
||||
``ETHTOOL_GET_DUMP_FLAG`` n/a
|
||||
``ETHTOOL_GET_DUMP_DATA`` n/a
|
||||
``ETHTOOL_GET_TS_INFO`` n/a
|
||||
``ETHTOOL_GET_TS_INFO`` ``ETHTOOL_MSG_TSINFO_GET``
|
||||
``ETHTOOL_GMODULEINFO`` n/a
|
||||
``ETHTOOL_GMODULEEEPROM`` n/a
|
||||
``ETHTOOL_GEEE`` n/a
|
||||
``ETHTOOL_SEEE`` n/a
|
||||
``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET``
|
||||
``ETHTOOL_SEEE`` ``ETHTOOL_MSG_EEE_SET``
|
||||
``ETHTOOL_GRSSH`` n/a
|
||||
``ETHTOOL_SRSSH`` n/a
|
||||
``ETHTOOL_GTUNABLE`` n/a
|
||||
|
@ -596,6 +596,9 @@ struct ethtool_pauseparam {
|
||||
* @ETH_SS_LINK_MODES: link mode names
|
||||
* @ETH_SS_MSG_CLASSES: debug message class names
|
||||
* @ETH_SS_WOL_MODES: wake-on-lan modes
|
||||
* @ETH_SS_SOF_TIMESTAMPING: SOF_TIMESTAMPING_* flags
|
||||
* @ETH_SS_TS_TX_TYPES: timestamping Tx types
|
||||
* @ETH_SS_TS_RX_FILTERS: timestamping Rx filters
|
||||
*/
|
||||
enum ethtool_stringset {
|
||||
ETH_SS_TEST = 0,
|
||||
@ -610,6 +613,9 @@ enum ethtool_stringset {
|
||||
ETH_SS_LINK_MODES,
|
||||
ETH_SS_MSG_CLASSES,
|
||||
ETH_SS_WOL_MODES,
|
||||
ETH_SS_SOF_TIMESTAMPING,
|
||||
ETH_SS_TS_TX_TYPES,
|
||||
ETH_SS_TS_RX_FILTERS,
|
||||
|
||||
/* add new constants above here */
|
||||
ETH_SS_COUNT
|
||||
|
@ -32,6 +32,13 @@ enum {
|
||||
ETHTOOL_MSG_RINGS_SET,
|
||||
ETHTOOL_MSG_CHANNELS_GET,
|
||||
ETHTOOL_MSG_CHANNELS_SET,
|
||||
ETHTOOL_MSG_COALESCE_GET,
|
||||
ETHTOOL_MSG_COALESCE_SET,
|
||||
ETHTOOL_MSG_PAUSE_GET,
|
||||
ETHTOOL_MSG_PAUSE_SET,
|
||||
ETHTOOL_MSG_EEE_GET,
|
||||
ETHTOOL_MSG_EEE_SET,
|
||||
ETHTOOL_MSG_TSINFO_GET,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_MSG_USER_CNT,
|
||||
@ -60,6 +67,13 @@ enum {
|
||||
ETHTOOL_MSG_RINGS_NTF,
|
||||
ETHTOOL_MSG_CHANNELS_GET_REPLY,
|
||||
ETHTOOL_MSG_CHANNELS_NTF,
|
||||
ETHTOOL_MSG_COALESCE_GET_REPLY,
|
||||
ETHTOOL_MSG_COALESCE_NTF,
|
||||
ETHTOOL_MSG_PAUSE_GET_REPLY,
|
||||
ETHTOOL_MSG_PAUSE_NTF,
|
||||
ETHTOOL_MSG_EEE_GET_REPLY,
|
||||
ETHTOOL_MSG_EEE_NTF,
|
||||
ETHTOOL_MSG_TSINFO_GET_REPLY,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_MSG_KERNEL_CNT,
|
||||
@ -310,6 +324,85 @@ enum {
|
||||
ETHTOOL_A_CHANNELS_MAX = (__ETHTOOL_A_CHANNELS_CNT - 1)
|
||||
};
|
||||
|
||||
/* COALESCE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_COALESCE_UNSPEC,
|
||||
ETHTOOL_A_COALESCE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_COALESCE_RX_USECS, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_USECS_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, /* u32 */
|
||||
ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, /* u8 */
|
||||
ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, /* u8 */
|
||||
ETHTOOL_A_COALESCE_PKT_RATE_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_USECS_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_PKT_RATE_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_USECS_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_COALESCE_CNT,
|
||||
ETHTOOL_A_COALESCE_MAX = (__ETHTOOL_A_COALESCE_CNT - 1)
|
||||
};
|
||||
|
||||
/* PAUSE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PAUSE_UNSPEC,
|
||||
ETHTOOL_A_PAUSE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PAUSE_AUTONEG, /* u8 */
|
||||
ETHTOOL_A_PAUSE_RX, /* u8 */
|
||||
ETHTOOL_A_PAUSE_TX, /* u8 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PAUSE_CNT,
|
||||
ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1)
|
||||
};
|
||||
|
||||
/* EEE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_EEE_UNSPEC,
|
||||
ETHTOOL_A_EEE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_EEE_MODES_OURS, /* bitset */
|
||||
ETHTOOL_A_EEE_MODES_PEER, /* bitset */
|
||||
ETHTOOL_A_EEE_ACTIVE, /* u8 */
|
||||
ETHTOOL_A_EEE_ENABLED, /* u8 */
|
||||
ETHTOOL_A_EEE_TX_LPI_ENABLED, /* u8 */
|
||||
ETHTOOL_A_EEE_TX_LPI_TIMER, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_EEE_CNT,
|
||||
ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1)
|
||||
};
|
||||
|
||||
/* TSINFO */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TSINFO_UNSPEC,
|
||||
ETHTOOL_A_TSINFO_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_TSINFO_TIMESTAMPING, /* bitset */
|
||||
ETHTOOL_A_TSINFO_TX_TYPES, /* bitset */
|
||||
ETHTOOL_A_TSINFO_RX_FILTERS, /* bitset */
|
||||
ETHTOOL_A_TSINFO_PHC_INDEX, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TSINFO_CNT,
|
||||
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
|
||||
};
|
||||
|
||||
/* generic netlink info */
|
||||
#define ETHTOOL_GENL_NAME "ethtool"
|
||||
#define ETHTOOL_GENL_VERSION 1
|
||||
|
@ -98,6 +98,9 @@ enum hwtstamp_tx_types {
|
||||
* receive a time stamp via the socket error queue.
|
||||
*/
|
||||
HWTSTAMP_TX_ONESTEP_P2P,
|
||||
|
||||
/* add new constants above here */
|
||||
__HWTSTAMP_TX_CNT
|
||||
};
|
||||
|
||||
/* possible values for hwtstamp_config->rx_filter */
|
||||
@ -140,6 +143,9 @@ enum hwtstamp_rx_filters {
|
||||
|
||||
/* NTP, UDP, all versions and packet modes */
|
||||
HWTSTAMP_FILTER_NTP_ALL,
|
||||
|
||||
/* add new constants above here */
|
||||
__HWTSTAMP_FILTER_CNT
|
||||
};
|
||||
|
||||
/* SCM_TIMESTAMPING_PKTINFO control message */
|
||||
|
@ -190,6 +190,9 @@ static int net_hwtstamp_validate(struct ifreq *ifr)
|
||||
case HWTSTAMP_TX_ONESTEP_P2P:
|
||||
tx_type_valid = 1;
|
||||
break;
|
||||
case __HWTSTAMP_TX_CNT:
|
||||
/* not a real value */
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rx_filter) {
|
||||
@ -211,6 +214,9 @@ static int net_hwtstamp_validate(struct ifreq *ifr)
|
||||
case HWTSTAMP_FILTER_NTP_ALL:
|
||||
rx_filter_valid = 1;
|
||||
break;
|
||||
case __HWTSTAMP_FILTER_CNT:
|
||||
/* not a real value */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tx_type_valid || !rx_filter_valid)
|
||||
|
@ -6,4 +6,4 @@ obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
|
||||
|
||||
ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \
|
||||
linkstate.o debug.o wol.o features.o privflags.o rings.o \
|
||||
channels.o
|
||||
channels.o coalesce.o pause.o eee.o tsinfo.o
|
||||
|
353
net/ethtool/coalesce.c
Normal file
353
net/ethtool/coalesce.c
Normal file
@ -0,0 +1,353 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
|
||||
struct coalesce_req_info {
|
||||
struct ethnl_req_info base;
|
||||
};
|
||||
|
||||
struct coalesce_reply_data {
|
||||
struct ethnl_reply_data base;
|
||||
struct ethtool_coalesce coalesce;
|
||||
u32 supported_params;
|
||||
};
|
||||
|
||||
#define COALESCE_REPDATA(__reply_base) \
|
||||
container_of(__reply_base, struct coalesce_reply_data, base)
|
||||
|
||||
#define __SUPPORTED_OFFSET ETHTOOL_A_COALESCE_RX_USECS
|
||||
static u32 attr_to_mask(unsigned int attr_type)
|
||||
{
|
||||
return BIT(attr_type - __SUPPORTED_OFFSET);
|
||||
}
|
||||
|
||||
/* build time check that indices in ethtool_ops::supported_coalesce_params
|
||||
* match corresponding attribute types with an offset
|
||||
*/
|
||||
#define __CHECK_SUPPORTED_OFFSET(x) \
|
||||
static_assert((ETHTOOL_ ## x) == \
|
||||
BIT((ETHTOOL_A_ ## x) - __SUPPORTED_OFFSET))
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_IRQ);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_IRQ);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_IRQ);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_IRQ);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_STATS_BLOCK_USECS);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_RX);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_TX);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_LOW);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_LOW);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_LOW);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_LOW);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_LOW);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_HIGH);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_HIGH);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_HIGH);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH);
|
||||
__CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL);
|
||||
|
||||
static const struct nla_policy
|
||||
coalesce_get_policy[ETHTOOL_A_COALESCE_MAX + 1] = {
|
||||
[ETHTOOL_A_COALESCE_UNSPEC] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_HEADER] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_REJECT },
|
||||
};
|
||||
|
||||
static int coalesce_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->get_coalesce)
|
||||
return -EOPNOTSUPP;
|
||||
data->supported_params = dev->ethtool_ops->supported_coalesce_params;
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dev->ethtool_ops->get_coalesce(dev, &data->coalesce);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coalesce_reply_size(const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
return nla_total_size(sizeof(u32)) + /* _RX_USECS */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_MAX_FRAMES */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_USECS_IRQ */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_MAX_FRAMES_IRQ */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_USECS */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_MAX_FRAMES */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_USECS_IRQ */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_MAX_FRAMES_IRQ */
|
||||
nla_total_size(sizeof(u32)) + /* _STATS_BLOCK_USECS */
|
||||
nla_total_size(sizeof(u8)) + /* _USE_ADAPTIVE_RX */
|
||||
nla_total_size(sizeof(u8)) + /* _USE_ADAPTIVE_TX */
|
||||
nla_total_size(sizeof(u32)) + /* _PKT_RATE_LOW */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_USECS_LOW */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_MAX_FRAMES_LOW */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_USECS_LOW */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_MAX_FRAMES_LOW */
|
||||
nla_total_size(sizeof(u32)) + /* _PKT_RATE_HIGH */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_USECS_HIGH */
|
||||
nla_total_size(sizeof(u32)) + /* _RX_MAX_FRAMES_HIGH */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_USECS_HIGH */
|
||||
nla_total_size(sizeof(u32)) + /* _TX_MAX_FRAMES_HIGH */
|
||||
nla_total_size(sizeof(u32)); /* _RATE_SAMPLE_INTERVAL */
|
||||
}
|
||||
|
||||
static bool coalesce_put_u32(struct sk_buff *skb, u16 attr_type, u32 val,
|
||||
u32 supported_params)
|
||||
{
|
||||
if (!val && !(supported_params & attr_to_mask(attr_type)))
|
||||
return false;
|
||||
return nla_put_u32(skb, attr_type, val);
|
||||
}
|
||||
|
||||
static bool coalesce_put_bool(struct sk_buff *skb, u16 attr_type, u32 val,
|
||||
u32 supported_params)
|
||||
{
|
||||
if (!val && !(supported_params & attr_to_mask(attr_type)))
|
||||
return false;
|
||||
return nla_put_u8(skb, attr_type, !!val);
|
||||
}
|
||||
|
||||
static int coalesce_fill_reply(struct sk_buff *skb,
|
||||
const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
const struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
|
||||
const struct ethtool_coalesce *coal = &data->coalesce;
|
||||
u32 supported = data->supported_params;
|
||||
|
||||
if (coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS,
|
||||
coal->rx_coalesce_usecs, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES,
|
||||
coal->rx_max_coalesced_frames, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_IRQ,
|
||||
coal->rx_coalesce_usecs_irq, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,
|
||||
coal->rx_max_coalesced_frames_irq, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS,
|
||||
coal->tx_coalesce_usecs, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES,
|
||||
coal->tx_max_coalesced_frames, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_IRQ,
|
||||
coal->tx_coalesce_usecs_irq, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,
|
||||
coal->tx_max_coalesced_frames_irq, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,
|
||||
coal->stats_block_coalesce_usecs, supported) ||
|
||||
coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,
|
||||
coal->use_adaptive_rx_coalesce, supported) ||
|
||||
coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,
|
||||
coal->use_adaptive_tx_coalesce, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_PKT_RATE_LOW,
|
||||
coal->pkt_rate_low, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_LOW,
|
||||
coal->rx_coalesce_usecs_low, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,
|
||||
coal->rx_max_coalesced_frames_low, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_LOW,
|
||||
coal->tx_coalesce_usecs_low, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,
|
||||
coal->tx_max_coalesced_frames_low, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_PKT_RATE_HIGH,
|
||||
coal->pkt_rate_high, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_HIGH,
|
||||
coal->rx_coalesce_usecs_high, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,
|
||||
coal->rx_max_coalesced_frames_high, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_HIGH,
|
||||
coal->tx_coalesce_usecs_high, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
|
||||
coal->tx_max_coalesced_frames_high, supported) ||
|
||||
coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
|
||||
coal->rate_sample_interval, supported))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethnl_request_ops ethnl_coalesce_request_ops = {
|
||||
.request_cmd = ETHTOOL_MSG_COALESCE_GET,
|
||||
.reply_cmd = ETHTOOL_MSG_COALESCE_GET_REPLY,
|
||||
.hdr_attr = ETHTOOL_A_COALESCE_HEADER,
|
||||
.max_attr = ETHTOOL_A_COALESCE_MAX,
|
||||
.req_info_size = sizeof(struct coalesce_req_info),
|
||||
.reply_data_size = sizeof(struct coalesce_reply_data),
|
||||
.request_policy = coalesce_get_policy,
|
||||
|
||||
.prepare_data = coalesce_prepare_data,
|
||||
.reply_size = coalesce_reply_size,
|
||||
.fill_reply = coalesce_fill_reply,
|
||||
};
|
||||
|
||||
/* COALESCE_SET */
|
||||
|
||||
static const struct nla_policy
|
||||
coalesce_set_policy[ETHTOOL_A_COALESCE_MAX + 1] = {
|
||||
[ETHTOOL_A_COALESCE_UNSPEC] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_COALESCE_HEADER] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .type = NLA_U8 },
|
||||
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .type = NLA_U8 },
|
||||
[ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *tb[ETHTOOL_A_COALESCE_MAX + 1];
|
||||
struct ethtool_coalesce coalesce = {};
|
||||
struct ethnl_req_info req_info = {};
|
||||
const struct ethtool_ops *ops;
|
||||
struct net_device *dev;
|
||||
u32 supported_params;
|
||||
bool mod = false;
|
||||
int ret;
|
||||
u16 a;
|
||||
|
||||
ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
|
||||
ETHTOOL_A_COALESCE_MAX, coalesce_set_policy,
|
||||
info->extack);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ethnl_parse_header_dev_get(&req_info,
|
||||
tb[ETHTOOL_A_COALESCE_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_coalesce || !ops->set_coalesce)
|
||||
goto out_dev;
|
||||
|
||||
/* make sure that only supported parameters are present */
|
||||
supported_params = ops->supported_coalesce_params;
|
||||
for (a = ETHTOOL_A_COALESCE_RX_USECS; a < __ETHTOOL_A_COALESCE_CNT; a++)
|
||||
if (tb[a] && !(supported_params & attr_to_mask(a))) {
|
||||
ret = -EINVAL;
|
||||
NL_SET_ERR_MSG_ATTR(info->extack, tb[a],
|
||||
"cannot modify an unsupported parameter");
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
goto out_rtnl;
|
||||
ret = ops->get_coalesce(dev, &coalesce);
|
||||
if (ret < 0)
|
||||
goto out_ops;
|
||||
|
||||
ethnl_update_u32(&coalesce.rx_coalesce_usecs,
|
||||
tb[ETHTOOL_A_COALESCE_RX_USECS], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_max_coalesced_frames,
|
||||
tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_coalesce_usecs_irq,
|
||||
tb[ETHTOOL_A_COALESCE_RX_USECS_IRQ], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_max_coalesced_frames_irq,
|
||||
tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_coalesce_usecs,
|
||||
tb[ETHTOOL_A_COALESCE_TX_USECS], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_max_coalesced_frames,
|
||||
tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_coalesce_usecs_irq,
|
||||
tb[ETHTOOL_A_COALESCE_TX_USECS_IRQ], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_max_coalesced_frames_irq,
|
||||
tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ], &mod);
|
||||
ethnl_update_u32(&coalesce.stats_block_coalesce_usecs,
|
||||
tb[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS], &mod);
|
||||
ethnl_update_bool32(&coalesce.use_adaptive_rx_coalesce,
|
||||
tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX], &mod);
|
||||
ethnl_update_bool32(&coalesce.use_adaptive_tx_coalesce,
|
||||
tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX], &mod);
|
||||
ethnl_update_u32(&coalesce.pkt_rate_low,
|
||||
tb[ETHTOOL_A_COALESCE_PKT_RATE_LOW], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_coalesce_usecs_low,
|
||||
tb[ETHTOOL_A_COALESCE_RX_USECS_LOW], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_max_coalesced_frames_low,
|
||||
tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_coalesce_usecs_low,
|
||||
tb[ETHTOOL_A_COALESCE_TX_USECS_LOW], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_max_coalesced_frames_low,
|
||||
tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW], &mod);
|
||||
ethnl_update_u32(&coalesce.pkt_rate_high,
|
||||
tb[ETHTOOL_A_COALESCE_PKT_RATE_HIGH], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_coalesce_usecs_high,
|
||||
tb[ETHTOOL_A_COALESCE_RX_USECS_HIGH], &mod);
|
||||
ethnl_update_u32(&coalesce.rx_max_coalesced_frames_high,
|
||||
tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_coalesce_usecs_high,
|
||||
tb[ETHTOOL_A_COALESCE_TX_USECS_HIGH], &mod);
|
||||
ethnl_update_u32(&coalesce.tx_max_coalesced_frames_high,
|
||||
tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH], &mod);
|
||||
ethnl_update_u32(&coalesce.rate_sample_interval,
|
||||
tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL], &mod);
|
||||
ret = 0;
|
||||
if (!mod)
|
||||
goto out_ops;
|
||||
|
||||
ret = dev->ethtool_ops->set_coalesce(dev, &coalesce);
|
||||
if (ret < 0)
|
||||
goto out_ops;
|
||||
ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);
|
||||
|
||||
out_ops:
|
||||
ethnl_ops_complete(dev);
|
||||
out_rtnl:
|
||||
rtnl_unlock();
|
||||
out_dev:
|
||||
dev_put(dev);
|
||||
return ret;
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
|
||||
@ -204,6 +207,53 @@ const char wol_mode_names[][ETH_GSTRING_LEN] = {
|
||||
};
|
||||
static_assert(ARRAY_SIZE(wol_mode_names) == WOL_MODE_COUNT);
|
||||
|
||||
const char sof_timestamping_names[][ETH_GSTRING_LEN] = {
|
||||
[const_ilog2(SOF_TIMESTAMPING_TX_HARDWARE)] = "hardware-transmit",
|
||||
[const_ilog2(SOF_TIMESTAMPING_TX_SOFTWARE)] = "software-transmit",
|
||||
[const_ilog2(SOF_TIMESTAMPING_RX_HARDWARE)] = "hardware-receive",
|
||||
[const_ilog2(SOF_TIMESTAMPING_RX_SOFTWARE)] = "software-receive",
|
||||
[const_ilog2(SOF_TIMESTAMPING_SOFTWARE)] = "software-system-clock",
|
||||
[const_ilog2(SOF_TIMESTAMPING_SYS_HARDWARE)] = "hardware-legacy-clock",
|
||||
[const_ilog2(SOF_TIMESTAMPING_RAW_HARDWARE)] = "hardware-raw-clock",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_ID)] = "option-id",
|
||||
[const_ilog2(SOF_TIMESTAMPING_TX_SCHED)] = "sched-transmit",
|
||||
[const_ilog2(SOF_TIMESTAMPING_TX_ACK)] = "ack-transmit",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_CMSG)] = "option-cmsg",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_TSONLY)] = "option-tsonly",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_STATS)] = "option-stats",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_PKTINFO)] = "option-pktinfo",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw",
|
||||
};
|
||||
static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT);
|
||||
|
||||
const char ts_tx_type_names[][ETH_GSTRING_LEN] = {
|
||||
[HWTSTAMP_TX_OFF] = "off",
|
||||
[HWTSTAMP_TX_ON] = "on",
|
||||
[HWTSTAMP_TX_ONESTEP_SYNC] = "onestep-sync",
|
||||
[HWTSTAMP_TX_ONESTEP_P2P] = "onestep-p2p",
|
||||
};
|
||||
static_assert(ARRAY_SIZE(ts_tx_type_names) == __HWTSTAMP_TX_CNT);
|
||||
|
||||
const char ts_rx_filter_names[][ETH_GSTRING_LEN] = {
|
||||
[HWTSTAMP_FILTER_NONE] = "none",
|
||||
[HWTSTAMP_FILTER_ALL] = "all",
|
||||
[HWTSTAMP_FILTER_SOME] = "some",
|
||||
[HWTSTAMP_FILTER_PTP_V1_L4_EVENT] = "ptpv1-l4-event",
|
||||
[HWTSTAMP_FILTER_PTP_V1_L4_SYNC] = "ptpv1-l4-sync",
|
||||
[HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ] = "ptpv1-l4-delay-req",
|
||||
[HWTSTAMP_FILTER_PTP_V2_L4_EVENT] = "ptpv2-l4-event",
|
||||
[HWTSTAMP_FILTER_PTP_V2_L4_SYNC] = "ptpv2-l4-sync",
|
||||
[HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ] = "ptpv2-l4-delay-req",
|
||||
[HWTSTAMP_FILTER_PTP_V2_L2_EVENT] = "ptpv2-l2-event",
|
||||
[HWTSTAMP_FILTER_PTP_V2_L2_SYNC] = "ptpv2-l2-sync",
|
||||
[HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ] = "ptpv2-l2-delay-req",
|
||||
[HWTSTAMP_FILTER_PTP_V2_EVENT] = "ptpv2-event",
|
||||
[HWTSTAMP_FILTER_PTP_V2_SYNC] = "ptpv2-sync",
|
||||
[HWTSTAMP_FILTER_PTP_V2_DELAY_REQ] = "ptpv2-delay-req",
|
||||
[HWTSTAMP_FILTER_NTP_ALL] = "ntp-all",
|
||||
};
|
||||
static_assert(ARRAY_SIZE(ts_rx_filter_names) == __HWTSTAMP_FILTER_CNT);
|
||||
|
||||
/* return false if legacy contained non-0 deprecated fields
|
||||
* maxtxpkt/maxrxpkt. rest of ksettings always updated
|
||||
*/
|
||||
@ -301,3 +351,23 @@ int ethtool_check_ops(const struct ethtool_ops *ops)
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->cmd = ETHTOOL_GET_TS_INFO;
|
||||
|
||||
if (phy_has_tsinfo(phydev))
|
||||
return phy_ts_info(phydev, info);
|
||||
if (ops->get_ts_info)
|
||||
return ops->get_ts_info(dev, info);
|
||||
|
||||
info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
info->phc_index = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
#define ETHTOOL_LINK_MODE(speed, type, duplex) \
|
||||
ETHTOOL_LINK_MODE_ ## speed ## base ## type ## _ ## duplex ## _BIT
|
||||
|
||||
#define __SOF_TIMESTAMPING_CNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1)
|
||||
|
||||
extern const char
|
||||
netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
|
||||
extern const char
|
||||
@ -23,6 +25,9 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
|
||||
extern const char link_mode_names[][ETH_GSTRING_LEN];
|
||||
extern const char netif_msg_class_names[][ETH_GSTRING_LEN];
|
||||
extern const char wol_mode_names[][ETH_GSTRING_LEN];
|
||||
extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
|
||||
extern const char ts_tx_type_names[][ETH_GSTRING_LEN];
|
||||
extern const char ts_rx_filter_names[][ETH_GSTRING_LEN];
|
||||
|
||||
int __ethtool_get_link(struct net_device *dev);
|
||||
|
||||
@ -30,5 +35,6 @@ bool convert_legacy_settings_to_link_ksettings(
|
||||
struct ethtool_link_ksettings *link_ksettings,
|
||||
const struct ethtool_cmd *legacy_settings);
|
||||
int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max);
|
||||
int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
|
||||
|
||||
#endif /* _ETHTOOL_COMMON_H */
|
||||
|
206
net/ethtool/eee.c
Normal file
206
net/ethtool/eee.c
Normal file
@ -0,0 +1,206 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "bitset.h"
|
||||
|
||||
#define EEE_MODES_COUNT \
|
||||
(sizeof_field(struct ethtool_eee, supported) * BITS_PER_BYTE)
|
||||
|
||||
struct eee_req_info {
|
||||
struct ethnl_req_info base;
|
||||
};
|
||||
|
||||
struct eee_reply_data {
|
||||
struct ethnl_reply_data base;
|
||||
struct ethtool_eee eee;
|
||||
};
|
||||
|
||||
#define EEE_REPDATA(__reply_base) \
|
||||
container_of(__reply_base, struct eee_reply_data, base)
|
||||
|
||||
static const struct nla_policy
|
||||
eee_get_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_REJECT },
|
||||
[ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_EEE_ENABLED] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_REJECT },
|
||||
};
|
||||
|
||||
static int eee_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct eee_reply_data *data = EEE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->get_eee)
|
||||
return -EOPNOTSUPP;
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dev->ethtool_ops->get_eee(dev, &data->eee);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eee_reply_size(const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
const struct eee_reply_data *data = EEE_REPDATA(reply_base);
|
||||
const struct ethtool_eee *eee = &data->eee;
|
||||
int len = 0;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(sizeof(eee->advertised) * BITS_PER_BYTE !=
|
||||
EEE_MODES_COUNT);
|
||||
BUILD_BUG_ON(sizeof(eee->lp_advertised) * BITS_PER_BYTE !=
|
||||
EEE_MODES_COUNT);
|
||||
|
||||
/* MODES_OURS */
|
||||
ret = ethnl_bitset32_size(&eee->advertised, &eee->supported,
|
||||
EEE_MODES_COUNT, link_mode_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret;
|
||||
/* MODES_PEERS */
|
||||
ret = ethnl_bitset32_size(&eee->lp_advertised, NULL,
|
||||
EEE_MODES_COUNT, link_mode_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret;
|
||||
|
||||
len += nla_total_size(sizeof(u8)) + /* _EEE_ACTIVE */
|
||||
nla_total_size(sizeof(u8)) + /* _EEE_ENABLED */
|
||||
nla_total_size(sizeof(u8)) + /* _EEE_TX_LPI_ENABLED */
|
||||
nla_total_size(sizeof(u32)); /* _EEE_TX_LPI_TIMER */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int eee_fill_reply(struct sk_buff *skb,
|
||||
const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
const struct eee_reply_data *data = EEE_REPDATA(reply_base);
|
||||
const struct ethtool_eee *eee = &data->eee;
|
||||
int ret;
|
||||
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_OURS,
|
||||
&eee->advertised, &eee->supported,
|
||||
EEE_MODES_COUNT, link_mode_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_PEER,
|
||||
&eee->lp_advertised, NULL, EEE_MODES_COUNT,
|
||||
link_mode_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (nla_put_u8(skb, ETHTOOL_A_EEE_ACTIVE, !!eee->eee_active) ||
|
||||
nla_put_u8(skb, ETHTOOL_A_EEE_ENABLED, !!eee->eee_enabled) ||
|
||||
nla_put_u8(skb, ETHTOOL_A_EEE_TX_LPI_ENABLED,
|
||||
!!eee->tx_lpi_enabled) ||
|
||||
nla_put_u32(skb, ETHTOOL_A_EEE_TX_LPI_TIMER, eee->tx_lpi_timer))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethnl_request_ops ethnl_eee_request_ops = {
|
||||
.request_cmd = ETHTOOL_MSG_EEE_GET,
|
||||
.reply_cmd = ETHTOOL_MSG_EEE_GET_REPLY,
|
||||
.hdr_attr = ETHTOOL_A_EEE_HEADER,
|
||||
.max_attr = ETHTOOL_A_EEE_MAX,
|
||||
.req_info_size = sizeof(struct eee_req_info),
|
||||
.reply_data_size = sizeof(struct eee_reply_data),
|
||||
.request_policy = eee_get_policy,
|
||||
|
||||
.prepare_data = eee_prepare_data,
|
||||
.reply_size = eee_reply_size,
|
||||
.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);
|
||||
if (ret < 0)
|
||||
goto out_ops;
|
||||
ethtool_notify(dev, ETHTOOL_MSG_EEE_NTF, NULL);
|
||||
|
||||
out_ops:
|
||||
ethnl_ops_complete(dev);
|
||||
out_rtnl:
|
||||
rtnl_unlock();
|
||||
out_dev:
|
||||
dev_put(dev);
|
||||
return ret;
|
||||
}
|
@ -1354,6 +1354,7 @@ static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
|
||||
static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_eee edata;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->set_eee)
|
||||
return -EOPNOTSUPP;
|
||||
@ -1361,7 +1362,10 @@ static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
|
||||
if (copy_from_user(&edata, useraddr, sizeof(edata)))
|
||||
return -EFAULT;
|
||||
|
||||
return dev->ethtool_ops->set_eee(dev, &edata);
|
||||
ret = dev->ethtool_ops->set_eee(dev, &edata);
|
||||
if (!ret)
|
||||
ethtool_notify(dev, ETHTOOL_MSG_EEE_NTF, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_nway_reset(struct net_device *dev)
|
||||
@ -1571,6 +1575,7 @@ static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
|
||||
void __user *useraddr)
|
||||
{
|
||||
struct ethtool_coalesce coalesce;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->set_coalesce)
|
||||
return -EOPNOTSUPP;
|
||||
@ -1581,7 +1586,10 @@ static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
|
||||
if (!ethtool_set_coalesce_supported(dev, &coalesce))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return dev->ethtool_ops->set_coalesce(dev, &coalesce);
|
||||
ret = dev->ethtool_ops->set_coalesce(dev, &coalesce);
|
||||
if (!ret)
|
||||
ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
|
||||
@ -1701,6 +1709,7 @@ static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
|
||||
static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_pauseparam pauseparam;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->set_pauseparam)
|
||||
return -EOPNOTSUPP;
|
||||
@ -1708,7 +1717,10 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
|
||||
if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
|
||||
return -EFAULT;
|
||||
|
||||
return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
|
||||
ret = dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
|
||||
if (!ret)
|
||||
ethtool_notify(dev, ETHTOOL_MSG_PAUSE_NTF, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
|
||||
@ -2128,32 +2140,17 @@ static int ethtool_get_dump_data(struct net_device *dev,
|
||||
|
||||
static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
int err = 0;
|
||||
struct ethtool_ts_info info;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.cmd = ETHTOOL_GET_TS_INFO;
|
||||
|
||||
if (phy_has_tsinfo(phydev)) {
|
||||
err = phy_ts_info(phydev, &info);
|
||||
} else if (ops->get_ts_info) {
|
||||
err = ops->get_ts_info(dev, &info);
|
||||
} else {
|
||||
info.so_timestamping =
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
info.phc_index = -1;
|
||||
}
|
||||
int err;
|
||||
|
||||
err = __ethtool_get_ts_info(dev, &info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (copy_to_user(useraddr, &info, sizeof(info)))
|
||||
err = -EFAULT;
|
||||
return -EFAULT;
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __ethtool_get_module_info(struct net_device *dev,
|
||||
|
@ -227,6 +227,10 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
|
||||
[ETHTOOL_MSG_PRIVFLAGS_GET] = ðnl_privflags_request_ops,
|
||||
[ETHTOOL_MSG_RINGS_GET] = ðnl_rings_request_ops,
|
||||
[ETHTOOL_MSG_CHANNELS_GET] = ðnl_channels_request_ops,
|
||||
[ETHTOOL_MSG_COALESCE_GET] = ðnl_coalesce_request_ops,
|
||||
[ETHTOOL_MSG_PAUSE_GET] = ðnl_pause_request_ops,
|
||||
[ETHTOOL_MSG_EEE_GET] = ðnl_eee_request_ops,
|
||||
[ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops,
|
||||
};
|
||||
|
||||
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
|
||||
@ -543,6 +547,9 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
|
||||
[ETHTOOL_MSG_PRIVFLAGS_NTF] = ðnl_privflags_request_ops,
|
||||
[ETHTOOL_MSG_RINGS_NTF] = ðnl_rings_request_ops,
|
||||
[ETHTOOL_MSG_CHANNELS_NTF] = ðnl_channels_request_ops,
|
||||
[ETHTOOL_MSG_COALESCE_NTF] = ðnl_coalesce_request_ops,
|
||||
[ETHTOOL_MSG_PAUSE_NTF] = ðnl_pause_request_ops,
|
||||
[ETHTOOL_MSG_EEE_NTF] = ðnl_eee_request_ops,
|
||||
};
|
||||
|
||||
/* default notification handler */
|
||||
@ -632,6 +639,9 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
|
||||
[ETHTOOL_MSG_PRIVFLAGS_NTF] = ethnl_default_notify,
|
||||
[ETHTOOL_MSG_RINGS_NTF] = ethnl_default_notify,
|
||||
[ETHTOOL_MSG_CHANNELS_NTF] = ethnl_default_notify,
|
||||
[ETHTOOL_MSG_COALESCE_NTF] = ethnl_default_notify,
|
||||
[ETHTOOL_MSG_PAUSE_NTF] = ethnl_default_notify,
|
||||
[ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify,
|
||||
};
|
||||
|
||||
void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
|
||||
@ -786,6 +796,49 @@ static const struct genl_ops ethtool_genl_ops[] = {
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.doit = ethnl_set_channels,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_COALESCE_GET,
|
||||
.doit = ethnl_default_doit,
|
||||
.start = ethnl_default_start,
|
||||
.dumpit = ethnl_default_dumpit,
|
||||
.done = ethnl_default_done,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_COALESCE_SET,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.doit = ethnl_set_coalesce,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_PAUSE_GET,
|
||||
.doit = ethnl_default_doit,
|
||||
.start = ethnl_default_start,
|
||||
.dumpit = ethnl_default_dumpit,
|
||||
.done = ethnl_default_done,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_PAUSE_SET,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.doit = ethnl_set_pause,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_EEE_GET,
|
||||
.doit = ethnl_default_doit,
|
||||
.start = ethnl_default_start,
|
||||
.dumpit = ethnl_default_dumpit,
|
||||
.done = ethnl_default_done,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_EEE_SET,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.doit = ethnl_set_eee,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_TSINFO_GET,
|
||||
.doit = ethnl_default_doit,
|
||||
.start = ethnl_default_start,
|
||||
.dumpit = ethnl_default_dumpit,
|
||||
.done = ethnl_default_done,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
|
||||
|
@ -341,6 +341,10 @@ extern const struct ethnl_request_ops ethnl_features_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_privflags_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_rings_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_channels_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_coalesce_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_pause_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_eee_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_tsinfo_request_ops;
|
||||
|
||||
int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
|
||||
int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
|
||||
@ -350,5 +354,8 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
|
||||
int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info);
|
||||
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_coalesce(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 */
|
||||
|
145
net/ethtool/pause.c
Normal file
145
net/ethtool/pause.c
Normal file
@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
|
||||
struct pause_req_info {
|
||||
struct ethnl_req_info base;
|
||||
};
|
||||
|
||||
struct pause_reply_data {
|
||||
struct ethnl_reply_data base;
|
||||
struct ethtool_pauseparam pauseparam;
|
||||
};
|
||||
|
||||
#define PAUSE_REPDATA(__reply_base) \
|
||||
container_of(__reply_base, struct pause_reply_data, base)
|
||||
|
||||
static const struct nla_policy
|
||||
pause_get_policy[ETHTOOL_A_PAUSE_MAX + 1] = {
|
||||
[ETHTOOL_A_PAUSE_UNSPEC] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_PAUSE_HEADER] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_PAUSE_AUTONEG] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_PAUSE_RX] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_PAUSE_TX] = { .type = NLA_REJECT },
|
||||
};
|
||||
|
||||
static int pause_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct pause_reply_data *data = PAUSE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->get_pauseparam)
|
||||
return -EOPNOTSUPP;
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dev->ethtool_ops->get_pauseparam(dev, &data->pauseparam);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pause_reply_size(const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
return nla_total_size(sizeof(u8)) + /* _PAUSE_AUTONEG */
|
||||
nla_total_size(sizeof(u8)) + /* _PAUSE_RX */
|
||||
nla_total_size(sizeof(u8)); /* _PAUSE_TX */
|
||||
}
|
||||
|
||||
static int pause_fill_reply(struct sk_buff *skb,
|
||||
const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
const struct pause_reply_data *data = PAUSE_REPDATA(reply_base);
|
||||
const struct ethtool_pauseparam *pauseparam = &data->pauseparam;
|
||||
|
||||
if (nla_put_u8(skb, ETHTOOL_A_PAUSE_AUTONEG, !!pauseparam->autoneg) ||
|
||||
nla_put_u8(skb, ETHTOOL_A_PAUSE_RX, !!pauseparam->rx_pause) ||
|
||||
nla_put_u8(skb, ETHTOOL_A_PAUSE_TX, !!pauseparam->tx_pause))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethnl_request_ops ethnl_pause_request_ops = {
|
||||
.request_cmd = ETHTOOL_MSG_PAUSE_GET,
|
||||
.reply_cmd = ETHTOOL_MSG_PAUSE_GET_REPLY,
|
||||
.hdr_attr = ETHTOOL_A_PAUSE_HEADER,
|
||||
.max_attr = ETHTOOL_A_PAUSE_MAX,
|
||||
.req_info_size = sizeof(struct pause_req_info),
|
||||
.reply_data_size = sizeof(struct pause_reply_data),
|
||||
.request_policy = pause_get_policy,
|
||||
|
||||
.prepare_data = pause_prepare_data,
|
||||
.reply_size = pause_reply_size,
|
||||
.fill_reply = pause_fill_reply,
|
||||
};
|
||||
|
||||
/* PAUSE_SET */
|
||||
|
||||
static const struct nla_policy
|
||||
pause_set_policy[ETHTOOL_A_PAUSE_MAX + 1] = {
|
||||
[ETHTOOL_A_PAUSE_UNSPEC] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_PAUSE_HEADER] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_PAUSE_AUTONEG] = { .type = NLA_U8 },
|
||||
[ETHTOOL_A_PAUSE_RX] = { .type = NLA_U8 },
|
||||
[ETHTOOL_A_PAUSE_TX] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *tb[ETHTOOL_A_PAUSE_MAX + 1];
|
||||
struct ethtool_pauseparam params = {};
|
||||
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_PAUSE_MAX,
|
||||
pause_set_policy, info->extack);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ethnl_parse_header_dev_get(&req_info,
|
||||
tb[ETHTOOL_A_PAUSE_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_pauseparam || !ops->set_pauseparam)
|
||||
goto out_dev;
|
||||
|
||||
rtnl_lock();
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
goto out_rtnl;
|
||||
ops->get_pauseparam(dev, ¶ms);
|
||||
|
||||
ethnl_update_bool32(¶ms.autoneg, tb[ETHTOOL_A_PAUSE_AUTONEG], &mod);
|
||||
ethnl_update_bool32(¶ms.rx_pause, tb[ETHTOOL_A_PAUSE_RX], &mod);
|
||||
ethnl_update_bool32(¶ms.tx_pause, tb[ETHTOOL_A_PAUSE_TX], &mod);
|
||||
ret = 0;
|
||||
if (!mod)
|
||||
goto out_ops;
|
||||
|
||||
ret = dev->ethtool_ops->set_pauseparam(dev, ¶ms);
|
||||
if (ret < 0)
|
||||
goto out_ops;
|
||||
ethtool_notify(dev, ETHTOOL_MSG_PAUSE_NTF, NULL);
|
||||
|
||||
out_ops:
|
||||
ethnl_ops_complete(dev);
|
||||
out_rtnl:
|
||||
rtnl_unlock();
|
||||
out_dev:
|
||||
dev_put(dev);
|
||||
return ret;
|
||||
}
|
@ -175,9 +175,10 @@ int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info)
|
||||
return ret;
|
||||
dev = req_info.dev;
|
||||
ops = dev->ethtool_ops;
|
||||
ret = -EOPNOTSUPP;
|
||||
if (!ops->get_priv_flags || !ops->set_priv_flags ||
|
||||
!ops->get_sset_count || !ops->get_strings)
|
||||
return -EOPNOTSUPP;
|
||||
goto out_dev;
|
||||
|
||||
rtnl_lock();
|
||||
ret = ethnl_ops_begin(dev);
|
||||
@ -204,6 +205,7 @@ int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info)
|
||||
ethnl_ops_complete(dev);
|
||||
out_rtnl:
|
||||
rtnl_unlock();
|
||||
out_dev:
|
||||
dev_put(dev);
|
||||
return ret;
|
||||
}
|
||||
|
@ -60,6 +60,21 @@ static const struct strset_info info_template[] = {
|
||||
.count = WOL_MODE_COUNT,
|
||||
.strings = wol_mode_names,
|
||||
},
|
||||
[ETH_SS_SOF_TIMESTAMPING] = {
|
||||
.per_dev = false,
|
||||
.count = __SOF_TIMESTAMPING_CNT,
|
||||
.strings = sof_timestamping_names,
|
||||
},
|
||||
[ETH_SS_TS_TX_TYPES] = {
|
||||
.per_dev = false,
|
||||
.count = __HWTSTAMP_TX_CNT,
|
||||
.strings = ts_tx_type_names,
|
||||
},
|
||||
[ETH_SS_TS_RX_FILTERS] = {
|
||||
.per_dev = false,
|
||||
.count = __HWTSTAMP_FILTER_CNT,
|
||||
.strings = ts_rx_filter_names,
|
||||
},
|
||||
};
|
||||
|
||||
struct strset_req_info {
|
||||
|
143
net/ethtool/tsinfo.c
Normal file
143
net/ethtool/tsinfo.c
Normal file
@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "bitset.h"
|
||||
|
||||
struct tsinfo_req_info {
|
||||
struct ethnl_req_info base;
|
||||
};
|
||||
|
||||
struct tsinfo_reply_data {
|
||||
struct ethnl_reply_data base;
|
||||
struct ethtool_ts_info ts_info;
|
||||
};
|
||||
|
||||
#define TSINFO_REPDATA(__reply_base) \
|
||||
container_of(__reply_base, struct tsinfo_reply_data, base)
|
||||
|
||||
static const struct nla_policy
|
||||
tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1] = {
|
||||
[ETHTOOL_A_TSINFO_UNSPEC] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_TSINFO_HEADER] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_TSINFO_TIMESTAMPING] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_TSINFO_TX_TYPES] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_TSINFO_RX_FILTERS] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_TSINFO_PHC_INDEX] = { .type = NLA_REJECT },
|
||||
};
|
||||
|
||||
static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = __ethtool_get_ts_info(dev, &data->ts_info);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tsinfo_reply_size(const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
const struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
|
||||
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
const struct ethtool_ts_info *ts_info = &data->ts_info;
|
||||
int len = 0;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(__SOF_TIMESTAMPING_CNT > 32);
|
||||
BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32);
|
||||
BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32);
|
||||
|
||||
if (ts_info->so_timestamping) {
|
||||
ret = ethnl_bitset32_size(&ts_info->so_timestamping, NULL,
|
||||
__SOF_TIMESTAMPING_CNT,
|
||||
sof_timestamping_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret; /* _TSINFO_TIMESTAMPING */
|
||||
}
|
||||
if (ts_info->tx_types) {
|
||||
ret = ethnl_bitset32_size(&ts_info->tx_types, NULL,
|
||||
__HWTSTAMP_TX_CNT,
|
||||
ts_tx_type_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret; /* _TSINFO_TX_TYPES */
|
||||
}
|
||||
if (ts_info->rx_filters) {
|
||||
ret = ethnl_bitset32_size(&ts_info->rx_filters, NULL,
|
||||
__HWTSTAMP_FILTER_CNT,
|
||||
ts_rx_filter_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret; /* _TSINFO_RX_FILTERS */
|
||||
}
|
||||
if (ts_info->phc_index >= 0)
|
||||
len += nla_total_size(sizeof(u32)); /* _TSINFO_PHC_INDEX */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int tsinfo_fill_reply(struct sk_buff *skb,
|
||||
const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
const struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
|
||||
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
const struct ethtool_ts_info *ts_info = &data->ts_info;
|
||||
int ret;
|
||||
|
||||
if (ts_info->so_timestamping) {
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_TIMESTAMPING,
|
||||
&ts_info->so_timestamping, NULL,
|
||||
__SOF_TIMESTAMPING_CNT,
|
||||
sof_timestamping_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ts_info->tx_types) {
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_TX_TYPES,
|
||||
&ts_info->tx_types, NULL,
|
||||
__HWTSTAMP_TX_CNT,
|
||||
ts_tx_type_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ts_info->rx_filters) {
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_RX_FILTERS,
|
||||
&ts_info->rx_filters, NULL,
|
||||
__HWTSTAMP_FILTER_CNT,
|
||||
ts_rx_filter_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ts_info->phc_index >= 0 &&
|
||||
nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX, ts_info->phc_index))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethnl_request_ops ethnl_tsinfo_request_ops = {
|
||||
.request_cmd = ETHTOOL_MSG_TSINFO_GET,
|
||||
.reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY,
|
||||
.hdr_attr = ETHTOOL_A_TSINFO_HEADER,
|
||||
.max_attr = ETHTOOL_A_TSINFO_MAX,
|
||||
.req_info_size = sizeof(struct tsinfo_req_info),
|
||||
.reply_data_size = sizeof(struct tsinfo_reply_data),
|
||||
.request_policy = tsinfo_get_policy,
|
||||
|
||||
.prepare_data = tsinfo_prepare_data,
|
||||
.reply_size = tsinfo_reply_size,
|
||||
.fill_reply = tsinfo_fill_reply,
|
||||
};
|
Loading…
Reference in New Issue
Block a user