Commit 3f1ac7a7 authored by David Decotigny's avatar David Decotigny Committed by David S. Miller

net: ethtool: add new ETHTOOL_xLINKSETTINGS API

This patch defines a new ETHTOOL_GLINKSETTINGS/SLINKSETTINGS API,
handled by the new get_link_ksettings/set_link_ksettings callbacks.
This API provides support for most legacy ethtool_cmd fields, adds
support for larger link mode masks (up to 4064 bits, variable length),
and removes ethtool_cmd deprecated
fields (transceiver/maxrxpkt/maxtxpkt).

This API is deprecating the legacy ETHTOOL_GSET/SSET API and provides
the following backward compatibility properties:
 - legacy ethtool with legacy drivers: no change, still using the
   get_settings/set_settings callbacks.
 - legacy ethtool with new get/set_link_ksettings drivers: the new
   driver callbacks are used, data internally converted to legacy
   ethtool_cmd. ETHTOOL_GSET will return only the 1st 32b of each link
   mode mask. ETHTOOL_SSET will fail if user tries to set the
   ethtool_cmd deprecated fields to
   non-0 (transceiver/maxrxpkt/maxtxpkt). A kernel warning is logged if
   driver sets higher bits.
 - future ethtool with legacy drivers: no change, still using the
   get_settings/set_settings callbacks, internally converted to new data
   structure. Deprecated fields (transceiver/maxrxpkt/maxtxpkt) will be
   ignored and seen as 0 from user space. Note that that "future"
   ethtool tool will not allow changes to these deprecated fields.
 - future ethtool with new drivers: direct call to the new callbacks.

By "future" ethtool, what is meant is:
 - query: first try ETHTOOL_GLINKSETTINGS, and revert to ETHTOOL_GSET if
   fails
 - set: query first and remember which of ETHTOOL_GLINKSETTINGS or
   ETHTOOL_GSET was successful
   + if ETHTOOL_GLINKSETTINGS was successful, then change config with
     ETHTOOL_SLINKSETTINGS. A failure there is final (do not try
     ETHTOOL_SSET).
   + otherwise ETHTOOL_GSET was successful, change config with
     ETHTOOL_SSET. A failure there is final (do not try
     ETHTOOL_SLINKSETTINGS).

The interaction user/kernel via the new API requires a small
ETHTOOL_GLINKSETTINGS handshake first to agree on the length of the link
mode bitmaps. If kernel doesn't agree with user, it returns the bitmap
length it is expecting from user as a negative length (and cmd field is
0). When kernel and user agree, kernel returns valid info in all
fields (ie. link mode length > 0 and cmd is ETHTOOL_GLINKSETTINGS).

Data structure crossing user/kernel boundary is 32/64-bit
agnostic. Converted internally to a legal kernel bitmap.

The internal __ethtool_get_settings kernel helper will gradually be
replaced by __ethtool_get_link_ksettings by the time the first
"link_settings" drivers start to appear. So this patch doesn't change
it, it will be removed before it needs to be changed.
Signed-off-by: default avatarDavid Decotigny <decot@googlers.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 48133335
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#ifndef _LINUX_ETHTOOL_H #ifndef _LINUX_ETHTOOL_H
#define _LINUX_ETHTOOL_H #define _LINUX_ETHTOOL_H
#include <linux/bitmap.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <uapi/linux/ethtool.h> #include <uapi/linux/ethtool.h>
...@@ -40,9 +41,6 @@ struct compat_ethtool_rxnfc { ...@@ -40,9 +41,6 @@ struct compat_ethtool_rxnfc {
#include <linux/rculist.h> #include <linux/rculist.h>
extern int __ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd);
/** /**
* enum ethtool_phys_id_state - indicator state for physical identification * enum ethtool_phys_id_state - indicator state for physical identification
* @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
...@@ -97,13 +95,74 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) ...@@ -97,13 +95,74 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
return index % n_rx_rings; return index % n_rx_rings;
} }
/* number of link mode bits/ulongs handled internally by kernel */
#define __ETHTOOL_LINK_MODE_MASK_NBITS \
(__ETHTOOL_LINK_MODE_LAST + 1)
/* declare a link mode bitmap */
#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
/* drivers must ignore base.cmd and base.link_mode_masks_nwords
* fields, but they are allowed to overwrite them (will be ignored).
*/
struct ethtool_link_ksettings {
struct ethtool_link_settings base;
struct {
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
} link_modes;
};
/**
* ethtool_link_ksettings_zero_link_mode - clear link_ksettings link mode mask
* @ptr : pointer to struct ethtool_link_ksettings
* @name : one of supported/advertising/lp_advertising
*/
#define ethtool_link_ksettings_zero_link_mode(ptr, name) \
bitmap_zero((ptr)->link_modes.name, __ETHTOOL_LINK_MODE_MASK_NBITS)
/**
* ethtool_link_ksettings_add_link_mode - set bit in link_ksettings
* link mode mask
* @ptr : pointer to struct ethtool_link_ksettings
* @name : one of supported/advertising/lp_advertising
* @mode : one of the ETHTOOL_LINK_MODE_*_BIT
* (not atomic, no bound checking)
*/
#define ethtool_link_ksettings_add_link_mode(ptr, name, mode) \
__set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
/**
* ethtool_link_ksettings_test_link_mode - test bit in ksettings link mode mask
* @ptr : pointer to struct ethtool_link_ksettings
* @name : one of supported/advertising/lp_advertising
* @mode : one of the ETHTOOL_LINK_MODE_*_BIT
* (not atomic, no bound checking)
*
* Returns true/false.
*/
#define ethtool_link_ksettings_test_link_mode(ptr, name, mode) \
test_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
extern int
__ethtool_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *link_ksettings);
/* DEPRECATED, use __ethtool_get_link_ksettings */
extern int __ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd);
/** /**
* struct ethtool_ops - optional netdev operations * struct ethtool_ops - optional netdev operations
* @get_settings: Get various device settings including Ethernet link * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
* API. Get various device settings including Ethernet link
* settings. The @cmd parameter is expected to have been cleared * settings. The @cmd parameter is expected to have been cleared
* before get_settings is called. Returns a negative error code or * before get_settings is called. Returns a negative error code
* zero. * or zero.
* @set_settings: Set various device settings including Ethernet link * @set_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
* API. Set various device settings including Ethernet link
* settings. Returns a negative error code or zero. * settings. Returns a negative error code or zero.
* @get_drvinfo: Report driver/device information. Should only set the * @get_drvinfo: Report driver/device information. Should only set the
* @driver, @version, @fw_version and @bus_info fields. If not * @driver, @version, @fw_version and @bus_info fields. If not
...@@ -211,6 +270,19 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) ...@@ -211,6 +270,19 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
* a TX queue has this number, return -EINVAL. If only a RX queue or a TX * a TX queue has this number, return -EINVAL. If only a RX queue or a TX
* queue has this number, ignore the inapplicable fields. * queue has this number, ignore the inapplicable fields.
* Returns a negative error code or zero. * Returns a negative error code or zero.
* @get_link_ksettings: When defined, takes precedence over the
* %get_settings method. Get various device settings
* including Ethernet link settings. The %cmd and
* %link_mode_masks_nwords fields should be ignored (use
* %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), any
* change to them will be overwritten by kernel. Returns a
* negative error code or zero.
* @set_link_ksettings: When defined, takes precedence over the
* %set_settings method. Set various device settings including
* Ethernet link settings. The %cmd and %link_mode_masks_nwords
* fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS
* instead of the latter), any change to them will be overwritten
* by kernel. Returns a negative error code or zero.
* *
* All operations are optional (i.e. the function pointer may be set * All operations are optional (i.e. the function pointer may be set
* to %NULL) and callers must take this into account. Callers must * to %NULL) and callers must take this into account. Callers must
...@@ -293,6 +365,9 @@ struct ethtool_ops { ...@@ -293,6 +365,9 @@ struct ethtool_ops {
struct ethtool_coalesce *); struct ethtool_coalesce *);
int (*set_per_queue_coalesce)(struct net_device *, u32, int (*set_per_queue_coalesce)(struct net_device *, u32,
struct ethtool_coalesce *); struct ethtool_coalesce *);
int (*get_link_ksettings)(struct net_device *,
struct ethtool_link_ksettings *);
int (*set_link_ksettings)(struct net_device *,
const struct ethtool_link_ksettings *);
}; };
#endif /* _LINUX_ETHTOOL_H */ #endif /* _LINUX_ETHTOOL_H */
This diff is collapsed.
This diff is collapsed.
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