Netdev List
 help / color / mirror / Atom feed
* [RFC PATCH ethtool v2 00/23] ethtool netlink interface (userspace side) (WiP)
From: Michal Kubecek @ 2018-07-30 12:55 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, John W. Linville

(The series is based on v4.17)

This patch series is and ethtool counterpart to kernel series "ethtool
netlink interface (WiP)"; it's marked as "v2" to match kernel series
version even if I never really sent "v1" to the list. It's only an RFC
as the netlink API it implements is still only a proposal.

The series modifies ethtool to use the netlink based kernel API when
available. If not, it falls back to the ioctl API. The aim is to
preserve command line syntax (with few extensions) and preserve the
output as much as possible.

This brings a natural question: why? It would be certainly tempting to
start with a new tool without the limitations of the old command line
syntax and without having to immitatte strange artefacts of the past.
It may still come to that but experience with iproute2 shows even if you
provide a new tool with cleaner syntax, more features and better
organized output, 19 years later you may still meet (a lot of) people
still using the old tool and claiming they are not going to learn some
new tools with "strange syntax and incomprehensible output" (the sadest
part being that many of them haven't learn using ifconfig before it had
been already obsolete for ten years). That's why I tried to give this
approach at least a try.

As both parser and dump functions in current ethtool code are closely
tied to data structures used by ioctl API, only very little of existing
code could be reused. The parts used also by netlink code were moved to
common.h and common.c. New netlink related code resides in netlink/
subdirectory. Copies of kernel uapi headers were moved to uapi/
directory to make their status more apparent. Netlink code uses libmnl
for message composition and parsing.

Currently reimplemented functions are

  -i / --driver
  (no option)
  -s
  -k / --show-features / --show-offload
  -K / --features / --offload
  -c / --show-coalesce
  -C / --coalesce
  -g / --show-ring
  -G / --set-ring
  -a / --show-pause
  -A / --pause
  -l / --show-channels
  -L / --set-channels
  --show-eee
  --set-eee
  --show-fec
  --set-fec

For all "get" type options, "*" can be used as device name to request
information about all interfaces supporting that request type.

The most interesting new feature is notification monitoring. When
started as

  ethtool --monitor --all

ethtool will listen to netlink notifications and display information
about changes. Replacing "--all" with one of the options above will show
only notifications about changes related to that option. A device name
can be also used to display only notifications related to that device.

ToDo / open questions:

- the most important question still is if we want to reimplement ethtool
  or come with a completely new utility instead

- if we go on with teaching ethtool netlink, another interesting
  question is how closely we need to stick to current output and its
  formatting; even if people are told not to, there are certainly tons
  of scripts parsing ethtool output which may break on any change

- an example of this are legacy "flags" for netdev features; we will
  have to make sure "ethtool -K dev tso off" will do what users expect
  it to but can we get rid of them at least in "ethtool -k" output?

- having to say "--monitor -all" for monitoring all events while just
  "--monitor" only watches for sset ("-s") type changes is probably
  counterintuitive; would it be better to make "--all" default and leave
  only "--monitor -s" for watching only "sset" events

Michal Kubecek (23):
  move UAPI header copies to a separate directory
  update UAPI header copies
  netlink: add netlink interface
  netlink: add support for string sets
  netlink: add notification monitor
  netlink: add netlink handler for gdrv (-i)
  netlink: add netlink handler for gset (no option)
  netlink: add helpers for command line parsing
  netlink: add netlink handler for sset (-s)
  netlink: add netlink handler for gfeatures (-k)
  netlink: add netlink handler for sfeatures (-K)
  netlink: add netlink handler for gcoalesce (-c)
  netlink: add netlink handler for gring (-g)
  netlink: add netlink handler for gpause (-a)
  netlink: add netlink handler for gchannels (-l)
  netlink: add netlink handler for geee (--show-eee)
  netlink: add netlink handler for gfec (--show-fec)
  netlink: add netlink handler for scoalesce (-C)
  netlink: add netlink handler for sring (-G)
  netlink: add netlink handler for spause (-A)
  netlink: add netlink handler for schannels (-L)
  netlink: add netlink handler for seee (--set-eee)
  netlink: add netlink handler for sfec (--set-fec)

 Makefile.am                                  |   20 +-
 common.c                                     |  325 ++++++
 common.h                                     |   83 ++
 configure.ac                                 |   14 +-
 ethtool.c                                    |  437 +++-----
 internal.h                                   |   12 +-
 netlink/drvinfo.c                            |   43 +
 netlink/extapi.h                             |   37 +
 netlink/monitor.c                            |  283 +++++
 netlink/netlink.c                            |  681 ++++++++++++
 netlink/netlink.h                            |  189 ++++
 netlink/params.c                             |  659 +++++++++++
 netlink/parser.c                             |  559 ++++++++++
 netlink/parser.h                             |   49 +
 netlink/settings.c                           | 1035 ++++++++++++++++++
 netlink/strset.c                             |  265 +++++
 netlink/strset.h                             |   16 +
 ethtool-copy.h => uapi/linux/ethtool.h       |   13 +-
 uapi/linux/ethtool_netlink.h                 |  325 ++++++
 uapi/linux/genetlink.h                       |   89 ++
 net_tstamp-copy.h => uapi/linux/net_tstamp.h |   19 +
 uapi/linux/netlink.h                         |  247 +++++
 22 files changed, 5134 insertions(+), 266 deletions(-)
 create mode 100644 common.c
 create mode 100644 common.h
 create mode 100644 netlink/drvinfo.c
 create mode 100644 netlink/extapi.h
 create mode 100644 netlink/monitor.c
 create mode 100644 netlink/netlink.c
 create mode 100644 netlink/netlink.h
 create mode 100644 netlink/params.c
 create mode 100644 netlink/parser.c
 create mode 100644 netlink/parser.h
 create mode 100644 netlink/settings.c
 create mode 100644 netlink/strset.c
 create mode 100644 netlink/strset.h
 rename ethtool-copy.h => uapi/linux/ethtool.h (99%)
 create mode 100644 uapi/linux/ethtool_netlink.h
 create mode 100644 uapi/linux/genetlink.h
 rename net_tstamp-copy.h => uapi/linux/net_tstamp.h (89%)
 create mode 100644 uapi/linux/netlink.h

-- 
2.18.0

^ permalink raw reply

* [RFC PATCH net-next v2 17/17] ethtool: implement SET_PARAMS message
From: Michal Kubecek @ 2018-07-30 12:54 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Sets the information provided by ETHTOOL_SCOALESCE, ETHTOOL_SRINGPARAM,
ETHTOOL_SPAUSEPARAM, ETHTOOL_SCHANNELS, ETHTOOL_SEEE and ETHTOOL_SFECPARAM.
Each of these has corresponding nesting attribute containing attributes for
its settings. This way, userspace can request changes equivalent to one or
more of the legacy requests (and provide only part of the data to update).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  71 ++-
 net/ethtool/netlink.c                        |   6 +
 net/ethtool/params.c                         | 429 +++++++++++++++++++
 3 files changed, 499 insertions(+), 7 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 630eebd7e741..2b70736110fe 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -126,7 +126,7 @@ List of message types
     ETHNL_CMD_GET_SETTINGS
     ETHNL_CMD_SET_SETTINGS
     ETHNL_CMD_GET_PARAMS
-    ETHNL_CMD_SET_PARAMS		response only (for now)
+    ETHNL_CMD_SET_PARAMS
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -408,6 +408,63 @@ to them are broadcasted as notifications on change of these settings using
 netlink or ioctl ethtool interface.
 
 
+SET_PARAMS
+----------
+
+SET_PARAMS request modifies the settings retrieved by GET_PARAMS, i.e. it
+replaces ETHTOOL_SCOALESCE, ETHTOOL_SRINGPARAM, ETHTOOL_SPAUSEPARAM,
+ETHTOOL_SCHANNELS, ETHTOOL_SEEE and ETHTOOL_SFECPARAM legacy commands. For
+each of these, relevant data attributes are contained in a corresponding nest
+attribute. Some of the attributes provided by GET_SETPARAMS are read only and
+cannot be set by SET_PARAMS request.
+
+    ETHA_PARAMS_COALESCE	(nest)		coalescing
+        ETHA_COALESCE_RX_USECS			(u32)
+        ETHA_COALESCE_RX_MAXFRM			(u32)
+        ETHA_COALESCE_RX_USECS_IRQ		(u32)
+        ETHA_COALESCE_RX_MAXFRM_IRQ		(u32)
+        ETHA_COALESCE_RX_USECS_LOW		(u32)
+        ETHA_COALESCE_RX_MAXFRM_LOW		(u32)
+        ETHA_COALESCE_RX_USECS_HIGH		(u32)
+        ETHA_COALESCE_RX_MAXFRM_HIGH		(u32)
+        ETHA_COALESCE_TX_USECS			(u32)
+        ETHA_COALESCE_TX_MAXFRM			(u32)
+        ETHA_COALESCE_TX_USECS_IRQ		(u32)
+        ETHA_COALESCE_TX_MAXFRM_IRQ		(u32)
+        ETHA_COALESCE_TX_USECS_LOW		(u32)
+        ETHA_COALESCE_TX_MAXFRM_LOW		(u32)
+        ETHA_COALESCE_TX_USECS_HIGH		(u32)
+        ETHA_COALESCE_TX_MAXFRM_HIGH		(u32)
+        ETHA_COALESCE_PKT_RATE_LOW		(u32)
+        ETHA_COALESCE_PKT_RATE_HIGH		(u32)
+        ETHA_COALESCE_RX_USE_ADAPTIVE		(bool)
+        ETHA_COALESCE_TX_USE_ADAPTIVE		(bool)
+        ETHA_COALESCE_RATE_SAMPLE_INTERVAL	(u32)
+        ETHA_COALESCE_STATS_BLOCK_USECS		(u32)
+    ETHA_PARAMS_RING		(nest)		ring parameters
+        ETHA_RING_RX_PENDING			(u32)
+        ETHA_RING_RX_MINI_PENDING		(u32)
+        ETHA_RING_RX_JUMBO_PENDING		(u32)
+        ETHA_RING_TX_PENDING			(u32)
+    ETHA_PARAMS_PAUSE		(nest)		pause parameters
+        ETHA_PAUSE_AUTONEG			(bool)
+        ETHA_PAUSE_RX				(bool)
+        ETHA_PAUSE_TX				(bool)
+    ETHA_PARAMS_CHANNELS	(nest)		channel settings
+        ETHA_CHANNELS_RX_COUNT			(u32)
+        ETHA_CHANNELS_TX_COUNT			(u32)
+        ETHA_CHANNELS_OTHER_COUNT		(u32)
+        ETHA_CHANNELS_COMBINED_COUNT		(u32)
+    ETHA_PARAMS_EEE		(nest)		EEE settings
+        ETHA_EEE_LINK_MODES			(bitset)
+		- change modes for which EEE is advertised
+        ETHA_EEE_ENABLED			(bool)
+        ETHA_EEE_TX_LPI_ENABLED			(bool)
+        ETHA_EEE_TX_LPI_TIMER			(u32)
+    ETHA_PARAMS_FEC		(nest)		FEC parameters
+        ETHA_FEC_MODES				(bitfield32)
+		- change configured FEC encodings
+
 
 Request translation
 -------------------
@@ -431,11 +488,11 @@ ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
 ETHTOOL_GCOALESCE		ETHNL_CMD_GET_PARAMS
-ETHTOOL_SCOALESCE		n/a
+ETHTOOL_SCOALESCE		ETHNL_CMD_SET_PARAMS
 ETHTOOL_GRINGPARAM		ETHNL_CMD_GET_PARAMS
-ETHTOOL_SRINGPARAM		n/a
+ETHTOOL_SRINGPARAM		ETHNL_CMD_SET_PARAMS
 ETHTOOL_GPAUSEPARAM		ETHNL_CMD_GET_PARAMS
-ETHTOOL_SPAUSEPARAM		n/a
+ETHTOOL_SPAUSEPARAM		ETHNL_CMD_SET_PARAMS
 ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SRXCSUM			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GTXCSUM			ETHNL_CMD_GET_SETTINGS
@@ -477,7 +534,7 @@ ETHTOOL_SRXFHINDIR		n/a
 ETHTOOL_GFEATURES		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFEATURES		n/a
 ETHTOOL_GCHANNELS		ETHNL_CMD_GET_PARAMS
-ETHTOOL_SCHANNELS		n/a
+ETHTOOL_SCHANNELS		ETHNL_CMD_SET_PARAMS
 ETHTOOL_SET_DUMP		n/a
 ETHTOOL_GET_DUMP_FLAG		n/a
 ETHTOOL_GET_DUMP_DATA		n/a
@@ -485,7 +542,7 @@ ETHTOOL_GET_TS_INFO		n/a
 ETHTOOL_GMODULEINFO		n/a
 ETHTOOL_GMODULEEEPROM		n/a
 ETHTOOL_GEEE			ETHNL_CMD_GET_PARAMS
-ETHTOOL_SEEE			n/a
+ETHTOOL_SEEE			ETHNL_CMD_SET_PARAMS
 ETHTOOL_GRSSH			n/a
 ETHTOOL_SRSSH			n/a
 ETHTOOL_GTUNABLE		n/a
@@ -497,5 +554,5 @@ ETHTOOL_SLINKSETTINGS		ETHNL_CMD_SET_SETTINGS
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
 ETHTOOL_GFECPARAM		ETHNL_CMD_GET_PARAMS
-ETHTOOL_SFECPARAM		n/a
+ETHTOOL_SFECPARAM		ETHNL_CMD_SET_PARAMS
 
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index b24a0e045ec0..17fee1ce077b 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -735,6 +735,7 @@ int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_settings(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_params(struct sk_buff *skb, struct genl_info *info);
+int ethnl_set_params(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_strset_start(struct netlink_callback *cb);
 int ethnl_drvinfo_start(struct netlink_callback *cb);
@@ -778,6 +779,11 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.dumpit	= ethnl_dumpit,
 		.done	= ethnl_params_done,
 	},
+	{
+		.cmd	= ETHNL_CMD_SET_PARAMS,
+		.flags	= GENL_UNS_ADMIN_PERM,
+		.doit	= ethnl_set_params,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/params.c b/net/ethtool/params.c
index 773e13fc1ae6..8cbf33ad81b8 100644
--- a/net/ethtool/params.c
+++ b/net/ethtool/params.c
@@ -577,3 +577,432 @@ void ethnl_params_notify(struct netdev_notifier_ethtool_info *info)
 err_skb:
 	nlmsg_free(skb);
 }
+
+static const struct nla_policy coalesce_policy[ETHA_COALESCE_MAX + 1] = {
+	[ETHA_COALESCE_UNSPEC]			= { .type = NLA_UNSPEC },
+	[ETHA_COALESCE_RX_USECS]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_MAXFRM]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_USECS_IRQ]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_MAXFRM_IRQ]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_USECS_LOW]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_MAXFRM_LOW]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_USECS_HIGH]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_MAXFRM_HIGH]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_USECS]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_MAXFRM]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_USECS_IRQ]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_MAXFRM_IRQ]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_USECS_LOW]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_MAXFRM_LOW]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_USECS_HIGH]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_TX_MAXFRM_HIGH]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_PKT_RATE_LOW]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_PKT_RATE_HIGH]		= { .type = NLA_U32 },
+	[ETHA_COALESCE_RX_USE_ADAPTIVE]		= { .type = NLA_U8 },
+	[ETHA_COALESCE_TX_USE_ADAPTIVE]		= { .type = NLA_U8 },
+	[ETHA_COALESCE_RATE_SAMPLE_INTERVAL]	= { .type = NLA_U32 },
+	[ETHA_COALESCE_STATS_BLOCK_USECS]	= { .type = NLA_U32 },
+};
+
+static int update_coalesce(struct genl_info *info, struct net_device *dev,
+			   struct nlattr *nest)
+{
+	struct nlattr *tb[ETHA_COALESCE_MAX + 1];
+	struct ethtool_coalesce data = {};
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	if (!dev->ethtool_ops->get_coalesce || !dev->ethtool_ops->set_coalesce)
+		return -EOPNOTSUPP;
+	ret = dev->ethtool_ops->get_coalesce(dev, &data);
+	if (ret < 0)
+		return ret;
+
+	ret = nla_parse_nested(tb, ETHA_COALESCE_MAX, nest, coalesce_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+
+	if (ethnl_update_u32(&data.rx_coalesce_usecs,
+			     tb[ETHA_COALESCE_RX_USECS]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_max_coalesced_frames,
+			     tb[ETHA_COALESCE_RX_MAXFRM]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_coalesce_usecs_irq,
+			     tb[ETHA_COALESCE_RX_USECS_IRQ]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_max_coalesced_frames_irq,
+			     tb[ETHA_COALESCE_RX_MAXFRM_IRQ]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_coalesce_usecs_low,
+			     tb[ETHA_COALESCE_RX_USECS_LOW]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_max_coalesced_frames_low,
+			     tb[ETHA_COALESCE_RX_MAXFRM_LOW]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_coalesce_usecs_high,
+			     tb[ETHA_COALESCE_RX_USECS_HIGH]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_max_coalesced_frames_high,
+			     tb[ETHA_COALESCE_RX_MAXFRM_HIGH]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_coalesce_usecs,
+			     tb[ETHA_COALESCE_TX_USECS]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_max_coalesced_frames,
+			     tb[ETHA_COALESCE_TX_MAXFRM]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_coalesce_usecs_irq,
+			     tb[ETHA_COALESCE_TX_USECS_IRQ]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_max_coalesced_frames_irq,
+			     tb[ETHA_COALESCE_TX_MAXFRM_IRQ]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_coalesce_usecs_low,
+			     tb[ETHA_COALESCE_TX_USECS_LOW]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_max_coalesced_frames_low,
+			     tb[ETHA_COALESCE_TX_MAXFRM_LOW]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_coalesce_usecs_high,
+			     tb[ETHA_COALESCE_TX_USECS_HIGH]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_max_coalesced_frames_high,
+			     tb[ETHA_COALESCE_TX_MAXFRM_HIGH]))
+		mod = true;
+	if (ethnl_update_u32(&data.pkt_rate_low,
+			     tb[ETHA_COALESCE_PKT_RATE_LOW]))
+		mod = true;
+	if (ethnl_update_u32(&data.pkt_rate_high,
+			     tb[ETHA_COALESCE_PKT_RATE_HIGH]))
+		mod = true;
+	if (ethnl_update_bool32(&data.use_adaptive_rx_coalesce,
+				tb[ETHA_COALESCE_RX_USE_ADAPTIVE]))
+		mod = true;
+	if (ethnl_update_bool32(&data.use_adaptive_tx_coalesce,
+				tb[ETHA_COALESCE_TX_USE_ADAPTIVE]))
+		mod = true;
+	if (ethnl_update_u32(&data.rate_sample_interval,
+			     tb[ETHA_COALESCE_RATE_SAMPLE_INTERVAL]))
+		mod = true;
+	if (ethnl_update_u32(&data.stats_block_coalesce_usecs,
+			     tb[ETHA_COALESCE_STATS_BLOCK_USECS]))
+		mod = true;
+
+	if (!mod)
+		return 0;
+	ret = dev->ethtool_ops->set_coalesce(dev, &data);
+	return (ret < 0) ? ret : 1;
+}
+
+static const struct nla_policy ring_policy[ETHA_RING_MAX + 1] = {
+	[ETHA_RING_UNSPEC]			= { .type = NLA_UNSPEC },
+	[ETHA_RING_RX_MAX_PENDING]		= { .type = NLA_U32 },
+	[ETHA_RING_RX_MINI_MAX_PENDING]		= { .type = NLA_U32 },
+	[ETHA_RING_RX_JUMBO_MAX_PENDING]	= { .type = NLA_U32 },
+	[ETHA_RING_TX_MAX_PENDING]		= { .type = NLA_U32 },
+	[ETHA_RING_RX_PENDING]			= { .type = NLA_U32 },
+	[ETHA_RING_RX_MINI_PENDING]		= { .type = NLA_U32 },
+	[ETHA_RING_RX_JUMBO_PENDING]		= { .type = NLA_U32 },
+	[ETHA_RING_TX_PENDING]			= { .type = NLA_U32 },
+};
+
+static int update_ring(struct genl_info *info, struct net_device *dev,
+		       struct nlattr *nest)
+{
+	struct nlattr *tb[ETHA_RING_MAX + 1];
+	struct ethtool_ringparam data = {};
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	if (!dev->ethtool_ops->get_ringparam ||
+	    !dev->ethtool_ops->set_ringparam)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_ringparam(dev, &data);
+
+	ret = nla_parse_nested(tb, ETHA_RING_MAX, nest, ring_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+	/* read only attributes */
+	if (tb[ETHA_RING_RX_MAX_PENDING] || tb[ETHA_RING_RX_MINI_MAX_PENDING] ||
+	    tb[ETHA_RING_RX_JUMBO_MAX_PENDING] ||
+	    tb[ETHA_RING_TX_MAX_PENDING]) {
+		ETHNL_SET_ERRMSG(info, "attempt to set a read only attribute");
+		return -EINVAL;
+	}
+
+	if (ethnl_update_u32(&data.rx_pending, tb[ETHA_RING_RX_PENDING]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_mini_pending,
+			     tb[ETHA_RING_RX_MINI_PENDING]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_jumbo_pending,
+			     tb[ETHA_RING_RX_JUMBO_PENDING]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_pending, tb[ETHA_RING_TX_PENDING]))
+		mod = true;
+	if (!mod)
+		return 0;
+
+	/* ensure new ring parameters are within the maximums */
+	if (data.rx_pending > data.rx_max_pending ||
+	    data.rx_mini_pending > data.rx_mini_max_pending ||
+	    data.rx_jumbo_pending > data.rx_jumbo_max_pending ||
+	    data.tx_pending > data.tx_max_pending) {
+		ETHNL_SET_ERRMSG(info,
+				 "requested ring param value exceeeds maximum");
+		return -EINVAL;
+	}
+
+	ret = dev->ethtool_ops->set_ringparam(dev, &data);
+	return (ret < 0) ? ret : 1;
+}
+
+static const struct nla_policy pause_policy[ETHA_PAUSE_MAX + 1] = {
+	[ETHA_PAUSE_UNSPEC]	= { .type = NLA_UNSPEC },
+	[ETHA_PAUSE_AUTONEG]	= { .type = NLA_U8 },
+	[ETHA_PAUSE_RX]		= { .type = NLA_U8 },
+	[ETHA_PAUSE_TX]		= { .type = NLA_U8 },
+};
+
+static int update_pause(struct genl_info *info, struct net_device *dev,
+			struct nlattr *nest)
+{
+	struct nlattr *tb[ETHA_RING_MAX + 1];
+	struct ethtool_pauseparam data = {};
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	if (!dev->ethtool_ops->get_pauseparam ||
+	    !dev->ethtool_ops->set_pauseparam)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_pauseparam(dev, &data);
+
+	ret = nla_parse_nested(tb, ETHA_PAUSE_MAX, nest, pause_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+
+	if (ethnl_update_u32(&data.autoneg, tb[ETHA_PAUSE_AUTONEG]))
+		mod = true;
+	if (ethnl_update_u32(&data.rx_pause, tb[ETHA_PAUSE_RX]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_pause, tb[ETHA_PAUSE_TX]))
+		mod = true;
+
+	if (!mod)
+		return 0;
+	ret = dev->ethtool_ops->set_pauseparam(dev, &data);
+	return (ret < 0) ? ret : 1;
+}
+
+static const struct nla_policy channels_policy[ETHA_CHANNELS_MAX + 1] = {
+	[ETHA_CHANNELS_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_CHANNELS_MAX_RX]		= { .type = NLA_U32 },
+	[ETHA_CHANNELS_MAX_TX]		= { .type = NLA_U32 },
+	[ETHA_CHANNELS_MAX_OTHER]	= { .type = NLA_U32 },
+	[ETHA_CHANNELS_MAX_COMBINED]	= { .type = NLA_U32 },
+	[ETHA_CHANNELS_RX_COUNT]	= { .type = NLA_U32 },
+	[ETHA_CHANNELS_TX_COUNT]	= { .type = NLA_U32 },
+	[ETHA_CHANNELS_OTHER_COUNT]	= { .type = NLA_U32 },
+	[ETHA_CHANNELS_COMBINED_COUNT]	= { .type = NLA_U32 },
+};
+
+static int update_channels(struct genl_info *info, struct net_device *dev,
+			   struct nlattr *nest)
+{
+	struct nlattr *tb[ETHA_CHANNELS_MAX + 1];
+	struct ethtool_channels data = {};
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	if (!dev->ethtool_ops->get_channels ||
+	    !dev->ethtool_ops->set_channels)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_channels(dev, &data);
+
+	ret = nla_parse_nested(tb, ETHA_CHANNELS_MAX, nest, channels_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+	/* read only attributes */
+	if (tb[ETHA_CHANNELS_MAX_RX] || tb[ETHA_CHANNELS_MAX_TX] ||
+	    tb[ETHA_CHANNELS_MAX_OTHER] || tb[ETHA_CHANNELS_MAX_COMBINED]) {
+		ETHNL_SET_ERRMSG(info, "attempt to set a read only attribute");
+		return -EINVAL;
+	}
+
+	if (ethnl_update_u32(&data.rx_count, tb[ETHA_CHANNELS_RX_COUNT]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_count, tb[ETHA_CHANNELS_TX_COUNT]))
+		mod = true;
+	if (ethnl_update_u32(&data.other_count, tb[ETHA_CHANNELS_OTHER_COUNT]))
+		mod = true;
+	if (ethnl_update_u32(&data.combined_count,
+			     tb[ETHA_CHANNELS_COMBINED_COUNT]))
+		mod = true;
+
+	if (!mod)
+		return 0;
+	ret = dev->ethtool_ops->set_channels(dev, &data);
+	return (ret < 0) ? ret : 1;
+}
+
+static const struct nla_policy eee_policy[ETHA_EEE_MAX + 1] = {
+	[ETHA_EEE_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_EEE_LINK_MODES]		= { .type = NLA_NESTED },
+	[ETHA_EEE_PEER_MODES]		= { .type = NLA_NESTED },
+	[ETHA_EEE_ACTIVE]		= { .type = NLA_U8 },
+	[ETHA_EEE_ENABLED]		= { .type = NLA_U8 },
+	[ETHA_EEE_TX_LPI_ENABLED]	= { .type = NLA_U8 },
+	[ETHA_EEE_TX_LPI_TIMER]		= { .type = NLA_U32 },
+};
+
+static int update_eee(struct genl_info *info, struct net_device *dev,
+		      struct nlattr *nest)
+{
+	struct nlattr *tb[ETHA_EEE_MAX + 1];
+	struct ethtool_eee data = {};
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	if (!dev->ethtool_ops->get_eee ||
+	    !dev->ethtool_ops->set_eee)
+		return -EOPNOTSUPP;
+	ret = dev->ethtool_ops->get_eee(dev, &data);
+	if (ret < 0)
+		return ret;
+
+	ret = nla_parse_nested(tb, ETHA_EEE_MAX, nest, eee_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+	/* read only attributes */
+	if (tb[ETHA_EEE_PEER_MODES] || tb[ETHA_EEE_ACTIVE]) {
+		ETHNL_SET_ERRMSG(info, "attempt to set a read only attribute");
+		return -EINVAL;
+	}
+
+	if (ethnl_update_bitset32(&data.advertised, NULL, 32,
+				  tb[ETHA_EEE_LINK_MODES], &ret,
+				  link_mode_names, info))
+		mod = true;
+	if (ret < 0)
+		return ret;
+	if (ethnl_update_bool32(&data.eee_enabled, tb[ETHA_EEE_ENABLED]))
+		mod = true;
+	if (ethnl_update_bool32(&data.tx_lpi_enabled,
+				tb[ETHA_EEE_TX_LPI_ENABLED]))
+		mod = true;
+	if (ethnl_update_u32(&data.tx_lpi_timer, tb[ETHA_EEE_TX_LPI_TIMER]))
+		mod = true;
+
+	if (!mod)
+		return 0;
+	ret = dev->ethtool_ops->set_eee(dev, &data);
+	return (ret < 0) ? ret : 1;
+}
+
+static const struct nla_policy fec_policy[ETHA_FEC_MAX + 1] = {
+	[ETHA_FEC_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_FEC_MODES]		= { .type = NLA_U32 },
+};
+
+static int update_fec(struct genl_info *info, struct net_device *dev,
+		      struct nlattr *nest)
+{
+	struct nlattr *tb[ETHA_FEC_MAX + 1];
+	struct ethtool_fecparam data = {};
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	if (!dev->ethtool_ops->get_fecparam ||
+	    !dev->ethtool_ops->set_fecparam)
+		return -EOPNOTSUPP;
+	ret = dev->ethtool_ops->get_fecparam(dev, &data);
+	if (ret < 0)
+		return ret;
+
+	ret = nla_parse_nested(tb, ETHA_FEC_MAX, nest, fec_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+
+	if (ethnl_update_bitfield32(&data.fec, tb[ETHA_FEC_MODES]))
+		mod = true;
+
+	if (!mod)
+		return 0;
+	ret = dev->ethtool_ops->set_fecparam(dev, &data);
+	return (ret < 0) ? ret : 1;
+}
+
+int ethnl_set_params(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *tb[ETHA_PARAMS_MAX + 1];
+	struct net_device *dev;
+	u32 req_mask = 0;
+	int ret;
+
+	ret = genlmsg_parse(info->nlhdr, &ethtool_genl_family, tb,
+			    ETHA_PARAMS_MAX, params_policy, info->extack);
+	if (ret < 0)
+		return ret;
+	dev = ethnl_dev_get(info, tb[ETHA_PARAMS_DEV]);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+	rtnl_lock();
+
+	ret = update_coalesce(info, dev, tb[ETHA_PARAMS_COALESCE]);
+	if (ret < 0)
+		goto out_unlock;
+	if (ret)
+		req_mask |= ETH_PARAMS_IM_COALESCE;
+	ret = update_ring(info, dev, tb[ETHA_PARAMS_RING]);
+	if (ret < 0)
+		goto out_unlock;
+	if (ret)
+		req_mask |= ETH_PARAMS_IM_RING;
+	ret = update_pause(info, dev, tb[ETHA_PARAMS_PAUSE]);
+	if (ret < 0)
+		goto out_unlock;
+	if (ret)
+		req_mask |= ETH_PARAMS_IM_PAUSE;
+	ret = update_channels(info, dev, tb[ETHA_PARAMS_CHANNELS]);
+	if (ret < 0)
+		goto out_unlock;
+	if (ret)
+		req_mask |= ETH_PARAMS_IM_CHANNELS;
+	ret = update_eee(info, dev, tb[ETHA_PARAMS_EEE]);
+	if (ret < 0)
+		goto out_unlock;
+	if (ret)
+		req_mask |= ETH_PARAMS_IM_EEE;
+	ret = update_fec(info, dev, tb[ETHA_PARAMS_FEC]);
+	if (ret < 0)
+		goto out_unlock;
+	if (ret)
+		req_mask |= ETH_PARAMS_IM_FEC;
+
+	ret = 0;
+out_unlock:
+	if (req_mask)
+		ethnl_notify(dev, NULL, ETHNL_CMD_SET_PARAMS, req_mask);
+	rtnl_unlock();
+	dev_put(dev);
+	return ret;
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 15/17] ethtool: implement GET_PARAMS message
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Requests the information provide by ETHTOOL_GCOALESCE, ETHTOOL_GRINGPARAM,
ETHTOOL_GPAUSEPARAM, ETHTOOL_GCHANNELS, ETHTOOL_GEEE and ETHTOOL_GFECPARAM.
Flags in info_mask allow selecting only some (or on) of these categories.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt | 107 +++-
 include/uapi/linux/ethtool_netlink.h         | 119 ++++
 net/ethtool/Makefile                         |   2 +-
 net/ethtool/netlink.c                        |  10 +
 net/ethtool/params.c                         | 539 +++++++++++++++++++
 5 files changed, 770 insertions(+), 7 deletions(-)
 create mode 100644 net/ethtool/params.c

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 307d8c6c6c85..630eebd7e741 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -125,6 +125,8 @@ List of message types
     ETHNL_CMD_SET_DRVINFO		response only
     ETHNL_CMD_GET_SETTINGS
     ETHNL_CMD_SET_SETTINGS
+    ETHNL_CMD_GET_PARAMS
+    ETHNL_CMD_SET_PARAMS		response only (for now)
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -314,6 +316,99 @@ the operation); mask shows bits which have been changed and value their new
 values.
 
 
+GET_PARAMS
+----------
+
+GET_PARAMS request retrieves information provided by legacy comands
+ETHTOOL_GCOALESCE (coalescing setting), ETHTOOL_GRINGPARAM (ring parameters),
+ETHTOOL_GPAUSEPARAM (pause parameters), ETHTOOL_GCHANNELS (channel settings),
+ETHTOOL_GEEE (EEE settings) and ETHTOOL_GFECPARAM (FEC parameters). For each
+of these, there is a bit in header info_mask so that only one type of
+information can be requested.
+
+Request contents:
+
+    ETHA_PARAMS_DEV		(nested)	device identification
+    ETHA_PARAMS_INFOMASK	(u32)		info mask
+    ETHA_PARAMS_COMPACT		(flag)		request compact bitsets
+
+Info mask bits:
+
+    ETH_PARAMS_IM_COALESCE		coalescing settings
+    ETH_PARAMS_IM_RING			ring parameters
+    ETH_PARAMS_IM_PAUSE			pause parameters
+    ETH_PARAMS_IM_CHANNELS		channel settings
+    ETH_PARAMS_IM_EEE			EEE settings
+    ETH_PARAMS_IM_FEC			FEC parameters
+
+Response contents: On top level, there is one attribute for each of the
+information categories, the information is nested in it.
+
+    ETHA_PARAMS_DEV		(nested)	device identification
+    ETHA_PARAMS_COALESCE	(nested)	coalescing
+        ETHA_COALESCE_RX_USECS			(u32)
+        ETHA_COALESCE_RX_MAXFRM			(u32)
+        ETHA_COALESCE_RX_USECS_IRQ		(u32)
+        ETHA_COALESCE_RX_MAXFRM_IRQ		(u32)
+        ETHA_COALESCE_RX_USECS_LOW		(u32)
+        ETHA_COALESCE_RX_MAXFRM_LOW		(u32)
+        ETHA_COALESCE_RX_USECS_HIGH		(u32)
+        ETHA_COALESCE_RX_MAXFRM_HIGH		(u32)
+        ETHA_COALESCE_TX_USECS			(u32)
+        ETHA_COALESCE_TX_MAXFRM			(u32)
+        ETHA_COALESCE_TX_USECS_IRQ		(u32)
+        ETHA_COALESCE_TX_MAXFRM_IRQ		(u32)
+        ETHA_COALESCE_TX_USECS_LOW		(u32)
+        ETHA_COALESCE_TX_MAXFRM_LOW		(u32)
+        ETHA_COALESCE_TX_USECS_HIGH		(u32)
+        ETHA_COALESCE_TX_MAXFRM_HIGH		(u32)
+        ETHA_COALESCE_PKT_RATE_LOW		(u32)
+        ETHA_COALESCE_PKT_RATE_HIGH		(u32)
+        ETHA_COALESCE_RX_USE_ADAPTIVE		(bool)
+        ETHA_COALESCE_TX_USE_ADAPTIVE		(bool)
+        ETHA_COALESCE_RATE_SAMPLE_INTERVAL	(u32)
+        ETHA_COALESCE_STATS_BLOCK_USECS		(u32)
+    ETHA_PARAMS_RING		(nested)	ring parameters
+        ETHA_RING_RX_MAX_PENDING		(u32)
+        ETHA_RING_RX_MINI_MAX_PENDING		(u32)
+        ETHA_RING_RX_JUMBO_MAX_PENDING		(u32)
+        ETHA_RING_TX_MAX_PENDING		(u32)
+        ETHA_RING_RX_PENDING			(u32)
+        ETHA_RING_RX_MINI_PENDING		(u32)
+        ETHA_RING_RX_JUMBO_PENDING		(u32)
+        ETHA_RING_TX_PENDING			(u32)
+    ETHA_PARAMS_PAUSE		(nested)	pause parameters
+        ETHA_PAUSE_AUTONEG			(bool)
+        ETHA_PAUSE_RX				(bool)
+        ETHA_PAUSE_TX				(bool)
+    ETHA_PARAMS_CHANNELS	(nested)	channel settings
+        ETHA_CHANNELS_MAX_RX			(u32)
+        ETHA_CHANNELS_MAX_TX			(u32)
+        ETHA_CHANNELS_MAX_OTHER			(u32)
+        ETHA_CHANNELS_MAX_COMBINED		(u32)
+        ETHA_CHANNELS_RX_COUNT			(u32)
+        ETHA_CHANNELS_TX_COUNT			(u32)
+        ETHA_CHANNELS_OTHER_COUNT		(u32)
+        ETHA_CHANNELS_COMBINED_COUNT		(u32)
+    ETHA_PARAMS_EEE		(nested)	EEE settings
+        ETHA_EEE_LINK_MODES			(bitset)
+		- modes for which EEE is advertised (value) or supported (mask)
+        ETHA_EEE_PEER_MODES			(bitset)
+		- modes for which link partner advertises EEE
+        ETHA_EEE_ACTIVE				(bool)
+        ETHA_EEE_ENABLED			(bool)
+        ETHA_EEE_TX_LPI_ENABLED			(bool)
+        ETHA_EEE_TX_LPI_TIMER			(u32)
+    ETHA_PARAMS_FEC		(nested)	FEC parameters
+        ETHA_FEC_MODES				(bitfield32)
+		- active (value) and configured (selector) FEC encodings
+
+GET_PARAMS requests allow dumps and messages in the same format as response
+to them are broadcasted as notifications on change of these settings using
+netlink or ioctl ethtool interface.
+
+
+
 Request translation
 -------------------
 
@@ -335,11 +430,11 @@ ETHTOOL_NWAY_RST		n/a
 ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
-ETHTOOL_GCOALESCE		n/a
+ETHTOOL_GCOALESCE		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SCOALESCE		n/a
-ETHTOOL_GRINGPARAM		n/a
+ETHTOOL_GRINGPARAM		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SRINGPARAM		n/a
-ETHTOOL_GPAUSEPARAM		n/a
+ETHTOOL_GPAUSEPARAM		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SPAUSEPARAM		n/a
 ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SRXCSUM			ETHNL_CMD_SET_SETTINGS
@@ -381,7 +476,7 @@ ETHTOOL_GRXFHINDIR		n/a
 ETHTOOL_SRXFHINDIR		n/a
 ETHTOOL_GFEATURES		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFEATURES		n/a
-ETHTOOL_GCHANNELS		n/a
+ETHTOOL_GCHANNELS		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SCHANNELS		n/a
 ETHTOOL_SET_DUMP		n/a
 ETHTOOL_GET_DUMP_FLAG		n/a
@@ -389,7 +484,7 @@ ETHTOOL_GET_DUMP_DATA		n/a
 ETHTOOL_GET_TS_INFO		n/a
 ETHTOOL_GMODULEINFO		n/a
 ETHTOOL_GMODULEEEPROM		n/a
-ETHTOOL_GEEE			n/a
+ETHTOOL_GEEE			ETHNL_CMD_GET_PARAMS
 ETHTOOL_SEEE			n/a
 ETHTOOL_GRSSH			n/a
 ETHTOOL_SRSSH			n/a
@@ -401,6 +496,6 @@ ETHTOOL_GLINKSETTINGS		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SLINKSETTINGS		ETHNL_CMD_SET_SETTINGS
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
-ETHTOOL_GFECPARAM		n/a
+ETHTOOL_GFECPARAM		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SFECPARAM		n/a
 
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 8dfcb9ef4009..fec0f2000dc5 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -14,6 +14,8 @@ enum {
 	ETHNL_CMD_SET_DRVINFO,		/* only for reply */
 	ETHNL_CMD_GET_SETTINGS,
 	ETHNL_CMD_SET_SETTINGS,
+	ETHNL_CMD_GET_PARAMS,
+	ETHNL_CMD_SET_PARAMS,
 
 	__ETHNL_CMD_MAX,
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
@@ -197,6 +199,123 @@ enum {
 	ETHA_FEATURES_MAX = (__ETHA_FEATURES_MAX - 1)
 };
 
+/* GET_PARAMS / SET_PARAMS */
+
+enum {
+	ETHA_PARAMS_UNSPEC,
+	ETHA_PARAMS_DEV,			/* nest - ETHA_DEV_* */
+	ETHA_PARAMS_INFOMASK,			/* u32 */
+	ETHA_PARAMS_COMPACT,			/* flag */
+	ETHA_PARAMS_COALESCE,			/* nest - ETHA_COALESCE_* */
+	ETHA_PARAMS_RING,			/* nest - ETHA_RING_* */
+	ETHA_PARAMS_PAUSE,			/* nest - ETHA_PAUSE_* */
+	ETHA_PARAMS_CHANNELS,			/* nest - ETHA_CHANNELS_* */
+	ETHA_PARAMS_EEE,			/* nest - ETHA_EEE_* */
+	ETHA_PARAMS_FEC,			/* nest - ETHA_FEC_* */
+
+	__ETHA_PARAMS_MAX,
+	ETHA_PARAMS_MAX = (__ETHA_PARAMS_MAX - 1)
+};
+
+#define ETH_PARAMS_IM_COALESCE			0x01
+#define ETH_PARAMS_IM_RING			0x02
+#define ETH_PARAMS_IM_PAUSE			0x04
+#define ETH_PARAMS_IM_CHANNELS			0x08
+#define ETH_PARAMS_IM_EEE			0x10
+#define ETH_PARAMS_IM_FEC			0x20
+
+#define ETH_PARAMS_IM_DEFAULT			0x3f
+
+enum {
+	ETHA_COALESCE_UNSPEC,
+	ETHA_COALESCE_RX_USECS,			/* u32 */
+	ETHA_COALESCE_RX_MAXFRM,		/* u32 */
+	ETHA_COALESCE_RX_USECS_IRQ,		/* u32 */
+	ETHA_COALESCE_RX_MAXFRM_IRQ,		/* u32 */
+	ETHA_COALESCE_RX_USECS_LOW,		/* u32 */
+	ETHA_COALESCE_RX_MAXFRM_LOW,		/* u32 */
+	ETHA_COALESCE_RX_USECS_HIGH,		/* u32 */
+	ETHA_COALESCE_RX_MAXFRM_HIGH,		/* u32 */
+	ETHA_COALESCE_TX_USECS,			/* u32 */
+	ETHA_COALESCE_TX_MAXFRM,		/* u32 */
+	ETHA_COALESCE_TX_USECS_IRQ,		/* u32 */
+	ETHA_COALESCE_TX_MAXFRM_IRQ,		/* u32 */
+	ETHA_COALESCE_TX_USECS_LOW,		/* u32 */
+	ETHA_COALESCE_TX_MAXFRM_LOW,		/* u32 */
+	ETHA_COALESCE_TX_USECS_HIGH,		/* u32 */
+	ETHA_COALESCE_TX_MAXFRM_HIGH,		/* u32 */
+	ETHA_COALESCE_PKT_RATE_LOW,		/* u32 */
+	ETHA_COALESCE_PKT_RATE_HIGH,		/* u32 */
+	ETHA_COALESCE_RX_USE_ADAPTIVE,		/* u8 */
+	ETHA_COALESCE_TX_USE_ADAPTIVE,		/* u8 */
+	ETHA_COALESCE_RATE_SAMPLE_INTERVAL,	/* u32 */
+	ETHA_COALESCE_STATS_BLOCK_USECS,	/* u32 */
+
+	__ETHA_COALESCE_MAX,
+	ETHA_COALESCE_MAX = (__ETHA_COALESCE_MAX - 1)
+};
+
+enum {
+	ETHA_RING_UNSPEC,
+	ETHA_RING_RX_MAX_PENDING,		/* u32 */
+	ETHA_RING_RX_MINI_MAX_PENDING,		/* u32 */
+	ETHA_RING_RX_JUMBO_MAX_PENDING,		/* u32 */
+	ETHA_RING_TX_MAX_PENDING,		/* u32 */
+	ETHA_RING_RX_PENDING,			/* u32 */
+	ETHA_RING_RX_MINI_PENDING,		/* u32 */
+	ETHA_RING_RX_JUMBO_PENDING,		/* u32 */
+	ETHA_RING_TX_PENDING,			/* u32 */
+
+	__ETHA_RING_MAX,
+	ETHA_RING_MAX = (__ETHA_RING_MAX - 1)
+};
+
+enum {
+	ETHA_PAUSE_UNSPEC,
+	ETHA_PAUSE_AUTONEG,			/* u8 */
+	ETHA_PAUSE_RX,				/* u8 */
+	ETHA_PAUSE_TX,				/* u8 */
+
+	__ETHA_PAUSE_MAX,
+	ETHA_PAUSE_MAX = (__ETHA_PAUSE_MAX - 1)
+};
+
+enum {
+	ETHA_CHANNELS_UNSPEC,
+	ETHA_CHANNELS_MAX_RX,			/* u32 */
+	ETHA_CHANNELS_MAX_TX,			/* u32 */
+	ETHA_CHANNELS_MAX_OTHER,		/* u32 */
+	ETHA_CHANNELS_MAX_COMBINED,		/* u32 */
+	ETHA_CHANNELS_RX_COUNT,			/* u32 */
+	ETHA_CHANNELS_TX_COUNT,			/* u32 */
+	ETHA_CHANNELS_OTHER_COUNT,		/* u32 */
+	ETHA_CHANNELS_COMBINED_COUNT,		/* u32 */
+
+	__ETHA_CHANNELS_MAX,
+	ETHA_CHANNELS_MAX = (__ETHA_CHANNELS_MAX - 1)
+};
+
+enum {
+	ETHA_EEE_UNSPEC,
+	ETHA_EEE_LINK_MODES,			/* bitset */
+	ETHA_EEE_PEER_MODES,			/* bitset */
+	ETHA_EEE_ACTIVE,			/* u8 */
+	ETHA_EEE_ENABLED,			/* u8 */
+	ETHA_EEE_TX_LPI_ENABLED,		/* u8 */
+	ETHA_EEE_TX_LPI_TIMER,			/* u32 */
+
+	__ETHA_EEE_MAX,
+	ETHA_EEE_MAX = (__ETHA_EEE_MAX - 1)
+};
+
+enum {
+	ETHA_FEC_UNSPEC,
+	ETHA_FEC_MODES,				/* bitfield32 */
+
+	__ETHA_FEC_MAX,
+	ETHA_FEC_MAX = (__ETHA_FEC_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 8dd98310ed6f..10aeedcee336 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -4,4 +4,4 @@ obj-y				+= ioctl.o common.o
 
 obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o
 
-ethtool_nl-y	:= netlink.o strset.o drvinfo.o settings.o
+ethtool_nl-y	:= netlink.o strset.o drvinfo.o settings.o params.o
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 6e183caca01f..721101ed2ab6 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -731,13 +731,16 @@ int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_settings(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info);
+int ethnl_get_params(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_strset_start(struct netlink_callback *cb);
 int ethnl_drvinfo_start(struct netlink_callback *cb);
 int ethnl_settings_start(struct netlink_callback *cb);
+int ethnl_params_start(struct netlink_callback *cb);
 
 int ethnl_strset_done(struct netlink_callback *cb);
 int ethnl_settings_done(struct netlink_callback *cb);
+int ethnl_params_done(struct netlink_callback *cb);
 
 static const struct genl_ops ethtool_genl_ops[] = {
 	{
@@ -765,6 +768,13 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= ethnl_set_settings,
 	},
+	{
+		.cmd	= ETHNL_CMD_GET_PARAMS,
+		.doit	= ethnl_get_params,
+		.start	= ethnl_params_start,
+		.dumpit	= ethnl_dumpit,
+		.done	= ethnl_params_done,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/params.c b/net/ethtool/params.c
new file mode 100644
index 000000000000..07d4c527abf2
--- /dev/null
+++ b/net/ethtool/params.c
@@ -0,0 +1,539 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include "netlink.h"
+#include "common.h"
+
+static const struct nla_policy params_policy[ETHA_PARAMS_MAX + 1] = {
+	[ETHA_PARAMS_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_PARAMS_DEV]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_INFOMASK]		= { .type = NLA_U32 },
+	[ETHA_PARAMS_COMPACT]		= { .type = NLA_FLAG },
+	[ETHA_PARAMS_COALESCE]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_RING]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_PAUSE]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_CHANNELS]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_EEE]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_FEC]		= { .type = NLA_NESTED },
+};
+
+struct params_data {
+	struct ethtool_coalesce		coalesce;
+	struct ethtool_channels		channels;
+	struct ethtool_pauseparam	pause;
+	struct ethtool_ringparam	ring;
+	struct ethtool_eee		eee;
+	struct ethtool_fecparam		fec;
+	u32				req_mask;
+};
+
+struct params_reqinfo {
+	struct net_device		*dev;
+	u32				req_mask;
+	bool				compact;
+	bool				have_rtnl;
+};
+
+static int ethnl_get_coalesce(struct net_device *dev,
+			      struct ethtool_coalesce *data)
+{
+	if (!dev->ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+	return dev->ethtool_ops->get_coalesce(dev, data);
+}
+
+static int ethnl_get_ring(struct net_device *dev,
+			  struct ethtool_ringparam *data)
+{
+	if (!dev->ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_ringparam(dev, data);
+	return 0;
+}
+
+static int ethnl_get_pause(struct net_device *dev,
+			   struct ethtool_pauseparam *data)
+{
+	if (!dev->ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_pauseparam(dev, data);
+	return 0;
+}
+
+static int ethnl_get_channels(struct net_device *dev,
+			      struct ethtool_channels *data)
+{
+	if (!dev->ethtool_ops->get_channels)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_channels(dev, data);
+	return 0;
+}
+
+static int ethnl_get_eee(struct net_device *dev, struct ethtool_eee *data)
+{
+	if (!dev->ethtool_ops->get_eee)
+		return -EOPNOTSUPP;
+	return dev->ethtool_ops->get_eee(dev, data);
+}
+
+static int ethnl_get_fec(struct net_device *dev, struct ethtool_fecparam *data)
+{
+	if (!dev->ethtool_ops->get_fecparam)
+		return -EOPNOTSUPP;
+	return dev->ethtool_ops->get_fecparam(dev, data);
+}
+
+static int params_size(struct params_data *data,
+		       struct params_reqinfo *req_info)
+{
+	struct ethtool_eee *eee = &data->eee;
+	u32 req_mask = req_info->req_mask;
+	bool compact = req_info->compact;
+	int len = 0;
+
+	if (req_mask & ETH_PARAMS_IM_COALESCE)
+		len += nla_total_size(20 * nla_total_size(sizeof(u32)) +
+				      2 * nla_total_size(sizeof(u8)));
+	if (req_mask & ETH_PARAMS_IM_RING)
+		len += nla_total_size(8 * nla_total_size(sizeof(u32)));
+	if (req_mask & ETH_PARAMS_IM_PAUSE)
+		len += nla_total_size(3 * nla_total_size(sizeof(u8)));
+	if (req_mask & ETH_PARAMS_IM_CHANNELS)
+		len += nla_total_size(8 * nla_total_size(sizeof(u32)));
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		int nlen = 0;
+		int ret;
+
+		/* link_modes */
+		ret = ethnl_bitset32_size(compact, sizeof(u32) * 8,
+					  &eee->advertised, &eee->supported,
+					  link_mode_names);
+		if (ret < 0)
+			return ret;
+		nlen += ret;
+		/* peer_modes */
+		ret = ethnl_bitset32_size(compact, sizeof(u32) * 8,
+					  &eee->lp_advertised,
+					  &eee->lp_advertised, link_mode_names);
+		if (ret < 0)
+			return ret;
+		nlen += ret;
+		/* active, enabled, tx_lpi_enabled */
+		nlen += 3 * nla_total_size(sizeof(u8));
+		/* tx_lpi_timer */
+		nlen += nla_total_size(sizeof(u32));
+		/* nest */
+		len += nla_total_size(nlen);
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		int nlen = nla_total_size(sizeof(struct nla_bitfield32));
+
+		len += nla_total_size(nlen);
+	}
+
+	return len;
+}
+
+static int fill_coalesce(struct sk_buff *skb, struct ethtool_coalesce *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_COALESCE);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_COALESCE_RX_USECS,
+			data->rx_coalesce_usecs) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM,
+			data->rx_max_coalesced_frames) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_USECS_IRQ,
+			data->rx_coalesce_usecs_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM_IRQ,
+			data->rx_max_coalesced_frames_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_USECS_LOW,
+			data->rx_coalesce_usecs_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM_LOW,
+			data->rx_max_coalesced_frames_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_USECS_HIGH,
+			data->rx_coalesce_usecs_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM_HIGH,
+			data->rx_max_coalesced_frames_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS,
+			data->tx_coalesce_usecs) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM,
+			data->tx_max_coalesced_frames) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS_IRQ,
+			data->tx_coalesce_usecs_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM_IRQ,
+			data->tx_max_coalesced_frames_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS_LOW,
+			data->tx_coalesce_usecs_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM_LOW,
+			data->tx_max_coalesced_frames_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS_HIGH,
+			data->tx_coalesce_usecs_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM_HIGH,
+			data->tx_max_coalesced_frames_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_PKT_RATE_LOW,
+			data->pkt_rate_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_PKT_RATE_HIGH,
+			data->pkt_rate_high) ||
+	    nla_put_u8(skb, ETHA_COALESCE_RX_USE_ADAPTIVE,
+		       !!data->use_adaptive_rx_coalesce) ||
+	    nla_put_u8(skb, ETHA_COALESCE_TX_USE_ADAPTIVE,
+		       !!data->use_adaptive_tx_coalesce) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RATE_SAMPLE_INTERVAL,
+			data->rate_sample_interval) ||
+	    nla_put_u32(skb, ETHA_COALESCE_STATS_BLOCK_USECS,
+			data->stats_block_coalesce_usecs)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_ring(struct sk_buff *skb, struct ethtool_ringparam *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_RING);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_RING_RX_MAX_PENDING,
+			data->rx_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_MINI_MAX_PENDING,
+			data->rx_mini_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_JUMBO_MAX_PENDING,
+			data->rx_jumbo_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_TX_MAX_PENDING,
+			data->tx_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_PENDING,
+			data->rx_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_MINI_PENDING,
+			data->rx_mini_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_JUMBO_PENDING,
+			data->rx_jumbo_pending) ||
+	    nla_put_u32(skb, ETHA_RING_TX_PENDING,
+			data->tx_pending)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_pause(struct sk_buff *skb, struct ethtool_pauseparam *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_PAUSE);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u8(skb, ETHA_PAUSE_AUTONEG, !!data->autoneg) ||
+	    nla_put_u8(skb, ETHA_PAUSE_RX, !!data->rx_pause) ||
+	    nla_put_u8(skb, ETHA_PAUSE_TX, !!data->tx_pause)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_channels(struct sk_buff *skb, struct ethtool_channels *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_CHANNELS);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_CHANNELS_MAX_RX, data->max_rx) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_MAX_TX, data->max_tx) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_MAX_OTHER, data->max_other) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_MAX_COMBINED, data->max_combined) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_RX_COUNT, data->rx_count) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_TX_COUNT, data->tx_count) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_OTHER_COUNT, data->other_count) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_COMBINED_COUNT,
+			data->combined_count)) {
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_eee(struct sk_buff *skb, struct ethtool_eee *data, bool compact)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_EEE);
+	int ret;
+
+	if (!nest)
+		return -EMSGSIZE;
+	ret = ethnl_put_bitset32(skb, ETHA_EEE_LINK_MODES, compact,
+				 sizeof(data->advertised) * 8,
+				 &data->advertised, &data->supported,
+				 link_mode_names);
+	if (ret < 0)
+		goto err;
+	ret = ethnl_put_bitset32(skb, ETHA_EEE_PEER_MODES, compact,
+				 sizeof(data->advertised) * 8,
+				 &data->lp_advertised, &data->lp_advertised,
+				 link_mode_names);
+	if (ret < 0)
+		goto err;
+
+	if (nla_put_u8(skb, ETHA_EEE_ACTIVE, !!data->eee_active) ||
+	    nla_put_u8(skb, ETHA_EEE_ENABLED, !!data->eee_enabled) ||
+	    nla_put_u8(skb, ETHA_EEE_TX_LPI_ENABLED, !!data->tx_lpi_enabled) ||
+	    nla_put_u32(skb, ETHA_EEE_TX_LPI_TIMER, data->tx_lpi_timer)) {
+		ret = -EMSGSIZE;
+		goto err;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+err:
+	nla_nest_cancel(skb, nest);
+	return ret;
+}
+
+static int fill_fec(struct sk_buff *skb, struct ethtool_fecparam *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_FEC);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_bitfield32(skb, ETHA_FEC_MODES, data->active_fec,
+			       data->fec)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int parse_params_req(struct params_reqinfo *req_info,
+			    struct genl_info *info, struct sk_buff *skb,
+			    const struct nlmsghdr *nlhdr)
+{
+	struct nlattr *tb[ETHA_PARAMS_MAX + 1];
+	int ret;
+
+	memset(req_info, '\0', sizeof(*req_info));
+
+	ret = genlmsg_parse(nlhdr, &ethtool_genl_family, tb,
+			    ETHA_PARAMS_MAX, params_policy,
+			    info ? info->extack : NULL);
+	if (ret < 0)
+		return ret;
+
+	if (tb[ETHA_PARAMS_DEV]) {
+		req_info->dev = ethnl_dev_get(info, tb[ETHA_PARAMS_DEV]);
+		if (IS_ERR(req_info->dev)) {
+			ret = PTR_ERR(req_info->dev);
+			req_info->dev = NULL;
+			return ret;
+		}
+	}
+	if (tb[ETHA_PARAMS_INFOMASK])
+		req_info->req_mask = nla_get_u32(tb[ETHA_PARAMS_INFOMASK]);
+	if (tb[ETHA_PARAMS_COMPACT])
+		req_info->compact = true;
+	if (req_info->req_mask == 0)
+		req_info->req_mask = ETH_PARAMS_IM_DEFAULT;
+
+	return 0;
+}
+
+static int prepare_params(struct params_data *data,
+			  struct params_reqinfo *req_info,
+			  struct genl_info *info, struct net_device *dev)
+{
+	u32 req_mask = req_info->req_mask;
+	int ret;
+
+	memset(data, '\0', sizeof(*data));
+	if (!req_info->have_rtnl)
+		rtnl_lock();
+	if (req_mask & ETH_PARAMS_IM_COALESCE) {
+		ret = ethnl_get_coalesce(dev, &data->coalesce);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_COALESCE;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_RING) {
+		ret = ethnl_get_ring(dev, &data->ring);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_RING;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_PAUSE) {
+		ret = ethnl_get_pause(dev, &data->pause);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_PAUSE;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_CHANNELS) {
+		ret = ethnl_get_channels(dev, &data->channels);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_CHANNELS;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		ret = ethnl_get_eee(dev, &data->eee);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_EEE;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		ret = ethnl_get_fec(dev, &data->fec);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_FEC;
+		}
+	}
+	if (!req_info->have_rtnl)
+		rtnl_unlock();
+
+	data->req_mask = req_mask;
+	return 0;
+}
+
+static int fill_params(struct sk_buff *rskb, struct params_data *data,
+		       struct params_reqinfo *req_info)
+{
+	u32 req_mask = data->req_mask;
+	int ret;
+
+	if (req_mask & ETH_PARAMS_IM_COALESCE) {
+		ret = fill_coalesce(rskb, &data->coalesce);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_RING) {
+		ret = fill_ring(rskb, &data->ring);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_PAUSE) {
+		ret = fill_pause(rskb, &data->pause);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_CHANNELS) {
+		ret = fill_channels(rskb, &data->channels);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		ret = fill_eee(rskb, &data->eee, req_info->compact);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		ret = fill_fec(rskb, &data->fec);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int ethnl_get_params(struct sk_buff *skb, struct genl_info *info)
+{
+	struct params_data data;
+	struct params_reqinfo req_info;
+	struct sk_buff *rskb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = parse_params_req(&req_info, info, skb, info->nlhdr);
+	if (ret < 0)
+		goto err_dev;
+	ret = prepare_params(&data, &req_info, info, req_info.dev);
+	if (ret < 0)
+		goto err_dev;
+	reply_len = params_size(&data, &req_info);
+	if (ret < 0)
+		goto err_dev;
+	ret = -ENOMEM;
+	rskb = ethnl_reply_init(reply_len, req_info.dev, ETHNL_CMD_SET_PARAMS,
+				ETHA_PARAMS_DEV, info, &ehdr);
+	if (!rskb)
+		goto err_dev;
+	ret = fill_params(rskb, &data, &req_info);
+	if (ret < 0)
+		goto err;
+
+	genlmsg_end(rskb, ehdr);
+	dev_put(req_info.dev);
+	return genlmsg_reply(rskb, info);
+
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+err_dev:
+	if (req_info.dev)
+		dev_put(req_info.dev);
+	return ret;
+}
+
+static int params_dump(struct sk_buff *skb, struct netlink_callback *cb,
+		       struct net_device *dev)
+{
+	struct params_data data;
+	struct params_reqinfo *req_info;
+	int ret;
+
+	req_info = (struct params_reqinfo *)cb->args[4];
+	ret = prepare_params(&data, req_info, NULL, dev);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_fill_dev(skb, dev, ETHA_PARAMS_DEV);
+	if (ret < 0)
+		return ret;
+	ret = fill_params(skb, &data, req_info);
+	return ret;
+}
+
+int ethnl_params_start(struct netlink_callback *cb)
+{
+	struct params_reqinfo *req_info;
+	int ret;
+
+	req_info = kmalloc(sizeof(*req_info), GFP_KERNEL);
+	if (!req_info)
+		return -ENOMEM;
+	ret = parse_params_req(req_info, NULL, cb->skb, cb->nlh);
+	if (ret < 0) {
+		if (req_info->dev)
+			dev_put(req_info->dev);
+		req_info->dev = NULL;
+		return ret;
+	}
+
+	cb->args[0] = (long)params_dump;
+	cb->args[1] = ETHNL_CMD_SET_PARAMS;
+	cb->args[4] = (long)req_info;
+
+	return 0;
+}
+
+int ethnl_params_done(struct netlink_callback *cb)
+{
+	struct params_reqinfo *req_info;
+
+	req_info = (struct params_reqinfo *)cb->args[4];
+	if (req_info->dev)
+		dev_put(req_info->dev);
+	kfree(req_info);
+
+	return 0;
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 13/17] ethtool: implement SET_SETTINGS message
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Sets the information provided by ETHTOOL_SLINKSETTINGS, ETHTOOL_SWOL and
ETHTOOL_SMSGLVL. Unlike with ioctl(), userspace can send only some
attributes so that we only need to call ethtool_ops callbacks which we
really need (and the "set" callback is only called when we actually changed
some setting).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  43 +-
 net/ethtool/netlink.c                        |   6 +
 net/ethtool/settings.c                       | 495 +++++++++++++++++++
 3 files changed, 539 insertions(+), 5 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 3993652f81a9..c7fe4f518972 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -124,7 +124,7 @@ List of message types
     ETHNL_CMD_GET_DRVINFO
     ETHNL_CMD_SET_DRVINFO		response only
     ETHNL_CMD_GET_SETTINGS
-    ETHNL_CMD_SET_SETTINGS		response only (for now)
+    ETHNL_CMD_SET_SETTINGS
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -267,6 +267,39 @@ netlink or ioctl ethtool interface; feature notifications are also sent
 whenever netdev_update_features() or netdev_change_features() is called.
 
 
+SET_SETTINGS
+------------
+
+SET_SETTINGS request allows setting some of the data reported by GET_SETTINGS.
+Request flags, info_mask and index are ignored. These attributes are allowed
+to be passed with SET_SETTINGS request:
+
+    ETHA_SETTINGS_DEV		(nested)	device identification
+    ETHA_SETTINGS_SPEED         (u32)           link speed (Mb/s)
+    ETHA_SETTINGS_DUPLEX        (u8)            duplex mode
+    ETHA_SETTINGS_PORT          (u8)            physical port
+    ETHA_SETTINGS_PHYADDR       (u8)            MDIO address of phy
+    ETHA_SETTINGS_AUTONEG       (u8)            autoneotiation status
+    ETHA_SETTINGS_TP_MDIX_CTRL  (u8)            MDI(-X) control
+    ETHA_SETTINGS_WOL_MODES     (bitfield32)    wake-on-lan modes
+    ETHA_SETTINGS_SOPASS        (binary)        SecureOn(tm) password
+    ETHA_SETTINGS_MSGLVL        (bitfield32)    debug level
+    ETHA_SETTINGS_LINK_MODES    (bitset)        device link modes
+
+For both bitfield32 types, value and selector work the usual way, i.e. bits
+set in selector are set to corresponding bits from value and the rest is
+preserved. In a similar fashion, ETHA_SETTINGS_LINK_MODES allows setting
+advertised link modes.
+
+If autonegotiation is on (either set now or kept from before), advertised
+modes are not changed (no ETHA_SETTINGS_LINK_MODES attribute) and at least one
+of speed and duplex is specified, kernel adjusts advertised modes to all
+supported modes matching speed, duplex or both (whatever is specified). This
+autoselection is done on ethtool side with ioctl interface, netlink interface
+is supposed to allow requesting changes without knowing what exactly kernel
+supports.
+
+
 Request translation
 -------------------
 
@@ -277,13 +310,13 @@ have their netlink replacement yet.
 ioctl command			netlink command
 ---------------------------------------------------------------------
 ETHTOOL_GSET			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SSET			n/a
+ETHTOOL_SSET			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GDRVINFO		ETHNL_CMD_GET_DRVINFO
 ETHTOOL_GREGS			n/a
 ETHTOOL_GWOL			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SWOL			n/a
+ETHTOOL_SWOL			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GMSGLVL			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SMSGLVL			n/a
+ETHTOOL_SMSGLVL			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_NWAY_RST		n/a
 ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
@@ -351,7 +384,7 @@ ETHTOOL_STUNABLE		n/a
 ETHTOOL_GPHYSTATS		n/a
 ETHTOOL_PERQUEUE		n/a
 ETHTOOL_GLINKSETTINGS		ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SLINKSETTINGS		n/a
+ETHTOOL_SLINKSETTINGS		ETHNL_CMD_SET_SETTINGS
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
 ETHTOOL_GFECPARAM		n/a
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 0e2158092a44..6e183caca01f 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -730,6 +730,7 @@ static struct notifier_block ethnl_netdev_notifier = {
 int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_settings(struct sk_buff *skb, struct genl_info *info);
+int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_strset_start(struct netlink_callback *cb);
 int ethnl_drvinfo_start(struct netlink_callback *cb);
@@ -759,6 +760,11 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.dumpit	= ethnl_dumpit,
 		.done	= ethnl_settings_done,
 	},
+	{
+		.cmd	= ETHNL_CMD_SET_SETTINGS,
+		.flags	= GENL_UNS_ADMIN_PERM,
+		.doit	= ethnl_set_settings,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 739bd006c924..678199e621a2 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -88,6 +88,222 @@ struct settings_reqinfo {
 	bool				have_rtnl;
 };
 
+struct link_mode_info {
+	int				speed;
+	u8				duplex;
+};
+
+static const struct link_mode_info link_mode_params[] = {
+	[ETHTOOL_LINK_MODE_10baseT_Half_BIT]		= {
+		.speed	= 10,
+		.duplex	= DUPLEX_HALF,
+	},
+	[ETHTOOL_LINK_MODE_10baseT_Full_BIT]		= {
+		.speed	= 10,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_100baseT_Half_BIT]		= {
+		.speed	= 100,
+		.duplex	= DUPLEX_HALF,
+	},
+	[ETHTOOL_LINK_MODE_100baseT_Full_BIT]		= {
+		.speed	= 100,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_1000baseT_Half_BIT]		= {
+		.speed	= 1000,
+		.duplex	= DUPLEX_HALF,
+	},
+	[ETHTOOL_LINK_MODE_1000baseT_Full_BIT]		= {
+		.speed	= 1000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_Autoneg_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_TP_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_AUI_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_MII_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_FIBRE_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_BNC_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_10000baseT_Full_BIT]		= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_Pause_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_Asym_Pause_BIT]		= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_2500baseX_Full_BIT]		= {
+		.speed	= 2500,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_Backplane_BIT]		= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_1000baseKX_Full_BIT]		= {
+		.speed	= 1000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseKR_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT]		= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT]	= {
+		.speed	= 20000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT]	= {
+		.speed	= 20000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT]	= {
+		.speed	= 40000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT]	= {
+		.speed	= 40000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT]	= {
+		.speed	= 40000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT]	= {
+		.speed	= 40000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT]	= {
+		.speed	= 56000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT]	= {
+		.speed	= 56000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT]	= {
+		.speed	= 56000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT]	= {
+		.speed	= 56000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_25000baseCR_Full_BIT]	= {
+		.speed	= 25000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_25000baseKR_Full_BIT]	= {
+		.speed	= 25000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_25000baseSR_Full_BIT]	= {
+		.speed	= 25000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT]	= {
+		.speed	= 50000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT]	= {
+		.speed	= 50000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT]	= {
+		.speed	= 100000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT]	= {
+		.speed	= 100000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT]	= {
+		.speed	= 100000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT]	= {
+		.speed	= 100000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT]	= {
+		.speed	= 50000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_1000baseX_Full_BIT]		= {
+		.speed	= 1000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseCR_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseSR_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseLR_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_10000baseER_Full_BIT]	= {
+		.speed	= 10000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_2500baseT_Full_BIT]		= {
+		.speed	= 2500,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_5000baseT_Full_BIT]		= {
+		.speed	= 5000,
+		.duplex	= DUPLEX_FULL,
+	},
+	[ETHTOOL_LINK_MODE_FEC_NONE_BIT]		= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_FEC_RS_BIT]			= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+	[ETHTOOL_LINK_MODE_FEC_BASER_BIT]		= {
+		.speed	= SPEED_UNKNOWN,
+		.duplex	= DUPLEX_UNKNOWN,
+	},
+};
+
 /* We want to allow ~0 as selector for backward compatibility (to just set
  * given set of modes, whatever kernel supports) so that we allow all bits
  * on validation and do our own sanity check later.
@@ -606,3 +822,282 @@ void ethnl_settings_notify(struct netdev_notifier_ethtool_info *info)
 err_skb:
 	nlmsg_free(skb);
 }
+
+/* SET_SETTINGS */
+
+static int ethnl_set_link_ksettings(struct genl_info *info,
+				    struct net_device *dev,
+				    struct ethtool_link_ksettings *ksettings)
+{
+	int ret = dev->ethtool_ops->set_link_ksettings(dev, ksettings);
+
+	if (ret < 0)
+		ETHNL_SET_ERRMSG(info, "link settings update failed");
+	return ret;
+}
+
+static int ethnl_set_legacy_settings(struct genl_info *info,
+				     struct net_device *dev,
+				     struct ethtool_cmd *cmd)
+{
+	int ret;
+
+	if (!dev->ethtool_ops->set_settings) {
+		/* we already tried ->set_link_ksettings */
+		ETHNL_SET_ERRMSG(info, "link settings update unsupported");
+		return -EOPNOTSUPP;
+	}
+	ret = dev->ethtool_ops->set_settings(dev, cmd);
+	if (ret < 0)
+		ETHNL_SET_ERRMSG(info, "link settings update failed");
+
+	return ret;
+}
+
+static int ethnl_set_wol(struct genl_info *info, struct net_device *dev,
+			 struct ethtool_wolinfo *wolinfo)
+{
+	int ret = dev->ethtool_ops->set_wol(dev, wolinfo);
+
+	if (ret < 0)
+		ETHNL_SET_ERRMSG(info, "wol info update failed");
+	return ret;
+}
+
+/* Set advertised link modes to all supported modes matching requested speed
+ * and duplex values. Called when autonegotiation is on, speed or duplex is
+ * requested but no link mode change. This is done in userspace with ioctl()
+ * interface, move it into kernel for netlink.
+ * Returns true if advertised modes bitmap was modified.
+ */
+static bool auto_link_modes(unsigned long *supported,
+			    unsigned long *advertising, unsigned int nbits,
+			    struct nlattr *speed_attr,
+			    struct nlattr *duplex_attr)
+{
+	u8 duplex = duplex_attr ? nla_get_u8(duplex_attr) : DUPLEX_UNKNOWN;
+	u32 speed = speed_attr ? nla_get_u32(speed_attr) : SPEED_UNKNOWN;
+	DECLARE_BITMAP(old_adv, nbits);
+	unsigned int i;
+
+	bitmap_copy(old_adv, advertising, nbits);
+
+	for (i = 0; i < nbits; i++) {
+		const struct link_mode_info *info = &link_mode_params[i];
+
+		if (info->speed == SPEED_UNKNOWN)
+			continue;
+		if (test_bit(i, supported) &&
+		    (!speed_attr || info->speed == speed) &&
+		    (!duplex_attr || info->duplex == duplex))
+			set_bit(i, advertising);
+		else
+			clear_bit(i, advertising);
+	}
+
+	return !bitmap_equal(old_adv, advertising, nbits);
+}
+
+/* Update device settings using ->set_link_ksettings() callback */
+static int ethnl_update_ksettings(struct genl_info *info, struct nlattr **tb,
+				  struct net_device *dev)
+{
+	struct ethtool_link_ksettings ksettings = {};
+	struct ethtool_link_settings *lsettings;
+	bool mod = false;
+	int ret;
+
+	ret = ethnl_get_link_ksettings(info, dev, &ksettings);
+	if (ret < 0)
+		return ret;
+	lsettings = &ksettings.base;
+
+	mod = false;
+	if (ethnl_update_u32(&lsettings->speed, tb[ETHA_SETTINGS_SPEED]))
+		mod = true;
+	if (ethnl_update_u8(&lsettings->duplex, tb[ETHA_SETTINGS_DUPLEX]))
+		mod = true;
+	if (ethnl_update_u8(&lsettings->port, tb[ETHA_SETTINGS_PORT]))
+		mod = true;
+	if (ethnl_update_u8(&lsettings->phy_address, tb[ETHA_SETTINGS_PHYADDR]))
+		mod = true;
+	if (ethnl_update_u8(&lsettings->autoneg, tb[ETHA_SETTINGS_AUTONEG]))
+		mod = true;
+	if (ethnl_update_u8(&lsettings->eth_tp_mdix_ctrl,
+			    tb[ETHA_SETTINGS_TP_MDIX_CTRL]))
+		mod = true;
+	if (ethnl_update_bitset(ksettings.link_modes.advertising, NULL,
+				__ETHTOOL_LINK_MODE_MASK_NBITS,
+				tb[ETHA_SETTINGS_LINK_MODES],
+				&ret, link_mode_names, info))
+		mod = true;
+	if (ret < 0)
+		return ret;
+
+	if (!tb[ETHA_SETTINGS_LINK_MODES] && lsettings->autoneg &&
+	    (tb[ETHA_SETTINGS_SPEED] || tb[ETHA_SETTINGS_DUPLEX])) {
+		if (auto_link_modes(ksettings.link_modes.supported,
+				    ksettings.link_modes.advertising,
+				    __ETHTOOL_LINK_MODE_MASK_NBITS,
+				    tb[ETHA_SETTINGS_SPEED],
+				    tb[ETHA_SETTINGS_DUPLEX]))
+			mod = true;
+	}
+
+	if (mod) {
+		ret = ethnl_set_link_ksettings(info, dev, &ksettings);
+		if (ret < 0)
+			return ret;
+	}
+
+	return mod ? 1 : 0;
+}
+
+/* Update legacy settings using ->set_settings() callback. */
+static int ethnl_update_lsettings(struct genl_info *info, struct nlattr **tb,
+				  struct net_device *dev)
+{
+	struct ethtool_cmd cmd = {};
+	const unsigned int nbits = sizeof(cmd.advertising) * BITS_PER_BYTE;
+	DECLARE_BITMAP(advertising, nbits);
+	DECLARE_BITMAP(supported, nbits);
+	bool mod = false;
+	u32 speed;
+	int ret;
+
+	ret = ethnl_get_legacy_settings(info, dev, &cmd);
+	if (ret < 0)
+		return ret;
+	bitmap_from_arr32(supported, &cmd.supported, nbits);
+	bitmap_from_arr32(advertising, &cmd.advertising, nbits);
+
+	mod = false;
+	speed = ethtool_cmd_speed(&cmd);
+	if (ethnl_update_u32(&speed, tb[ETHA_SETTINGS_SPEED])) {
+		ethtool_cmd_speed_set(&cmd, speed);
+		mod = true;
+	}
+	if (ethnl_update_u8(&cmd.duplex, tb[ETHA_SETTINGS_DUPLEX]))
+		mod = true;
+	if (ethnl_update_u8(&cmd.port, tb[ETHA_SETTINGS_PORT]))
+		mod = true;
+	if (ethnl_update_u8(&cmd.phy_address, tb[ETHA_SETTINGS_PHYADDR]))
+		mod = true;
+	if (ethnl_update_u8(&cmd.autoneg, tb[ETHA_SETTINGS_AUTONEG]))
+		mod = true;
+	if (ethnl_update_u8(&cmd.eth_tp_mdix_ctrl,
+			    tb[ETHA_SETTINGS_TP_MDIX_CTRL]))
+		mod = true;
+	if (ethnl_update_bitset(advertising, NULL, nbits,
+				tb[ETHA_SETTINGS_LINK_MODES],
+				&ret, link_mode_names, info)) {
+		bitmap_to_arr32(&cmd.advertising, advertising, nbits);
+		mod = true;
+	}
+	if (ret < 0)
+		return ret;
+
+	if (!tb[ETHA_SETTINGS_LINK_MODES] && cmd.autoneg &&
+	    (tb[ETHA_SETTINGS_SPEED] || tb[ETHA_SETTINGS_DUPLEX])) {
+		if (auto_link_modes(supported, advertising, nbits,
+				    tb[ETHA_SETTINGS_SPEED],
+				    tb[ETHA_SETTINGS_DUPLEX])) {
+			bitmap_to_arr32(&cmd.advertising, advertising, nbits);
+			mod = true;
+		}
+	}
+
+	if (mod) {
+		ret = ethnl_set_legacy_settings(info, dev, &cmd);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *tb[ETHA_SETTINGS_MAX + 1];
+	struct ethtool_wolinfo wolinfo = {};
+	struct net_device *dev;
+	u32 req_mask = 0;
+	bool mod;
+	int ret;
+
+	ret = genlmsg_parse(info->nlhdr, &ethtool_genl_family, tb,
+			    ETHA_SETTINGS_MAX, settings_policy, info->extack);
+	if (ret < 0)
+		return ret;
+	dev = ethnl_dev_get(info, tb[ETHA_SETTINGS_DEV]);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+	rtnl_lock();
+
+	/* read only attributes */
+	ret = -EINVAL;
+	if (tb[ETHA_SETTINGS_MDIO_SUPPORT] || tb[ETHA_SETTINGS_TP_MDIX] ||
+	    tb[ETHA_SETTINGS_TRANSCEIVER] || tb[ETHA_SETTINGS_PEER_MODES] ||
+	    tb[ETHA_SETTINGS_LINK]) {
+		ETHNL_SET_ERRMSG(info, "attempt to set a read only attribute");
+		goto out_unlock;
+	}
+
+	if (tb[ETHA_SETTINGS_SPEED] || tb[ETHA_SETTINGS_DUPLEX] ||
+	    tb[ETHA_SETTINGS_PORT] || tb[ETHA_SETTINGS_PHYADDR] ||
+	    tb[ETHA_SETTINGS_AUTONEG] || tb[ETHA_SETTINGS_TP_MDIX_CTRL] ||
+	    tb[ETHA_SETTINGS_LINK_MODES]) {
+		if (dev->ethtool_ops->get_link_ksettings)
+			ret = ethnl_update_ksettings(info, tb, dev);
+		else
+			ret = ethnl_update_lsettings(info, tb, dev);
+		if (ret < 0)
+			goto out_unlock;
+		req_mask |= ETH_SETTINGS_IM_LINKINFO |
+			    ETH_SETTINGS_IM_LINKMODES;
+	}
+	if (tb[ETHA_SETTINGS_WOL_MODES] || tb[ETHA_SETTINGS_SOPASS]) {
+		ret = ethnl_get_wol(info, dev, &wolinfo);
+		if (ret < 0)
+			goto out_unlock;
+
+		mod = false;
+		if (ethnl_update_bitfield32(&wolinfo.wolopts,
+					    tb[ETHA_SETTINGS_WOL_MODES]))
+			mod = true;
+		if (ethnl_update_binary(wolinfo.sopass, SOPASS_MAX,
+					tb[ETHA_SETTINGS_SOPASS]))
+			mod = true;
+		if (mod) {
+			ret = ethnl_set_wol(info, dev, &wolinfo);
+			if (ret < 0)
+				goto out_unlock;
+			req_mask |= ETH_SETTINGS_IM_WOLINFO;
+		}
+	}
+	if (tb[ETHA_SETTINGS_MSGLVL]) {
+		u32 msglvl;
+
+		ret = -EOPNOTSUPP;
+		if (!dev->ethtool_ops->get_msglevel ||
+		    !dev->ethtool_ops->set_msglevel) {
+			ETHNL_SET_ERRMSG(info,
+					 "device does not provide msglvl access");
+			goto out_unlock;
+		}
+		msglvl = dev->ethtool_ops->get_msglevel(dev);
+		if (ethnl_update_bitfield32(&msglvl,
+					    tb[ETHA_SETTINGS_MSGLVL])) {
+			dev->ethtool_ops->set_msglevel(dev, msglvl);
+			req_mask |= ETH_SETTINGS_IM_MSGLEVEL;
+		}
+	}
+	ret = 0;
+
+out_unlock:
+	if (req_mask)
+		ethnl_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS, req_mask);
+	rtnl_unlock();
+	dev_put(dev);
+	return ret;
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 12/17] ethtool: implement SET_SETTINGS notification
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

SET_SETTINGS notification message has the same format as response to
GET_SETTINGS request and is broadcasted on change of relevant fields. Info
mask can be used to limit the information passed to userspace.

Also trigger the notification on analogous changes performed via the legacy
ioctl interface.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  3 +-
 net/core/dev.c                               |  3 ++
 net/ethtool/ioctl.c                          | 36 +++++++++++++++--
 net/ethtool/netlink.c                        |  2 +
 net/ethtool/settings.c                       | 41 ++++++++++++++++++++
 5 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 82b839c03707..3993652f81a9 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -263,7 +263,8 @@ requests.
 
 GET_SETTINGS requests allow dumps and messages in the same format as response
 to them are broadcasted as notifications on change of these settings using
-netlink or ioctl ethtool interface.
+netlink or ioctl ethtool interface; feature notifications are also sent
+whenever netdev_update_features() or netdev_change_features() is called.
 
 
 Request translation
diff --git a/net/core/dev.c b/net/core/dev.c
index 8a0773a52dd7..66932a9f133e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -93,6 +93,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/ethtool_netlink.h>
 #include <linux/notifier.h>
 #include <linux/skbuff.h>
 #include <linux/bpf.h>
@@ -1318,6 +1319,8 @@ int dev_get_alias(const struct net_device *dev, char *name, size_t len)
 void netdev_features_change(struct net_device *dev)
 {
 	call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev);
+	netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+				   ETH_SETTINGS_IM_FEATURES);
 }
 EXPORT_SYMBOL(netdev_features_change);
 
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 39e9aea60516..2754d3f6fd75 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -27,6 +27,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/sched/signal.h>
 #include <linux/net.h>
+#include <linux/ethtool_netlink.h>
 #include "common.h"
 
 /*
@@ -125,6 +126,8 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
 	dev->wanted_features &= ~valid;
 	dev->wanted_features |= wanted & valid;
 	__netdev_update_features(dev);
+	netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+				   ETH_SETTINGS_IM_FEATURES);
 
 	if ((dev->wanted_features ^ dev->features) & valid)
 		ret |= ETHTOOL_F_WISH;
@@ -243,6 +246,8 @@ static int ethtool_set_one_feature(struct net_device *dev,
 		dev->wanted_features &= ~mask;
 
 	__netdev_update_features(dev);
+	netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+				   ETH_SETTINGS_IM_FEATURES);
 
 	return 0;
 }
@@ -298,6 +303,8 @@ static int __ethtool_set_flags(struct net_device *dev, u32 data)
 		(dev->wanted_features & ~changed) | (features & changed);
 
 	__netdev_update_features(dev);
+	netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+				   ETH_SETTINGS_IM_FEATURES);
 
 	return 0;
 }
@@ -638,6 +645,7 @@ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
 static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_cmd cmd;
+	int ret;
 
 	ASSERT_RTNL();
 
@@ -655,8 +663,14 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 		link_ksettings.base.cmd = ETHTOOL_SLINKSETTINGS;
 		link_ksettings.base.link_mode_masks_nwords
 			= __ETHTOOL_LINK_MODE_MASK_NU32;
-		return dev->ethtool_ops->set_link_ksettings(dev,
-							    &link_ksettings);
+		ret = dev->ethtool_ops->set_link_ksettings(dev,
+							   &link_ksettings);
+		if (ret >= 0)
+			netdev_ethtool_info_change(dev, NULL,
+						   ETHNL_CMD_SET_SETTINGS,
+						   ETH_SETTINGS_IM_LINKINFO |
+						   ETH_SETTINGS_IM_LINKMODES);
+		return ret;
 	}
 
 	/* legacy %ethtool_cmd API */
@@ -668,7 +682,12 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 	if (!dev->ethtool_ops->set_settings)
 		return -EOPNOTSUPP;
 
-	return dev->ethtool_ops->set_settings(dev, &cmd);
+	ret = dev->ethtool_ops->set_settings(dev, &cmd);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+					   ETH_SETTINGS_IM_LINKINFO |
+					   ETH_SETTINGS_IM_LINKMODES);
+	return ret;
 }
 
 static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
@@ -1279,6 +1298,7 @@ static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
 static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_wolinfo wol;
+	int ret;
 
 	if (!dev->ethtool_ops->set_wol)
 		return -EOPNOTSUPP;
@@ -1286,7 +1306,11 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
 	if (copy_from_user(&wol, useraddr, sizeof(wol)))
 		return -EFAULT;
 
-	return dev->ethtool_ops->set_wol(dev, &wol);
+	ret = dev->ethtool_ops->set_wol(dev, &wol);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+					   ETH_SETTINGS_IM_WOLINFO);
+	return ret;
 }
 
 static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
@@ -2478,6 +2502,10 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_SMSGLVL:
 		rc = ethtool_set_value_void(dev, useraddr,
 				       dev->ethtool_ops->set_msglevel);
+		if (rc >= 0)
+			netdev_ethtool_info_change(dev, NULL,
+						   ETHNL_CMD_SET_SETTINGS,
+						   ETH_SETTINGS_IM_MSGLEVEL);
 		break;
 	case ETHTOOL_GEEE:
 		rc = ethtool_get_eee(dev, useraddr);
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 6c14185a6466..0e2158092a44 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -629,7 +629,9 @@ int ethnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 
 typedef void (*ethnl_notify_handler_t)(struct netdev_notifier_ethtool_info *);
 
+void ethnl_settings_notify(struct netdev_notifier_ethtool_info *);
 ethnl_notify_handler_t ethnl_notify_handlers[] = {
+	[ETHNL_CMD_SET_SETTINGS]	= ethnl_settings_notify,
 };
 
 static void __ethnl_notify(struct netdev_notifier_ethtool_info *info)
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index fdca418a6d8e..739bd006c924 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -565,3 +565,44 @@ int ethnl_settings_done(struct netlink_callback *cb)
 
 	return 0;
 }
+
+void ethnl_settings_notify(struct netdev_notifier_ethtool_info *info)
+{
+	struct settings_reqinfo req_info = {
+		.dev		= info->info.dev,
+		.req_mask	= info->ethtool_info.req_mask,
+		.compact	= true,
+		.is_privileged	= false,
+		.have_rtnl	= true,
+	};
+	struct settings_data data;
+	struct sk_buff *skb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = prepare_settings(&data, &req_info, NULL, req_info.dev);
+	if (ret < 0)
+		return;
+	reply_len = settings_size(&data, &req_info);
+	if (ret < 0)
+		return;
+	skb = genlmsg_new(reply_len, GFP_KERNEL);
+	if (!skb)
+		return;
+	ehdr = genlmsg_put(skb, 0, ++ethnl_bcast_seq, &ethtool_genl_family, 0,
+			   ETHNL_CMD_SET_SETTINGS);
+	ret = ethnl_fill_dev(skb, req_info.dev, ETHA_SETTINGS_DEV);
+	if (ret < 0)
+		goto err_skb;
+	ret = fill_settings(skb, &data, &req_info);
+	if (ret < 0)
+		goto err_skb;
+	genlmsg_end(skb, ehdr);
+
+	genlmsg_multicast(&ethtool_genl_family, skb, 0, ETHNL_MCGRP_MONITOR,
+			  GFP_KERNEL);
+	return;
+err_skb:
+	nlmsg_free(skb);
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 11/17] ethtool: implement GET_SETTINGS request for features
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

With ETH_SETTINGS_IM_FEATURES info mask, ETHNL_CMD_GET_SETTINGS request
gets network device feature values. This is the same information as
provided via ETHTOOL_GFEATURES ioctl request.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  33 ++--
 include/uapi/linux/ethtool_netlink.h         |  15 +-
 net/ethtool/common.h                         |   2 +
 net/ethtool/ioctl.c                          |   2 -
 net/ethtool/settings.c                       | 151 +++++++++++++++++++
 5 files changed, 191 insertions(+), 12 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 60d426cf6dad..82b839c03707 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -214,6 +214,7 @@ Info mask bits meaning:
     ETH_SETTINGS_IM_MSGLEVEL		msglevel
     ETH_SETTINGS_IM_WOLINFO		struct ethtool_wolinfo
     ETH_SETTINGS_IM_LINK		link state
+    ETH_SETTINGS_IM_FEATURES		features
 
 Response contents:
 
@@ -233,6 +234,11 @@ Response contents:
     ETHA_SETTINGS_LINK_MODES	(bitset)	device link modes
     ETHA_SETTINGS_PEER_MODES	(bitset)	link partner link modes
     ETHA_SETTINGS_LINK		(u32)		link state
+    ETHA_SETTINGS_FEATURES	(nested)	device features
+        ETHA_FEATURES_HW		(bitset)	dev->hw_features
+        ETHA_FEATURES_WANTED		(bitset)	dev->wanted_features
+        ETHA_FEATURES_ACTIVE		(bitset)	dev->features
+        ETHA_FEATURES_NOCHANGE		(bitset)	NETIF_F_NEVER_CHANGE
 
 Most of the attributes have the same meaning (including values) as
 corresponding members of ioctl structures. For ETHA_SETTINGS_MDIO_SUPPORT and
@@ -242,6 +248,15 @@ ETHA_SETTINGS_LINK_MODES, value represent advertised modes and mask represents
 supported modes. For ETHA_SETTINGS_PEER_MODES, both value and mask represent
 partner advertised link modes.
 
+Bitmaps contained in ETHA_SETTINGS_FEATURES have the same meaning as bitmaps
+used in ioctl interference but attribute names are different (they are based
+on corresponding members of struct net_device). Legacy "flags" are not
+provided, if userspace needs them (most likely only ethtool for backward
+compatibility), it can calculate their values from related feature bits
+itself. ETHA_FEATURES_HW uses mask consisting of all features recognized by
+kernel (to provide all names when using verbose bitmap format), remaining
+three use mask equal to value (to save space).
+
 GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
 is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
 requests.
@@ -278,30 +293,30 @@ ETHTOOL_GRINGPARAM		n/a
 ETHTOOL_SRINGPARAM		n/a
 ETHTOOL_GPAUSEPARAM		n/a
 ETHTOOL_SPAUSEPARAM		n/a
-ETHTOOL_GRXCSUM			n/a
+ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SRXCSUM			n/a
-ETHTOOL_GTXCSUM			n/a
+ETHTOOL_GTXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_STXCSUM			n/a
-ETHTOOL_GSG			n/a
+ETHTOOL_GSG			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SSG			n/a
 ETHTOOL_TEST			n/a
 ETHTOOL_GSTRINGS		ETHNL_CMD_GET_STRSET
 ETHTOOL_PHYS_ID			n/a
 ETHTOOL_GSTATS			n/a
-ETHTOOL_GTSO			n/a
+ETHTOOL_GTSO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_STSO			n/a
 ETHTOOL_GPERMADDR		n/a
-ETHTOOL_GUFO			n/a
+ETHTOOL_GUFO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SUFO			n/a
-ETHTOOL_GGSO			n/a
+ETHTOOL_GGSO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SGSO			n/a
-ETHTOOL_GFLAGS			n/a
+ETHTOOL_GFLAGS			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFLAGS			n/a
 ETHTOOL_GPFLAGS			n/a
 ETHTOOL_SPFLAGS			n/a
 ETHTOOL_GRXFH			n/a
 ETHTOOL_SRXFH			n/a
-ETHTOOL_GGRO			n/a
+ETHTOOL_GGRO			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SGRO			n/a
 ETHTOOL_GRXRINGS		n/a
 ETHTOOL_GRXCLSRLCNT		n/a
@@ -316,7 +331,7 @@ ETHTOOL_GRXNTUPLE		n/a
 ETHTOOL_GSSET_INFO		ETHNL_CMD_GET_STRSET
 ETHTOOL_GRXFHINDIR		n/a
 ETHTOOL_SRXFHINDIR		n/a
-ETHTOOL_GFEATURES		n/a
+ETHTOOL_GFEATURES		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFEATURES		n/a
 ETHTOOL_GCHANNELS		n/a
 ETHTOOL_SCHANNELS		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 66df44aa7226..06c78b281275 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -170,6 +170,7 @@ enum {
 	ETHA_SETTINGS_LINK_MODES,		/* bitset */
 	ETHA_SETTINGS_PEER_MODES,		/* bitset */
 	ETHA_SETTINGS_LINK,			/* u32 */
+	ETHA_SETTINGS_FEATURES,			/* nest - ETHA_FEATURES_* */
 
 	__ETHA_SETTINGS_MAX,
 	ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_MAX - 1)
@@ -180,8 +181,20 @@ enum {
 #define ETH_SETTINGS_IM_MSGLEVEL		0x04
 #define ETH_SETTINGS_IM_WOLINFO			0x08
 #define ETH_SETTINGS_IM_LINK			0x10
+#define ETH_SETTINGS_IM_FEATURES		0x20
 
-#define ETH_SETTINGS_IM_DEFAULT			0x1f
+#define ETH_SETTINGS_IM_DEFAULT			0x3f
+
+enum {
+	ETHA_FEATURES_UNSPEC,
+	ETHA_FEATURES_HW,			/* bitset */
+	ETHA_FEATURES_WANTED,			/* bitset */
+	ETHA_FEATURES_ACTIVE,			/* bitset */
+	ETHA_FEATURES_NOCHANGE,			/* bitset */
+
+	__ETHA_FEATURES_MAX,
+	ETHA_FEATURES_MAX = (__ETHA_FEATURES_MAX - 1)
+};
 
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index ec90d4ccddf7..3b00ed6bfe10 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -6,6 +6,8 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 
+#define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
+
 extern const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
 extern const char rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN];
 extern const char tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 8613434b6fc0..39e9aea60516 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -54,8 +54,6 @@ EXPORT_SYMBOL(ethtool_op_get_ts_info);
 
 /* Handlers for each ethtool command */
 
-#define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
-
 static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_gfeatures cmd = {
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index dd76599f311f..fdca418a6d8e 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -4,6 +4,66 @@
 #include "common.h"
 #include <linux/rtnetlink.h>
 
+#define FEATURE_NAME_PTR(id) [id] = netdev_features_strings[id]
+static const char *feature_names[] = {
+	FEATURE_NAME_PTR(NETIF_F_SG_BIT),
+	FEATURE_NAME_PTR(NETIF_F_IP_CSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_CSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_IPV6_CSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HIGHDMA_BIT),
+	FEATURE_NAME_PTR(NETIF_F_FRAGLIST_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_VLAN_CTAG_TX_BIT),
+
+	FEATURE_NAME_PTR(NETIF_F_HW_VLAN_CTAG_RX_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_VLAN_CTAG_FILTER_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_VLAN_STAG_TX_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_VLAN_STAG_RX_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_VLAN_STAG_FILTER_BIT),
+	FEATURE_NAME_PTR(NETIF_F_VLAN_CHALLENGED_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_BIT),
+	FEATURE_NAME_PTR(NETIF_F_LLTX_BIT),
+	FEATURE_NAME_PTR(NETIF_F_NETNS_LOCAL_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GRO_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GRO_HW_BIT),
+	FEATURE_NAME_PTR(NETIF_F_LRO_BIT),
+
+	FEATURE_NAME_PTR(NETIF_F_TSO_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_ROBUST_BIT),
+	FEATURE_NAME_PTR(NETIF_F_TSO_ECN_BIT),
+	FEATURE_NAME_PTR(NETIF_F_TSO_MANGLEID_BIT),
+	FEATURE_NAME_PTR(NETIF_F_TSO6_BIT),
+	FEATURE_NAME_PTR(NETIF_F_FSO_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_GRE_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_GRE_CSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_IPXIP4_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_IPXIP6_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_UDP_TUNNEL_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_PARTIAL_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_SCTP_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_ESP_BIT),
+	FEATURE_NAME_PTR(NETIF_F_GSO_UDP_L4_BIT),
+
+	FEATURE_NAME_PTR(NETIF_F_FCOE_CRC_BIT),
+	FEATURE_NAME_PTR(NETIF_F_SCTP_CRC_BIT),
+	FEATURE_NAME_PTR(NETIF_F_FCOE_MTU_BIT),
+	FEATURE_NAME_PTR(NETIF_F_NTUPLE_BIT),
+	FEATURE_NAME_PTR(NETIF_F_RXHASH_BIT),
+	FEATURE_NAME_PTR(NETIF_F_RXCSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_NOCACHE_COPY_BIT),
+	FEATURE_NAME_PTR(NETIF_F_LOOPBACK_BIT),
+	FEATURE_NAME_PTR(NETIF_F_RXFCS_BIT),
+	FEATURE_NAME_PTR(NETIF_F_RXALL_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_L2FW_DOFFLOAD_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_TC_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_ESP_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_ESP_TX_CSUM_BIT),
+	FEATURE_NAME_PTR(NETIF_F_RX_UDP_TUNNEL_PORT_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_TLS_RECORD_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_TLS_TX_BIT),
+	FEATURE_NAME_PTR(NETIF_F_HW_TLS_RX_BIT),
+};
+
 struct settings_data {
 	struct ethtool_link_ksettings	ksettings;
 	struct ethtool_link_settings	*lsettings;
@@ -12,6 +72,12 @@ struct settings_data {
 	u32				msglevel;
 	bool				lpm_empty;
 	u32				req_mask;
+	struct {
+		u32	hw[ETHTOOL_DEV_FEATURE_WORDS];
+		u32	wanted[ETHTOOL_DEV_FEATURE_WORDS];
+		u32	active[ETHTOOL_DEV_FEATURE_WORDS];
+		u32	nochange[ETHTOOL_DEV_FEATURE_WORDS];
+	} features;
 };
 
 struct settings_reqinfo {
@@ -51,6 +117,7 @@ static const struct nla_policy settings_policy[ETHA_SETTINGS_MAX + 1] = {
 	[ETHA_SETTINGS_LINK_MODES]	= { .type = NLA_NESTED },
 	[ETHA_SETTINGS_PEER_MODES]	= { .type = NLA_NESTED },
 	[ETHA_SETTINGS_LINK]		= { .type = NLA_FLAG },
+	[ETHA_SETTINGS_FEATURES]	= { .type = NLA_NESTED },
 };
 
 /* To keep things simple, reserve space for some attributes which may not
@@ -105,6 +172,35 @@ static int settings_size(struct settings_data *data,
 	}
 	if (req_mask & ETH_SETTINGS_IM_LINK)
 		len += nla_total_size(sizeof(u32));
+	if (req_mask & ETH_SETTINGS_IM_FEATURES) {
+		ret = ethnl_bitset32_size(compact, NETDEV_FEATURE_COUNT,
+					  data->features.hw, NULL,
+					  feature_names);
+		if (ret < 0)
+			return ret;
+		len += ret;
+		ret = ethnl_bitset32_size(compact, NETDEV_FEATURE_COUNT,
+					  data->features.wanted,
+					  data->features.wanted,
+					  feature_names);
+		if (ret < 0)
+			return ret;
+		len += ret;
+		ret = ethnl_bitset32_size(compact, NETDEV_FEATURE_COUNT,
+					  data->features.active,
+					  data->features.active,
+					  feature_names);
+		if (ret < 0)
+			return ret;
+		len += ret;
+		ret = ethnl_bitset32_size(compact, NETDEV_FEATURE_COUNT,
+					  data->features.nochange,
+					  data->features.nochange,
+					  feature_names);
+		if (ret < 0)
+			return ret;
+		len += ret;
+	}
 
 	return len;
 }
@@ -150,6 +246,24 @@ static int ethnl_get_wol(struct genl_info *info, struct net_device *dev,
 	return ret;
 }
 
+static void features_to_bitmap(u32 *dest, netdev_features_t src)
+{
+	unsigned int i;
+
+	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++)
+		dest[i] = (u32)(src >> (32 * i));
+}
+
+static int ethnl_get_features(struct net_device *dev,
+			      struct settings_data *data)
+{
+	features_to_bitmap(data->features.hw, dev->hw_features);
+	features_to_bitmap(data->features.wanted, dev->wanted_features);
+	features_to_bitmap(data->features.active, dev->features);
+	features_to_bitmap(data->features.nochange, NETIF_F_NEVER_CHANGE);
+	return 0;
+}
+
 static int parse_settings_req(struct settings_reqinfo *req_info,
 			      struct genl_info *info, struct sk_buff *skb,
 			      const struct nlmsghdr *nlhdr)
@@ -233,6 +347,8 @@ static int prepare_settings(struct settings_data *data,
 	}
 	if (req_mask & ETH_SETTINGS_IM_LINK)
 		data->link = __ethtool_get_link(dev);
+	if (req_mask & ETH_SETTINGS_IM_FEATURES)
+		ethnl_get_features(dev, data);
 	if (!req_info->have_rtnl)
 		rtnl_unlock();
 
@@ -316,6 +432,41 @@ static int fill_settings(struct sk_buff *rskb, struct settings_data *data,
 		if (nla_put_u32(rskb, ETHA_SETTINGS_LINK, data->link))
 			return ret;
 	}
+	if (req_mask & ETH_SETTINGS_IM_FEATURES) {
+		struct nlattr *feat_attr;
+
+		feat_attr = ethnl_nest_start(rskb, ETHA_SETTINGS_FEATURES);
+		if (!feat_attr)
+			return -ENOMEM;
+		ret = ethnl_put_bitset32(rskb, ETHA_FEATURES_HW,
+					 compact, NETDEV_FEATURE_COUNT,
+					 data->features.hw, NULL,
+					 feature_names);
+		if (ret < 0)
+			return ret;
+		ret = ethnl_put_bitset32(rskb, ETHA_FEATURES_WANTED,
+					 compact, NETDEV_FEATURE_COUNT,
+					 data->features.wanted,
+					 data->features.wanted,
+					 feature_names);
+		if (ret < 0)
+			return ret;
+		ret = ethnl_put_bitset32(rskb, ETHA_FEATURES_ACTIVE,
+					 compact, NETDEV_FEATURE_COUNT,
+					 data->features.active,
+					 data->features.active,
+					 feature_names);
+		if (ret < 0)
+			return ret;
+		ret = ethnl_put_bitset32(rskb, ETHA_FEATURES_NOCHANGE,
+					 compact, NETDEV_FEATURE_COUNT,
+					 data->features.nochange,
+					 data->features.nochange,
+					 feature_names);
+		if (ret < 0)
+			return ret;
+		nla_nest_end(rskb, feat_attr);
+	}
 
 	return 0;
 }
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 10/17] ethtool: implement GET_SETTINGS message
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Requests the information provided by ETHTOOL_GLINKSETTINGS, ETHTOOL_GWOL
and ETHTOOL_GMSGLVL. The info_mask header field can be used to request only
part of the information. Flag ETH_SETTINGS_RF_COMPACT_BITSETS switches
between flag-by-flag list and compact bitmaps for link modes in the reply.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  69 ++-
 include/linux/ethtool_netlink.h              |   3 +
 include/linux/netdevice.h                    |   2 +
 include/uapi/linux/ethtool.h                 |   3 +
 include/uapi/linux/ethtool_netlink.h         |  37 ++
 net/ethtool/Makefile                         |   2 +-
 net/ethtool/common.c                         | 112 +++++
 net/ethtool/common.h                         |   8 +
 net/ethtool/ioctl.c                          | 108 +----
 net/ethtool/netlink.c                        |  69 +++
 net/ethtool/netlink.h                        |   2 +
 net/ethtool/settings.c                       | 416 +++++++++++++++++++
 12 files changed, 725 insertions(+), 106 deletions(-)
 create mode 100644 net/ethtool/settings.c

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 1e3d5ffc97ab..60d426cf6dad 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -123,6 +123,8 @@ List of message types
     ETHNL_CMD_SET_STRSET		response only
     ETHNL_CMD_GET_DRVINFO
     ETHNL_CMD_SET_DRVINFO		response only
+    ETHNL_CMD_GET_SETTINGS
+    ETHNL_CMD_SET_SETTINGS		response only (for now)
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -192,6 +194,63 @@ GET_DRVINFO requests).
 GET_DRVINFO requests allow dumps.
 
 
+GET_SETTINGS
+------------
+
+GET_SETTINGS request retrieves information provided by ETHTOOL_GLINKSETTINGS,
+ETHTOOL_GWOL, ETHTOOL_GMSGLVL and ETHTOOL_GLINK ioctl requests. The request
+doesn't use any attributes.
+
+Request attributes:
+
+    ETHA_SETTINGS_DEV		(nested)	device identification
+    ETHA_SETTINGS_INFOMASK	(u32)		info mask
+    ETHA_SETTINGS_COMPACT	(flag)		request compact bitsets
+
+Info mask bits meaning:
+
+    ETH_SETTINGS_IM_LINKINFO		link_ksettings except link modes
+    ETH_SETTINGS_IM_LINKMODES		link modes from link_ksettings
+    ETH_SETTINGS_IM_MSGLEVEL		msglevel
+    ETH_SETTINGS_IM_WOLINFO		struct ethtool_wolinfo
+    ETH_SETTINGS_IM_LINK		link state
+
+Response contents:
+
+    ETHA_SETTINGS_DEV		(nested)	device identification
+    ETHA_SETTINGS_SPEED		(u32)		link speed (Mb/s)
+    ETHA_SETTINGS_DUPLEX	(u8)		duplex mode
+    ETHA_SETTINGS_PORT		(u8)		physical port
+    ETHA_SETTINGS_PHYADDR	(u8)		MDIO address of phy
+    ETHA_SETTINGS_AUTONEG	(u8)		autoneotiation status
+    ETHA_SETTINGS_MDIO_SUPPORT	(bitfield32)	MDIO support flags
+    ETHA_SETTINGS_TP_MDIX	(u8)		MDI(-X) status
+    ETHA_SETTINGS_TP_MDIX_CTRL	(u8)		MDI(-X) control
+    ETHA_SETTINGS_TRANSCEIVER	(u8)		transceiver
+    ETHA_SETTINGS_WOL_MODES	(bitfield32)	wake-on-lan modes
+    ETHA_SETTINGS_SOPASS	(binary)	SecureOn(tm) password
+    ETHA_SETTINGS_MSGLVL	(bitfield32)	debug level
+    ETHA_SETTINGS_LINK_MODES	(bitset)	device link modes
+    ETHA_SETTINGS_PEER_MODES	(bitset)	link partner link modes
+    ETHA_SETTINGS_LINK		(u32)		link state
+
+Most of the attributes have the same meaning (including values) as
+corresponding members of ioctl structures. For ETHA_SETTINGS_MDIO_SUPPORT and
+ETHA_SETTINGS_MSGLVL, selector reports flags supported by kernel. For
+ETHA_SETTINGS_WOL_MODES it reports flags supported by the device. For
+ETHA_SETTINGS_LINK_MODES, value represent advertised modes and mask represents
+supported modes. For ETHA_SETTINGS_PEER_MODES, both value and mask represent
+partner advertised link modes.
+
+GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
+is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
+requests.
+
+GET_SETTINGS requests allow dumps and messages in the same format as response
+to them are broadcasted as notifications on change of these settings using
+netlink or ioctl ethtool interface.
+
+
 Request translation
 -------------------
 
@@ -201,16 +260,16 @@ have their netlink replacement yet.
 
 ioctl command			netlink command
 ---------------------------------------------------------------------
-ETHTOOL_GSET			n/a
+ETHTOOL_GSET			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SSET			n/a
 ETHTOOL_GDRVINFO		ETHNL_CMD_GET_DRVINFO
 ETHTOOL_GREGS			n/a
-ETHTOOL_GWOL			n/a
+ETHTOOL_GWOL			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SWOL			n/a
-ETHTOOL_GMSGLVL			n/a
+ETHTOOL_GMSGLVL			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SMSGLVL			n/a
 ETHTOOL_NWAY_RST		n/a
-ETHTOOL_GLINK			n/a
+ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
 ETHTOOL_GCOALESCE		n/a
@@ -275,7 +334,7 @@ ETHTOOL_GTUNABLE		n/a
 ETHTOOL_STUNABLE		n/a
 ETHTOOL_GPHYSTATS		n/a
 ETHTOOL_PERQUEUE		n/a
-ETHTOOL_GLINKSETTINGS		n/a
+ETHTOOL_GLINKSETTINGS		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SLINKSETTINGS		n/a
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
index 2a15e64a16f3..fba8ff961887 100644
--- a/include/linux/ethtool_netlink.h
+++ b/include/linux/ethtool_netlink.h
@@ -7,6 +7,9 @@
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 
+#define __ETHTOOL_LINK_MODE_MASK_NWORDS \
+	((__ETHTOOL_LINK_MODE_MASK_NBITS + 31) / 32)
+
 enum ethtool_multicast_groups {
 	ETHNL_MCGRP_MONITOR,
 };
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c4b0c575d57e..93071380558c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3738,6 +3738,8 @@ enum {
 	NETIF_MSG_PKTDATA	= 0x1000,
 	NETIF_MSG_HW		= 0x2000,
 	NETIF_MSG_WOL		= 0x4000,
+
+	NETIF_MSG_ALL		= 0x7fff,
 };
 
 #define netif_msg_drv(p)	((p)->msg_enable & NETIF_MSG_DRV)
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 2ae393963704..98f645a38168 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -143,6 +143,9 @@ static inline __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep)
  */
 #define ETH_MDIO_SUPPORTS_C45	2
 
+/* All defined ETH_MDIO_SUPPORTS_* flags */
+#define ETH_MDIO_SUPPORTS_ALL (ETH_MDIO_SUPPORTS_C22 | ETH_MDIO_SUPPORTS_C45)
+
 #define ETHTOOL_FWVERS_LEN	32
 #define ETHTOOL_BUSINFO_LEN	32
 #define ETHTOOL_EROMVERS_LEN	32
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index df4de61fac48..66df44aa7226 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -12,6 +12,8 @@ enum {
 	ETHNL_CMD_SET_STRSET,		/* only for reply */
 	ETHNL_CMD_GET_DRVINFO,
 	ETHNL_CMD_SET_DRVINFO,		/* only for reply */
+	ETHNL_CMD_GET_SETTINGS,
+	ETHNL_CMD_SET_SETTINGS,
 
 	__ETHNL_CMD_MAX,
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
@@ -146,6 +148,41 @@ enum {
 	ETHA_DRVINFO_MAX = (__ETHA_DRVINFO_MAX - 1)
 };
 
+/* GET_SETTINGS / SET_SETTINGS */
+
+enum {
+	ETHA_SETTINGS_UNSPEC,
+	ETHA_SETTINGS_DEV,			/* nest - ETHA_DEV_* */
+	ETHA_SETTINGS_INFOMASK,			/* u32 */
+	ETHA_SETTINGS_COMPACT,			/* flag */
+	ETHA_SETTINGS_SPEED,			/* u32 */
+	ETHA_SETTINGS_DUPLEX,			/* u8 */
+	ETHA_SETTINGS_PORT,			/* u8 */
+	ETHA_SETTINGS_PHYADDR,			/* u8 */
+	ETHA_SETTINGS_AUTONEG,			/* u8 */
+	ETHA_SETTINGS_MDIO_SUPPORT,		/* bitfield32 */
+	ETHA_SETTINGS_TP_MDIX,			/* u8 */
+	ETHA_SETTINGS_TP_MDIX_CTRL,		/* u8 */
+	ETHA_SETTINGS_TRANSCEIVER,		/* u8 */
+	ETHA_SETTINGS_WOL_MODES,		/* bitfield32 */
+	ETHA_SETTINGS_SOPASS,			/* binary */
+	ETHA_SETTINGS_MSGLVL,			/* bitfield32 */
+	ETHA_SETTINGS_LINK_MODES,		/* bitset */
+	ETHA_SETTINGS_PEER_MODES,		/* bitset */
+	ETHA_SETTINGS_LINK,			/* u32 */
+
+	__ETHA_SETTINGS_MAX,
+	ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_MAX - 1)
+};
+
+#define ETH_SETTINGS_IM_LINKINFO		0x01
+#define ETH_SETTINGS_IM_LINKMODES		0x02
+#define ETH_SETTINGS_IM_MSGLEVEL		0x04
+#define ETH_SETTINGS_IM_WOLINFO			0x08
+#define ETH_SETTINGS_IM_LINK			0x10
+
+#define ETH_SETTINGS_IM_DEFAULT			0x1f
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 2e840ae0ba1e..8dd98310ed6f 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -4,4 +4,4 @@ obj-y				+= ioctl.o common.o
 
 obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o
 
-ethtool_nl-y	:= netlink.o strset.o drvinfo.o
+ethtool_nl-y	:= netlink.o strset.o drvinfo.o settings.o
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 1dc4a6515996..986e82664447 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -128,3 +128,115 @@ int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 	return 0;
 }
 EXPORT_SYMBOL(__ethtool_get_drvinfo);
+
+/* return false if legacy contained non-0 deprecated fields
+ * maxtxpkt/maxrxpkt. rest of ksettings always updated
+ */
+bool
+convert_legacy_settings_to_link_ksettings(
+	struct ethtool_link_ksettings *link_ksettings,
+	const struct ethtool_cmd *legacy_settings)
+{
+	bool retval = true;
+
+	memset(link_ksettings, 0, sizeof(*link_ksettings));
+
+	/* This is used to tell users that driver is still using these
+	 * deprecated legacy fields, and they should not use
+	 * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
+	 */
+	if (legacy_settings->maxtxpkt ||
+	    legacy_settings->maxrxpkt)
+		retval = false;
+
+	ethtool_convert_legacy_u32_to_link_mode(
+		link_ksettings->link_modes.supported,
+		legacy_settings->supported);
+	ethtool_convert_legacy_u32_to_link_mode(
+		link_ksettings->link_modes.advertising,
+		legacy_settings->advertising);
+	ethtool_convert_legacy_u32_to_link_mode(
+		link_ksettings->link_modes.lp_advertising,
+		legacy_settings->lp_advertising);
+	link_ksettings->base.speed
+		= ethtool_cmd_speed(legacy_settings);
+	link_ksettings->base.duplex
+		= legacy_settings->duplex;
+	link_ksettings->base.port
+		= legacy_settings->port;
+	link_ksettings->base.phy_address
+		= legacy_settings->phy_address;
+	link_ksettings->base.autoneg
+		= legacy_settings->autoneg;
+	link_ksettings->base.mdio_support
+		= legacy_settings->mdio_support;
+	link_ksettings->base.eth_tp_mdix
+		= legacy_settings->eth_tp_mdix;
+	link_ksettings->base.eth_tp_mdix_ctrl
+		= legacy_settings->eth_tp_mdix_ctrl;
+	return retval;
+}
+
+/* Internal kernel helper to query a device ethtool_link_settings.
+ *
+ * Backward compatibility note: for compatibility with legacy drivers
+ * that implement only the ethtool_cmd API, this has to work with both
+ * drivers implementing get_link_ksettings API and drivers
+ * implementing get_settings API. When drivers implement get_settings
+ * and report ethtool_cmd deprecated fields
+ * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored
+ * because the resulting struct ethtool_link_settings does not report them.
+ */
+int __ethtool_get_link_ksettings(struct net_device *dev,
+				 struct ethtool_link_ksettings *link_ksettings)
+{
+	int err;
+	struct ethtool_cmd cmd;
+
+	ASSERT_RTNL();
+
+	if (dev->ethtool_ops->get_link_ksettings) {
+		memset(link_ksettings, 0, sizeof(*link_ksettings));
+		return dev->ethtool_ops->get_link_ksettings(dev,
+							    link_ksettings);
+	}
+
+	/* driver doesn't support %ethtool_link_ksettings API. revert to
+	 * legacy %ethtool_cmd API, unless it's not supported either.
+	 * TODO: remove when ethtool_ops::get_settings disappears internally
+	 */
+	if (!dev->ethtool_ops->get_settings)
+		return -EOPNOTSUPP;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = ETHTOOL_GSET;
+	err = dev->ethtool_ops->get_settings(dev, &cmd);
+	if (err < 0)
+		return err;
+
+	/* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt
+	 */
+	convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd);
+	return err;
+}
+EXPORT_SYMBOL(__ethtool_get_link_ksettings);
+
+int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	if (!dev->ethtool_ops->get_wol)
+		return -EOPNOTSUPP;
+
+	dev->ethtool_ops->get_wol(dev, wol);
+
+	return 0;
+}
+EXPORT_SYMBOL(__ethtool_get_wol);
+
+int __ethtool_get_link(struct net_device *dev)
+{
+	if (!dev->ethtool_ops->get_link)
+		return -EOPNOTSUPP;
+
+	return netif_running(dev) && dev->ethtool_ops->get_link(dev);
+}
+EXPORT_SYMBOL(__ethtool_get_link);
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 0f768c1be527..ec90d4ccddf7 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -12,5 +12,13 @@ extern const char tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
 extern const char phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
 
 int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
+int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
+int __ethtool_get_link_ksettings(struct net_device *dev,
+				 struct ethtool_link_ksettings *link_ksettings);
+int __ethtool_get_link(struct net_device *dev);
+
+bool convert_legacy_settings_to_link_ksettings(
+	struct ethtool_link_ksettings *link_ksettings,
+	const struct ethtool_cmd *legacy_settings);
 
 #endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 7b5831d35bca..8613434b6fc0 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -352,54 +352,6 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
 }
 EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
 
-/* return false if legacy contained non-0 deprecated fields
- * maxtxpkt/maxrxpkt. rest of ksettings always updated
- */
-static bool
-convert_legacy_settings_to_link_ksettings(
-	struct ethtool_link_ksettings *link_ksettings,
-	const struct ethtool_cmd *legacy_settings)
-{
-	bool retval = true;
-
-	memset(link_ksettings, 0, sizeof(*link_ksettings));
-
-	/* This is used to tell users that driver is still using these
-	 * deprecated legacy fields, and they should not use
-	 * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
-	 */
-	if (legacy_settings->maxtxpkt ||
-	    legacy_settings->maxrxpkt)
-		retval = false;
-
-	ethtool_convert_legacy_u32_to_link_mode(
-		link_ksettings->link_modes.supported,
-		legacy_settings->supported);
-	ethtool_convert_legacy_u32_to_link_mode(
-		link_ksettings->link_modes.advertising,
-		legacy_settings->advertising);
-	ethtool_convert_legacy_u32_to_link_mode(
-		link_ksettings->link_modes.lp_advertising,
-		legacy_settings->lp_advertising);
-	link_ksettings->base.speed
-		= ethtool_cmd_speed(legacy_settings);
-	link_ksettings->base.duplex
-		= legacy_settings->duplex;
-	link_ksettings->base.port
-		= legacy_settings->port;
-	link_ksettings->base.phy_address
-		= legacy_settings->phy_address;
-	link_ksettings->base.autoneg
-		= legacy_settings->autoneg;
-	link_ksettings->base.mdio_support
-		= legacy_settings->mdio_support;
-	link_ksettings->base.eth_tp_mdix
-		= legacy_settings->eth_tp_mdix;
-	link_ksettings->base.eth_tp_mdix_ctrl
-		= legacy_settings->eth_tp_mdix_ctrl;
-	return retval;
-}
-
 /* return false if ksettings link modes had higher bits
  * set. legacy_settings always updated (best effort)
  */
@@ -460,50 +412,6 @@ struct ethtool_link_usettings {
 	} link_modes;
 };
 
-/* Internal kernel helper to query a device ethtool_link_settings.
- *
- * Backward compatibility note: for compatibility with legacy drivers
- * that implement only the ethtool_cmd API, this has to work with both
- * drivers implementing get_link_ksettings API and drivers
- * implementing get_settings API. When drivers implement get_settings
- * and report ethtool_cmd deprecated fields
- * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored
- * because the resulting struct ethtool_link_settings does not report them.
- */
-int __ethtool_get_link_ksettings(struct net_device *dev,
-				 struct ethtool_link_ksettings *link_ksettings)
-{
-	int err;
-	struct ethtool_cmd cmd;
-
-	ASSERT_RTNL();
-
-	if (dev->ethtool_ops->get_link_ksettings) {
-		memset(link_ksettings, 0, sizeof(*link_ksettings));
-		return dev->ethtool_ops->get_link_ksettings(dev,
-							    link_ksettings);
-	}
-
-	/* driver doesn't support %ethtool_link_ksettings API. revert to
-	 * legacy %ethtool_cmd API, unless it's not supported either.
-	 * TODO: remove when ethtool_ops::get_settings disappears internally
-	 */
-	if (!dev->ethtool_ops->get_settings)
-		return -EOPNOTSUPP;
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cmd = ETHTOOL_GSET;
-	err = dev->ethtool_ops->get_settings(dev, &cmd);
-	if (err < 0)
-		return err;
-
-	/* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt
-	 */
-	convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd);
-	return err;
-}
-EXPORT_SYMBOL(__ethtool_get_link_ksettings);
-
 /* convert ethtool_link_usettings in user space to a kernel internal
  * ethtool_link_ksettings. return 0 on success, errno on error.
  */
@@ -1359,11 +1267,11 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
 static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+	int rc;
 
-	if (!dev->ethtool_ops->get_wol)
-		return -EOPNOTSUPP;
-
-	dev->ethtool_ops->get_wol(dev, &wol);
+	rc = __ethtool_get_wol(dev, &wol);
+	if (rc < 0)
+		return rc;
 
 	if (copy_to_user(useraddr, &wol, sizeof(wol)))
 		return -EFAULT;
@@ -1428,12 +1336,12 @@ static int ethtool_nway_reset(struct net_device *dev)
 static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
+	int link = __ethtool_get_link(dev);
 
-	if (!dev->ethtool_ops->get_link)
-		return -EOPNOTSUPP;
-
-	edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);
+	if (link < 0)
+		return link;
 
+	edata.data = link;
 	if (copy_to_user(useraddr, &edata, sizeof(edata)))
 		return -EFAULT;
 	return 0;
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 305baa02ff70..6c14185a6466 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -2,12 +2,68 @@
 
 #include <linux/module.h>
 #include <linux/bitmap.h>
+#include <linux/rtnetlink.h>
 #include <net/sock.h>
 #include <linux/ethtool_netlink.h>
 #include "netlink.h"
 
 u32 ethnl_bcast_seq;
 
+const char *const link_mode_names[] = {
+	[ETHTOOL_LINK_MODE_10baseT_Half_BIT]		= "10baseT/Half",
+	[ETHTOOL_LINK_MODE_10baseT_Full_BIT]		= "10baseT/Full",
+	[ETHTOOL_LINK_MODE_100baseT_Half_BIT]		= "100baseT/Half",
+	[ETHTOOL_LINK_MODE_100baseT_Full_BIT]		= "100baseT/Full",
+	[ETHTOOL_LINK_MODE_1000baseT_Half_BIT]		= "1000baseT/Half",
+	[ETHTOOL_LINK_MODE_1000baseT_Full_BIT]		= "1000baseT/Full",
+	[ETHTOOL_LINK_MODE_Autoneg_BIT]			= "Autoneg",
+	[ETHTOOL_LINK_MODE_TP_BIT]			= "TP",
+	[ETHTOOL_LINK_MODE_AUI_BIT]			= "AUI",
+	[ETHTOOL_LINK_MODE_MII_BIT]			= "MII",
+	[ETHTOOL_LINK_MODE_FIBRE_BIT]			= "FIBRE",
+	[ETHTOOL_LINK_MODE_BNC_BIT]			= "BNC",
+	[ETHTOOL_LINK_MODE_10000baseT_Full_BIT]		= "10000baseT/Full",
+	[ETHTOOL_LINK_MODE_Pause_BIT]			= "Pause",
+	[ETHTOOL_LINK_MODE_Asym_Pause_BIT]		= "Asym_Pause",
+	[ETHTOOL_LINK_MODE_2500baseX_Full_BIT]		= "2500baseX/Full",
+	[ETHTOOL_LINK_MODE_Backplane_BIT]		= "Backplane",
+	[ETHTOOL_LINK_MODE_1000baseKX_Full_BIT]		= "1000baseKX/Full",
+	[ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT]	= "10000baseKX4/Full",
+	[ETHTOOL_LINK_MODE_10000baseKR_Full_BIT]	= "10000baseKR/Full",
+	[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT]		= "10000baseR/FEC",
+	[ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT]	= "20000baseMLD2/Full",
+	[ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT]	= "20000baseKR2/Full",
+	[ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT]	= "40000baseKR4/Full",
+	[ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT]	= "40000baseCR4/Full",
+	[ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT]	= "40000baseSR4/Full",
+	[ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT]	= "40000baseLR4/Full",
+	[ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT]	= "56000baseKR4/Full",
+	[ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT]	= "56000baseCR4/Full",
+	[ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT]	= "56000baseSR4/Full",
+	[ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT]	= "56000baseLR4/Full",
+	[ETHTOOL_LINK_MODE_25000baseCR_Full_BIT]	= "25000baseCR/Full",
+	[ETHTOOL_LINK_MODE_25000baseKR_Full_BIT]	= "25000baseKR/Full",
+	[ETHTOOL_LINK_MODE_25000baseSR_Full_BIT]	= "25000baseSR/Full",
+	[ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT]	= "50000baseCR2/Full",
+	[ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT]	= "50000baseKR2/Full",
+	[ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT]	= "100000baseKR4/Full",
+	[ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT]	= "100000baseSR4/Full",
+	[ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT]	= "100000baseCR4/Full",
+	[ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT]	= "100000baseLR4/ER4_Full",
+	[ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT]	= "50000baseSR2/Full",
+	[ETHTOOL_LINK_MODE_1000baseX_Full_BIT]		= "1000baseX/Full",
+	[ETHTOOL_LINK_MODE_10000baseCR_Full_BIT]	= "10000baseCR/Full",
+	[ETHTOOL_LINK_MODE_10000baseSR_Full_BIT]	= "10000baseSR/Full",
+	[ETHTOOL_LINK_MODE_10000baseLR_Full_BIT]	= "10000baseLR/Full",
+	[ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT]	= "10000baseLRM/Full",
+	[ETHTOOL_LINK_MODE_10000baseER_Full_BIT]	= "10000baseER/Full",
+	[ETHTOOL_LINK_MODE_2500baseT_Full_BIT]		= "2500baseT/Full",
+	[ETHTOOL_LINK_MODE_5000baseT_Full_BIT]		= "5000baseT/Full",
+	[ETHTOOL_LINK_MODE_FEC_NONE_BIT]		= "None",
+	[ETHTOOL_LINK_MODE_FEC_RS_BIT]			= "RS",
+	[ETHTOOL_LINK_MODE_FEC_BASER_BIT]		= "BASER",
+};
+
 static const struct nla_policy dev_policy[ETHA_DEV_MAX + 1] = {
 	[ETHA_DEV_UNSPEC]	= { .type = NLA_UNSPEC },
 	[ETHA_DEV_INDEX]	= { .type = NLA_U32 },
@@ -671,11 +727,14 @@ static struct notifier_block ethnl_netdev_notifier = {
 
 int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info);
+int ethnl_get_settings(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_strset_start(struct netlink_callback *cb);
 int ethnl_drvinfo_start(struct netlink_callback *cb);
+int ethnl_settings_start(struct netlink_callback *cb);
 
 int ethnl_strset_done(struct netlink_callback *cb);
+int ethnl_settings_done(struct netlink_callback *cb);
 
 static const struct genl_ops ethtool_genl_ops[] = {
 	{
@@ -691,6 +750,13 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.start	= ethnl_drvinfo_start,
 		.dumpit	= ethnl_dumpit,
 	},
+	{
+		.cmd	= ETHNL_CMD_GET_SETTINGS,
+		.doit	= ethnl_get_settings,
+		.start	= ethnl_settings_start,
+		.dumpit	= ethnl_dumpit,
+		.done	= ethnl_settings_done,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
@@ -715,6 +781,9 @@ static int __init ethtool_nl_init(void)
 {
 	int ret;
 
+	BUILD_BUG_ON(ARRAY_SIZE(link_mode_names) <
+		     __ETHTOOL_LINK_MODE_MASK_NBITS);
+
 	ret = genl_register_family(&ethtool_genl_family);
 	if (ret < 0)
 		return ret;
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 94c14ec2c3fc..789aceae9f5e 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -15,6 +15,8 @@ extern u32 ethnl_bcast_seq;
 
 extern struct genl_family ethtool_genl_family;
 
+extern const char *const link_mode_names[];
+
 struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
 int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype);
 
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
new file mode 100644
index 000000000000..dd76599f311f
--- /dev/null
+++ b/net/ethtool/settings.c
@@ -0,0 +1,416 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include "netlink.h"
+#include "common.h"
+#include <linux/rtnetlink.h>
+
+struct settings_data {
+	struct ethtool_link_ksettings	ksettings;
+	struct ethtool_link_settings	*lsettings;
+	struct ethtool_wolinfo		wolinfo;
+	int				link;
+	u32				msglevel;
+	bool				lpm_empty;
+	u32				req_mask;
+};
+
+struct settings_reqinfo {
+	struct net_device		*dev;
+	u32				req_mask;
+	bool				compact;
+	bool				is_privileged;
+	bool				have_rtnl;
+};
+
+/* We want to allow ~0 as selector for backward compatibility (to just set
+ * given set of modes, whatever kernel supports) so that we allow all bits
+ * on validation and do our own sanity check later.
+ */
+static u32 all_bits = ~(u32)0;
+
+static const struct nla_policy settings_policy[ETHA_SETTINGS_MAX + 1] = {
+	[ETHA_SETTINGS_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_SETTINGS_DEV]		= { .type = NLA_NESTED },
+	[ETHA_SETTINGS_INFOMASK]	= { .type = NLA_U32 },
+	[ETHA_SETTINGS_COMPACT]		= { .type = NLA_FLAG },
+	[ETHA_SETTINGS_SPEED]		= { .type = NLA_U32 },
+	[ETHA_SETTINGS_DUPLEX]		= { .type = NLA_U8 },
+	[ETHA_SETTINGS_PORT]		= { .type = NLA_U8 },
+	[ETHA_SETTINGS_PHYADDR]		= { .type = NLA_U8 },
+	[ETHA_SETTINGS_AUTONEG]		= { .type = NLA_U8 },
+	[ETHA_SETTINGS_MDIO_SUPPORT]	= { .type = NLA_BITFIELD32 },
+	[ETHA_SETTINGS_TP_MDIX]		= { .type = NLA_U8 },
+	[ETHA_SETTINGS_TP_MDIX_CTRL]	= { .type = NLA_U8 },
+	[ETHA_SETTINGS_TRANSCEIVER]	= { .type = NLA_U8 },
+	[ETHA_SETTINGS_WOL_MODES]	= { .type = NLA_BITFIELD32,
+					    .validation_data = &all_bits },
+	[ETHA_SETTINGS_SOPASS]		= { .type = NLA_BINARY,
+					    .len = SOPASS_MAX },
+	[ETHA_SETTINGS_MSGLVL]		= { .type = NLA_BITFIELD32,
+					    .validation_data = &all_bits },
+	[ETHA_SETTINGS_LINK_MODES]	= { .type = NLA_NESTED },
+	[ETHA_SETTINGS_PEER_MODES]	= { .type = NLA_NESTED },
+	[ETHA_SETTINGS_LINK]		= { .type = NLA_FLAG },
+};
+
+/* To keep things simple, reserve space for some attributes which may not
+ * be added to the message (e.g. ETHA_SETTINGS_SOPASS); therefore the length
+ * returned may be bigger than the actual length of the message sent
+ */
+static int settings_size(struct settings_data *data,
+			 struct settings_reqinfo *req_info)
+{
+	struct ethtool_link_ksettings *ksettings = &data->ksettings;
+	u32 req_mask = req_info->req_mask;
+	bool compact = req_info->compact;
+	size_t len = 0;
+	int ret = 0;
+
+	if (req_mask & ETH_SETTINGS_IM_LINKINFO) {
+		/* speed */
+		len += nla_total_size(sizeof(u32));
+		/* duplex, autoneg, port, phyaddr, mdix, mdixctrl, transcvr */
+		len += 7 * nla_total_size(sizeof(u8));
+		/* mdio_support */
+		len += nla_total_size(sizeof(struct nla_bitfield32));
+	}
+	if (req_mask & ETH_SETTINGS_IM_LINKMODES) {
+		u32 *supported = (u32 *)ksettings->link_modes.supported;
+		u32 *advertising = (u32 *)ksettings->link_modes.advertising;
+		u32 *lp_advertising =
+			(u32 *)ksettings->link_modes.lp_advertising;
+
+		ret = ethnl_bitset32_size(compact,
+					  __ETHTOOL_LINK_MODE_MASK_NBITS,
+					  advertising, supported,
+					  link_mode_names);
+		if (ret < 0)
+			return ret;
+		len += ret;
+		ret = ethnl_bitset32_size(compact,
+					  __ETHTOOL_LINK_MODE_MASK_NBITS,
+					  lp_advertising, lp_advertising,
+					  link_mode_names);
+		if (ret < 0)
+			return ret;
+		len += ret;
+	}
+	if (req_mask & ETH_SETTINGS_IM_MSGLEVEL)
+		len += nla_total_size(sizeof(struct nla_bitfield32));
+	if (req_mask & ETH_SETTINGS_IM_WOLINFO) {
+		/* wolopts / wol_supported */
+		len += nla_total_size(sizeof(struct nla_bitfield32));
+		/* sopass */
+		len += nla_total_size(SOPASS_MAX);
+	}
+	if (req_mask & ETH_SETTINGS_IM_LINK)
+		len += nla_total_size(sizeof(u32));
+
+	return len;
+}
+
+static int ethnl_get_link_ksettings(struct genl_info *info,
+				    struct net_device *dev,
+				    struct ethtool_link_ksettings *ksettings)
+{
+	int ret;
+
+	ret = __ethtool_get_link_ksettings(dev, ksettings);
+
+	if (ret < 0)
+		ETHNL_SET_ERRMSG(info, "failed to retrieve link settings");
+	return ret;
+}
+
+static int ethnl_get_legacy_settings(struct genl_info *info,
+				     struct net_device *dev,
+				     struct ethtool_cmd *cmd)
+{
+	int ret;
+
+	if (!dev->ethtool_ops->get_settings) {
+		/* we already tried ->get_link_ksettings */
+		ETHNL_SET_ERRMSG(info, "link settings retrieval unsupported");
+		return -EOPNOTSUPP;
+	}
+	ret = dev->ethtool_ops->get_settings(dev, cmd);
+	if (ret < 0)
+		ETHNL_SET_ERRMSG(info, "failed to retrieve link settings");
+
+	return ret;
+}
+
+static int ethnl_get_wol(struct genl_info *info, struct net_device *dev,
+			 struct ethtool_wolinfo *wolinfo)
+{
+	int ret = __ethtool_get_wol(dev, wolinfo);
+
+	if (ret < 0)
+		ETHNL_SET_ERRMSG(info, "failed to retrieve wol info");
+	return ret;
+}
+
+static int parse_settings_req(struct settings_reqinfo *req_info,
+			      struct genl_info *info, struct sk_buff *skb,
+			      const struct nlmsghdr *nlhdr)
+{
+	struct nlattr *tb[ETHA_SETTINGS_MAX + 1];
+	int ret;
+
+	memset(req_info, '\0', sizeof(*req_info));
+	req_info->is_privileged = ethnl_is_privileged(skb);
+
+	ret = genlmsg_parse(nlhdr, &ethtool_genl_family, tb,
+			    ETHA_SETTINGS_MAX, settings_policy,
+			    info ? info->extack : NULL);
+	if (ret < 0)
+		return ret;
+
+	if (tb[ETHA_SETTINGS_DEV]) {
+		req_info->dev = ethnl_dev_get(info, tb[ETHA_SETTINGS_DEV]);
+		if (IS_ERR(req_info->dev)) {
+			ret = PTR_ERR(req_info->dev);
+			req_info->dev = NULL;
+			return ret;
+		}
+	}
+	if (tb[ETHA_SETTINGS_INFOMASK])
+		req_info->req_mask = nla_get_u32(tb[ETHA_SETTINGS_INFOMASK]);
+	if (tb[ETHA_SETTINGS_COMPACT])
+		req_info->compact = true;
+	if (req_info->req_mask == 0)
+		req_info->req_mask = ETH_SETTINGS_IM_DEFAULT;
+
+	return 0;
+}
+
+static int prepare_settings(struct settings_data *data,
+			    struct settings_reqinfo *req_info,
+			    struct genl_info *info, struct net_device *dev)
+{
+	u32 req_mask = req_info->req_mask;
+	int ret;
+
+	memset(data, '\0', sizeof(*data));
+	data->lsettings = &data->ksettings.base;
+	data->lpm_empty = true;
+	data->link = -EOPNOTSUPP;
+
+	if (!req_info->have_rtnl)
+		rtnl_lock();
+	if (req_mask & (ETH_SETTINGS_IM_LINKINFO | ETH_SETTINGS_IM_LINKMODES)) {
+		ret = ethnl_get_link_ksettings(info, dev, &data->ksettings);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~(ETH_SETTINGS_IM_LINKINFO |
+				      ETH_SETTINGS_IM_LINKMODES);
+		}
+	}
+	if (req_mask & ETH_SETTINGS_IM_LINKMODES) {
+		data->lpm_empty = bitmap_empty(data->ksettings.link_modes.lp_advertising,
+					       __ETHTOOL_LINK_MODE_MASK_NBITS);
+		ethnl_bitmap_to_u32(data->ksettings.link_modes.supported,
+				    __ETHTOOL_LINK_MODE_MASK_NWORDS);
+		ethnl_bitmap_to_u32(data->ksettings.link_modes.advertising,
+				    __ETHTOOL_LINK_MODE_MASK_NWORDS);
+		ethnl_bitmap_to_u32(data->ksettings.link_modes.lp_advertising,
+				    __ETHTOOL_LINK_MODE_MASK_NWORDS);
+	}
+	if (req_mask & ETH_SETTINGS_IM_MSGLEVEL) {
+		if (dev->ethtool_ops->get_msglevel) {
+			data->msglevel = dev->ethtool_ops->get_msglevel(dev);
+		} else {
+			warn_partial_info(info);
+			req_mask &= ~ETH_SETTINGS_IM_MSGLEVEL;
+		}
+	}
+	if (req_mask & ETH_SETTINGS_IM_WOLINFO) {
+		ret = ethnl_get_wol(info, dev, &data->wolinfo);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_SETTINGS_IM_WOLINFO;
+		}
+	}
+	if (req_mask & ETH_SETTINGS_IM_LINK)
+		data->link = __ethtool_get_link(dev);
+	if (!req_info->have_rtnl)
+		rtnl_unlock();
+
+	data->req_mask = req_mask;
+	return 0;
+}
+
+static int fill_settings(struct sk_buff *rskb, struct settings_data *data,
+			 struct settings_reqinfo *req_info)
+{
+	struct ethtool_link_settings *lsettings = data->lsettings;
+	u32 req_mask = data->req_mask;
+	bool compact = req_info->compact;
+	int ret;
+
+	ret = -EMSGSIZE;
+	if (req_mask & ETH_SETTINGS_IM_LINKINFO) {
+		if (nla_put_u32(rskb, ETHA_SETTINGS_SPEED, lsettings->speed) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_DUPLEX, lsettings->duplex) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_PORT, lsettings->port) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_PHYADDR,
+			       lsettings->phy_address) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_AUTONEG,
+			       lsettings->autoneg) ||
+		    nla_put_bitfield32(rskb, ETHA_SETTINGS_MDIO_SUPPORT,
+				       lsettings->mdio_support,
+				       ETH_MDIO_SUPPORTS_ALL) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_TP_MDIX,
+			       lsettings->eth_tp_mdix) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_TP_MDIX_CTRL,
+			       lsettings->eth_tp_mdix_ctrl) ||
+		    nla_put_u8(rskb, ETHA_SETTINGS_TRANSCEIVER,
+			       lsettings->transceiver))
+			return ret;
+	}
+	if (req_mask & ETH_SETTINGS_IM_LINKMODES) {
+		u32 *supported = (u32 *)data->ksettings.link_modes.supported;
+		u32 *advertising =
+			(u32 *)data->ksettings.link_modes.advertising;
+		u32 *lp_advertising =
+			(u32 *)data->ksettings.link_modes.lp_advertising;
+
+		ret = ethnl_put_bitset32(rskb, ETHA_SETTINGS_LINK_MODES,
+					 compact,
+					 __ETHTOOL_LINK_MODE_MASK_NBITS,
+					 advertising, supported,
+					 link_mode_names);
+		if (ret < 0)
+			return ret;
+		if (!data->lpm_empty) {
+			ret = ethnl_put_bitset32(rskb, ETHA_SETTINGS_PEER_MODES,
+						 compact,
+						 __ETHTOOL_LINK_MODE_MASK_NBITS,
+						 lp_advertising, lp_advertising,
+						 link_mode_names);
+			if (ret < 0)
+				return ret;
+		}
+		ret = -EMSGSIZE;
+	}
+	if (req_mask & ETH_SETTINGS_IM_MSGLEVEL) {
+		if (nla_put_bitfield32(rskb, ETHA_SETTINGS_MSGLVL,
+				       data->msglevel, NETIF_MSG_ALL))
+			return ret;
+	}
+	if (req_mask & ETH_SETTINGS_IM_WOLINFO) {
+		/* ioctl() restricts read access to wolinfo but the actual
+		 * reason is to hide sopass from unprivileged users; netlink
+		 * can show wol modes without sopass
+		 */
+		if (nla_put_bitfield32(rskb, ETHA_SETTINGS_WOL_MODES,
+				       data->wolinfo.wolopts,
+				       data->wolinfo.supported))
+			return ret;
+		if (req_info->is_privileged &&
+		    nla_put(rskb, ETHA_SETTINGS_SOPASS,
+			    sizeof(data->wolinfo.sopass), data->wolinfo.sopass))
+			return ret;
+	}
+	if (req_mask & ETH_SETTINGS_IM_LINK && data->link >= 0) {
+		if (nla_put_u32(rskb, ETHA_SETTINGS_LINK, data->link))
+			return ret;
+	}
+
+	return 0;
+}
+
+int ethnl_get_settings(struct sk_buff *skb, struct genl_info *info)
+{
+	struct settings_data data;
+	struct settings_reqinfo req_info;
+	struct sk_buff *rskb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = parse_settings_req(&req_info, info, skb, info->nlhdr);
+	if (ret < 0)
+		goto err_dev;
+	ret = prepare_settings(&data, &req_info, info, req_info.dev);
+	if (ret < 0)
+		goto err_dev;
+	reply_len = settings_size(&data, &req_info);
+	if (ret < 0)
+		goto err_dev;
+	ret = -ENOMEM;
+	rskb = ethnl_reply_init(reply_len, req_info.dev, ETHNL_CMD_SET_SETTINGS,
+				ETHA_SETTINGS_DEV, info, &ehdr);
+	if (!rskb)
+		goto err_dev;
+	ret = fill_settings(rskb, &data, &req_info);
+	if (ret < 0)
+		goto err;
+
+	genlmsg_end(rskb, ehdr);
+	dev_put(req_info.dev);
+	return genlmsg_reply(rskb, info);
+
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+err_dev:
+	if (req_info.dev)
+		dev_put(req_info.dev);
+	return ret;
+}
+
+static int settings_dump(struct sk_buff *skb, struct netlink_callback *cb,
+			struct net_device *dev)
+{
+	struct settings_data data;
+	struct settings_reqinfo *req_info;
+	int ret;
+
+	req_info = (struct settings_reqinfo *)cb->args[4];
+	ret = prepare_settings(&data, req_info, NULL, dev);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_fill_dev(skb, dev, ETHA_SETTINGS_DEV);
+	if (ret < 0)
+		return ret;
+	ret = fill_settings(skb, &data, req_info);
+	return ret;
+}
+
+int ethnl_settings_start(struct netlink_callback *cb)
+{
+	struct settings_reqinfo *req_info;
+	int ret;
+
+	req_info = kmalloc(sizeof(*req_info), GFP_KERNEL);
+	if (!req_info)
+		return -ENOMEM;
+	ret = parse_settings_req(req_info, NULL, cb->skb, cb->nlh);
+	if (ret < 0) {
+		if (req_info->dev)
+			dev_put(req_info->dev);
+		req_info->dev = NULL;
+		return ret;
+	}
+
+	cb->args[0] = (long)settings_dump;
+	cb->args[1] = ETHNL_CMD_SET_SETTINGS;
+	cb->args[4] = (long)req_info;
+
+	return 0;
+}
+
+int ethnl_settings_done(struct netlink_callback *cb)
+{
+	struct settings_reqinfo *req_info;
+
+	req_info = (struct settings_reqinfo *)cb->args[4];
+	if (req_info->dev)
+		dev_put(req_info->dev);
+	kfree(req_info);
+
+	return 0;
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 08/17] ethtool: implement GET_STRSET message
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Requests a contents of a string set, i.e. indexed array of strings; this
information is provided by ETHTOOL_GSSET_INFO and ETHTOOL_GSTRINGS commands
of ioctl interface. There are three types of requests

  - no NLM_F_DUMP, no device: get all "global" stringsets
  - no NLM_F_DUMP, with device: get all string sets related to the device
  - NLM_F_DUMP, no device: get all device related string sets for all
    devices

It's also possible to request only specific string sets.

In addition to string sets recognized by ioctl interface, GET_STRSET
request can also retrieve list of link modes.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |   6 +-
 include/uapi/linux/ethtool.h                 |   4 +
 include/uapi/linux/ethtool_netlink.h         |  42 ++
 net/ethtool/Makefile                         |   2 +-
 net/ethtool/common.c                         |  87 +++
 net/ethtool/common.h                         |  13 +
 net/ethtool/ioctl.c                          |  80 ---
 net/ethtool/netlink.c                        |  13 +
 net/ethtool/strset.c                         | 552 +++++++++++++++++++
 9 files changed, 716 insertions(+), 83 deletions(-)
 create mode 100644 net/ethtool/common.c
 create mode 100644 net/ethtool/common.h
 create mode 100644 net/ethtool/strset.c

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 0e83397f2975..8b43f41a8140 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -119,6 +119,8 @@ List of message types
 ---------------------
 
     ETHNL_CMD_EVENT			notification only
+    ETHNL_CMD_GET_STRSET
+    ETHNL_CMD_SET_STRSET		response only
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -188,7 +190,7 @@ ETHTOOL_STXCSUM			n/a
 ETHTOOL_GSG			n/a
 ETHTOOL_SSG			n/a
 ETHTOOL_TEST			n/a
-ETHTOOL_GSTRINGS		n/a
+ETHTOOL_GSTRINGS		ETHNL_CMD_GET_STRSET
 ETHTOOL_PHYS_ID			n/a
 ETHTOOL_GSTATS			n/a
 ETHTOOL_GTSO			n/a
@@ -216,7 +218,7 @@ ETHTOOL_FLASHDEV		n/a
 ETHTOOL_RESET			n/a
 ETHTOOL_SRXNTUPLE		n/a
 ETHTOOL_GRXNTUPLE		n/a
-ETHTOOL_GSSET_INFO		n/a
+ETHTOOL_GSSET_INFO		ETHNL_CMD_GET_STRSET
 ETHTOOL_GRXFHINDIR		n/a
 ETHTOOL_SRXFHINDIR		n/a
 ETHTOOL_GFEATURES		n/a
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 7363f18e65a5..2ae393963704 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -578,6 +578,10 @@ enum ethtool_stringset {
 	ETH_SS_TUNABLES,
 	ETH_SS_PHY_STATS,
 	ETH_SS_PHY_TUNABLES,
+	ETH_SS_LINK_MODES,
+
+	__ETH_SS_MAX,
+	ETH_SS_MAX = (__ETH_SS_MAX - 1)
 };
 
 /**
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index f162cd6f80d4..5177c1940c2b 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -8,6 +8,8 @@
 enum {
 	ETHNL_CMD_NOOP,
 	ETHNL_CMD_EVENT,		/* only for notifications */
+	ETHNL_CMD_GET_STRSET,
+	ETHNL_CMD_SET_STRSET,		/* only for reply */
 
 	__ETHNL_CMD_MAX,
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
@@ -82,6 +84,46 @@ enum {
 	ETHA_EVENT_MAX = (__ETHA_EVENT_MAX - 1)
 };
 
+/* string sets */
+
+enum {
+	ETHA_STRING_UNSPEC,
+	ETHA_STRING_INDEX,			/* u32 */
+	ETHA_STRING_VALUE,			/* string */
+
+	__ETHA_STRING_MAX,
+	ETHA_STRING_MAX = (__ETHA_STRING_MAX - 1)
+};
+
+enum {
+	ETHA_STRINGS_UNSPEC,
+	ETHA_STRINGS_STRING,			/* nest - ETHA_STRINGS_* */
+
+	__ETHA_STRINGS_MAX,
+	ETHA_STRINGS_MAX = (__ETHA_STRINGS_MAX - 1)
+};
+
+enum {
+	ETHA_STRINGSET_UNSPEC,
+	ETHA_STRINGSET_ID,			/* u32 */
+	ETHA_STRINGSET_COUNT,			/* u32 */
+	ETHA_STRINGSET_STRINGS,			/* nest - ETHA_STRINGS_* */
+
+	__ETHA_STRINGSET_MAX,
+	ETHA_STRINGSET_MAX = (__ETHA_STRINGSET_MAX - 1)
+};
+
+/* GET_STRINGSET / SET_STRINGSET */
+
+enum {
+	ETHA_STRSET_UNSPEC,
+	ETHA_STRSET_DEV,			/* nest - ETHA_DEV_* */
+	ETHA_STRSET_STRINGSET,			/* nest - ETHA_STRSET_* */
+
+	__ETHA_STRSET_MAX,
+	ETHA_STRSET_MAX = (__ETHA_STRSET_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index f30e0da88be5..ba260d5b53b2 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -4,4 +4,4 @@ obj-y				+= ioctl.o
 
 obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o
 
-ethtool_nl-y	:= netlink.o
+ethtool_nl-y	:= netlink.o strset.o
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
new file mode 100644
index 000000000000..208259c51b73
--- /dev/null
+++ b/net/ethtool/common.c
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include "common.h"
+
+const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
+	[NETIF_F_SG_BIT] =               "tx-scatter-gather",
+	[NETIF_F_IP_CSUM_BIT] =          "tx-checksum-ipv4",
+	[NETIF_F_HW_CSUM_BIT] =          "tx-checksum-ip-generic",
+	[NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",
+	[NETIF_F_HIGHDMA_BIT] =          "highdma",
+	[NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist",
+	[NETIF_F_HW_VLAN_CTAG_TX_BIT] =  "tx-vlan-hw-insert",
+
+	[NETIF_F_HW_VLAN_CTAG_RX_BIT] =  "rx-vlan-hw-parse",
+	[NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter",
+	[NETIF_F_HW_VLAN_STAG_TX_BIT] =  "tx-vlan-stag-hw-insert",
+	[NETIF_F_HW_VLAN_STAG_RX_BIT] =  "rx-vlan-stag-hw-parse",
+	[NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
+	[NETIF_F_VLAN_CHALLENGED_BIT] =  "vlan-challenged",
+	[NETIF_F_GSO_BIT] =              "tx-generic-segmentation",
+	[NETIF_F_LLTX_BIT] =             "tx-lockless",
+	[NETIF_F_NETNS_LOCAL_BIT] =      "netns-local",
+	[NETIF_F_GRO_BIT] =              "rx-gro",
+	[NETIF_F_GRO_HW_BIT] =           "rx-gro-hw",
+	[NETIF_F_LRO_BIT] =              "rx-lro",
+
+	[NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
+	[NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
+	[NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
+	[NETIF_F_TSO_MANGLEID_BIT] =	 "tx-tcp-mangleid-segmentation",
+	[NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
+	[NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
+	[NETIF_F_GSO_GRE_BIT] =		 "tx-gre-segmentation",
+	[NETIF_F_GSO_GRE_CSUM_BIT] =	 "tx-gre-csum-segmentation",
+	[NETIF_F_GSO_IPXIP4_BIT] =	 "tx-ipxip4-segmentation",
+	[NETIF_F_GSO_IPXIP6_BIT] =	 "tx-ipxip6-segmentation",
+	[NETIF_F_GSO_UDP_TUNNEL_BIT] =	 "tx-udp_tnl-segmentation",
+	[NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
+	[NETIF_F_GSO_PARTIAL_BIT] =	 "tx-gso-partial",
+	[NETIF_F_GSO_SCTP_BIT] =	 "tx-sctp-segmentation",
+	[NETIF_F_GSO_ESP_BIT] =		 "tx-esp-segmentation",
+	[NETIF_F_GSO_UDP_L4_BIT] =	 "tx-udp-segmentation",
+
+	[NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",
+	[NETIF_F_SCTP_CRC_BIT] =        "tx-checksum-sctp",
+	[NETIF_F_FCOE_MTU_BIT] =         "fcoe-mtu",
+	[NETIF_F_NTUPLE_BIT] =           "rx-ntuple-filter",
+	[NETIF_F_RXHASH_BIT] =           "rx-hashing",
+	[NETIF_F_RXCSUM_BIT] =           "rx-checksum",
+	[NETIF_F_NOCACHE_COPY_BIT] =     "tx-nocache-copy",
+	[NETIF_F_LOOPBACK_BIT] =         "loopback",
+	[NETIF_F_RXFCS_BIT] =            "rx-fcs",
+	[NETIF_F_RXALL_BIT] =            "rx-all",
+	[NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
+	[NETIF_F_HW_TC_BIT] =		 "hw-tc-offload",
+	[NETIF_F_HW_ESP_BIT] =		 "esp-hw-offload",
+	[NETIF_F_HW_ESP_TX_CSUM_BIT] =	 "esp-tx-csum-hw-offload",
+	[NETIF_F_RX_UDP_TUNNEL_PORT_BIT] =	 "rx-udp_tunnel-port-offload",
+	[NETIF_F_HW_TLS_RECORD_BIT] =	"tls-hw-record",
+	[NETIF_F_HW_TLS_TX_BIT] =	 "tls-hw-tx-offload",
+	[NETIF_F_HW_TLS_RX_BIT] =	 "tls-hw-rx-offload",
+};
+EXPORT_SYMBOL(netdev_features_strings);
+
+const char
+rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
+	[ETH_RSS_HASH_TOP_BIT] =	"toeplitz",
+	[ETH_RSS_HASH_XOR_BIT] =	"xor",
+	[ETH_RSS_HASH_CRC32_BIT] =	"crc32",
+};
+EXPORT_SYMBOL(rss_hash_func_strings);
+
+const char
+tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
+	[ETHTOOL_ID_UNSPEC]     = "Unspec",
+	[ETHTOOL_RX_COPYBREAK]	= "rx-copybreak",
+	[ETHTOOL_TX_COPYBREAK]	= "tx-copybreak",
+	[ETHTOOL_PFC_PREVENTION_TOUT] = "pfc-prevention-tout",
+};
+EXPORT_SYMBOL(tunable_strings);
+
+const char
+phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
+	[ETHTOOL_ID_UNSPEC]     = "Unspec",
+	[ETHTOOL_PHY_DOWNSHIFT]	= "phy-downshift",
+};
+EXPORT_SYMBOL(phy_tunable_strings);
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
new file mode 100644
index 000000000000..45c6492e4aee
--- /dev/null
+++ b/net/ethtool/common.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _ETHTOOL_COMMON_H
+#define _ETHTOOL_COMMON_H
+
+#include <linux/ethtool.h>
+
+extern const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
+extern const char rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN];
+extern const char tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
+extern const char phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
+
+#endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index c9993c6c2fd4..a91b597073f8 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -55,86 +55,6 @@ EXPORT_SYMBOL(ethtool_op_get_ts_info);
 
 #define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
 
-static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
-	[NETIF_F_SG_BIT] =               "tx-scatter-gather",
-	[NETIF_F_IP_CSUM_BIT] =          "tx-checksum-ipv4",
-	[NETIF_F_HW_CSUM_BIT] =          "tx-checksum-ip-generic",
-	[NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",
-	[NETIF_F_HIGHDMA_BIT] =          "highdma",
-	[NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist",
-	[NETIF_F_HW_VLAN_CTAG_TX_BIT] =  "tx-vlan-hw-insert",
-
-	[NETIF_F_HW_VLAN_CTAG_RX_BIT] =  "rx-vlan-hw-parse",
-	[NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter",
-	[NETIF_F_HW_VLAN_STAG_TX_BIT] =  "tx-vlan-stag-hw-insert",
-	[NETIF_F_HW_VLAN_STAG_RX_BIT] =  "rx-vlan-stag-hw-parse",
-	[NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
-	[NETIF_F_VLAN_CHALLENGED_BIT] =  "vlan-challenged",
-	[NETIF_F_GSO_BIT] =              "tx-generic-segmentation",
-	[NETIF_F_LLTX_BIT] =             "tx-lockless",
-	[NETIF_F_NETNS_LOCAL_BIT] =      "netns-local",
-	[NETIF_F_GRO_BIT] =              "rx-gro",
-	[NETIF_F_GRO_HW_BIT] =           "rx-gro-hw",
-	[NETIF_F_LRO_BIT] =              "rx-lro",
-
-	[NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
-	[NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
-	[NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
-	[NETIF_F_TSO_MANGLEID_BIT] =	 "tx-tcp-mangleid-segmentation",
-	[NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
-	[NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
-	[NETIF_F_GSO_GRE_BIT] =		 "tx-gre-segmentation",
-	[NETIF_F_GSO_GRE_CSUM_BIT] =	 "tx-gre-csum-segmentation",
-	[NETIF_F_GSO_IPXIP4_BIT] =	 "tx-ipxip4-segmentation",
-	[NETIF_F_GSO_IPXIP6_BIT] =	 "tx-ipxip6-segmentation",
-	[NETIF_F_GSO_UDP_TUNNEL_BIT] =	 "tx-udp_tnl-segmentation",
-	[NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
-	[NETIF_F_GSO_PARTIAL_BIT] =	 "tx-gso-partial",
-	[NETIF_F_GSO_SCTP_BIT] =	 "tx-sctp-segmentation",
-	[NETIF_F_GSO_ESP_BIT] =		 "tx-esp-segmentation",
-	[NETIF_F_GSO_UDP_L4_BIT] =	 "tx-udp-segmentation",
-
-	[NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",
-	[NETIF_F_SCTP_CRC_BIT] =        "tx-checksum-sctp",
-	[NETIF_F_FCOE_MTU_BIT] =         "fcoe-mtu",
-	[NETIF_F_NTUPLE_BIT] =           "rx-ntuple-filter",
-	[NETIF_F_RXHASH_BIT] =           "rx-hashing",
-	[NETIF_F_RXCSUM_BIT] =           "rx-checksum",
-	[NETIF_F_NOCACHE_COPY_BIT] =     "tx-nocache-copy",
-	[NETIF_F_LOOPBACK_BIT] =         "loopback",
-	[NETIF_F_RXFCS_BIT] =            "rx-fcs",
-	[NETIF_F_RXALL_BIT] =            "rx-all",
-	[NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
-	[NETIF_F_HW_TC_BIT] =		 "hw-tc-offload",
-	[NETIF_F_HW_ESP_BIT] =		 "esp-hw-offload",
-	[NETIF_F_HW_ESP_TX_CSUM_BIT] =	 "esp-tx-csum-hw-offload",
-	[NETIF_F_RX_UDP_TUNNEL_PORT_BIT] =	 "rx-udp_tunnel-port-offload",
-	[NETIF_F_HW_TLS_RECORD_BIT] =	"tls-hw-record",
-	[NETIF_F_HW_TLS_TX_BIT] =	 "tls-hw-tx-offload",
-	[NETIF_F_HW_TLS_RX_BIT] =	 "tls-hw-rx-offload",
-};
-
-static const char
-rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
-	[ETH_RSS_HASH_TOP_BIT] =	"toeplitz",
-	[ETH_RSS_HASH_XOR_BIT] =	"xor",
-	[ETH_RSS_HASH_CRC32_BIT] =	"crc32",
-};
-
-static const char
-tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
-	[ETHTOOL_ID_UNSPEC]     = "Unspec",
-	[ETHTOOL_RX_COPYBREAK]	= "rx-copybreak",
-	[ETHTOOL_TX_COPYBREAK]	= "tx-copybreak",
-	[ETHTOOL_PFC_PREVENTION_TOUT] = "pfc-prevention-tout",
-};
-
-static const char
-phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
-	[ETHTOOL_ID_UNSPEC]     = "Unspec",
-	[ETHTOOL_PHY_DOWNSHIFT]	= "phy-downshift",
-};
-
 static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_gfeatures cmd = {
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 543560778c80..237a2cb40be4 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -669,7 +669,20 @@ static struct notifier_block ethnl_netdev_notifier = {
 
 /* genetlink setup */
 
+int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info);
+
+int ethnl_strset_start(struct netlink_callback *cb);
+
+int ethnl_strset_done(struct netlink_callback *cb);
+
 static const struct genl_ops ethtool_genl_ops[] = {
+	{
+		.cmd	= ETHNL_CMD_GET_STRSET,
+		.doit	= ethnl_get_strset,
+		.start	= ethnl_strset_start,
+		.dumpit	= ethnl_dumpit,
+		.done	= ethnl_strset_done,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c
new file mode 100644
index 000000000000..32543c68fae8
--- /dev/null
+++ b/net/ethtool/strset.c
@@ -0,0 +1,552 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include "netlink.h"
+#include "common.h"
+
+enum strset_type {
+	ETH_SS_TYPE_NONE,
+	ETH_SS_TYPE_LEGACY,
+	ETH_SS_TYPE_SIMPLE,
+};
+
+struct strset_info {
+	enum strset_type type;
+	bool per_dev;
+	bool free_data;
+	unsigned int count;
+	union {
+		const char (*legacy)[ETH_GSTRING_LEN];
+		const char * const *simple;
+		void *ptr;
+	} data;
+};
+
+static const struct strset_info info_template[] = {
+	[ETH_SS_TEST] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= true,
+	},
+	[ETH_SS_STATS] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= true,
+	},
+	[ETH_SS_PRIV_FLAGS] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= true,
+	},
+	[ETH_SS_NTUPLE_FILTERS] = {
+		.type		= ETH_SS_TYPE_NONE,
+	},
+	[ETH_SS_FEATURES] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= false,
+		.count		= ARRAY_SIZE(netdev_features_strings),
+		.data		= { .legacy = netdev_features_strings },
+	},
+	[ETH_SS_RSS_HASH_FUNCS] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= false,
+		.count		= ARRAY_SIZE(rss_hash_func_strings),
+		.data		= { .legacy = rss_hash_func_strings },
+	},
+	[ETH_SS_TUNABLES] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= false,
+		.count		= ARRAY_SIZE(tunable_strings),
+		.data		= { .legacy = tunable_strings },
+	},
+	[ETH_SS_PHY_STATS] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= true,
+	},
+	[ETH_SS_PHY_TUNABLES] = {
+		.type		= ETH_SS_TYPE_LEGACY,
+		.per_dev	= false,
+		.count		= ARRAY_SIZE(phy_tunable_strings),
+		.data		= { .legacy = phy_tunable_strings },
+	},
+	[ETH_SS_LINK_MODES] = {
+		.type		= ETH_SS_TYPE_SIMPLE,
+		.per_dev	= false,
+		.count		= __ETHTOOL_LINK_MODE_MASK_NBITS,
+		.data		= { .simple = link_mode_names },
+	},
+};
+
+struct strset_data {
+	struct net_device	*dev;
+	struct strset_info	info[ETH_SS_MAX + 1];
+};
+
+struct strset_reqinfo {
+	struct net_device	*dev;
+	u32			req_ids;
+	bool			have_rtnl;
+};
+
+static const struct nla_policy get_strset_policy[ETHA_STRSET_MAX + 1] = {
+	[ETHA_STRSET_DEV]		= { .type = NLA_NESTED },
+        [ETHA_STRSET_STRINGSET]		= { .type = NLA_NESTED },
+};
+
+static const struct nla_policy stringset_policy[ETHA_STRINGSET_MAX + 1] = {
+	[ETHA_STRINGSET_ID]		= { .type = NLA_U32 },
+	[ETHA_STRINGSET_COUNT]		= { .type = NLA_U32 },
+	[ETHA_STRINGSET_STRINGS]	= { .type = NLA_NESTED },
+};
+
+static int legacy_set_size(const char (*set)[ETH_GSTRING_LEN], unsigned count)
+{
+	unsigned len = 0;
+	unsigned int i;
+
+	for (i = 0; i < count; i++)
+		len += nla_total_size(nla_total_size(sizeof(u32)) +
+				      ethnl_str_size(set[i]));
+	len = 2 * nla_total_size(sizeof(u32)) + nla_total_size(len);
+
+	return nla_total_size(len);
+}
+
+static int simple_set_size(const char * const *set, unsigned count)
+{
+	unsigned len = 0;
+	unsigned int i;
+
+	for (i = 0; i < count; i++)
+		len += nla_total_size(nla_total_size(sizeof(u32)) +
+				      ethnl_str_size(set[i]));
+	len = 2 * nla_total_size(sizeof(u32)) + nla_total_size(len);
+
+	return nla_total_size(len);
+}
+
+static int set_size(const struct strset_info *info)
+{
+	if (info->count == 0)
+		return 0;
+
+	switch(info->type) {
+	case ETH_SS_TYPE_LEGACY:
+		return legacy_set_size(info->data.legacy, info->count);
+	case ETH_SS_TYPE_SIMPLE:
+		return simple_set_size(info->data.simple, info->count);
+	default:
+		return -EINVAL;
+	};
+}
+
+static bool id_requested(const struct strset_reqinfo *req_info, u32 id)
+{
+	return req_info->req_ids & (1U << id);
+}
+
+static bool include_set(struct strset_data *data,
+			struct strset_reqinfo *req_info, u32 id)
+{
+	/* once ETH_SS_MAX reaches 32, we will need to change
+	 * strset_info::req_ids to u64; one day we might even need to use
+	 * generic bitmap but let's not complicate the code prematurely
+	 */
+	BUILD_BUG_ON(ETH_SS_MAX >= BITS_PER_BYTE * sizeof(req_info->req_ids));
+
+	if (req_info->req_ids)
+		return id_requested(req_info, id);
+	else {
+		bool per_dev = data->info[id].per_dev;
+
+		if (data->info[id].type == ETH_SS_TYPE_NONE)
+			return false;
+		return data->dev ? per_dev : !per_dev;
+	}
+}
+
+static int strset_size(struct strset_data *data,
+		       struct strset_reqinfo *req_info)
+{
+	unsigned int i;
+	int len = 0;
+	int ret;
+	for (i = 0; i <= ETH_SS_MAX; i++) {
+		const struct strset_info *info = &data->info[i];
+
+		if (!include_set(data, req_info, i) ||
+		    (info->type == ETH_SS_TYPE_NONE))
+			continue;
+
+		ret = set_size(info);
+		if (ret < 0)
+			return ret;
+		else
+			len += ret;
+	}
+
+	return len;
+}
+
+const char *str_value(struct strset_info *info, unsigned int i)
+{
+	switch(info->type) {
+	case ETH_SS_TYPE_LEGACY:
+		return info->data.legacy[i];
+	case ETH_SS_TYPE_SIMPLE:
+		return info->data.simple[i];
+	default:
+		WARN_ONCE(1, "unexpected string set type");
+		return "";
+	}
+}
+
+static int get_strset_id(const struct nlattr *nest, u32 *val,
+			 struct genl_info *info)
+{
+	struct nlattr *tb[ETHA_STRINGSET_MAX + 1];
+	int ret;
+
+	ret = nla_parse_nested(tb, ETHA_STRINGSET_MAX, nest, stringset_policy,
+			       info ? info->extack : NULL);
+	if (ret < 0)
+		return ret;
+	if (!tb[ETHA_STRINGSET_ID])
+		return -EINVAL;
+
+	*val = nla_get_u32(tb[ETHA_STRINGSET_ID]);
+	return 0;
+}
+
+static int parse_strset_req(struct strset_reqinfo *req_info,
+			    struct genl_info *info, struct sk_buff *skb,
+			    const struct nlmsghdr *nlhdr)
+{
+	struct nlattr *tb[ETHA_STRSET_MAX + 1];
+	int ret;
+
+	memset(req_info, '\0', sizeof(*req_info));
+
+	ret = genlmsg_parse(nlhdr, &ethtool_genl_family, tb,
+			    ETHA_STRSET_MAX, get_strset_policy,
+			    info ? info->extack : NULL);
+	if (ret < 0)
+		return ret;
+
+	if (tb[ETHA_STRSET_DEV]) {
+		req_info->dev = ethnl_dev_get(info, tb[ETHA_STRSET_DEV]);
+		if (IS_ERR(req_info->dev)) {
+			ret = PTR_ERR(req_info->dev);
+			req_info->dev = NULL;
+			return ret;
+		}
+	}
+	if (tb[ETHA_STRSET_STRINGSET]) {
+		struct nlattr *set;
+		int rem;
+
+		nlmsg_for_each_attr(set, nlhdr, GENL_HDRLEN, rem) {
+			u32 id;
+
+			ret = get_strset_id(set, &id, info);
+			if (ret < 0)
+				return ret;
+			if (ret > ETH_SS_MAX)
+				return -EOPNOTSUPP;
+			req_info->req_ids |= (1U << id);
+		}
+	}
+
+	return 0;
+}
+
+static void free_strset(struct strset_data *data)
+{
+	unsigned int i;
+
+	for (i = 0; i <= ETH_SS_MAX; i++)
+		if (data->info[i].free_data) {
+			kfree(data->info[i].data.ptr);
+			data->info[i].data.ptr = NULL;
+			data->info[i].free_data = false;
+		}
+}
+
+static int prepare_one_stringset(struct strset_info *info,
+				 struct net_device *dev, unsigned int id)
+{
+	const struct ethtool_ops *ops = dev->ethtool_ops;
+	void *strings;
+	int count, ret;
+
+
+	if (id == ETH_SS_PHY_STATS && dev->phydev &&
+	    !ops->get_ethtool_phy_stats)
+		ret = phy_ethtool_get_sset_count(dev->phydev);
+	else if (ops->get_sset_count && ops->get_strings)
+		ret = ops->get_sset_count(dev, id);
+	else
+		ret = -EOPNOTSUPP;
+	if (ret <= 0) {
+		info->count = 0;
+		return 0;
+	}
+
+	count = ret;
+	strings = kcalloc(count, ETH_GSTRING_LEN, GFP_KERNEL);
+	if (!strings)
+		return -ENOMEM;
+	if (id == ETH_SS_PHY_STATS && dev->phydev &&
+	    !ops->get_ethtool_phy_stats)
+		phy_ethtool_get_strings(dev->phydev, strings);
+	else
+		ops->get_strings(dev, id, strings);
+	info->count = count;
+	info->data.legacy = strings;
+	info->free_data = true;
+
+	return 0;
+}
+
+static int prepare_strset(struct strset_data *data,
+			  struct strset_reqinfo *req_info,
+			  struct genl_info *info, struct net_device *dev)
+{
+	unsigned int i;
+	int ret;
+
+	memset(data, '\0', sizeof(*data));
+	memcpy(&data->info, &info_template, sizeof(data->info));
+	data->dev = dev;
+
+	if (!dev)
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			if (id_requested(req_info, i) &&
+			    data->info[i].per_dev) {
+				ETHNL_SET_ERRMSG(info,
+						 "requested per device strings without dev");
+				return -EINVAL;
+			}
+
+	if (!req_info->have_rtnl)
+		rtnl_lock();
+	for (i = 0; i <= ETH_SS_MAX; i++) {
+		if (!include_set(data, req_info, i) || !data->info[i].per_dev)
+		    continue;
+		if (WARN_ONCE(data->info[i].type != ETH_SS_TYPE_LEGACY,
+			      "unexpected string set type %u",
+			      data->info[i].type))
+			goto err_free;
+
+		ret = prepare_one_stringset(&data->info[i], dev, i);
+		if (ret < 0)
+			goto err_free;
+	}
+	if (!req_info->have_rtnl)
+		rtnl_unlock();
+
+	return 0;
+err_free:
+	if (!req_info->have_rtnl)
+		rtnl_unlock();
+	free_strset(data);
+	return ret;
+}
+
+static int fill_set(struct sk_buff *skb, struct strset_data *data, u32 id)
+{
+	struct strset_info *info = &data->info[id];
+	struct nlattr *strings;
+	struct nlattr *nest;
+	unsigned int i = (unsigned int)(-1);
+
+	if (info->type == ETH_SS_TYPE_NONE)
+		return -EOPNOTSUPP;
+	if (info->count == 0)
+		return 0;
+	nest = ethnl_nest_start(skb, ETHA_STRSET_STRINGSET);
+	if (!nest)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(skb, ETHA_STRINGSET_ID, id) ||
+	    nla_put_u32(skb, ETHA_STRINGSET_COUNT, info->count))
+		goto err;
+
+	strings = ethnl_nest_start(skb, ETHA_STRINGSET_STRINGS);
+	if (!strings)
+		goto err;
+	for (i = 0; i < info->count; i++) {
+		struct nlattr *string = ethnl_nest_start(skb,
+							 ETHA_STRINGS_STRING);
+
+		if (!string)
+			goto err;
+		if (nla_put_u32(skb, ETHA_STRING_INDEX, i) ||
+		    nla_put_string(skb, ETHA_STRING_VALUE, str_value(info, i)))
+			goto err;
+		nla_nest_end(skb, string);
+	}
+	nla_nest_end(skb, strings);
+
+	nla_nest_end(skb, nest);
+	return 0;
+
+err:
+	nla_nest_cancel(skb, nest);
+	return -EMSGSIZE;
+}
+
+static int fill_strset(struct sk_buff *skb, struct strset_data *data,
+		       struct strset_reqinfo *req_info)
+{
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i <= ETH_SS_MAX; i++)
+		if (include_set(data, req_info, i)) {
+		    ret = fill_set(skb, data, i);
+		    if (ret < 0)
+			    return ret;
+		}
+
+	return 0;
+}
+
+int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info)
+{
+	struct strset_data data;
+	struct strset_reqinfo req_info;
+	struct sk_buff *rskb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = parse_strset_req(&req_info, info, skb, info->nlhdr);
+	if (ret < 0)
+		goto err_dev;
+	ret = prepare_strset(&data, &req_info, info, req_info.dev);
+	if (ret < 0)
+		goto err_dev;
+	ret = strset_size(&data, &req_info);
+	if (ret < 0)
+		goto err_data;
+	reply_len = ret;
+	ret = -ENOMEM;
+	rskb = ethnl_reply_init(reply_len, req_info.dev, ETHNL_CMD_SET_STRSET,
+				ETHA_STRSET_DEV, info, &ehdr);
+	if (!rskb)
+		goto err_data;
+	ret = fill_strset(rskb, &data, &req_info);
+	if (ret < 0)
+		goto err;
+
+	genlmsg_end(rskb, ehdr);
+	free_strset(&data);
+	if (req_info.dev)
+		dev_put(req_info.dev);
+	return genlmsg_reply(rskb, info);
+
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+err_data:
+	free_strset(&data);
+err_dev:
+	if (req_info.dev)
+		dev_put(req_info.dev);
+	return ret;
+}
+
+static int strset_dump(struct sk_buff *skb, struct netlink_callback *cb,
+		       struct net_device *dev)
+{
+	struct strset_data data;
+	struct strset_reqinfo *req_info;
+	int ret;
+
+	req_info = (struct strset_reqinfo *)cb->args[4];
+	ret = prepare_strset(&data, req_info, NULL, dev);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_fill_dev(skb, dev, ETHA_STRSET_DEV);
+	if (ret < 0)
+		goto out;
+	ret = fill_strset(skb, &data, req_info);
+out:
+	free_strset(&data);
+	return ret;
+}
+
+int ethnl_strset_start(struct netlink_callback *cb)
+{
+	struct strset_reqinfo *req_info;
+	int ret;
+
+	req_info = kmalloc(sizeof(*req_info), GFP_KERNEL);
+	if (!req_info)
+		return -ENOMEM;
+	ret = parse_strset_req(req_info, NULL, cb->skb, cb->nlh);
+	if (ret < 0) {
+		if (req_info->dev)
+			dev_put(req_info->dev);
+		req_info->dev = NULL;
+		return ret;
+	}
+
+	cb->args[0] = (long)strset_dump;
+	cb->args[1] = ETHNL_CMD_SET_STRSET;
+	cb->args[4] = (long)req_info;
+	cb->min_dump_alloc = 65535;
+
+	return 0;
+}
+
+int ethnl_strset_done(struct netlink_callback *cb)
+{
+	struct strset_reqinfo *req_info;
+
+	req_info = (struct strset_reqinfo *)cb->args[4];
+	if (req_info->dev)
+		dev_put(req_info->dev);
+	kfree(req_info);
+
+	return 0;
+}
+
+void ethnl_strset_notify(struct netdev_notifier_ethtool_info *info)
+{
+	struct strset_reqinfo req_info = {
+		.dev		= info->info.dev,
+		.have_rtnl	= true,
+	};
+	struct strset_data data;
+	struct sk_buff *skb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = prepare_strset(&data, &req_info, NULL, req_info.dev);
+	if (ret < 0)
+		return;
+	reply_len = strset_size(&data, &req_info);
+	if (reply_len < 0)
+		return;
+	skb = genlmsg_new(reply_len, GFP_KERNEL);
+	if (!skb)
+		return;
+	ehdr = genlmsg_put(skb, 0, ++ethnl_bcast_seq, &ethtool_genl_family, 0,
+			   ETHNL_CMD_SET_STRSET);
+	ret = ethnl_fill_dev(skb, req_info.dev, ETHA_STRSET_DEV);
+	if (ret < 0)
+		goto err_skb;
+	ret = fill_strset(skb, &data, &req_info);
+	if (ret < 0)
+		goto err_skb;
+	genlmsg_end(skb, ehdr);
+
+	genlmsg_multicast(&ethtool_genl_family, skb, 0, ETHNL_MCGRP_MONITOR,
+			  GFP_KERNEL);
+	return;
+err_skb:
+	nlmsg_free(skb);
+}
-- 
2.18.0

^ permalink raw reply related

* [PATCH net-next] net: phy: mscc: the extended page access register is 16 bits
From: Quentin Schulz @ 2018-07-30 12:53 UTC (permalink / raw)
  To: andrew, f.fainelli, davem
  Cc: netdev, alexandre.belloni, linux-kernel, thomas.petazzoni,
	Quentin Schulz

The Extended Page Access is a 16-bit register, so change the page
parameter of vsc85xx_phy_page_set to a u16.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/net/phy/mscc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 650c2667d523..84ca9ff40ae0 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -123,7 +123,7 @@ static const struct vsc8531_edge_rate_table edge_table[] = {
 };
 #endif /* CONFIG_OF_MDIO */
 
-static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
+static int vsc85xx_phy_page_set(struct phy_device *phydev, u16 page)
 {
 	int rc;
 
-- 
2.17.1

^ permalink raw reply related

* [RFC PATCH net-next v2 05/17] ethtool: netlink bitset handling
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Declare attribute type constants and add helper functions to handle
arbitrary length bit sets.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  56 +++
 include/uapi/linux/ethtool_netlink.h         |  31 ++
 net/ethtool/netlink.c                        | 395 +++++++++++++++++++
 net/ethtool/netlink.h                        |  26 ++
 4 files changed, 508 insertions(+)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 120376e0f91b..a49dfe3ef4bb 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -59,6 +59,62 @@ provided by kernel. In dump requests, device is not specified and kernel
 replies with one message per network device (only those for which the request
 is supported).
 
+Bit sets
+--------
+
+For short bitmaps of (reasonably) fixed length, standard NLA_BITFIELD32 type
+is used. For arbitrary length bitmaps, ethtool netlink uses a nested attribute
+with contents of one of two forms: compact (two binary bitmaps representing
+bit values and mask of affected bits) and bit-by-bit (list of bits identified
+by either index or name).
+
+Compact form: nested (bitset) atrribute contents:
+
+    ETHA_BITSET_SIZE	(u32)		number of significant bits
+    ETHA_BITSET_VALUE	(binary)	bitmap of bit values
+    ETHA_BITSET_MASK	(binary)	bitmap of valid bits
+
+Value and mask must have length at least ETHA_BITSET_SIZE bits rounded up to
+a multiple of 32 bits. They consist of 32-bit words in host byt order, words
+ordered from least significant to most significant (i.e. the same way as
+bitmaps are passed with ioctl interface).
+
+For compact form, ETHA_BITSET_SIZE and ETHA_BITSET_VALUE are mandatory.
+Similar to BITFIELD32, a compact form bit set requests to set bits in the mask
+to 1 (if set in value) or 0 (if not) and preserve the rest. If the mask is
+omitted, it is supposed to be "all ones", i.e. set all bits according to
+value.
+
+Kernel bit set length may differ from userspace length if older application is
+used on newer kernel or vice versa. If userspace bitmaps are longer, error is
+only issued if request actually tries to set bits not implemented in kernel.
+
+Bit-by-bit form: nested (bitset) attribute contents:
+
+    ETHA_BITSET_SIZE	(u32)		number of significant bits (optional)
+    ETHA_BITSET_BITS	(nested)	array of bits
+	ETHA_BITSET_BIT
+	    ETHA_BIT_INDEX	(u32)		bit index (0 for LSB)
+            ETHA_BIT_NAME	(string)	bit name
+	    ETHA_BIT_VALUE	(flag)		present if bit is set
+        ETHA_BITSET_BIT
+	...
+
+Bit size is optional for bit-by-bit form. ETHA_BITSET_BITS nest can only
+contain ETHA_BITS_BIT attributes but there can be an arbitrary number of them.
+A bit may be identified by its index or by its name. When used in requests,
+listed bits are set to 0 or 1 according to ETHA_BIT_VALUE, the rest is
+preserved. A request fails if index exceeds kernel bit length or if name is
+not recognized.
+
+In requests, application can use either form. Form used by kernel in reply is
+determined by a flag in flags field of request header. Semantics of value and
+mask depends on the attribute. General idea is that flags control request
+processing, info_mask control which parts of the information are returned in
+"get" request and index identifies a particular subcommand or an object to
+which the request applies.
+
+
 List of message types
 ---------------------
 
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 1df263d9feb7..98d6fae315f3 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -23,6 +23,37 @@ enum {
 	ETHA_DEV_MAX = (__ETHA_DEV_MAX - 1)
 };
 
+/* bit sets */
+
+enum {
+	ETHA_BIT_UNSPEC,
+	ETHA_BIT_INDEX,				/* u32 */
+	ETHA_BIT_NAME,				/* string */
+	ETHA_BIT_VALUE,				/* flag */
+
+	__ETHA_BIT_MAX,
+	ETHA_BIT_MAX = (__ETHA_BIT_MAX - 1)
+};
+
+enum {
+	ETHA_BITS_UNSPEC,
+	ETHA_BITS_BIT,
+
+	__ETHA_BITS_MAX,
+	ETHA_BITS_MAX = (__ETHA_BITS_MAX - 1)
+};
+
+enum {
+	ETHA_BITSET_UNSPEC,
+	ETHA_BITSET_SIZE,			/* u32 */
+	ETHA_BITSET_BITS,			/* nest - ETHA_BITS_* */
+	ETHA_BITSET_VALUE,			/* binary */
+	ETHA_BITSET_MASK,			/* binary */
+
+	__ETHA_BITSET_MAX,
+	ETHA_BITSET_MAX = (__ETHA_BITSET_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index bf234e5bc660..df065fd3dc80 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 
 #include <linux/module.h>
+#include <linux/bitmap.h>
 #include <net/sock.h>
 #include <linux/ethtool_netlink.h>
 #include "netlink.h"
@@ -67,6 +68,400 @@ int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype)
 	return ret;
 }
 
+/* bitset helper functions */
+
+static bool ethnl_test_bit(u32 *val, unsigned int index)
+{
+	if (val)
+		return val[index / 32] & (1 << (index % 32));
+	else
+		return true;
+}
+
+static void ethnl_copy_bitmap(u32 *dst, u32 *src, unsigned int size)
+{
+	unsigned int full_words = size / 32;
+
+	memcpy(dst, src, full_words * sizeof(u32));
+	if (size % 32 != 0)
+		dst[full_words] = src[full_words] & ((1U << (size % 32)) - 1);
+}
+
+static void ethnl_fill_bitmap(u32 *dst, unsigned int size)
+{
+	unsigned int full_words = size / 32;
+
+	memset(dst, 0xff, full_words * sizeof(u32));
+	if (size % 32 != 0)
+		dst[full_words] = (1U << (size % 32)) - 1;
+}
+
+/* convert standard kernel bitmap (long sized words) to ethtool one (u32 words)
+ * bitmap_to_arr32() is not guaranteed to do "in place" conversion correctly;
+ * moreover, we can use the fact that the conversion is no-op except for 64-bit
+ * big endian architectures
+ */
+#if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
+void ethnl_bitmap_to_u32(unsigned long *bitmap, unsigned int nwords)
+{
+	u32 *dst = (u32 *)bitmap;
+	unsigned int i;
+
+	for (i = 0; i < nwords; i++) {
+		unsigned long tmp = READ_ONCE(bitmap[i]);
+
+		dst[2 * i] = tmp & 0xffffffff;
+		dst[2 * i + 1] = tmp >> 32;
+	}
+}
+#endif
+
+/* calculate size for a bitset attribute
+ * see ethnl_put_bitset() for arguments
+ */
+int ethnl_bitset32_size(bool compact, unsigned int size, u32 *val, u32 *mask,
+			const char *const *names)
+{
+	unsigned int nwords = (size + 31) / 32;
+	unsigned int len;
+
+	if (WARN_ON(!compact && !names))
+		return -EINVAL;
+	/* size */
+	len = nla_total_size(sizeof(u32));
+
+	if (compact) {
+		/* values, mask */
+		len += 2 * nla_total_size(nwords * sizeof(u32));
+	} else {
+		unsigned int bits_len = 0;
+		unsigned int bit_len, i;
+
+		for (i = 0; i < size; i++) {
+			if (!ethnl_test_bit(mask, i))
+				continue;
+			/* index */
+			bit_len = nla_total_size(sizeof(u32));
+			/* name */
+			bit_len += ethnl_str_size(names[i] ?: "");
+			/* value */
+			if (ethnl_test_bit(val, i))
+				bit_len += nla_total_size(0);
+
+			/* bit nest */
+			bits_len += nla_total_size(bit_len);
+		}
+		len += nla_total_size(bits_len);
+	}
+
+	/* outermost nest */
+	return nla_total_size(len);
+}
+
+int ethnl_bitset_size(bool compact, unsigned int size, unsigned long *val,
+		      unsigned long *mask, const char *const *names)
+{
+	const unsigned int words = (size + 31) / 32;
+	u32 mask32[words];
+	u32 val32[words];
+	int ret;
+
+	bitmap_to_arr32(val32, val, size);
+	if (mask)
+		bitmap_to_arr32(mask32, mask, size);
+	ret = ethnl_bitset32_size(compact, size, val32, mask ? mask32 : NULL,
+				  names);
+	bitmap_from_arr32(val, val32, size);
+	if (mask)
+		bitmap_from_arr32(mask, mask32, size);
+
+	return ret;
+}
+
+/* put bitset into a message
+ * skb:      skb with the message
+ * attrtype: attribute type for the bitset
+ * compact:  compact (bitmaps) or verbose (bit-by-bit with names) format
+ * size:     size of the set in bits
+ * val:      bitset values
+ * mask:     mask of valid bits
+ * names:    bit names (only used for verbose format)
+ */
+int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, bool compact,
+		       unsigned int size, u32 *val, u32 *mask,
+		       const char *const *names)
+{
+	struct nlattr *nest;
+	struct nlattr *attr;
+	int ret;
+
+	if (WARN_ON(!compact && !names))
+		return -EINVAL;
+	nest = ethnl_nest_start(skb, attrtype);
+	if (!nest)
+		return -EMSGSIZE;
+
+	ret = -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_BITSET_SIZE, size))
+		goto err;
+	if (compact) {
+		unsigned int bytesize = ((size + 31) / 32) * sizeof(u32);
+
+		ret = -EMSGSIZE;
+		attr = nla_reserve(skb, ETHA_BITSET_VALUE, bytesize);
+		if (!attr)
+			goto err;
+		ethnl_copy_bitmap(nla_data(attr), val, size);
+		attr = nla_reserve(skb, ETHA_BITSET_MASK, bytesize);
+		if (!attr)
+			goto err;
+		if (mask)
+			ethnl_copy_bitmap(nla_data(attr), mask, size);
+		else
+			ethnl_fill_bitmap(nla_data(attr), size);
+	} else {
+		struct nlattr *bits;
+		unsigned int i;
+
+		bits = ethnl_nest_start(skb, ETHA_BITSET_BITS);
+		if (!bits)
+			goto err;
+		for (i = 0; i < size; i++) {
+			if (!ethnl_test_bit(mask, i))
+				continue;
+			attr = ethnl_nest_start(skb, ETHA_BITS_BIT);
+			if (!attr ||
+			    nla_put_u32(skb, ETHA_BIT_INDEX, i) ||
+			    nla_put_string(skb, ETHA_BIT_NAME, names[i] ?: ""))
+				goto err;
+			if (ethnl_test_bit(val, i))
+				if (nla_put_flag(skb, ETHA_BIT_VALUE))
+					goto err;
+			nla_nest_end(skb, attr);
+		}
+		nla_nest_end(skb, bits);
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+err:
+	nla_nest_cancel(skb, nest);
+	return ret;
+}
+
+int ethnl_put_bitset(struct sk_buff *skb, int attrtype, bool compact,
+		     unsigned int size, unsigned long *val, unsigned long *mask,
+		     const char *const *names)
+{
+	const unsigned int words = (size + 31) / 32;
+	u32 mask32[words];
+	u32 val32[words];
+	int ret;
+
+	bitmap_to_arr32(val32, val, size);
+	if (mask)
+		bitmap_to_arr32(mask32, mask, size);
+	ret = ethnl_put_bitset32(skb, attrtype, compact, size, val32,
+				 mask ? mask32 : NULL, names);
+	bitmap_from_arr32(val, val32, size);
+	if (mask)
+		bitmap_from_arr32(mask, mask32, size);
+
+	return ret;
+}
+
+static const struct nla_policy bitset_policy[ETHA_BITSET_MAX + 1] = {
+	[ETHA_BITSET_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_BITSET_SIZE]		= { .type = NLA_U32 },
+	[ETHA_BITSET_BITS]		= { .type = NLA_NESTED },
+	[ETHA_BITSET_VALUE]		= { .type = NLA_BINARY },
+	[ETHA_BITSET_MASK]		= { .type = NLA_BINARY },
+};
+
+static const struct nla_policy bit_policy[ETHA_BIT_MAX + 1] = {
+	[ETHA_BIT_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_BIT_INDEX]		= { .type = NLA_U32 },
+	[ETHA_BIT_NAME]			= { .type = NLA_STRING },
+	[ETHA_BIT_VALUE]		= { .type = NLA_FLAG },
+};
+
+static int ethnl_name_to_idx(const char *const *names, unsigned int n_names,
+			     const char *name, unsigned int name_len)
+{
+	unsigned int i;
+
+	for (i = 0; i < n_names; i++)
+		if (names[i] && !strncmp(names[i], name, name_len))
+			return i;
+
+	return n_names;
+}
+
+static int ethnl_update_bit(unsigned long *bitmap, unsigned long *bitmask,
+			    unsigned int nbits, struct nlattr *bit_attr,
+			    const char *const *names, struct genl_info *info)
+{
+	struct nlattr *tb[ETHA_BIT_MAX + 1];
+	int ret, idx;
+
+	if (nla_type(bit_attr) != ETHA_BITS_BIT) {
+		ETHNL_SET_ERRMSG(info,
+				 "ETHA_BITSET_BITS can contain only ETHA_BITS_BIT");
+		return genl_err_attr(info, -EINVAL, bit_attr);
+	}
+	ret = nla_parse_nested(tb, ETHA_BIT_MAX, bit_attr, bit_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+
+	if (tb[ETHA_BIT_INDEX]) {
+		idx = nla_get_u32(tb[ETHA_BIT_INDEX]);
+		if (idx >= nbits) {
+			ETHNL_SET_ERRMSG(info, "bit index too high");
+			return genl_err_attr(info, -EOPNOTSUPP,
+					     tb[ETHA_BIT_INDEX]);
+		}
+		if (tb[ETHA_BIT_NAME] && names[idx] &&
+		    strncmp(nla_data(tb[ETHA_BIT_NAME]), names[idx],
+			    nla_len(tb[ETHA_BIT_NAME]))) {
+			ETHNL_SET_ERRMSG(info, "bit index and name mismatch");
+			return genl_err_attr(info, -EINVAL, bit_attr);
+		}
+	} else if (tb[ETHA_BIT_NAME]) {
+		idx = ethnl_name_to_idx(names, nbits,
+					nla_data(tb[ETHA_BIT_NAME]),
+					nla_len(tb[ETHA_BIT_NAME]));
+		if (idx >= nbits) {
+			ETHNL_SET_ERRMSG(info, "bit name not found");
+			return genl_err_attr(info, -EOPNOTSUPP,
+					     tb[ETHA_BIT_NAME]);
+		}
+	} else {
+		ETHNL_SET_ERRMSG(info, "neither bit index nor name specified");
+		return genl_err_attr(info, -EINVAL, bit_attr);
+	}
+
+	if (tb[ETHA_BIT_VALUE])
+		set_bit(idx, bitmap);
+	else
+		clear_bit(idx, bitmap);
+	if (bitmask)
+		set_bit(idx, bitmask);
+	return 0;
+}
+
+bool ethnl_update_bitset(unsigned long *bitmap, unsigned long *bitmask,
+			 unsigned int nbits, struct nlattr *attr, int *err,
+			 const char *const *names, struct genl_info *info)
+{
+	struct nlattr *tb[ETHA_BITSET_MAX + 1];
+	unsigned int change_bits = 0;
+	bool mod = false;
+
+	if (!attr)
+		return false;
+	*err = nla_parse_nested(tb, ETHA_BITSET_MAX, attr, bitset_policy,
+				info->extack);
+	if (*err < 0)
+		return mod;
+
+	/* To let new userspace to work with old kernel, we allow bitmaps
+	 * from userspace to be longer than kernel ones and only issue an
+	 * error if userspace actually tries to change a bit not existing
+	 * in kernel.
+	 */
+	if (tb[ETHA_BITSET_SIZE])
+		change_bits = nla_get_u32(tb[ETHA_BITSET_SIZE]);
+
+	if (tb[ETHA_BITSET_BITS]) {
+		DECLARE_BITMAP(val, nbits);
+		DECLARE_BITMAP(mask, nbits);
+		struct nlattr *bit_attr;
+		int rem;
+
+		*err = -EINVAL;
+		if (tb[ETHA_BITSET_VALUE] || tb[ETHA_BITSET_MASK])
+			return mod;
+		bitmap_copy(val, bitmap, nbits);
+		bitmap_zero(mask, nbits);
+		nla_for_each_nested(bit_attr, tb[ETHA_BITSET_BITS], rem) {
+			*err = ethnl_update_bit(val, mask, nbits, bit_attr,
+						names, info);
+			if (*err < 0)
+				return mod;
+		}
+		mod = !bitmap_equal(val, bitmap, nbits);
+		if (mod)
+			bitmap_copy(bitmap, val, nbits);
+		if (bitmask)
+			bitmap_copy(bitmask, mask, nbits);
+	} else {
+		const unsigned int max_bits =
+			max_t(unsigned int, nbits, change_bits);
+		unsigned int nwords = (change_bits + 31) / 32;
+		DECLARE_BITMAP(mask, max_bits);
+		DECLARE_BITMAP(val, max_bits);
+
+		*err = -EINVAL;
+		if (!change_bits || !tb[ETHA_BITSET_VALUE])
+			return mod;
+		if (nla_len(tb[ETHA_BITSET_VALUE]) < nwords * sizeof(u32))
+			return mod;
+		if (tb[ETHA_BITSET_MASK] &&
+		    nla_len(tb[ETHA_BITSET_VALUE]) < nwords * sizeof(u32))
+			return mod;
+
+		bitmap_zero(val, max_bits);
+		bitmap_from_arr32(val, nla_data(tb[ETHA_BITSET_VALUE]),
+				  change_bits);
+		bitmap_zero(mask, max_bits);
+		if (tb[ETHA_BITSET_MASK])
+			bitmap_from_arr32(mask, nla_data(tb[ETHA_BITSET_MASK]),
+					  change_bits);
+		else
+			bitmap_fill(mask, change_bits);
+
+		if (nbits < change_bits) {
+			unsigned int idx = find_next_bit(mask, max_bits, nbits);
+
+			*err = -EINVAL;
+			if (idx >= nbits)
+				return mod;
+		}
+
+		if (bitmask)
+			bitmap_copy(bitmask, mask, nbits);
+		bitmap_and(val, val, mask, nbits);
+		bitmap_complement(mask, mask, nbits);
+		bitmap_and(mask, mask, bitmap, nbits);
+		bitmap_or(val, val, mask, nbits);
+		mod = !bitmap_equal(val, bitmap, nbits);
+		if (mod)
+			bitmap_copy(bitmap, val, nbits);
+	}
+
+	*err = 0;
+	return mod;
+}
+
+bool ethnl_update_bitset32(u32 *bitmap, u32 *bitmask, unsigned int nbits,
+			   struct nlattr *attr, int *err,
+			   const char *const *names, struct genl_info *info)
+{
+	DECLARE_BITMAP(tmp, nbits);
+	DECLARE_BITMAP(tmp_mask, nbits);
+	bool mod;
+
+	bitmap_from_arr32(tmp, bitmap, nbits);
+	bitmap_zero(tmp_mask, nbits);
+	mod = ethnl_update_bitset(tmp, tmp_mask, nbits, attr, err, names, info);
+	if (!*err && mod)
+		bitmap_to_arr32(bitmap, tmp, nbits);
+	if (bitmask)
+		bitmap_to_arr32(bitmask, tmp_mask, nbits);
+	return (!*err && mod);
+}
+
 /* create skb for a reply
  * payload: payload length (without netlink, genetlink and ethnl headers)
  * dev:     device the reply is about
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index acfed5ba6b54..6e9e854eec5d 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -20,6 +20,32 @@ struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
 				 u16 dev_attrtype, struct genl_info *info,
 				 void **ehdrp);
 
+#if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
+void ethnl_bitmap_to_u32(unsigned long *bitmap, unsigned int nwords);
+#else
+static inline void ethnl_bitmap_to_u32(unsigned long *bitmap,
+				       unsigned int nwords)
+{
+}
+#endif
+
+int ethnl_bitset_size(bool compact, unsigned int size, unsigned long *val,
+		      unsigned long *mask, const char *const *names);
+int ethnl_bitset32_size(bool compact, unsigned int size, u32 *val, u32 *mask,
+			const char *const *names);
+int ethnl_put_bitset(struct sk_buff *skb, int attrtype, bool compact,
+		     unsigned int size, unsigned long *val, unsigned long *mask,
+		     const char *const *names);
+int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, bool compact,
+		       unsigned int size, u32 *val, u32 *mask,
+		       const char *const *names);
+bool ethnl_update_bitset(unsigned long *bitmap, unsigned long *bitmask,
+			 unsigned int nbits, struct nlattr *attr, int *err,
+			 const char *const *names, struct genl_info *info);
+bool ethnl_update_bitset32(u32 *bitmap, u32 *bitmask, unsigned int nbits,
+			   struct nlattr *attr, int *err,
+			   const char *const *names, struct genl_info *info);
+
 static inline int ethnl_str_size(const char *s)
 {
 	return nla_total_size(strlen(s) + 1);
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 04/17] ethtool: helper functions for netlink interface
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Misc helpers used by ethtool netlink code.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/uapi/linux/ethtool_netlink.h |  11 ++
 net/ethtool/netlink.c                | 163 +++++++++++++++++++++++++++
 net/ethtool/netlink.h                | 124 ++++++++++++++++++++
 3 files changed, 298 insertions(+)

diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 3c0c5c70692b..1df263d9feb7 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -12,6 +12,17 @@ enum {
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
 };
 
+/* device specification */
+
+enum {
+	ETHA_DEV_UNSPEC,
+	ETHA_DEV_INDEX,				/* u32 */
+	ETHA_DEV_NAME,				/* string */
+
+	__ETHA_DEV_MAX,
+	ETHA_DEV_MAX = (__ETHA_DEV_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1c6efb9b2eae..bf234e5bc660 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -1,9 +1,172 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 
 #include <linux/module.h>
+#include <net/sock.h>
 #include <linux/ethtool_netlink.h>
 #include "netlink.h"
 
+static const struct nla_policy dev_policy[ETHA_DEV_MAX + 1] = {
+	[ETHA_DEV_UNSPEC]	= { .type = NLA_UNSPEC },
+	[ETHA_DEV_INDEX]	= { .type = NLA_U32 },
+	[ETHA_DEV_NAME]		= { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
+};
+
+struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest)
+{
+	struct net *net = genl_info_net(info);
+	struct nlattr *tb[ETHA_DEV_MAX + 1];
+	struct net_device *dev;
+	int ret;
+
+	ret = nla_parse_nested(tb, ETHA_DEV_MAX, nest, dev_policy,
+			       info->extack);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	if (tb[ETHA_DEV_INDEX]) {
+		dev = dev_get_by_index(net, nla_get_u32(tb[ETHA_BIT_INDEX]));
+		if (!dev)
+			return ERR_PTR(-ENODEV);
+		/* if both ifindex and ifname are passed, they must match */
+		if (tb[ETHA_DEV_NAME]) {
+			const char *nl_name = nla_data(tb[ETHA_DEV_NAME]);
+
+			if (strncmp(dev->name, nl_name, IFNAMSIZ)) {
+				ETHNL_SET_ERRMSG(info,
+						 "ifindex and ifname do not match");
+				return ERR_PTR(-ENODEV);
+			}
+		}
+		return dev;
+	} else if (tb[ETHA_DEV_NAME]) {
+		dev = dev_get_by_name(net, nla_data(tb[ETHA_DEV_NAME]));
+		return dev ?: ERR_PTR(-ENODEV);
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype)
+{
+	struct nlattr *nest;
+	int ret = -EMSGSIZE;
+
+	nest = ethnl_nest_start(msg, attrtype);
+	if (!nest)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(msg, ETHA_DEV_INDEX, (u32)dev->ifindex))
+		goto err;
+	if (nla_put_string(msg, ETHA_DEV_NAME, dev->name))
+		goto err;
+
+	nla_nest_end(msg, nest);
+	return 0;
+err:
+	nla_nest_cancel(msg, nest);
+	return ret;
+}
+
+/* create skb for a reply
+ * payload: payload length (without netlink, genetlink and ethnl headers)
+ * dev:     device the reply is about
+ * cmd:     ETHNL_CMD_* command for reply
+ * info:    info for the received packet we respond to
+ * ehdrp:   place to store payload pointer returned by genlmsg_new()
+ * returns: skb or null on error
+ */
+struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
+				 u16 dev_attrtype, struct genl_info *info,
+				 void **ehdrp)
+{
+	void *ehdr;
+	struct sk_buff *rskb;
+
+	if (dev)
+		payload += nla_total_size(nla_total_size(sizeof(u32)) +
+					  nla_total_size(IFNAMSIZ));
+	rskb = genlmsg_new(payload, GFP_KERNEL);
+	if (!rskb) {
+		ETHNL_SET_ERRMSG(info,
+				 "failed to allocate reply message");
+		return NULL;
+	}
+
+	ehdr = genlmsg_put_reply(rskb, info, &ethtool_genl_family, 0, cmd);
+	if (!ehdr)
+		goto err;
+	if (ehdrp)
+		*ehdrp = ehdr;
+	if (dev) {
+		int ret = ethnl_fill_dev(rskb, dev, dev_attrtype);
+
+		if (ret < 0)
+			goto err;
+	}
+
+	return rskb;
+err:
+	nlmsg_free(rskb);
+	return NULL;
+}
+
+/* device iteration copied from rtnl_dump_ifinfo()
+ * cb->args[0]: command specific dump function
+ * cb->args[1]: ethnl command to use in reply
+ * cb->args[2]: position - hashbucket
+ * cb->args[3]: position - ifindex
+ */
+int ethnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	int (*dumpfn)(struct sk_buff *skb, struct netlink_callback *cb,
+		      struct net_device *dev);
+	struct net *net = sock_net(skb->sk);
+	struct hlist_head *head;
+	struct net_device *dev;
+	int h, s_h, idx = 0, s_idx;
+	int ret = 0;
+	void *ehdr;
+	u8 rcmd;
+
+	dumpfn = (void *)cb->args[0];
+	rcmd = cb->args[1];
+	s_h = cb->args[2];
+	s_idx = cb->args[3];
+
+	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+		idx = 0;
+		head = &net->dev_index_head[h];
+		hlist_for_each_entry(dev, head, index_hlist) {
+			if (idx < s_idx)
+				goto cont;
+			ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
+					   cb->nlh->nlmsg_seq,
+					   &ethtool_genl_family, 0, rcmd);
+			ret = dumpfn(skb, cb, dev);
+			if (ret < 0) {
+				genlmsg_cancel(skb, ehdr);
+				if (ret == -EOPNOTSUPP)
+					goto cont;
+				if (likely(skb->len))
+					goto out;
+				goto out_err;
+			}
+			genlmsg_end(skb, ehdr);
+cont:
+			idx++;
+		}
+	}
+out:
+	ret = skb->len;
+out_err:
+	cb->args[2] = h;
+	cb->args[3] = idx;
+	cb->seq = net->dev_base_seq;
+	nl_dump_check_consistent(cb, nlmsg_hdr(skb));
+
+	return ret;
+}
+
 /* genetlink setup */
 
 static const struct genl_ops ethtool_genl_ops[] = {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 63063b582ca2..acfed5ba6b54 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -6,7 +6,131 @@
 #include <linux/ethtool_netlink.h>
 #include <linux/netdevice.h>
 #include <net/genetlink.h>
+#include <net/sock.h>
+
+#define ETHNL_SET_ERRMSG(info, msg) \
+	do { if (info) GENL_SET_ERR_MSG(info, msg); } while (0)
 
 extern struct genl_family ethtool_genl_family;
 
+struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
+int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype);
+
+struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
+				 u16 dev_attrtype, struct genl_info *info,
+				 void **ehdrp);
+
+static inline int ethnl_str_size(const char *s)
+{
+	return nla_total_size(strlen(s) + 1);
+}
+
+static inline int ethnl_str_ifne_size(const char *s)
+{
+	return s[0] ? ethnl_str_size(s) : 0;
+}
+
+static inline int ethnl_put_str_ifne(struct sk_buff *skb, int attrtype,
+				     const char *s)
+{
+	if (!s[0])
+		return 0;
+	return nla_put_string(skb, attrtype, s);
+}
+
+static inline struct nlattr *ethnl_nest_start(struct sk_buff *skb,
+					      int attrtype)
+{
+	return nla_nest_start(skb, attrtype | NLA_F_NESTED);
+}
+
+/* ethnl_update_* return true if the value is changed */
+static inline bool ethnl_update_u32(u32 *dst, struct nlattr *attr)
+{
+	u32 val;
+
+	if (!attr)
+		return false;
+	val = nla_get_u32(attr);
+	if (*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+static inline bool ethnl_update_u8(u8 *dst, struct nlattr *attr)
+{
+	u8 val;
+
+	if (!attr)
+		return false;
+	val = nla_get_u8(attr);
+	if (*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+/* update u32 value used as bool from NLA_U8 */
+static inline bool ethnl_update_bool32(u32 *dst, struct nlattr *attr)
+{
+	u8 val;
+
+	if (!attr)
+		return false;
+	val = !!nla_get_u8(attr);
+	if (!!*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+static inline bool ethnl_update_binary(u8 *dst, unsigned int len, struct nlattr *attr)
+{
+	if (!attr)
+		return false;
+	if (nla_len(attr) < len)
+		len = nla_len(attr);
+	if (!memcmp(dst, nla_data(attr), len))
+		return false;
+
+	memcpy(dst, nla_data(attr), len);
+	return true;
+}
+
+static inline bool ethnl_update_bitfield32(u32 *dst, struct nlattr *attr)
+{
+	struct nla_bitfield32 change;
+	u32 newval;
+
+	if (!attr)
+		return false;
+	change = nla_get_bitfield32(attr);
+	newval = (*dst & ~change.selector) | (change.value & change.selector);
+	if (*dst == newval)
+		return false;
+
+	*dst = newval;
+	return true;
+}
+
+static inline void warn_partial_info(struct genl_info *info)
+{
+	ETHNL_SET_ERRMSG(info, "not all requested data could be retrieved");
+}
+
+/* Check user privileges explicitly to allow finer access control based on
+ * context of the request or hiding part of the information from unprivileged
+ * users
+ */
+static inline bool ethnl_is_privileged(struct sk_buff *skb)
+{
+	struct net *net = sock_net(skb->sk);
+
+	return netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN);
+}
+
 #endif /* _NET_ETHTOOL_NETLINK_H */
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 03/17] ethtool: introduce ethtool netlink interface
From: Michal Kubecek @ 2018-07-30 12:52 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

No function implemented yet, only genetlink and module infrastructure.
Register/unregister genetlink family "ethtool" and allow the module to be
autoloaded by genetlink code (if built as a module, distributions would
probably prefer "y").

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt | 168 +++++++++++++++++++
 include/linux/ethtool_netlink.h              |   9 +
 include/uapi/linux/ethtool_netlink.h         |  19 +++
 net/Kconfig                                  |   7 +
 net/ethtool/Makefile                         |   6 +-
 net/ethtool/netlink.c                        |  41 +++++
 net/ethtool/netlink.h                        |  12 ++
 7 files changed, 261 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/networking/ethtool-netlink.txt
 create mode 100644 include/linux/ethtool_netlink.h
 create mode 100644 include/uapi/linux/ethtool_netlink.h
 create mode 100644 net/ethtool/netlink.c
 create mode 100644 net/ethtool/netlink.h

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
new file mode 100644
index 000000000000..120376e0f91b
--- /dev/null
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -0,0 +1,168 @@
+                        Netlink interface for ethtool
+                        =============================
+
+
+Basic information
+-----------------
+
+Netlink interface for ethtool uses generic netlink family "ethtool" (userspace
+application should use macros ETHTOOL_GENL_NAME and ETHTOOL_GENL_VERSION
+defined in <linux/ethtool_netlink.h> uapi header). This family does not use
+a specific header, all information in requests and replies is passed using
+netlink attributes.
+
+In requests, device can be identified by ifindex or by name; if both are used,
+they must match. In replies, kernel fills both. The meaning of flags,
+info_mask and index fields depends on request type.
+
+The ethtool netlink interface uses extended ACK for error and warning
+reporting, userspace application developers are encouraged to make these
+messages available to user in a suitable way.
+
+Requests can be divided into three categories: "get" (retrieving information),
+"set" (setting parameters) and "action" (invoking an action).
+
+All "set" and "action" type requests require admin privileges (CAP_NET_ADMIN
+in the namespace). Most "get" type request are allowed for anyone but there
+are exceptions (where the response contains sensitive information). In some
+cases, the request as such is allowed for anyone but unprivileged users have
+attributes with sensitive information (e.g. wake-on-lan password) omitted.
+
+
+Conventions
+-----------
+
+Attributes which represent a boolean value usually use u8 type so that we can
+distinguish three states: "on", "off" and "not present" (meaning the
+information is not available in "get" requests or value is not to be changed
+in "set" requests). For these attributes, the "true" value should be passed as
+number 1 but any non-zero value should be understood as "true" by recipient.
+
+Some request types allow passing an attribute named ETHA_*_INFOMASK with
+a bitmask telling kernel that we are only interested in some parts of the
+information. If info mask is omitted, all available information is returned.
+Meaning of info mask bits depends on request type and is listed below.
+
+
+Device identification
+---------------------
+
+When appropriate, network device is identified by a nested attribute named
+ETHA_*_DEV. This attribute can contain
+
+    ETHA_DEV_INDEX	(u32)		device ifindex
+    ETHA_DEV_NAME	(string)	device name
+
+In device related requests, one of these is sufficient; if both are used, they
+must match (i.e. identify the same device). In device related replies both are
+provided by kernel. In dump requests, device is not specified and kernel
+replies with one message per network device (only those for which the request
+is supported).
+
+List of message types
+---------------------
+
+All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
+to indicate the type.
+
+Messages of type "get" are used by userspace to request information and
+usually do not contain any attributes (that may be added later for dump
+filtering). Kernel response is in the form of corresponding "set" message;
+the same message can be also used to set (some of) the parameters, except for
+messages marked as "response only" in the table above. "Get" messages with
+NLM_F_DUMP flags and no device identification dump the information for all
+devices supporting the request.
+
+Later sections describe the format and semantics of these request messages.
+
+
+Request translation
+-------------------
+
+The following table maps iosctl commands to netlink commands providing their
+functionality. Entries with "n/a" in right column are commands which do not
+have their netlink replacement yet.
+
+ioctl command			netlink command
+---------------------------------------------------------------------
+ETHTOOL_GSET			n/a
+ETHTOOL_SSET			n/a
+ETHTOOL_GDRVINFO		n/a
+ETHTOOL_GREGS			n/a
+ETHTOOL_GWOL			n/a
+ETHTOOL_SWOL			n/a
+ETHTOOL_GMSGLVL			n/a
+ETHTOOL_SMSGLVL			n/a
+ETHTOOL_NWAY_RST		n/a
+ETHTOOL_GLINK			n/a
+ETHTOOL_GEEPROM			n/a
+ETHTOOL_SEEPROM			n/a
+ETHTOOL_GCOALESCE		n/a
+ETHTOOL_SCOALESCE		n/a
+ETHTOOL_GRINGPARAM		n/a
+ETHTOOL_SRINGPARAM		n/a
+ETHTOOL_GPAUSEPARAM		n/a
+ETHTOOL_SPAUSEPARAM		n/a
+ETHTOOL_GRXCSUM			n/a
+ETHTOOL_SRXCSUM			n/a
+ETHTOOL_GTXCSUM			n/a
+ETHTOOL_STXCSUM			n/a
+ETHTOOL_GSG			n/a
+ETHTOOL_SSG			n/a
+ETHTOOL_TEST			n/a
+ETHTOOL_GSTRINGS		n/a
+ETHTOOL_PHYS_ID			n/a
+ETHTOOL_GSTATS			n/a
+ETHTOOL_GTSO			n/a
+ETHTOOL_STSO			n/a
+ETHTOOL_GPERMADDR		n/a
+ETHTOOL_GUFO			n/a
+ETHTOOL_SUFO			n/a
+ETHTOOL_GGSO			n/a
+ETHTOOL_SGSO			n/a
+ETHTOOL_GFLAGS			n/a
+ETHTOOL_SFLAGS			n/a
+ETHTOOL_GPFLAGS			n/a
+ETHTOOL_SPFLAGS			n/a
+ETHTOOL_GRXFH			n/a
+ETHTOOL_SRXFH			n/a
+ETHTOOL_GGRO			n/a
+ETHTOOL_SGRO			n/a
+ETHTOOL_GRXRINGS		n/a
+ETHTOOL_GRXCLSRLCNT		n/a
+ETHTOOL_GRXCLSRULE		n/a
+ETHTOOL_GRXCLSRLALL		n/a
+ETHTOOL_SRXCLSRLDEL		n/a
+ETHTOOL_SRXCLSRLINS		n/a
+ETHTOOL_FLASHDEV		n/a
+ETHTOOL_RESET			n/a
+ETHTOOL_SRXNTUPLE		n/a
+ETHTOOL_GRXNTUPLE		n/a
+ETHTOOL_GSSET_INFO		n/a
+ETHTOOL_GRXFHINDIR		n/a
+ETHTOOL_SRXFHINDIR		n/a
+ETHTOOL_GFEATURES		n/a
+ETHTOOL_SFEATURES		n/a
+ETHTOOL_GCHANNELS		n/a
+ETHTOOL_SCHANNELS		n/a
+ETHTOOL_SET_DUMP		n/a
+ETHTOOL_GET_DUMP_FLAG		n/a
+ETHTOOL_GET_DUMP_DATA		n/a
+ETHTOOL_GET_TS_INFO		n/a
+ETHTOOL_GMODULEINFO		n/a
+ETHTOOL_GMODULEEEPROM		n/a
+ETHTOOL_GEEE			n/a
+ETHTOOL_SEEE			n/a
+ETHTOOL_GRSSH			n/a
+ETHTOOL_SRSSH			n/a
+ETHTOOL_GTUNABLE		n/a
+ETHTOOL_STUNABLE		n/a
+ETHTOOL_GPHYSTATS		n/a
+ETHTOOL_PERQUEUE		n/a
+ETHTOOL_GLINKSETTINGS		n/a
+ETHTOOL_SLINKSETTINGS		n/a
+ETHTOOL_PHY_GTUNABLE		n/a
+ETHTOOL_PHY_STUNABLE		n/a
+ETHTOOL_GFECPARAM		n/a
+ETHTOOL_SFECPARAM		n/a
+
diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
new file mode 100644
index 000000000000..0412adb4f42f
--- /dev/null
+++ b/include/linux/ethtool_netlink.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _LINUX_ETHTOOL_NETLINK_H_
+#define _LINUX_ETHTOOL_NETLINK_H_
+
+#include <uapi/linux/ethtool_netlink.h>
+#include <linux/ethtool.h>
+
+#endif /* _LINUX_ETHTOOL_NETLINK_H_ */
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
new file mode 100644
index 000000000000..3c0c5c70692b
--- /dev/null
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_H_
+#define _UAPI_LINUX_ETHTOOL_NETLINK_H_
+
+#include <linux/ethtool.h>
+
+enum {
+	ETHNL_CMD_NOOP,
+
+	__ETHNL_CMD_MAX,
+	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
+};
+
+/* generic netlink info */
+#define ETHTOOL_GENL_NAME "ethtool"
+#define ETHTOOL_GENL_VERSION 1
+
+#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
diff --git a/net/Kconfig b/net/Kconfig
index 228dfa382eec..12e763449525 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -445,6 +445,13 @@ config FAILOVER
 	  migration of VMs with direct attached VFs by failing over to the
 	  paravirtual datapath when the VF is unplugged.
 
+config ETHTOOL_NETLINK
+	tristate "Netlink interface for ethtool"
+	default m
+	help
+	   New netlink based interface for ethtool which is going to obsolete
+	   the old ioctl based one once it provides all features.
+
 endif   # if NET
 
 # Used by archs to tell that they support BPF JIT compiler plus which flavour.
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 3ebfab2bca66..f30e0da88be5 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -1,3 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-y		+= ioctl.o
+obj-y				+= ioctl.o
+
+obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o
+
+ethtool_nl-y	:= netlink.o
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
new file mode 100644
index 000000000000..1c6efb9b2eae
--- /dev/null
+++ b/net/ethtool/netlink.c
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include <linux/module.h>
+#include <linux/ethtool_netlink.h>
+#include "netlink.h"
+
+/* genetlink setup */
+
+static const struct genl_ops ethtool_genl_ops[] = {
+};
+
+struct genl_family ethtool_genl_family = {
+	.hdrsize	= 0,
+	.name		= ETHTOOL_GENL_NAME,
+	.version	= ETHTOOL_GENL_VERSION,
+	.netnsok	= true,
+	.parallel_ops	= true,
+	.ops		= ethtool_genl_ops,
+	.n_ops		= ARRAY_SIZE(ethtool_genl_ops),
+};
+
+/* module setup */
+
+static int __init ethtool_nl_init(void)
+{
+	return genl_register_family(&ethtool_genl_family);
+}
+
+static void __exit ethtool_nl_exit(void)
+{
+	genl_unregister_family(&ethtool_genl_family);
+}
+
+module_init(ethtool_nl_init);
+module_exit(ethtool_nl_exit);
+
+/* alias for module autoload */
+MODULE_ALIAS_GENL_FAMILY(ETHTOOL_GENL_NAME);
+MODULE_AUTHOR("Michal Kubecek <mkubecek@suse.cz>");
+MODULE_DESCRIPTION("Netlink interface for ethtool");
+MODULE_LICENSE("GPL");
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
new file mode 100644
index 000000000000..63063b582ca2
--- /dev/null
+++ b/net/ethtool/netlink.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _NET_ETHTOOL_NETLINK_H
+#define _NET_ETHTOOL_NETLINK_H
+
+#include <linux/ethtool_netlink.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+
+extern struct genl_family ethtool_genl_family;
+
+#endif /* _NET_ETHTOOL_NETLINK_H */
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 02/17] ethtool: move to its own directory
From: Michal Kubecek @ 2018-07-30 12:52 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

With ethtool netlink interface, there is going to be a lot of new files
so that it seem more convenient to put them into a separate directory
net/ethtool. Start with moving current file with ioctl implementation
there and renaming it to ioctl.c.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 net/Makefile                            | 2 +-
 net/core/Makefile                       | 2 +-
 net/ethtool/Makefile                    | 3 +++
 net/{core/ethtool.c => ethtool/ioctl.c} | 0
 4 files changed, 5 insertions(+), 2 deletions(-)
 create mode 100644 net/ethtool/Makefile
 rename net/{core/ethtool.c => ethtool/ioctl.c} (100%)

diff --git a/net/Makefile b/net/Makefile
index bdaf53925acd..6c68520e5eb9 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_NET)		+= $(tmp-y)
 
 # LLC has to be linked before the files in net/802/
 obj-$(CONFIG_LLC)		+= llc/
-obj-$(CONFIG_NET)		+= ethernet/ 802/ sched/ netlink/ bpf/
+obj-$(CONFIG_NET)		+= ethernet/ 802/ sched/ netlink/ bpf/ ethtool/
 obj-$(CONFIG_NETFILTER)		+= netfilter/
 obj-$(CONFIG_INET)		+= ipv4/
 obj-$(CONFIG_TLS)		+= tls/
diff --git a/net/core/Makefile b/net/core/Makefile
index 80175e6a2eb8..55734d0a1603 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -8,7 +8,7 @@ obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
-obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
+obj-y		     += dev.o dev_addr_lists.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
 			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
 			fib_notifier.o xdp.o
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
new file mode 100644
index 000000000000..3ebfab2bca66
--- /dev/null
+++ b/net/ethtool/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y		+= ioctl.o
diff --git a/net/core/ethtool.c b/net/ethtool/ioctl.c
similarity index 100%
rename from net/core/ethtool.c
rename to net/ethtool/ioctl.c
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 01/17] netlink: introduce nla_put_bitfield32()
From: Michal Kubecek @ 2018-07-30 12:52 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Similar to other data types, this helper puts NLA_BITFIELD32 attribute into
a netlink message. It takes separate value and selector arguments, if you
already have struct nla_bitfield32, you can use nla_put().

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/net/netlink.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/net/netlink.h b/include/net/netlink.h
index 0c154f98e987..6d4eb6bd9235 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -1064,6 +1064,21 @@ static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype,
 	return nla_put(skb, attrtype, sizeof(*addr), addr);
 }
 
+/**
+ * nla_put_bitfield32 - Add a bitfield32 value/selector attribute to
+ * a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @value: 32-bit value bitmap
+ * @selector: 32-bit selector bitmap
+ */
+static inline int nla_put_bitfield32(struct sk_buff *skb, int attrtype,
+				     u32 value, u32 selector)
+{
+	struct nla_bitfield32 tmp = { .value = value, .selector = selector };
+
+	return nla_put(skb, attrtype, sizeof(tmp), &tmp);
+}
+
 /**
  * nla_get_u32 - return payload of u32 attribute
  * @nla: u32 netlink attribute
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 00/17] ethtool netlink interface (WiP)
From: Michal Kubecek @ 2018-07-30 12:52 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville

A netlink based interface for ethtool is a recurring discussion theme;
such discussion happens from time to time but never seems to reach any
clear conclusion except that netlink interface is desperately needed.
I'm sending this hoping that having a proposal (even if partial) on the
table could help move the discussion further.

The interface used for communication between ethtool and kernel is based on
ioctl() and suffers from many problems. The most pressing seems the be the
lack of extensibility. While some of the newer commands use structures
designed to allow future extensions (e.g. GFEATURES or TEST), most either
allow no extension at all (GPAUSEPARAM, GCOALESCE) or only limited set of
reserved fields (GDRVINFO, GEEE). Even most of those which support future
extensions limit the data types that can be used.

This series aims to provide an alternative interface based on netlink which
is what other network configuration utilities use. In particular, it uses
generic netlink (family "ethtool"). The goal is to provide an interface
which would be extensible, flexible and practical both for ethtool and for
other network configuration tools (e.g. wicked, systemd-networkd or
NetworkManager).

The interface is documented in Documentation/networking/ethtool-netlink.txt

A series for ethtool utility will follow shortly.

Basic concepts:

- the interface is based on generic netlink (family name "ethtool")

- the goal is to provide all features of ioctl interface but allow
  easier future extensions

- inextensibility of ioctl interface resulted in way too many commands,
  many of them obsoleted by newer ones; reduce the number by  ignoring the
  obsolete commands and grouping some together

- for "set" type commands, netlink allows providing only the attributes to
  be changed; therefore we don't need a get-modify-set cycle (which is
  inherently racy), userspace can simply say what it wants to change

- provide notifications to multicast group "monitor" like rtnetlink
  does, i.e. in the form of messages close to replies to "get" requests

- allow dump requests to get some information about all network defices
  providing it

- be less dependent on ethtool and kernel being in sync; allow e.g. saying
  "ethtool -s eth0 advertise foo off" without ethtool knowing what "foo"
  means; it's kernel's job to know what mode "xyz" is and if it exists
  and is supported

Main changes again RFC v1:

- support dumps for all "get" requests
- provide notifications for changes related to supported request types
- support getting string sets (both global and per device)
- support getting/setting device features
- get rid of family specific header, everything passed as attributes
- split netlink code into multiple files in net/ethtool/ directory

ToDo / open questions:

- as some comments in discussion on v1 pointed out, some features of
  ethtool would rather belong to devlink; phy_tunables and phy_stats
  seem to be candidates, maybe part of drvinfo; are there more?

- another question is where to do the split; should ethtool use devlink
  API for these or can we provide them in ethtool API as well but with
  devlink backend (for communication with NIC)

- currently, all communication with drivers via ethtool_ops is done
  under RTNL as this is what ioctl interface does and I suspect many
  ethtool_ops rely on that; can we do without RTNL?

- notifications are sent whenever a change is done via netlink API or
  ioctl API and for netdev features also whenever they are updated using
  netdev_change_features(); it would be desirable to notify also about
  link state and negotiation result (speed/duplex and partner link
  modes) but it would be more tricky

- find reasonable format for data transfers (e.g. eeprom dump or flash);
  I don't have clear idea how big these can get and if 64 KB limit on
  attribute size (including nested ones) is a problem; if so, dumps can
  be an answer for dumps, some kind of multi-message requests would be
  needed for flashes

- while the netlink interface allows easy future extensions, ethtool_ops
  interface does not; some settings could be implemented using tunables and
  accessed via relevant netlink messages (as well as tunables) from
  userspace but in the long term, something better will be needed

- it would be nice if driver could provide useful error/warning messages to
  be passed to userspace via extended ACK; example: while testing, I found
  a driver which only allows values 0, 1, 3 and 10000 for certain parameter
  but the only way poor user can find out is either by trying all values or
  by checking driver source

- some of the functions for GET_SETTINGS and GET_PARAMS are quite
  similar (e.g. ethtool_get_*); it might be beneficial to introduce some
  "ops", leave only "parse", "prepare", "size" and "fill" handlers and
  make the rest generic (like ethnl_dumpit()).

- the counts and sizes in GET_DRVINFO reply seem to be a relic of the
  past and if userspace needs them, there are (or will be) other ways to
  get them; they should most likely go


Michal Kubecek (17):
  netlink: introduce nla_put_bitfield32()
  ethtool: move to its own directory
  ethtool: introduce ethtool netlink interface
  ethtool: helper functions for netlink interface
  ethtool: netlink bitset handling
  ethtool: support for netlink notifications
  ethtool: implement EVENT notifications
  ethtool: implement GET_STRSET message
  ethtool: implement GET_DRVINFO message
  ethtool: implement GET_SETTINGS message
  ethtool: implement GET_SETTINGS request for features
  ethtool: implement SET_SETTINGS notification
  ethtool: implement SET_SETTINGS message
  ethtool: implement SET_SETTINGS request for features
  ethtool: implement GET_PARAMS message
  ethtool: implement SET_PARAMS notification
  ethtool: implement SET_PARAMS message

 Documentation/networking/ethtool-netlink.txt |  558 ++++++++
 include/linux/ethtool_netlink.h              |   17 +
 include/linux/netdevice.h                    |   25 +
 include/net/netlink.h                        |   15 +
 include/uapi/linux/ethtool.h                 |    7 +
 include/uapi/linux/ethtool_netlink.h         |  325 +++++
 net/Kconfig                                  |    7 +
 net/Makefile                                 |    2 +-
 net/core/Makefile                            |    2 +-
 net/core/dev.c                               |   27 +-
 net/ethtool/Makefile                         |    7 +
 net/ethtool/common.c                         |  242 ++++
 net/ethtool/common.h                         |   26 +
 net/ethtool/drvinfo.c                        |  131 ++
 net/{core/ethtool.c => ethtool/ioctl.c}      |  310 ++---
 net/ethtool/netlink.c                        |  840 ++++++++++++
 net/ethtool/netlink.h                        |  169 +++
 net/ethtool/params.c                         | 1008 ++++++++++++++
 net/ethtool/settings.c                       | 1230 ++++++++++++++++++
 net/ethtool/strset.c                         |  552 ++++++++
 20 files changed, 5269 insertions(+), 231 deletions(-)
 create mode 100644 Documentation/networking/ethtool-netlink.txt
 create mode 100644 include/linux/ethtool_netlink.h
 create mode 100644 include/uapi/linux/ethtool_netlink.h
 create mode 100644 net/ethtool/Makefile
 create mode 100644 net/ethtool/common.c
 create mode 100644 net/ethtool/common.h
 create mode 100644 net/ethtool/drvinfo.c
 rename net/{core/ethtool.c => ethtool/ioctl.c} (88%)
 create mode 100644 net/ethtool/netlink.c
 create mode 100644 net/ethtool/netlink.h
 create mode 100644 net/ethtool/params.c
 create mode 100644 net/ethtool/settings.c
 create mode 100644 net/ethtool/strset.c

-- 
2.18.0

^ permalink raw reply

* [PATCH net-next 10/10] net: mscc: ocelot: make use of SerDes PHYs for handling their configuration
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

Previously, the SerDes muxing was hardcoded to a given mode in the MAC
controller driver. Now, the SerDes muxing is configured within the
Device Tree and is enforced in the MAC controller driver so we can have
a lot of different SerDes configurations.

Make use of the SerDes PHYs in the MAC controller to set up the SerDes
according to the SerDes<->switch port mapping and the communication mode
with the Ethernet PHY.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/net/ethernet/mscc/Kconfig        |  2 +-
 drivers/net/ethernet/mscc/ocelot.c       | 16 ++++++++-
 drivers/net/ethernet/mscc/ocelot.h       |  5 +++-
 drivers/net/ethernet/mscc/ocelot_board.c | 43 +++++++++++++++++++------
 4 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/mscc/Kconfig b/drivers/net/ethernet/mscc/Kconfig
index 36c8462..bcec058 100644
--- a/drivers/net/ethernet/mscc/Kconfig
+++ b/drivers/net/ethernet/mscc/Kconfig
@@ -23,6 +23,8 @@ config MSCC_OCELOT_SWITCH
 config MSCC_OCELOT_SWITCH_OCELOT
 	tristate "Ocelot switch driver on Ocelot"
 	depends on MSCC_OCELOT_SWITCH
+	depends on GENERIC_PHY
+	depends on OF_NET
 	help
 	  This driver supports the Ocelot network switch device as present on
 	  the Ocelot SoCs.
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 1a4f2bb..8f11fdb 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -472,6 +472,7 @@ static int ocelot_port_open(struct net_device *dev)
 {
 	struct ocelot_port *port = netdev_priv(dev);
 	struct ocelot *ocelot = port->ocelot;
+	enum phy_mode phy_mode;
 	int err;
 
 	/* Enable receiving frames on the port, and activate auto-learning of
@@ -482,8 +483,21 @@ static int ocelot_port_open(struct net_device *dev)
 			 ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port),
 			 ANA_PORT_PORT_CFG, port->chip_port);
 
+	if (port->serdes) {
+		if (port->phy_mode == PHY_INTERFACE_MODE_SGMII)
+			phy_mode = PHY_MODE_SGMII;
+		else
+			phy_mode = PHY_MODE_QSGMII;
+
+		err = phy_set_mode(port->serdes, phy_mode);
+		if (err) {
+			netdev_err(dev, "Could not set mode of SerDes\n");
+			return err;
+		}
+	}
+
 	err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link,
-				 PHY_INTERFACE_MODE_NA);
+				 port->phy_mode);
 	if (err) {
 		netdev_err(dev, "Could not attach to PHY\n");
 		return err;
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 3720e51..62c7c8e 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -11,6 +11,8 @@
 #include <linux/bitops.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
@@ -453,6 +455,9 @@ struct ocelot_port {
 	u8 vlan_aware;
 
 	u64 *stats;
+
+	phy_interface_t phy_mode;
+	struct phy *serdes;
 };
 
 u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index b7d755b..3bb71b7 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -6,6 +6,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/of_net.h>
 #include <linux/netdevice.h>
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
@@ -247,18 +248,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&ocelot->multicast);
 	ocelot_init(ocelot);
 
-	ocelot_rmw(ocelot, HSIO_HW_CFG_DEV1G_4_MODE |
-		     HSIO_HW_CFG_DEV1G_6_MODE |
-		     HSIO_HW_CFG_DEV1G_9_MODE,
-		     HSIO_HW_CFG_DEV1G_4_MODE |
-		     HSIO_HW_CFG_DEV1G_6_MODE |
-		     HSIO_HW_CFG_DEV1G_9_MODE,
-		     HSIO_HW_CFG);
-
 	for_each_available_child_of_node(ports, portnp) {
 		struct device_node *phy_node;
 		struct phy_device *phy;
 		struct resource *res;
+		struct phy *serdes;
+		enum phy_mode phy_mode;
 		void __iomem *regs;
 		char res_name[8];
 		u32 port;
@@ -283,10 +278,38 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 			continue;
 
 		err = ocelot_probe_port(ocelot, port, regs, phy);
-		if (err) {
-			dev_err(&pdev->dev, "failed to probe ports\n");
+		if (err)
+			return err;
+
+		err = of_get_phy_mode(portnp);
+		if (err < 0)
+			ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA;
+		else
+			ocelot->ports[port]->phy_mode = err;
+
+		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_NA)
+			continue;
+
+		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_SGMII)
+			phy_mode = PHY_MODE_SGMII;
+		else
+			phy_mode = PHY_MODE_QSGMII;
+
+		serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
+		if (IS_ERR(serdes)) {
+			if (PTR_ERR(serdes) == -EPROBE_DEFER) {
+				dev_err(ocelot->dev, "deferring probe\n");
+				err = -EPROBE_DEFER;
+				goto err_probe_ports;
+			}
+
+			dev_err(ocelot->dev, "missing SerDes phys for port%d\n",
+				port);
+			err = -ENODEV;
 			goto err_probe_ports;
 		}
+
+		ocelot->ports[port]->serdes = serdes;
 	}
 
 	register_netdevice_notifier(&ocelot_netdevice_nb);
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH 09/10] phy: add driver for Microsemi Ocelot SerDes muxing
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

The Microsemi Ocelot can mux SerDes lanes (aka macros) to different
switch ports or even make it act as a PCIe interface.

This adds support for the muxing of the SerDes.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/phy/Kconfig                  |   1 +-
 drivers/phy/Makefile                 |   1 +-
 drivers/phy/mscc/Kconfig             |  11 +-
 drivers/phy/mscc/Makefile            |   5 +-
 drivers/phy/mscc/phy-ocelot-serdes.c | 314 ++++++++++++++++++++++++++++-
 5 files changed, 332 insertions(+)
 create mode 100644 drivers/phy/mscc/Kconfig
 create mode 100644 drivers/phy/mscc/Makefile
 create mode 100644 drivers/phy/mscc/phy-ocelot-serdes.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 5c8d452..c89d3ef 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -48,6 +48,7 @@ source "drivers/phy/lantiq/Kconfig"
 source "drivers/phy/marvell/Kconfig"
 source "drivers/phy/mediatek/Kconfig"
 source "drivers/phy/motorola/Kconfig"
+source "drivers/phy/mscc/Kconfig"
 source "drivers/phy/qualcomm/Kconfig"
 source "drivers/phy/ralink/Kconfig"
 source "drivers/phy/renesas/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 84e3bd9..ce8339f 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -18,6 +18,7 @@ obj-y					+= broadcom/	\
 					   hisilicon/	\
 					   marvell/	\
 					   motorola/	\
+					   mscc/	\
 					   qualcomm/	\
 					   ralink/	\
 					   samsung/	\
diff --git a/drivers/phy/mscc/Kconfig b/drivers/phy/mscc/Kconfig
new file mode 100644
index 0000000..2e2a466
--- /dev/null
+++ b/drivers/phy/mscc/Kconfig
@@ -0,0 +1,11 @@
+#
+# Phy drivers for Microsemi devices
+#
+
+config PHY_OCELOT_SERDES
+	tristate "SerDes PHY driver for Microsemi Ocelot"
+	select GENERIC_PHY
+	depends on OF
+	depends on MFD_SYSCON
+	help
+	  Enable this for supporting SerDes muxing with Microsemi Ocelot.
diff --git a/drivers/phy/mscc/Makefile b/drivers/phy/mscc/Makefile
new file mode 100644
index 0000000..e147491
--- /dev/null
+++ b/drivers/phy/mscc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Microsemi phy drivers.
+#
+
+obj-$(CONFIG_PHY_OCELOT_SERDES) := phy-ocelot-serdes.o
diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c
new file mode 100644
index 0000000..e87c400
--- /dev/null
+++ b/drivers/phy/mscc/phy-ocelot-serdes.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * SerDes PHY driver for Microsemi Ocelot
+ *
+ * Copyright (c) 2018 Microsemi
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <soc/mscc/ocelot_hsio.h>
+
+#define SERDES1G_MAX	6
+#define SERDES6G_MAX	3
+#define SERDES_MAX	(SERDES1G_MAX + SERDES6G_MAX)
+
+enum serdes_type {
+	SERDES1G = 1,
+	SERDES6G = 6,
+};
+
+struct serdes_ctrl {
+	struct regmap		*regs;
+	struct device		*dev;
+	struct phy		*phys[SERDES_MAX];
+};
+
+struct serdes_macro {
+	enum serdes_type	type;
+	u8			idx;
+	/* Not used when in QSGMII or PCIe mode */
+	int			port;
+	struct serdes_ctrl	*ctrl;
+};
+
+#define MCB_S1G_CFG_TIMEOUT     50
+
+static int __serdes_write_mcb_s1g(struct regmap *regmap, u8 macro, u32 op)
+{
+	unsigned int regval;
+
+	regmap_write(regmap, HSIO_MCB_S1G_ADDR_CFG, op |
+		     HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(BIT(macro)));
+
+	return regmap_read_poll_timeout(regmap, HSIO_MCB_S1G_ADDR_CFG, regval,
+					(regval & op) != op, 100,
+					MCB_S1G_CFG_TIMEOUT * 1000);
+}
+
+static int serdes_commit_mcb_s1g(struct regmap *regmap, u8 macro)
+{
+	return __serdes_write_mcb_s1g(regmap, macro,
+		HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT);
+}
+
+static int serdes_update_mcb_s1g(struct regmap *regmap, u8 macro)
+{
+	return __serdes_write_mcb_s1g(regmap, macro,
+		HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT);
+}
+
+static int serdes_init_s1g(struct regmap *regmap, u8 serdes)
+{
+	int ret;
+
+	ret = serdes_update_mcb_s1g(regmap, serdes);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG,
+			   HSIO_S1G_COMMON_CFG_SYS_RST |
+			   HSIO_S1G_COMMON_CFG_ENA_LANE |
+			   HSIO_S1G_COMMON_CFG_ENA_ELOOP |
+			   HSIO_S1G_COMMON_CFG_ENA_FLOOP,
+			   HSIO_S1G_COMMON_CFG_ENA_LANE);
+
+	regmap_update_bits(regmap, HSIO_S1G_PLL_CFG,
+			   HSIO_S1G_PLL_CFG_PLL_FSM_ENA |
+			   HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M,
+			   HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(200) |
+			   HSIO_S1G_PLL_CFG_PLL_FSM_ENA);
+
+	regmap_update_bits(regmap, HSIO_S1G_MISC_CFG,
+			   HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA |
+			   HSIO_S1G_MISC_CFG_LANE_RST,
+			   HSIO_S1G_MISC_CFG_LANE_RST);
+
+	ret = serdes_commit_mcb_s1g(regmap, serdes);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG,
+			   HSIO_S1G_COMMON_CFG_SYS_RST,
+			   HSIO_S1G_COMMON_CFG_SYS_RST);
+
+	regmap_update_bits(regmap, HSIO_S1G_MISC_CFG,
+			   HSIO_S1G_MISC_CFG_LANE_RST, 0);
+
+	ret = serdes_commit_mcb_s1g(regmap, serdes);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct serdes_mux {
+	enum serdes_type	type;
+	u8			idx;
+	u8			port;
+	enum phy_mode		mode;
+	u32			mask;
+	u32			mux;
+};
+
+#define SERDES_MUX(_type, _idx, _port, _mode, _mask, _mux) {	\
+	.type = _type,						\
+	.idx = _idx,					\
+	.port = _port,						\
+	.mode = _mode,						\
+	.mask = _mask,						\
+	.mux = _mux,						\
+}
+
+static const struct serdes_mux ocelot_serdes_muxes[] = {
+	SERDES_MUX(SERDES1G, 0, 0, PHY_MODE_SGMII, 0, 0),
+	SERDES_MUX(SERDES1G, 1, 1, PHY_MODE_SGMII, HSIO_HW_CFG_DEV1G_5_MODE, 0),
+	SERDES_MUX(SERDES1G, 1, 5, PHY_MODE_SGMII, HSIO_HW_CFG_QSGMII_ENA |
+		   HSIO_HW_CFG_DEV1G_5_MODE, HSIO_HW_CFG_DEV1G_5_MODE),
+	SERDES_MUX(SERDES1G, 2, 2, PHY_MODE_SGMII, HSIO_HW_CFG_DEV1G_4_MODE, 0),
+	SERDES_MUX(SERDES1G, 2, 4, PHY_MODE_SGMII, HSIO_HW_CFG_QSGMII_ENA |
+		   HSIO_HW_CFG_DEV1G_4_MODE, HSIO_HW_CFG_DEV1G_4_MODE),
+	SERDES_MUX(SERDES1G, 3, 3, PHY_MODE_SGMII, HSIO_HW_CFG_DEV1G_6_MODE, 0),
+	SERDES_MUX(SERDES1G, 3, 6, PHY_MODE_SGMII, HSIO_HW_CFG_QSGMII_ENA |
+		   HSIO_HW_CFG_DEV1G_6_MODE, HSIO_HW_CFG_DEV1G_6_MODE),
+	SERDES_MUX(SERDES1G, 4, 4, PHY_MODE_SGMII, HSIO_HW_CFG_QSGMII_ENA |
+		   HSIO_HW_CFG_DEV1G_4_MODE | HSIO_HW_CFG_DEV1G_9_MODE, 0),
+	SERDES_MUX(SERDES1G, 4, 9, PHY_MODE_SGMII, HSIO_HW_CFG_DEV1G_4_MODE |
+		   HSIO_HW_CFG_DEV1G_9_MODE, HSIO_HW_CFG_DEV1G_4_MODE |
+		   HSIO_HW_CFG_DEV1G_9_MODE),
+	SERDES_MUX(SERDES1G, 5, 5, PHY_MODE_SGMII, HSIO_HW_CFG_QSGMII_ENA |
+		   HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE, 0),
+	SERDES_MUX(SERDES1G, 5, 10, PHY_MODE_SGMII, HSIO_HW_CFG_PCIE_ENA |
+		   HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE,
+		   HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE),
+	SERDES_MUX(SERDES6G, 0, 4, PHY_MODE_QSGMII, HSIO_HW_CFG_QSGMII_ENA,
+		   HSIO_HW_CFG_QSGMII_ENA),
+	SERDES_MUX(SERDES6G, 0, 5, PHY_MODE_QSGMII, HSIO_HW_CFG_QSGMII_ENA,
+		   HSIO_HW_CFG_QSGMII_ENA),
+	SERDES_MUX(SERDES6G, 0, 6, PHY_MODE_QSGMII, HSIO_HW_CFG_QSGMII_ENA,
+		   HSIO_HW_CFG_QSGMII_ENA),
+	SERDES_MUX(SERDES6G, 0, 7, PHY_MODE_SGMII, HSIO_HW_CFG_QSGMII_ENA, 0),
+	SERDES_MUX(SERDES6G, 0, 7, PHY_MODE_QSGMII, HSIO_HW_CFG_QSGMII_ENA,
+		   HSIO_HW_CFG_QSGMII_ENA),
+	SERDES_MUX(SERDES6G, 1, 8, PHY_MODE_SGMII, 0, 0),
+	SERDES_MUX(SERDES6G, 2, 10, PHY_MODE_SGMII, HSIO_HW_CFG_PCIE_ENA |
+		   HSIO_HW_CFG_DEV2G5_10_MODE, 0),
+	SERDES_MUX(SERDES6G, 2, 10, PHY_MODE_PCIE, HSIO_HW_CFG_PCIE_ENA,
+		   HSIO_HW_CFG_PCIE_ENA),
+};
+
+static int serdes_set_mode(struct phy *phy, enum phy_mode mode)
+{
+	struct serdes_macro *macro = phy_get_drvdata(phy);
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(ocelot_serdes_muxes); i++) {
+		if (macro->type != ocelot_serdes_muxes[i].type ||
+		    macro->idx != ocelot_serdes_muxes[i].idx ||
+		    mode != ocelot_serdes_muxes[i].mode)
+			continue;
+
+		if (mode != PHY_MODE_QSGMII &&
+		    macro->port != ocelot_serdes_muxes[i].port)
+			continue;
+
+		ret = regmap_update_bits(macro->ctrl->regs, HSIO_HW_CFG,
+					 ocelot_serdes_muxes[i].mask,
+					 ocelot_serdes_muxes[i].mux);
+		if (ret)
+			return ret;
+
+		if (macro->type == SERDES1G)
+			return serdes_init_s1g(macro->ctrl->regs, macro->idx);
+
+		/* SERDES6G and PCIe not supported yet */
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const struct phy_ops serdes_ops = {
+	.set_mode	= serdes_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *serdes_simple_xlate(struct device *dev,
+				       struct of_phandle_args *args)
+{
+	enum serdes_type type;
+	int port, i;
+	u8 idx;
+	struct serdes_ctrl *ctrl = dev_get_drvdata(dev);
+
+	if (args->args_count != 3)
+		return ERR_PTR(-EINVAL);
+
+	type = args->args[0];
+	idx = args->args[1];
+	port = args->args[2];
+
+	for (i = 0; i < SERDES_MAX; i++) {
+		struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]);
+
+		if (type != macro->type)
+			continue;
+		if (idx != macro->idx)
+			continue;
+
+		/* SERDES6G_0 is the only SerDes capable of QSGMII */
+		if ((type == SERDES1G || macro->idx != 0) && macro->port >= 0)
+			return ERR_PTR(-EBUSY);
+
+		macro->port = port;
+		return ctrl->phys[i];
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx,
+			     enum serdes_type type, struct phy **phy)
+{
+	struct serdes_macro *macro;
+
+	*phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops);
+	if (IS_ERR(*phy))
+		return PTR_ERR(*phy);
+
+	macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL);
+	if (!macro)
+		return -ENOMEM;
+
+	macro->idx = idx;
+	macro->type = type;
+	macro->ctrl = ctrl;
+	macro->port = -1;
+
+	phy_set_drvdata(*phy, macro);
+
+	return 0;
+}
+
+static int serdes_probe(struct platform_device *pdev)
+{
+	struct phy_provider *provider;
+	struct serdes_ctrl *ctrl;
+	int i, ret;
+
+	ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	ctrl->dev = &pdev->dev;
+	ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node);
+	if (!ctrl->regs)
+		return -ENODEV;
+
+	for (i = 0; i < SERDES1G_MAX; i++) {
+		ret = serdes_phy_create(ctrl, i, SERDES1G, &ctrl->phys[i]);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < SERDES6G_MAX; i++) {
+		ret = serdes_phy_create(ctrl, i, SERDES6G,
+					&ctrl->phys[SERDES1G_MAX + i]);
+		if (ret)
+			return ret;
+	}
+
+	dev_set_drvdata(&pdev->dev, ctrl);
+
+	provider = devm_of_phy_provider_register(ctrl->dev,
+						 serdes_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id serdes_ids[] = {
+	{ .compatible = "mscc,vsc7514-serdes", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, serdes_ids);
+
+static struct platform_driver mscc_ocelot_serdes = {
+	.probe		= serdes_probe,
+	.driver		= {
+		.name	= "mscc,ocelot-serdes",
+		.of_match_table = of_match_ptr(serdes_ids),
+	},
+};
+
+module_platform_driver(mscc_ocelot_serdes);
+
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@bootlin.com>");
+MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot");
+MODULE_LICENSE("Dual MIT/GPL");
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH 08/10] MIPS: mscc: ocelot: add SerDes mux DT node
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

The Microsemi Ocelot has a set of register for SerDes/switch port muxing
as well as PCIe muxing for a specific SerDes, so let's add the device
and all SerDes in the Device Tree.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 arch/mips/boot/dts/mscc/ocelot.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi
index c51663a..e03edf3 100644
--- a/arch/mips/boot/dts/mscc/ocelot.dtsi
+++ b/arch/mips/boot/dts/mscc/ocelot.dtsi
@@ -223,6 +223,11 @@
 		hsio: syscon@10d0000 {
 			compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd";
 			reg = <0x10d0000 0x10000>;
+
+			serdes: serdes {
+				compatible = "mscc,vsc7514-serdes";
+				#phy-cells = <3>;
+			};
 		};
 	};
 };
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH 07/10] dt-bindings: phy: add DT binding for Microsemi Ocelot SerDes muxing
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt | 42 +++++++-
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt b/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt
new file mode 100644
index 0000000..25b102d
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt
@@ -0,0 +1,42 @@
+Microsemi Ocelot SerDes muxing driver
+-------------------------------------
+
+On Microsemi Ocelot, there is a handful of registers in HSIO address
+space for setting up the SerDes to switch port muxing.
+
+A SerDes X can be "muxed" to work with switch port Y or Z for example.
+One specific SerDes can also be used as a PCIe interface.
+
+Hence, a SerDes represents an interface, be it an Ethernet or a PCIe one.
+
+There are two kinds of SerDes: SERDES1G supports 10/100Mbps in
+half/full-duplex and 1000Mbps in full-duplex mode while SERDES6G supports
+10/100Mbps in half/full-duplex and 1000/2500Mbps in full-duplex mode.
+
+Also, SERDES6G number (aka "macro") 0 is the only interface supporting
+QSGMII.
+
+Required properties:
+
+- compatible: should be "mscc,vsc7514-serdes"
+- #phy-cells : from the generic phy bindings, must be 3. The first number
+               defines the kind of Serdes (1 for SERDES1G_X, 6 for
+	       SERDES6G_X), the second defines the macros in the specified
+	       kind of Serdes (X for SERDES1G_X or SERDES6G_X) and the
+	       last one defines the input port to use for a given SerDes
+	       macro,
+
+Example:
+
+	serdes: serdes {
+		compatible = "mscc,vsc7514-serdes";
+		#phy-cells = <3>;
+	};
+
+	ethernet {
+		port1 {
+			phy-handle = <&phy_foo>;
+			/* Link SERDES1G_5 to port1 */
+			phys = <&serdes 1 5 1>;
+		};
+	};
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH 06/10] phy: add QSGMII and PCIE modes
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

Prepare for upcoming phys that'll handle QSGMII or PCIe.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 include/linux/phy/phy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 9713aeb..03b319f 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -37,9 +37,11 @@ enum phy_mode {
 	PHY_MODE_USB_OTG,
 	PHY_MODE_SGMII,
 	PHY_MODE_2500SGMII,
+	PHY_MODE_QSGMII,
 	PHY_MODE_10GKR,
 	PHY_MODE_UFS_HS_A,
 	PHY_MODE_UFS_HS_B,
+	PHY_MODE_PCIE,
 };
 
 /**
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH net-next 05/10] net: mscc: ocelot: simplify register access for PLL5 configuration
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

Since HSIO address space can be accessed by different drivers, let's
simplify the register address definitions so that it can be easily used
by all drivers and put the register address definition in the
include/soc/mscc/ocelot_hsio.h header file.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/net/ethernet/mscc/ocelot.h      | 73 +---------------------
 drivers/net/ethernet/mscc/ocelot_regs.c | 92 ++------------------------
 include/soc/mscc/ocelot_hsio.h          | 74 +++++++++++++++++++++-
 3 files changed, 83 insertions(+), 156 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 2da20a3..3720e51 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -332,79 +332,6 @@ enum ocelot_reg {
 	SYS_CM_DATA_RD,
 	SYS_CM_OP,
 	SYS_CM_DATA,
-	HSIO_PLL5G_CFG0 = HSIO << TARGET_OFFSET,
-	HSIO_PLL5G_CFG1,
-	HSIO_PLL5G_CFG2,
-	HSIO_PLL5G_CFG3,
-	HSIO_PLL5G_CFG4,
-	HSIO_PLL5G_CFG5,
-	HSIO_PLL5G_CFG6,
-	HSIO_PLL5G_STATUS0,
-	HSIO_PLL5G_STATUS1,
-	HSIO_PLL5G_BIST_CFG0,
-	HSIO_PLL5G_BIST_CFG1,
-	HSIO_PLL5G_BIST_CFG2,
-	HSIO_PLL5G_BIST_STAT0,
-	HSIO_PLL5G_BIST_STAT1,
-	HSIO_RCOMP_CFG0,
-	HSIO_RCOMP_STATUS,
-	HSIO_SYNC_ETH_CFG,
-	HSIO_SYNC_ETH_PLL_CFG,
-	HSIO_S1G_DES_CFG,
-	HSIO_S1G_IB_CFG,
-	HSIO_S1G_OB_CFG,
-	HSIO_S1G_SER_CFG,
-	HSIO_S1G_COMMON_CFG,
-	HSIO_S1G_PLL_CFG,
-	HSIO_S1G_PLL_STATUS,
-	HSIO_S1G_DFT_CFG0,
-	HSIO_S1G_DFT_CFG1,
-	HSIO_S1G_DFT_CFG2,
-	HSIO_S1G_TP_CFG,
-	HSIO_S1G_RC_PLL_BIST_CFG,
-	HSIO_S1G_MISC_CFG,
-	HSIO_S1G_DFT_STATUS,
-	HSIO_S1G_MISC_STATUS,
-	HSIO_MCB_S1G_ADDR_CFG,
-	HSIO_S6G_DIG_CFG,
-	HSIO_S6G_DFT_CFG0,
-	HSIO_S6G_DFT_CFG1,
-	HSIO_S6G_DFT_CFG2,
-	HSIO_S6G_TP_CFG0,
-	HSIO_S6G_TP_CFG1,
-	HSIO_S6G_RC_PLL_BIST_CFG,
-	HSIO_S6G_MISC_CFG,
-	HSIO_S6G_OB_ANEG_CFG,
-	HSIO_S6G_DFT_STATUS,
-	HSIO_S6G_ERR_CNT,
-	HSIO_S6G_MISC_STATUS,
-	HSIO_S6G_DES_CFG,
-	HSIO_S6G_IB_CFG,
-	HSIO_S6G_IB_CFG1,
-	HSIO_S6G_IB_CFG2,
-	HSIO_S6G_IB_CFG3,
-	HSIO_S6G_IB_CFG4,
-	HSIO_S6G_IB_CFG5,
-	HSIO_S6G_OB_CFG,
-	HSIO_S6G_OB_CFG1,
-	HSIO_S6G_SER_CFG,
-	HSIO_S6G_COMMON_CFG,
-	HSIO_S6G_PLL_CFG,
-	HSIO_S6G_ACJTAG_CFG,
-	HSIO_S6G_GP_CFG,
-	HSIO_S6G_IB_STATUS0,
-	HSIO_S6G_IB_STATUS1,
-	HSIO_S6G_ACJTAG_STATUS,
-	HSIO_S6G_PLL_STATUS,
-	HSIO_S6G_REVID,
-	HSIO_MCB_S6G_ADDR_CFG,
-	HSIO_HW_CFG,
-	HSIO_HW_QSGMII_CFG,
-	HSIO_HW_QSGMII_STAT,
-	HSIO_CLK_CFG,
-	HSIO_TEMP_SENSOR_CTRL,
-	HSIO_TEMP_SENSOR_CFG,
-	HSIO_TEMP_SENSOR_STAT,
 };
 
 enum ocelot_regfield {
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index bf0c609..9271af1 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -103,82 +103,6 @@ static const u32 ocelot_qs_regmap[] = {
 	REG(QS_INH_DBG,                    0x000048),
 };
 
-static const u32 ocelot_hsio_regmap[] = {
-	REG(HSIO_PLL5G_CFG0,               0x000000),
-	REG(HSIO_PLL5G_CFG1,               0x000004),
-	REG(HSIO_PLL5G_CFG2,               0x000008),
-	REG(HSIO_PLL5G_CFG3,               0x00000c),
-	REG(HSIO_PLL5G_CFG4,               0x000010),
-	REG(HSIO_PLL5G_CFG5,               0x000014),
-	REG(HSIO_PLL5G_CFG6,               0x000018),
-	REG(HSIO_PLL5G_STATUS0,            0x00001c),
-	REG(HSIO_PLL5G_STATUS1,            0x000020),
-	REG(HSIO_PLL5G_BIST_CFG0,          0x000024),
-	REG(HSIO_PLL5G_BIST_CFG1,          0x000028),
-	REG(HSIO_PLL5G_BIST_CFG2,          0x00002c),
-	REG(HSIO_PLL5G_BIST_STAT0,         0x000030),
-	REG(HSIO_PLL5G_BIST_STAT1,         0x000034),
-	REG(HSIO_RCOMP_CFG0,               0x000038),
-	REG(HSIO_RCOMP_STATUS,             0x00003c),
-	REG(HSIO_SYNC_ETH_CFG,             0x000040),
-	REG(HSIO_SYNC_ETH_PLL_CFG,         0x000048),
-	REG(HSIO_S1G_DES_CFG,              0x00004c),
-	REG(HSIO_S1G_IB_CFG,               0x000050),
-	REG(HSIO_S1G_OB_CFG,               0x000054),
-	REG(HSIO_S1G_SER_CFG,              0x000058),
-	REG(HSIO_S1G_COMMON_CFG,           0x00005c),
-	REG(HSIO_S1G_PLL_CFG,              0x000060),
-	REG(HSIO_S1G_PLL_STATUS,           0x000064),
-	REG(HSIO_S1G_DFT_CFG0,             0x000068),
-	REG(HSIO_S1G_DFT_CFG1,             0x00006c),
-	REG(HSIO_S1G_DFT_CFG2,             0x000070),
-	REG(HSIO_S1G_TP_CFG,               0x000074),
-	REG(HSIO_S1G_RC_PLL_BIST_CFG,      0x000078),
-	REG(HSIO_S1G_MISC_CFG,             0x00007c),
-	REG(HSIO_S1G_DFT_STATUS,           0x000080),
-	REG(HSIO_S1G_MISC_STATUS,          0x000084),
-	REG(HSIO_MCB_S1G_ADDR_CFG,         0x000088),
-	REG(HSIO_S6G_DIG_CFG,              0x00008c),
-	REG(HSIO_S6G_DFT_CFG0,             0x000090),
-	REG(HSIO_S6G_DFT_CFG1,             0x000094),
-	REG(HSIO_S6G_DFT_CFG2,             0x000098),
-	REG(HSIO_S6G_TP_CFG0,              0x00009c),
-	REG(HSIO_S6G_TP_CFG1,              0x0000a0),
-	REG(HSIO_S6G_RC_PLL_BIST_CFG,      0x0000a4),
-	REG(HSIO_S6G_MISC_CFG,             0x0000a8),
-	REG(HSIO_S6G_OB_ANEG_CFG,          0x0000ac),
-	REG(HSIO_S6G_DFT_STATUS,           0x0000b0),
-	REG(HSIO_S6G_ERR_CNT,              0x0000b4),
-	REG(HSIO_S6G_MISC_STATUS,          0x0000b8),
-	REG(HSIO_S6G_DES_CFG,              0x0000bc),
-	REG(HSIO_S6G_IB_CFG,               0x0000c0),
-	REG(HSIO_S6G_IB_CFG1,              0x0000c4),
-	REG(HSIO_S6G_IB_CFG2,              0x0000c8),
-	REG(HSIO_S6G_IB_CFG3,              0x0000cc),
-	REG(HSIO_S6G_IB_CFG4,              0x0000d0),
-	REG(HSIO_S6G_IB_CFG5,              0x0000d4),
-	REG(HSIO_S6G_OB_CFG,               0x0000d8),
-	REG(HSIO_S6G_OB_CFG1,              0x0000dc),
-	REG(HSIO_S6G_SER_CFG,              0x0000e0),
-	REG(HSIO_S6G_COMMON_CFG,           0x0000e4),
-	REG(HSIO_S6G_PLL_CFG,              0x0000e8),
-	REG(HSIO_S6G_ACJTAG_CFG,           0x0000ec),
-	REG(HSIO_S6G_GP_CFG,               0x0000f0),
-	REG(HSIO_S6G_IB_STATUS0,           0x0000f4),
-	REG(HSIO_S6G_IB_STATUS1,           0x0000f8),
-	REG(HSIO_S6G_ACJTAG_STATUS,        0x0000fc),
-	REG(HSIO_S6G_PLL_STATUS,           0x000100),
-	REG(HSIO_S6G_REVID,                0x000104),
-	REG(HSIO_MCB_S6G_ADDR_CFG,         0x000108),
-	REG(HSIO_HW_CFG,                   0x00010c),
-	REG(HSIO_HW_QSGMII_CFG,            0x000110),
-	REG(HSIO_HW_QSGMII_STAT,           0x000114),
-	REG(HSIO_CLK_CFG,                  0x000118),
-	REG(HSIO_TEMP_SENSOR_CTRL,         0x00011c),
-	REG(HSIO_TEMP_SENSOR_CFG,          0x000120),
-	REG(HSIO_TEMP_SENSOR_STAT,         0x000124),
-};
-
 static const u32 ocelot_qsys_regmap[] = {
 	REG(QSYS_PORT_MODE,                0x011200),
 	REG(QSYS_SWITCH_PORT_MODE,         0x011234),
@@ -303,7 +227,6 @@ static const u32 ocelot_sys_regmap[] = {
 static const u32 *ocelot_regmap[] = {
 	[ANA] = ocelot_ana_regmap,
 	[QS] = ocelot_qs_regmap,
-	[HSIO] = ocelot_hsio_regmap,
 	[QSYS] = ocelot_qsys_regmap,
 	[REW] = ocelot_rew_regmap,
 	[SYS] = ocelot_sys_regmap,
@@ -454,9 +377,11 @@ static void ocelot_pll5_init(struct ocelot *ocelot)
 	/* Configure PLL5. This will need a proper CCF driver
 	 * The values are coming from the VTSS API for Ocelot
 	 */
-	ocelot_write(ocelot, HSIO_PLL5G_CFG4_IB_CTRL(0x7600) |
-		     HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8), HSIO_PLL5G_CFG4);
-	ocelot_write(ocelot, HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) |
+	regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG4,
+		     HSIO_PLL5G_CFG4_IB_CTRL(0x7600) |
+		     HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8));
+	regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG0,
+		     HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) |
 		     HSIO_PLL5G_CFG0_CPU_CLK_DIV(2) |
 		     HSIO_PLL5G_CFG0_ENA_BIAS |
 		     HSIO_PLL5G_CFG0_ENA_VCO_BUF |
@@ -466,13 +391,14 @@ static void ocelot_pll5_init(struct ocelot *ocelot)
 		     HSIO_PLL5G_CFG0_SELBGV820(4) |
 		     HSIO_PLL5G_CFG0_DIV4 |
 		     HSIO_PLL5G_CFG0_ENA_CLKTREE |
-		     HSIO_PLL5G_CFG0_ENA_LANE, HSIO_PLL5G_CFG0);
-	ocelot_write(ocelot, HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET |
+		     HSIO_PLL5G_CFG0_ENA_LANE);
+	regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG2,
+		     HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET |
 		     HSIO_PLL5G_CFG2_EN_RESET_OVERRUN |
 		     HSIO_PLL5G_CFG2_GAIN_TEST(0x8) |
 		     HSIO_PLL5G_CFG2_ENA_AMPCTRL |
 		     HSIO_PLL5G_CFG2_PWD_AMPCTRL_N |
-		     HSIO_PLL5G_CFG2_AMPC_SEL(0x10), HSIO_PLL5G_CFG2);
+		     HSIO_PLL5G_CFG2_AMPC_SEL(0x10));
 }
 
 int ocelot_chip_init(struct ocelot *ocelot)
diff --git a/include/soc/mscc/ocelot_hsio.h b/include/soc/mscc/ocelot_hsio.h
index d93ddec..43112dd 100644
--- a/include/soc/mscc/ocelot_hsio.h
+++ b/include/soc/mscc/ocelot_hsio.h
@@ -8,6 +8,80 @@
 #ifndef _MSCC_OCELOT_HSIO_H_
 #define _MSCC_OCELOT_HSIO_H_
 
+#define HSIO_PLL5G_CFG0			0x0000
+#define HSIO_PLL5G_CFG1			0x0004
+#define HSIO_PLL5G_CFG2			0x0008
+#define HSIO_PLL5G_CFG3			0x000c
+#define HSIO_PLL5G_CFG4			0x0010
+#define HSIO_PLL5G_CFG5			0x0014
+#define HSIO_PLL5G_CFG6			0x0018
+#define HSIO_PLL5G_STATUS0		0x001c
+#define HSIO_PLL5G_STATUS1		0x0020
+#define HSIO_PLL5G_BIST_CFG0		0x0024
+#define HSIO_PLL5G_BIST_CFG1		0x0028
+#define HSIO_PLL5G_BIST_CFG2		0x002c
+#define HSIO_PLL5G_BIST_STAT0		0x0030
+#define HSIO_PLL5G_BIST_STAT1		0x0034
+#define HSIO_RCOMP_CFG0			0x0038
+#define HSIO_RCOMP_STATUS		0x003c
+#define HSIO_SYNC_ETH_CFG		0x0040
+#define HSIO_SYNC_ETH_PLL_CFG		0x0048
+#define HSIO_S1G_DES_CFG		0x004c
+#define HSIO_S1G_IB_CFG			0x0050
+#define HSIO_S1G_OB_CFG			0x0054
+#define HSIO_S1G_SER_CFG		0x0058
+#define HSIO_S1G_COMMON_CFG		0x005c
+#define HSIO_S1G_PLL_CFG		0x0060
+#define HSIO_S1G_PLL_STATUS		0x0064
+#define HSIO_S1G_DFT_CFG0		0x0068
+#define HSIO_S1G_DFT_CFG1		0x006c
+#define HSIO_S1G_DFT_CFG2		0x0070
+#define HSIO_S1G_TP_CFG			0x0074
+#define HSIO_S1G_RC_PLL_BIST_CFG	0x0078
+#define HSIO_S1G_MISC_CFG		0x007c
+#define HSIO_S1G_DFT_STATUS		0x0080
+#define HSIO_S1G_MISC_STATUS		0x0084
+#define HSIO_MCB_S1G_ADDR_CFG		0x0088
+#define HSIO_S6G_DIG_CFG		0x008c
+#define HSIO_S6G_DFT_CFG0		0x0090
+#define HSIO_S6G_DFT_CFG1		0x0094
+#define HSIO_S6G_DFT_CFG2		0x0098
+#define HSIO_S6G_TP_CFG0		0x009c
+#define HSIO_S6G_TP_CFG1		0x00a0
+#define HSIO_S6G_RC_PLL_BIST_CFG	0x00a4
+#define HSIO_S6G_MISC_CFG		0x00a8
+#define HSIO_S6G_OB_ANEG_CFG		0x00ac
+#define HSIO_S6G_DFT_STATUS		0x00b0
+#define HSIO_S6G_ERR_CNT		0x00b4
+#define HSIO_S6G_MISC_STATUS		0x00b8
+#define HSIO_S6G_DES_CFG		0x00bc
+#define HSIO_S6G_IB_CFG			0x00c0
+#define HSIO_S6G_IB_CFG1		0x00c4
+#define HSIO_S6G_IB_CFG2		0x00c8
+#define HSIO_S6G_IB_CFG3		0x00cc
+#define HSIO_S6G_IB_CFG4		0x00d0
+#define HSIO_S6G_IB_CFG5		0x00d4
+#define HSIO_S6G_OB_CFG			0x00d8
+#define HSIO_S6G_OB_CFG1		0x00dc
+#define HSIO_S6G_SER_CFG		0x00e0
+#define HSIO_S6G_COMMON_CFG		0x00e4
+#define HSIO_S6G_PLL_CFG		0x00e8
+#define HSIO_S6G_ACJTAG_CFG		0x00ec
+#define HSIO_S6G_GP_CFG			0x00f0
+#define HSIO_S6G_IB_STATUS0		0x00f4
+#define HSIO_S6G_IB_STATUS1		0x00f8
+#define HSIO_S6G_ACJTAG_STATUS		0x00fc
+#define HSIO_S6G_PLL_STATUS		0x0100
+#define HSIO_S6G_REVID			0x0104
+#define HSIO_MCB_S6G_ADDR_CFG		0x0108
+#define HSIO_HW_CFG			0x010c
+#define HSIO_HW_QSGMII_CFG		0x0110
+#define HSIO_HW_QSGMII_STAT		0x0114
+#define HSIO_CLK_CFG			0x0118
+#define HSIO_TEMP_SENSOR_CTRL		0x011c
+#define HSIO_TEMP_SENSOR_CFG		0x0120
+#define HSIO_TEMP_SENSOR_STAT		0x0124
+
 #define HSIO_PLL5G_CFG0_ENA_ROT                           BIT(31)
 #define HSIO_PLL5G_CFG0_ENA_LANE                          BIT(30)
 #define HSIO_PLL5G_CFG0_ENA_CLKTREE                       BIT(29)
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH net-next 04/10] net: mscc: ocelot: move the HSIO header to include/soc
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

Since HSIO address space can be used by different drivers (PLL, SerDes
muxing, temperature sensor), let's move it somewhere it can be included
by all drivers.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/net/ethernet/mscc/ocelot.h      |   1 +-
 drivers/net/ethernet/mscc/ocelot_hsio.h | 785 +-------------------------
 drivers/net/ethernet/mscc/ocelot_regs.c |   1 +-
 include/soc/mscc/ocelot_hsio.h          | 785 +++++++++++++++++++++++++-
 4 files changed, 786 insertions(+), 786 deletions(-)
 delete mode 100644 drivers/net/ethernet/mscc/ocelot_hsio.h
 create mode 100644 include/soc/mscc/ocelot_hsio.h

diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 616bec3..2da20a3 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -16,7 +16,6 @@
 
 #include "ocelot_ana.h"
 #include "ocelot_dev.h"
-#include "ocelot_hsio.h"
 #include "ocelot_qsys.h"
 #include "ocelot_rew.h"
 #include "ocelot_sys.h"
diff --git a/drivers/net/ethernet/mscc/ocelot_hsio.h b/drivers/net/ethernet/mscc/ocelot_hsio.h
deleted file mode 100644
index d93ddec..0000000
--- a/drivers/net/ethernet/mscc/ocelot_hsio.h
+++ /dev/null
@@ -1,785 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_HSIO_H_
-#define _MSCC_OCELOT_HSIO_H_
-
-#define HSIO_PLL5G_CFG0_ENA_ROT                           BIT(31)
-#define HSIO_PLL5G_CFG0_ENA_LANE                          BIT(30)
-#define HSIO_PLL5G_CFG0_ENA_CLKTREE                       BIT(29)
-#define HSIO_PLL5G_CFG0_DIV4                              BIT(28)
-#define HSIO_PLL5G_CFG0_ENA_LOCK_FINE                     BIT(27)
-#define HSIO_PLL5G_CFG0_SELBGV820(x)                      (((x) << 23) & GENMASK(26, 23))
-#define HSIO_PLL5G_CFG0_SELBGV820_M                       GENMASK(26, 23)
-#define HSIO_PLL5G_CFG0_SELBGV820_X(x)                    (((x) & GENMASK(26, 23)) >> 23)
-#define HSIO_PLL5G_CFG0_LOOP_BW_RES(x)                    (((x) << 18) & GENMASK(22, 18))
-#define HSIO_PLL5G_CFG0_LOOP_BW_RES_M                     GENMASK(22, 18)
-#define HSIO_PLL5G_CFG0_LOOP_BW_RES_X(x)                  (((x) & GENMASK(22, 18)) >> 18)
-#define HSIO_PLL5G_CFG0_SELCPI(x)                         (((x) << 16) & GENMASK(17, 16))
-#define HSIO_PLL5G_CFG0_SELCPI_M                          GENMASK(17, 16)
-#define HSIO_PLL5G_CFG0_SELCPI_X(x)                       (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_PLL5G_CFG0_ENA_VCO_CONTRH                    BIT(15)
-#define HSIO_PLL5G_CFG0_ENA_CP1                           BIT(14)
-#define HSIO_PLL5G_CFG0_ENA_VCO_BUF                       BIT(13)
-#define HSIO_PLL5G_CFG0_ENA_BIAS                          BIT(12)
-#define HSIO_PLL5G_CFG0_CPU_CLK_DIV(x)                    (((x) << 6) & GENMASK(11, 6))
-#define HSIO_PLL5G_CFG0_CPU_CLK_DIV_M                     GENMASK(11, 6)
-#define HSIO_PLL5G_CFG0_CPU_CLK_DIV_X(x)                  (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_PLL5G_CFG0_CORE_CLK_DIV(x)                   ((x) & GENMASK(5, 0))
-#define HSIO_PLL5G_CFG0_CORE_CLK_DIV_M                    GENMASK(5, 0)
-
-#define HSIO_PLL5G_CFG1_ENA_DIRECT                        BIT(18)
-#define HSIO_PLL5G_CFG1_ROT_SPEED                         BIT(17)
-#define HSIO_PLL5G_CFG1_ROT_DIR                           BIT(16)
-#define HSIO_PLL5G_CFG1_READBACK_DATA_SEL                 BIT(15)
-#define HSIO_PLL5G_CFG1_RC_ENABLE                         BIT(14)
-#define HSIO_PLL5G_CFG1_RC_CTRL_DATA(x)                   (((x) << 6) & GENMASK(13, 6))
-#define HSIO_PLL5G_CFG1_RC_CTRL_DATA_M                    GENMASK(13, 6)
-#define HSIO_PLL5G_CFG1_RC_CTRL_DATA_X(x)                 (((x) & GENMASK(13, 6)) >> 6)
-#define HSIO_PLL5G_CFG1_QUARTER_RATE                      BIT(5)
-#define HSIO_PLL5G_CFG1_PWD_TX                            BIT(4)
-#define HSIO_PLL5G_CFG1_PWD_RX                            BIT(3)
-#define HSIO_PLL5G_CFG1_OUT_OF_RANGE_RECAL_ENA            BIT(2)
-#define HSIO_PLL5G_CFG1_HALF_RATE                         BIT(1)
-#define HSIO_PLL5G_CFG1_FORCE_SET_ENA                     BIT(0)
-
-#define HSIO_PLL5G_CFG2_ENA_TEST_MODE                     BIT(30)
-#define HSIO_PLL5G_CFG2_ENA_PFD_IN_FLIP                   BIT(29)
-#define HSIO_PLL5G_CFG2_ENA_VCO_NREF_TESTOUT              BIT(28)
-#define HSIO_PLL5G_CFG2_ENA_FBTESTOUT                     BIT(27)
-#define HSIO_PLL5G_CFG2_ENA_RCPLL                         BIT(26)
-#define HSIO_PLL5G_CFG2_ENA_CP2                           BIT(25)
-#define HSIO_PLL5G_CFG2_ENA_CLK_BYPASS1                   BIT(24)
-#define HSIO_PLL5G_CFG2_AMPC_SEL(x)                       (((x) << 16) & GENMASK(23, 16))
-#define HSIO_PLL5G_CFG2_AMPC_SEL_M                        GENMASK(23, 16)
-#define HSIO_PLL5G_CFG2_AMPC_SEL_X(x)                     (((x) & GENMASK(23, 16)) >> 16)
-#define HSIO_PLL5G_CFG2_ENA_CLK_BYPASS                    BIT(15)
-#define HSIO_PLL5G_CFG2_PWD_AMPCTRL_N                     BIT(14)
-#define HSIO_PLL5G_CFG2_ENA_AMPCTRL                       BIT(13)
-#define HSIO_PLL5G_CFG2_ENA_AMP_CTRL_FORCE                BIT(12)
-#define HSIO_PLL5G_CFG2_FRC_FSM_POR                       BIT(11)
-#define HSIO_PLL5G_CFG2_DISABLE_FSM_POR                   BIT(10)
-#define HSIO_PLL5G_CFG2_GAIN_TEST(x)                      (((x) << 5) & GENMASK(9, 5))
-#define HSIO_PLL5G_CFG2_GAIN_TEST_M                       GENMASK(9, 5)
-#define HSIO_PLL5G_CFG2_GAIN_TEST_X(x)                    (((x) & GENMASK(9, 5)) >> 5)
-#define HSIO_PLL5G_CFG2_EN_RESET_OVERRUN                  BIT(4)
-#define HSIO_PLL5G_CFG2_EN_RESET_LIM_DET                  BIT(3)
-#define HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET                  BIT(2)
-#define HSIO_PLL5G_CFG2_DISABLE_FSM                       BIT(1)
-#define HSIO_PLL5G_CFG2_ENA_GAIN_TEST                     BIT(0)
-
-#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL(x)               (((x) << 22) & GENMASK(23, 22))
-#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL_M                GENMASK(23, 22)
-#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL_X(x)             (((x) & GENMASK(23, 22)) >> 22)
-#define HSIO_PLL5G_CFG3_TESTOUT_SEL(x)                    (((x) << 19) & GENMASK(21, 19))
-#define HSIO_PLL5G_CFG3_TESTOUT_SEL_M                     GENMASK(21, 19)
-#define HSIO_PLL5G_CFG3_TESTOUT_SEL_X(x)                  (((x) & GENMASK(21, 19)) >> 19)
-#define HSIO_PLL5G_CFG3_ENA_ANA_TEST_OUT                  BIT(18)
-#define HSIO_PLL5G_CFG3_ENA_TEST_OUT                      BIT(17)
-#define HSIO_PLL5G_CFG3_SEL_FBDCLK                        BIT(16)
-#define HSIO_PLL5G_CFG3_SEL_CML_CMOS_PFD                  BIT(15)
-#define HSIO_PLL5G_CFG3_RST_FB_N                          BIT(14)
-#define HSIO_PLL5G_CFG3_FORCE_VCO_CONTRH                  BIT(13)
-#define HSIO_PLL5G_CFG3_FORCE_LO                          BIT(12)
-#define HSIO_PLL5G_CFG3_FORCE_HI                          BIT(11)
-#define HSIO_PLL5G_CFG3_FORCE_ENA                         BIT(10)
-#define HSIO_PLL5G_CFG3_FORCE_CP                          BIT(9)
-#define HSIO_PLL5G_CFG3_FBDIVSEL_TST_ENA                  BIT(8)
-#define HSIO_PLL5G_CFG3_FBDIVSEL(x)                       ((x) & GENMASK(7, 0))
-#define HSIO_PLL5G_CFG3_FBDIVSEL_M                        GENMASK(7, 0)
-
-#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL(x)                   (((x) << 16) & GENMASK(23, 16))
-#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL_M                    GENMASK(23, 16)
-#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL_X(x)                 (((x) & GENMASK(23, 16)) >> 16)
-#define HSIO_PLL5G_CFG4_IB_CTRL(x)                        ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_CFG4_IB_CTRL_M                         GENMASK(15, 0)
-
-#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL(x)                   (((x) << 16) & GENMASK(23, 16))
-#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL_M                    GENMASK(23, 16)
-#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL_X(x)                 (((x) & GENMASK(23, 16)) >> 16)
-#define HSIO_PLL5G_CFG5_OB_CTRL(x)                        ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_CFG5_OB_CTRL_M                         GENMASK(15, 0)
-
-#define HSIO_PLL5G_CFG6_REFCLK_SEL_SRC                    BIT(23)
-#define HSIO_PLL5G_CFG6_REFCLK_SEL(x)                     (((x) << 20) & GENMASK(22, 20))
-#define HSIO_PLL5G_CFG6_REFCLK_SEL_M                      GENMASK(22, 20)
-#define HSIO_PLL5G_CFG6_REFCLK_SEL_X(x)                   (((x) & GENMASK(22, 20)) >> 20)
-#define HSIO_PLL5G_CFG6_REFCLK_SRC                        BIT(19)
-#define HSIO_PLL5G_CFG6_POR_DEL_SEL(x)                    (((x) << 16) & GENMASK(17, 16))
-#define HSIO_PLL5G_CFG6_POR_DEL_SEL_M                     GENMASK(17, 16)
-#define HSIO_PLL5G_CFG6_POR_DEL_SEL_X(x)                  (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_PLL5G_CFG6_DIV125REF_SEL(x)                  (((x) << 8) & GENMASK(15, 8))
-#define HSIO_PLL5G_CFG6_DIV125REF_SEL_M                   GENMASK(15, 8)
-#define HSIO_PLL5G_CFG6_DIV125REF_SEL_X(x)                (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_PLL5G_CFG6_ENA_REFCLKC2                      BIT(7)
-#define HSIO_PLL5G_CFG6_ENA_FBCLKC2                       BIT(6)
-#define HSIO_PLL5G_CFG6_DDR_CLK_DIV(x)                    ((x) & GENMASK(5, 0))
-#define HSIO_PLL5G_CFG6_DDR_CLK_DIV_M                     GENMASK(5, 0)
-
-#define HSIO_PLL5G_STATUS0_RANGE_LIM                      BIT(12)
-#define HSIO_PLL5G_STATUS0_OUT_OF_RANGE_ERR               BIT(11)
-#define HSIO_PLL5G_STATUS0_CALIBRATION_ERR                BIT(10)
-#define HSIO_PLL5G_STATUS0_CALIBRATION_DONE               BIT(9)
-#define HSIO_PLL5G_STATUS0_READBACK_DATA(x)               (((x) << 1) & GENMASK(8, 1))
-#define HSIO_PLL5G_STATUS0_READBACK_DATA_M                GENMASK(8, 1)
-#define HSIO_PLL5G_STATUS0_READBACK_DATA_X(x)             (((x) & GENMASK(8, 1)) >> 1)
-#define HSIO_PLL5G_STATUS0_LOCK_STATUS                    BIT(0)
-
-#define HSIO_PLL5G_STATUS1_SIG_DEL(x)                     (((x) << 21) & GENMASK(28, 21))
-#define HSIO_PLL5G_STATUS1_SIG_DEL_M                      GENMASK(28, 21)
-#define HSIO_PLL5G_STATUS1_SIG_DEL_X(x)                   (((x) & GENMASK(28, 21)) >> 21)
-#define HSIO_PLL5G_STATUS1_GAIN_STAT(x)                   (((x) << 16) & GENMASK(20, 16))
-#define HSIO_PLL5G_STATUS1_GAIN_STAT_M                    GENMASK(20, 16)
-#define HSIO_PLL5G_STATUS1_GAIN_STAT_X(x)                 (((x) & GENMASK(20, 16)) >> 16)
-#define HSIO_PLL5G_STATUS1_FBCNT_DIF(x)                   (((x) << 4) & GENMASK(13, 4))
-#define HSIO_PLL5G_STATUS1_FBCNT_DIF_M                    GENMASK(13, 4)
-#define HSIO_PLL5G_STATUS1_FBCNT_DIF_X(x)                 (((x) & GENMASK(13, 4)) >> 4)
-#define HSIO_PLL5G_STATUS1_FSM_STAT(x)                    (((x) << 1) & GENMASK(3, 1))
-#define HSIO_PLL5G_STATUS1_FSM_STAT_M                     GENMASK(3, 1)
-#define HSIO_PLL5G_STATUS1_FSM_STAT_X(x)                  (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_PLL5G_STATUS1_FSM_LOCK                       BIT(0)
-
-#define HSIO_PLL5G_BIST_CFG0_PLLB_START_BIST              BIT(31)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_MEAS_MODE               BIT(30)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT(x)          (((x) << 20) & GENMASK(23, 20))
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT_M           GENMASK(23, 20)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT_X(x)        (((x) & GENMASK(23, 20)) >> 20)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT(x)          (((x) << 16) & GENMASK(19, 16))
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT_M           GENMASK(19, 16)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT_X(x)        (((x) & GENMASK(19, 16)) >> 16)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_DIV_FACTOR_PRE(x)       ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_BIST_CFG0_PLLB_DIV_FACTOR_PRE_M        GENMASK(15, 0)
-
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT(x)            (((x) << 4) & GENMASK(7, 4))
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT_M             GENMASK(7, 4)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT_X(x)          (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_BUSY                   BIT(2)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_DONE_N                 BIT(1)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FAIL                   BIT(0)
-
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT(x)             (((x) << 16) & GENMASK(31, 16))
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT_M              GENMASK(31, 16)
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT_X(x)           (((x) & GENMASK(31, 16)) >> 16)
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_REF_DIFF(x)        ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_REF_DIFF_M         GENMASK(15, 0)
-
-#define HSIO_RCOMP_CFG0_PWD_ENA                           BIT(13)
-#define HSIO_RCOMP_CFG0_RUN_CAL                           BIT(12)
-#define HSIO_RCOMP_CFG0_SPEED_SEL(x)                      (((x) << 10) & GENMASK(11, 10))
-#define HSIO_RCOMP_CFG0_SPEED_SEL_M                       GENMASK(11, 10)
-#define HSIO_RCOMP_CFG0_SPEED_SEL_X(x)                    (((x) & GENMASK(11, 10)) >> 10)
-#define HSIO_RCOMP_CFG0_MODE_SEL(x)                       (((x) << 8) & GENMASK(9, 8))
-#define HSIO_RCOMP_CFG0_MODE_SEL_M                        GENMASK(9, 8)
-#define HSIO_RCOMP_CFG0_MODE_SEL_X(x)                     (((x) & GENMASK(9, 8)) >> 8)
-#define HSIO_RCOMP_CFG0_FORCE_ENA                         BIT(4)
-#define HSIO_RCOMP_CFG0_RCOMP_VAL(x)                      ((x) & GENMASK(3, 0))
-#define HSIO_RCOMP_CFG0_RCOMP_VAL_M                       GENMASK(3, 0)
-
-#define HSIO_RCOMP_STATUS_BUSY                            BIT(12)
-#define HSIO_RCOMP_STATUS_DELTA_ALERT                     BIT(7)
-#define HSIO_RCOMP_STATUS_RCOMP(x)                        ((x) & GENMASK(3, 0))
-#define HSIO_RCOMP_STATUS_RCOMP_M                         GENMASK(3, 0)
-
-#define HSIO_SYNC_ETH_CFG_RSZ                             0x4
-
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC(x)             (((x) << 4) & GENMASK(7, 4))
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_M              GENMASK(7, 4)
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_X(x)           (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV(x)             (((x) << 1) & GENMASK(3, 1))
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_M              GENMASK(3, 1)
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_X(x)           (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_SYNC_ETH_CFG_RECO_CLK_ENA                    BIT(0)
-
-#define HSIO_SYNC_ETH_PLL_CFG_PLL_AUTO_SQUELCH_ENA        BIT(0)
-
-#define HSIO_S1G_DES_CFG_DES_PHS_CTRL(x)                  (((x) << 13) & GENMASK(16, 13))
-#define HSIO_S1G_DES_CFG_DES_PHS_CTRL_M                   GENMASK(16, 13)
-#define HSIO_S1G_DES_CFG_DES_PHS_CTRL_X(x)                (((x) & GENMASK(16, 13)) >> 13)
-#define HSIO_S1G_DES_CFG_DES_CPMD_SEL(x)                  (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S1G_DES_CFG_DES_CPMD_SEL_M                   GENMASK(12, 11)
-#define HSIO_S1G_DES_CFG_DES_CPMD_SEL_X(x)                (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL(x)                 (((x) << 8) & GENMASK(10, 8))
-#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL_M                  GENMASK(10, 8)
-#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL_X(x)               (((x) & GENMASK(10, 8)) >> 8)
-#define HSIO_S1G_DES_CFG_DES_BW_ANA(x)                    (((x) << 5) & GENMASK(7, 5))
-#define HSIO_S1G_DES_CFG_DES_BW_ANA_M                     GENMASK(7, 5)
-#define HSIO_S1G_DES_CFG_DES_BW_ANA_X(x)                  (((x) & GENMASK(7, 5)) >> 5)
-#define HSIO_S1G_DES_CFG_DES_SWAP_ANA                     BIT(4)
-#define HSIO_S1G_DES_CFG_DES_BW_HYST(x)                   (((x) << 1) & GENMASK(3, 1))
-#define HSIO_S1G_DES_CFG_DES_BW_HYST_M                    GENMASK(3, 1)
-#define HSIO_S1G_DES_CFG_DES_BW_HYST_X(x)                 (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_S1G_DES_CFG_DES_SWAP_HYST                    BIT(0)
-
-#define HSIO_S1G_IB_CFG_IB_FX100_ENA                      BIT(27)
-#define HSIO_S1G_IB_CFG_ACJTAG_HYST(x)                    (((x) << 24) & GENMASK(26, 24))
-#define HSIO_S1G_IB_CFG_ACJTAG_HYST_M                     GENMASK(26, 24)
-#define HSIO_S1G_IB_CFG_ACJTAG_HYST_X(x)                  (((x) & GENMASK(26, 24)) >> 24)
-#define HSIO_S1G_IB_CFG_IB_DET_LEV(x)                     (((x) << 19) & GENMASK(21, 19))
-#define HSIO_S1G_IB_CFG_IB_DET_LEV_M                      GENMASK(21, 19)
-#define HSIO_S1G_IB_CFG_IB_DET_LEV_X(x)                   (((x) & GENMASK(21, 19)) >> 19)
-#define HSIO_S1G_IB_CFG_IB_HYST_LEV                       BIT(14)
-#define HSIO_S1G_IB_CFG_IB_ENA_CMV_TERM                   BIT(13)
-#define HSIO_S1G_IB_CFG_IB_ENA_DC_COUPLING                BIT(12)
-#define HSIO_S1G_IB_CFG_IB_ENA_DETLEV                     BIT(11)
-#define HSIO_S1G_IB_CFG_IB_ENA_HYST                       BIT(10)
-#define HSIO_S1G_IB_CFG_IB_ENA_OFFSET_COMP                BIT(9)
-#define HSIO_S1G_IB_CFG_IB_EQ_GAIN(x)                     (((x) << 6) & GENMASK(8, 6))
-#define HSIO_S1G_IB_CFG_IB_EQ_GAIN_M                      GENMASK(8, 6)
-#define HSIO_S1G_IB_CFG_IB_EQ_GAIN_X(x)                   (((x) & GENMASK(8, 6)) >> 6)
-#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ(x)             (((x) << 4) & GENMASK(5, 4))
-#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ_M              GENMASK(5, 4)
-#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ_X(x)           (((x) & GENMASK(5, 4)) >> 4)
-#define HSIO_S1G_IB_CFG_IB_RESISTOR_CTRL(x)               ((x) & GENMASK(3, 0))
-#define HSIO_S1G_IB_CFG_IB_RESISTOR_CTRL_M                GENMASK(3, 0)
-
-#define HSIO_S1G_OB_CFG_OB_SLP(x)                         (((x) << 17) & GENMASK(18, 17))
-#define HSIO_S1G_OB_CFG_OB_SLP_M                          GENMASK(18, 17)
-#define HSIO_S1G_OB_CFG_OB_SLP_X(x)                       (((x) & GENMASK(18, 17)) >> 17)
-#define HSIO_S1G_OB_CFG_OB_AMP_CTRL(x)                    (((x) << 13) & GENMASK(16, 13))
-#define HSIO_S1G_OB_CFG_OB_AMP_CTRL_M                     GENMASK(16, 13)
-#define HSIO_S1G_OB_CFG_OB_AMP_CTRL_X(x)                  (((x) & GENMASK(16, 13)) >> 13)
-#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL(x)               (((x) << 10) & GENMASK(12, 10))
-#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL_M                GENMASK(12, 10)
-#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL_X(x)             (((x) & GENMASK(12, 10)) >> 10)
-#define HSIO_S1G_OB_CFG_OB_DIS_VCM_CTRL                   BIT(9)
-#define HSIO_S1G_OB_CFG_OB_EN_MEAS_VREG                   BIT(8)
-#define HSIO_S1G_OB_CFG_OB_VCM_CTRL(x)                    (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S1G_OB_CFG_OB_VCM_CTRL_M                     GENMASK(7, 4)
-#define HSIO_S1G_OB_CFG_OB_VCM_CTRL_X(x)                  (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S1G_OB_CFG_OB_RESISTOR_CTRL(x)               ((x) & GENMASK(3, 0))
-#define HSIO_S1G_OB_CFG_OB_RESISTOR_CTRL_M                GENMASK(3, 0)
-
-#define HSIO_S1G_SER_CFG_SER_IDLE                         BIT(9)
-#define HSIO_S1G_SER_CFG_SER_DEEMPH                       BIT(8)
-#define HSIO_S1G_SER_CFG_SER_CPMD_SEL                     BIT(7)
-#define HSIO_S1G_SER_CFG_SER_SWAP_CPMD                    BIT(6)
-#define HSIO_S1G_SER_CFG_SER_ALISEL(x)                    (((x) << 4) & GENMASK(5, 4))
-#define HSIO_S1G_SER_CFG_SER_ALISEL_M                     GENMASK(5, 4)
-#define HSIO_S1G_SER_CFG_SER_ALISEL_X(x)                  (((x) & GENMASK(5, 4)) >> 4)
-#define HSIO_S1G_SER_CFG_SER_ENHYS                        BIT(3)
-#define HSIO_S1G_SER_CFG_SER_BIG_WIN                      BIT(2)
-#define HSIO_S1G_SER_CFG_SER_EN_WIN                       BIT(1)
-#define HSIO_S1G_SER_CFG_SER_ENALI                        BIT(0)
-
-#define HSIO_S1G_COMMON_CFG_SYS_RST                       BIT(31)
-#define HSIO_S1G_COMMON_CFG_SE_AUTO_SQUELCH_ENA           BIT(21)
-#define HSIO_S1G_COMMON_CFG_ENA_LANE                      BIT(18)
-#define HSIO_S1G_COMMON_CFG_PWD_RX                        BIT(17)
-#define HSIO_S1G_COMMON_CFG_PWD_TX                        BIT(16)
-#define HSIO_S1G_COMMON_CFG_LANE_CTRL(x)                  (((x) << 13) & GENMASK(15, 13))
-#define HSIO_S1G_COMMON_CFG_LANE_CTRL_M                   GENMASK(15, 13)
-#define HSIO_S1G_COMMON_CFG_LANE_CTRL_X(x)                (((x) & GENMASK(15, 13)) >> 13)
-#define HSIO_S1G_COMMON_CFG_ENA_DIRECT                    BIT(12)
-#define HSIO_S1G_COMMON_CFG_ENA_ELOOP                     BIT(11)
-#define HSIO_S1G_COMMON_CFG_ENA_FLOOP                     BIT(10)
-#define HSIO_S1G_COMMON_CFG_ENA_ILOOP                     BIT(9)
-#define HSIO_S1G_COMMON_CFG_ENA_PLOOP                     BIT(8)
-#define HSIO_S1G_COMMON_CFG_HRATE                         BIT(7)
-#define HSIO_S1G_COMMON_CFG_IF_MODE                       BIT(0)
-
-#define HSIO_S1G_PLL_CFG_PLL_ENA_FB_DIV2                  BIT(22)
-#define HSIO_S1G_PLL_CFG_PLL_ENA_RC_DIV2                  BIT(21)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(x)             (((x) << 8) & GENMASK(15, 8))
-#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M              GENMASK(15, 8)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_X(x)           (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_ENA                      BIT(7)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_FORCE_SET_ENA            BIT(6)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_OOR_RECAL_ENA            BIT(5)
-#define HSIO_S1G_PLL_CFG_PLL_RB_DATA_SEL                  BIT(3)
-
-#define HSIO_S1G_PLL_STATUS_PLL_CAL_NOT_DONE              BIT(12)
-#define HSIO_S1G_PLL_STATUS_PLL_CAL_ERR                   BIT(11)
-#define HSIO_S1G_PLL_STATUS_PLL_OUT_OF_RANGE_ERR          BIT(10)
-#define HSIO_S1G_PLL_STATUS_PLL_RB_DATA(x)                ((x) & GENMASK(7, 0))
-#define HSIO_S1G_PLL_STATUS_PLL_RB_DATA_M                 GENMASK(7, 0)
-
-#define HSIO_S1G_DFT_CFG0_LAZYBIT                         BIT(31)
-#define HSIO_S1G_DFT_CFG0_INV_DIS                         BIT(23)
-#define HSIO_S1G_DFT_CFG0_PRBS_SEL(x)                     (((x) << 20) & GENMASK(21, 20))
-#define HSIO_S1G_DFT_CFG0_PRBS_SEL_M                      GENMASK(21, 20)
-#define HSIO_S1G_DFT_CFG0_PRBS_SEL_X(x)                   (((x) & GENMASK(21, 20)) >> 20)
-#define HSIO_S1G_DFT_CFG0_TEST_MODE(x)                    (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S1G_DFT_CFG0_TEST_MODE_M                     GENMASK(18, 16)
-#define HSIO_S1G_DFT_CFG0_TEST_MODE_X(x)                  (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S1G_DFT_CFG0_RX_PHS_CORR_DIS                 BIT(4)
-#define HSIO_S1G_DFT_CFG0_RX_PDSENS_ENA                   BIT(3)
-#define HSIO_S1G_DFT_CFG0_RX_DFT_ENA                      BIT(2)
-#define HSIO_S1G_DFT_CFG0_TX_DFT_ENA                      BIT(0)
-
-#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL_M                GENMASK(17, 8)
-#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ_M                  GENMASK(7, 4)
-#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S1G_DFT_CFG1_TX_JI_ENA                       BIT(3)
-#define HSIO_S1G_DFT_CFG1_TX_WAVEFORM_SEL                 BIT(2)
-#define HSIO_S1G_DFT_CFG1_TX_FREQOFF_DIR                  BIT(1)
-#define HSIO_S1G_DFT_CFG1_TX_FREQOFF_ENA                  BIT(0)
-
-#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL_M                GENMASK(17, 8)
-#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ_M                  GENMASK(7, 4)
-#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S1G_DFT_CFG2_RX_JI_ENA                       BIT(3)
-#define HSIO_S1G_DFT_CFG2_RX_WAVEFORM_SEL                 BIT(2)
-#define HSIO_S1G_DFT_CFG2_RX_FREQOFF_DIR                  BIT(1)
-#define HSIO_S1G_DFT_CFG2_RX_FREQOFF_ENA                  BIT(0)
-
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_ENA             BIT(20)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH(x)     (((x) << 16) & GENMASK(17, 16))
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_M      GENMASK(17, 16)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_X(x)   (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH(x)         (((x) << 8) & GENMASK(15, 8))
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_M          GENMASK(15, 8)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_X(x)       (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_LOW(x)          ((x) & GENMASK(7, 0))
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_LOW_M           GENMASK(7, 0)
-
-#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE(x)          (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE_M           GENMASK(12, 11)
-#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE_X(x)        (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_SWAP             BIT(10)
-#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_MODE             BIT(9)
-#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA              BIT(8)
-#define HSIO_S1G_MISC_CFG_RX_LPI_MODE_ENA                 BIT(5)
-#define HSIO_S1G_MISC_CFG_TX_LPI_MODE_ENA                 BIT(4)
-#define HSIO_S1G_MISC_CFG_RX_DATA_INV_ENA                 BIT(3)
-#define HSIO_S1G_MISC_CFG_TX_DATA_INV_ENA                 BIT(2)
-#define HSIO_S1G_MISC_CFG_LANE_RST                        BIT(0)
-
-#define HSIO_S1G_DFT_STATUS_PLL_BIST_NOT_DONE             BIT(7)
-#define HSIO_S1G_DFT_STATUS_PLL_BIST_FAILED               BIT(6)
-#define HSIO_S1G_DFT_STATUS_PLL_BIST_TIMEOUT_ERR          BIT(5)
-#define HSIO_S1G_DFT_STATUS_BIST_ACTIVE                   BIT(3)
-#define HSIO_S1G_DFT_STATUS_BIST_NOSYNC                   BIT(2)
-#define HSIO_S1G_DFT_STATUS_BIST_COMPLETE_N               BIT(1)
-#define HSIO_S1G_DFT_STATUS_BIST_ERROR                    BIT(0)
-
-#define HSIO_S1G_MISC_STATUS_DES_100FX_PHASE_SEL          BIT(0)
-
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT        BIT(31)
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT        BIT(30)
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(x)            ((x) & GENMASK(8, 0))
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR_M             GENMASK(8, 0)
-
-#define HSIO_S6G_DIG_CFG_GP(x)                            (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S6G_DIG_CFG_GP_M                             GENMASK(18, 16)
-#define HSIO_S6G_DIG_CFG_GP_X(x)                          (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S6G_DIG_CFG_TX_BIT_DOUBLING_MODE_ENA         BIT(7)
-#define HSIO_S6G_DIG_CFG_SIGDET_TESTMODE                  BIT(6)
-#define HSIO_S6G_DIG_CFG_SIGDET_AST(x)                    (((x) << 3) & GENMASK(5, 3))
-#define HSIO_S6G_DIG_CFG_SIGDET_AST_M                     GENMASK(5, 3)
-#define HSIO_S6G_DIG_CFG_SIGDET_AST_X(x)                  (((x) & GENMASK(5, 3)) >> 3)
-#define HSIO_S6G_DIG_CFG_SIGDET_DST(x)                    ((x) & GENMASK(2, 0))
-#define HSIO_S6G_DIG_CFG_SIGDET_DST_M                     GENMASK(2, 0)
-
-#define HSIO_S6G_DFT_CFG0_LAZYBIT                         BIT(31)
-#define HSIO_S6G_DFT_CFG0_INV_DIS                         BIT(23)
-#define HSIO_S6G_DFT_CFG0_PRBS_SEL(x)                     (((x) << 20) & GENMASK(21, 20))
-#define HSIO_S6G_DFT_CFG0_PRBS_SEL_M                      GENMASK(21, 20)
-#define HSIO_S6G_DFT_CFG0_PRBS_SEL_X(x)                   (((x) & GENMASK(21, 20)) >> 20)
-#define HSIO_S6G_DFT_CFG0_TEST_MODE(x)                    (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S6G_DFT_CFG0_TEST_MODE_M                     GENMASK(18, 16)
-#define HSIO_S6G_DFT_CFG0_TEST_MODE_X(x)                  (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S6G_DFT_CFG0_RX_PHS_CORR_DIS                 BIT(4)
-#define HSIO_S6G_DFT_CFG0_RX_PDSENS_ENA                   BIT(3)
-#define HSIO_S6G_DFT_CFG0_RX_DFT_ENA                      BIT(2)
-#define HSIO_S6G_DFT_CFG0_TX_DFT_ENA                      BIT(0)
-
-#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL_M                GENMASK(17, 8)
-#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ_M                  GENMASK(7, 4)
-#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S6G_DFT_CFG1_TX_JI_ENA                       BIT(3)
-#define HSIO_S6G_DFT_CFG1_TX_WAVEFORM_SEL                 BIT(2)
-#define HSIO_S6G_DFT_CFG1_TX_FREQOFF_DIR                  BIT(1)
-#define HSIO_S6G_DFT_CFG1_TX_FREQOFF_ENA                  BIT(0)
-
-#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL_M                GENMASK(17, 8)
-#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ_M                  GENMASK(7, 4)
-#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S6G_DFT_CFG2_RX_JI_ENA                       BIT(3)
-#define HSIO_S6G_DFT_CFG2_RX_WAVEFORM_SEL                 BIT(2)
-#define HSIO_S6G_DFT_CFG2_RX_FREQOFF_DIR                  BIT(1)
-#define HSIO_S6G_DFT_CFG2_RX_FREQOFF_ENA                  BIT(0)
-
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_ENA             BIT(20)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH(x)     (((x) << 16) & GENMASK(19, 16))
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_M      GENMASK(19, 16)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_X(x)   (((x) & GENMASK(19, 16)) >> 16)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH(x)         (((x) << 8) & GENMASK(15, 8))
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_M          GENMASK(15, 8)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_X(x)       (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_LOW(x)          ((x) & GENMASK(7, 0))
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_LOW_M           GENMASK(7, 0)
-
-#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK(x)                 (((x) << 13) & GENMASK(14, 13))
-#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK_M                  GENMASK(14, 13)
-#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK_X(x)               (((x) & GENMASK(14, 13)) >> 13)
-#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE(x)          (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE_M           GENMASK(12, 11)
-#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE_X(x)        (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_SWAP             BIT(10)
-#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_MODE             BIT(9)
-#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_ENA              BIT(8)
-#define HSIO_S6G_MISC_CFG_RX_BUS_FLIP_ENA                 BIT(7)
-#define HSIO_S6G_MISC_CFG_TX_BUS_FLIP_ENA                 BIT(6)
-#define HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA                 BIT(5)
-#define HSIO_S6G_MISC_CFG_TX_LPI_MODE_ENA                 BIT(4)
-#define HSIO_S6G_MISC_CFG_RX_DATA_INV_ENA                 BIT(3)
-#define HSIO_S6G_MISC_CFG_TX_DATA_INV_ENA                 BIT(2)
-#define HSIO_S6G_MISC_CFG_LANE_RST                        BIT(0)
-
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0(x)               (((x) << 23) & GENMASK(28, 23))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0_M                GENMASK(28, 23)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0_X(x)             (((x) & GENMASK(28, 23)) >> 23)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1(x)               (((x) << 18) & GENMASK(22, 18))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1_M                GENMASK(22, 18)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1_X(x)             (((x) & GENMASK(22, 18)) >> 18)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC(x)                (((x) << 13) & GENMASK(17, 13))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC_M                 GENMASK(17, 13)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC_X(x)              (((x) & GENMASK(17, 13)) >> 13)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS(x)             (((x) << 6) & GENMASK(8, 6))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS_M              GENMASK(8, 6)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS_X(x)           (((x) & GENMASK(8, 6)) >> 6)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_LEV(x)                 ((x) & GENMASK(5, 0))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_LEV_M                  GENMASK(5, 0)
-
-#define HSIO_S6G_DFT_STATUS_PRBS_SYNC_STAT                BIT(8)
-#define HSIO_S6G_DFT_STATUS_PLL_BIST_NOT_DONE             BIT(7)
-#define HSIO_S6G_DFT_STATUS_PLL_BIST_FAILED               BIT(6)
-#define HSIO_S6G_DFT_STATUS_PLL_BIST_TIMEOUT_ERR          BIT(5)
-#define HSIO_S6G_DFT_STATUS_BIST_ACTIVE                   BIT(3)
-#define HSIO_S6G_DFT_STATUS_BIST_NOSYNC                   BIT(2)
-#define HSIO_S6G_DFT_STATUS_BIST_COMPLETE_N               BIT(1)
-#define HSIO_S6G_DFT_STATUS_BIST_ERROR                    BIT(0)
-
-#define HSIO_S6G_MISC_STATUS_DES_100FX_PHASE_SEL          BIT(0)
-
-#define HSIO_S6G_DES_CFG_DES_PHS_CTRL(x)                  (((x) << 13) & GENMASK(16, 13))
-#define HSIO_S6G_DES_CFG_DES_PHS_CTRL_M                   GENMASK(16, 13)
-#define HSIO_S6G_DES_CFG_DES_PHS_CTRL_X(x)                (((x) & GENMASK(16, 13)) >> 13)
-#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL(x)                 (((x) << 10) & GENMASK(12, 10))
-#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL_M                  GENMASK(12, 10)
-#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL_X(x)               (((x) & GENMASK(12, 10)) >> 10)
-#define HSIO_S6G_DES_CFG_DES_CPMD_SEL(x)                  (((x) << 8) & GENMASK(9, 8))
-#define HSIO_S6G_DES_CFG_DES_CPMD_SEL_M                   GENMASK(9, 8)
-#define HSIO_S6G_DES_CFG_DES_CPMD_SEL_X(x)                (((x) & GENMASK(9, 8)) >> 8)
-#define HSIO_S6G_DES_CFG_DES_BW_HYST(x)                   (((x) << 5) & GENMASK(7, 5))
-#define HSIO_S6G_DES_CFG_DES_BW_HYST_M                    GENMASK(7, 5)
-#define HSIO_S6G_DES_CFG_DES_BW_HYST_X(x)                 (((x) & GENMASK(7, 5)) >> 5)
-#define HSIO_S6G_DES_CFG_DES_SWAP_HYST                    BIT(4)
-#define HSIO_S6G_DES_CFG_DES_BW_ANA(x)                    (((x) << 1) & GENMASK(3, 1))
-#define HSIO_S6G_DES_CFG_DES_BW_ANA_M                     GENMASK(3, 1)
-#define HSIO_S6G_DES_CFG_DES_BW_ANA_X(x)                  (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_S6G_DES_CFG_DES_SWAP_ANA                     BIT(0)
-
-#define HSIO_S6G_IB_CFG_IB_SOFSI(x)                       (((x) << 29) & GENMASK(30, 29))
-#define HSIO_S6G_IB_CFG_IB_SOFSI_M                        GENMASK(30, 29)
-#define HSIO_S6G_IB_CFG_IB_SOFSI_X(x)                     (((x) & GENMASK(30, 29)) >> 29)
-#define HSIO_S6G_IB_CFG_IB_VBULK_SEL                      BIT(28)
-#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ(x)                    (((x) << 24) & GENMASK(27, 24))
-#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ_M                     GENMASK(27, 24)
-#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ_X(x)                  (((x) & GENMASK(27, 24)) >> 24)
-#define HSIO_S6G_IB_CFG_IB_ICML_ADJ(x)                    (((x) << 20) & GENMASK(23, 20))
-#define HSIO_S6G_IB_CFG_IB_ICML_ADJ_M                     GENMASK(23, 20)
-#define HSIO_S6G_IB_CFG_IB_ICML_ADJ_X(x)                  (((x) & GENMASK(23, 20)) >> 20)
-#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL(x)               (((x) << 18) & GENMASK(19, 18))
-#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL_M                GENMASK(19, 18)
-#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL_X(x)             (((x) & GENMASK(19, 18)) >> 18)
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(x)             (((x) << 15) & GENMASK(17, 15))
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M              GENMASK(17, 15)
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_X(x)           (((x) & GENMASK(17, 15)) >> 15)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP(x)              (((x) << 13) & GENMASK(14, 13))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP_M               GENMASK(14, 13)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP_X(x)            (((x) & GENMASK(14, 13)) >> 13)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID(x)             (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID_M              GENMASK(12, 11)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID_X(x)           (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP(x)              (((x) << 9) & GENMASK(10, 9))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP_M               GENMASK(10, 9)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP_X(x)            (((x) & GENMASK(10, 9)) >> 9)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(x)          (((x) << 7) & GENMASK(8, 7))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M           GENMASK(8, 7)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_X(x)        (((x) & GENMASK(8, 7)) >> 7)
-#define HSIO_S6G_IB_CFG_IB_ANA_TEST_ENA                   BIT(6)
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_ENA                    BIT(5)
-#define HSIO_S6G_IB_CFG_IB_CONCUR                         BIT(4)
-#define HSIO_S6G_IB_CFG_IB_CAL_ENA                        BIT(3)
-#define HSIO_S6G_IB_CFG_IB_SAM_ENA                        BIT(2)
-#define HSIO_S6G_IB_CFG_IB_EQZ_ENA                        BIT(1)
-#define HSIO_S6G_IB_CFG_IB_REG_ENA                        BIT(0)
-
-#define HSIO_S6G_IB_CFG1_IB_TJTAG(x)                      (((x) << 17) & GENMASK(21, 17))
-#define HSIO_S6G_IB_CFG1_IB_TJTAG_M                       GENMASK(21, 17)
-#define HSIO_S6G_IB_CFG1_IB_TJTAG_X(x)                    (((x) & GENMASK(21, 17)) >> 17)
-#define HSIO_S6G_IB_CFG1_IB_TSDET(x)                      (((x) << 12) & GENMASK(16, 12))
-#define HSIO_S6G_IB_CFG1_IB_TSDET_M                       GENMASK(16, 12)
-#define HSIO_S6G_IB_CFG1_IB_TSDET_X(x)                    (((x) & GENMASK(16, 12)) >> 12)
-#define HSIO_S6G_IB_CFG1_IB_SCALY(x)                      (((x) << 8) & GENMASK(11, 8))
-#define HSIO_S6G_IB_CFG1_IB_SCALY_M                       GENMASK(11, 8)
-#define HSIO_S6G_IB_CFG1_IB_SCALY_X(x)                    (((x) & GENMASK(11, 8)) >> 8)
-#define HSIO_S6G_IB_CFG1_IB_FILT_HP                       BIT(7)
-#define HSIO_S6G_IB_CFG1_IB_FILT_MID                      BIT(6)
-#define HSIO_S6G_IB_CFG1_IB_FILT_LP                       BIT(5)
-#define HSIO_S6G_IB_CFG1_IB_FILT_OFFSET                   BIT(4)
-#define HSIO_S6G_IB_CFG1_IB_FRC_HP                        BIT(3)
-#define HSIO_S6G_IB_CFG1_IB_FRC_MID                       BIT(2)
-#define HSIO_S6G_IB_CFG1_IB_FRC_LP                        BIT(1)
-#define HSIO_S6G_IB_CFG1_IB_FRC_OFFSET                    BIT(0)
-
-#define HSIO_S6G_IB_CFG2_IB_TINFV(x)                      (((x) << 27) & GENMASK(29, 27))
-#define HSIO_S6G_IB_CFG2_IB_TINFV_M                       GENMASK(29, 27)
-#define HSIO_S6G_IB_CFG2_IB_TINFV_X(x)                    (((x) & GENMASK(29, 27)) >> 27)
-#define HSIO_S6G_IB_CFG2_IB_OINFI(x)                      (((x) << 22) & GENMASK(26, 22))
-#define HSIO_S6G_IB_CFG2_IB_OINFI_M                       GENMASK(26, 22)
-#define HSIO_S6G_IB_CFG2_IB_OINFI_X(x)                    (((x) & GENMASK(26, 22)) >> 22)
-#define HSIO_S6G_IB_CFG2_IB_TAUX(x)                       (((x) << 19) & GENMASK(21, 19))
-#define HSIO_S6G_IB_CFG2_IB_TAUX_M                        GENMASK(21, 19)
-#define HSIO_S6G_IB_CFG2_IB_TAUX_X(x)                     (((x) & GENMASK(21, 19)) >> 19)
-#define HSIO_S6G_IB_CFG2_IB_OINFS(x)                      (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S6G_IB_CFG2_IB_OINFS_M                       GENMASK(18, 16)
-#define HSIO_S6G_IB_CFG2_IB_OINFS_X(x)                    (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S6G_IB_CFG2_IB_OCALS(x)                      (((x) << 10) & GENMASK(15, 10))
-#define HSIO_S6G_IB_CFG2_IB_OCALS_M                       GENMASK(15, 10)
-#define HSIO_S6G_IB_CFG2_IB_OCALS_X(x)                    (((x) & GENMASK(15, 10)) >> 10)
-#define HSIO_S6G_IB_CFG2_IB_TCALV(x)                      (((x) << 5) & GENMASK(9, 5))
-#define HSIO_S6G_IB_CFG2_IB_TCALV_M                       GENMASK(9, 5)
-#define HSIO_S6G_IB_CFG2_IB_TCALV_X(x)                    (((x) & GENMASK(9, 5)) >> 5)
-#define HSIO_S6G_IB_CFG2_IB_UMAX(x)                       (((x) << 3) & GENMASK(4, 3))
-#define HSIO_S6G_IB_CFG2_IB_UMAX_M                        GENMASK(4, 3)
-#define HSIO_S6G_IB_CFG2_IB_UMAX_X(x)                     (((x) & GENMASK(4, 3)) >> 3)
-#define HSIO_S6G_IB_CFG2_IB_UREG(x)                       ((x) & GENMASK(2, 0))
-#define HSIO_S6G_IB_CFG2_IB_UREG_M                        GENMASK(2, 0)
-
-#define HSIO_S6G_IB_CFG3_IB_INI_HP(x)                     (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_CFG3_IB_INI_HP_M                      GENMASK(23, 18)
-#define HSIO_S6G_IB_CFG3_IB_INI_HP_X(x)                   (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_CFG3_IB_INI_MID(x)                    (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_CFG3_IB_INI_MID_M                     GENMASK(17, 12)
-#define HSIO_S6G_IB_CFG3_IB_INI_MID_X(x)                  (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_CFG3_IB_INI_LP(x)                     (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_CFG3_IB_INI_LP_M                      GENMASK(11, 6)
-#define HSIO_S6G_IB_CFG3_IB_INI_LP_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_CFG3_IB_INI_OFFSET(x)                 ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_CFG3_IB_INI_OFFSET_M                  GENMASK(5, 0)
-
-#define HSIO_S6G_IB_CFG4_IB_MAX_HP(x)                     (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_CFG4_IB_MAX_HP_M                      GENMASK(23, 18)
-#define HSIO_S6G_IB_CFG4_IB_MAX_HP_X(x)                   (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_CFG4_IB_MAX_MID(x)                    (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_CFG4_IB_MAX_MID_M                     GENMASK(17, 12)
-#define HSIO_S6G_IB_CFG4_IB_MAX_MID_X(x)                  (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_CFG4_IB_MAX_LP(x)                     (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_CFG4_IB_MAX_LP_M                      GENMASK(11, 6)
-#define HSIO_S6G_IB_CFG4_IB_MAX_LP_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_CFG4_IB_MAX_OFFSET(x)                 ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_CFG4_IB_MAX_OFFSET_M                  GENMASK(5, 0)
-
-#define HSIO_S6G_IB_CFG5_IB_MIN_HP(x)                     (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_CFG5_IB_MIN_HP_M                      GENMASK(23, 18)
-#define HSIO_S6G_IB_CFG5_IB_MIN_HP_X(x)                   (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_CFG5_IB_MIN_MID(x)                    (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_CFG5_IB_MIN_MID_M                     GENMASK(17, 12)
-#define HSIO_S6G_IB_CFG5_IB_MIN_MID_X(x)                  (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_CFG5_IB_MIN_LP(x)                     (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_CFG5_IB_MIN_LP_M                      GENMASK(11, 6)
-#define HSIO_S6G_IB_CFG5_IB_MIN_LP_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_CFG5_IB_MIN_OFFSET(x)                 ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_CFG5_IB_MIN_OFFSET_M                  GENMASK(5, 0)
-
-#define HSIO_S6G_OB_CFG_OB_IDLE                           BIT(31)
-#define HSIO_S6G_OB_CFG_OB_ENA1V_MODE                     BIT(30)
-#define HSIO_S6G_OB_CFG_OB_POL                            BIT(29)
-#define HSIO_S6G_OB_CFG_OB_POST0(x)                       (((x) << 23) & GENMASK(28, 23))
-#define HSIO_S6G_OB_CFG_OB_POST0_M                        GENMASK(28, 23)
-#define HSIO_S6G_OB_CFG_OB_POST0_X(x)                     (((x) & GENMASK(28, 23)) >> 23)
-#define HSIO_S6G_OB_CFG_OB_PREC(x)                        (((x) << 18) & GENMASK(22, 18))
-#define HSIO_S6G_OB_CFG_OB_PREC_M                         GENMASK(22, 18)
-#define HSIO_S6G_OB_CFG_OB_PREC_X(x)                      (((x) & GENMASK(22, 18)) >> 18)
-#define HSIO_S6G_OB_CFG_OB_R_ADJ_MUX                      BIT(17)
-#define HSIO_S6G_OB_CFG_OB_R_ADJ_PDR                      BIT(16)
-#define HSIO_S6G_OB_CFG_OB_POST1(x)                       (((x) << 11) & GENMASK(15, 11))
-#define HSIO_S6G_OB_CFG_OB_POST1_M                        GENMASK(15, 11)
-#define HSIO_S6G_OB_CFG_OB_POST1_X(x)                     (((x) & GENMASK(15, 11)) >> 11)
-#define HSIO_S6G_OB_CFG_OB_R_COR                          BIT(10)
-#define HSIO_S6G_OB_CFG_OB_SEL_RCTRL                      BIT(9)
-#define HSIO_S6G_OB_CFG_OB_SR_H                           BIT(8)
-#define HSIO_S6G_OB_CFG_OB_SR(x)                          (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S6G_OB_CFG_OB_SR_M                           GENMASK(7, 4)
-#define HSIO_S6G_OB_CFG_OB_SR_X(x)                        (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S6G_OB_CFG_OB_RESISTOR_CTRL(x)               ((x) & GENMASK(3, 0))
-#define HSIO_S6G_OB_CFG_OB_RESISTOR_CTRL_M                GENMASK(3, 0)
-
-#define HSIO_S6G_OB_CFG1_OB_ENA_CAS(x)                    (((x) << 6) & GENMASK(8, 6))
-#define HSIO_S6G_OB_CFG1_OB_ENA_CAS_M                     GENMASK(8, 6)
-#define HSIO_S6G_OB_CFG1_OB_ENA_CAS_X(x)                  (((x) & GENMASK(8, 6)) >> 6)
-#define HSIO_S6G_OB_CFG1_OB_LEV(x)                        ((x) & GENMASK(5, 0))
-#define HSIO_S6G_OB_CFG1_OB_LEV_M                         GENMASK(5, 0)
-
-#define HSIO_S6G_SER_CFG_SER_4TAP_ENA                     BIT(8)
-#define HSIO_S6G_SER_CFG_SER_CPMD_SEL                     BIT(7)
-#define HSIO_S6G_SER_CFG_SER_SWAP_CPMD                    BIT(6)
-#define HSIO_S6G_SER_CFG_SER_ALISEL(x)                    (((x) << 4) & GENMASK(5, 4))
-#define HSIO_S6G_SER_CFG_SER_ALISEL_M                     GENMASK(5, 4)
-#define HSIO_S6G_SER_CFG_SER_ALISEL_X(x)                  (((x) & GENMASK(5, 4)) >> 4)
-#define HSIO_S6G_SER_CFG_SER_ENHYS                        BIT(3)
-#define HSIO_S6G_SER_CFG_SER_BIG_WIN                      BIT(2)
-#define HSIO_S6G_SER_CFG_SER_EN_WIN                       BIT(1)
-#define HSIO_S6G_SER_CFG_SER_ENALI                        BIT(0)
-
-#define HSIO_S6G_COMMON_CFG_SYS_RST                       BIT(17)
-#define HSIO_S6G_COMMON_CFG_SE_DIV2_ENA                   BIT(16)
-#define HSIO_S6G_COMMON_CFG_SE_AUTO_SQUELCH_ENA           BIT(15)
-#define HSIO_S6G_COMMON_CFG_ENA_LANE                      BIT(14)
-#define HSIO_S6G_COMMON_CFG_PWD_RX                        BIT(13)
-#define HSIO_S6G_COMMON_CFG_PWD_TX                        BIT(12)
-#define HSIO_S6G_COMMON_CFG_LANE_CTRL(x)                  (((x) << 9) & GENMASK(11, 9))
-#define HSIO_S6G_COMMON_CFG_LANE_CTRL_M                   GENMASK(11, 9)
-#define HSIO_S6G_COMMON_CFG_LANE_CTRL_X(x)                (((x) & GENMASK(11, 9)) >> 9)
-#define HSIO_S6G_COMMON_CFG_ENA_DIRECT                    BIT(8)
-#define HSIO_S6G_COMMON_CFG_ENA_ELOOP                     BIT(7)
-#define HSIO_S6G_COMMON_CFG_ENA_FLOOP                     BIT(6)
-#define HSIO_S6G_COMMON_CFG_ENA_ILOOP                     BIT(5)
-#define HSIO_S6G_COMMON_CFG_ENA_PLOOP                     BIT(4)
-#define HSIO_S6G_COMMON_CFG_HRATE                         BIT(3)
-#define HSIO_S6G_COMMON_CFG_QRATE                         BIT(2)
-#define HSIO_S6G_COMMON_CFG_IF_MODE(x)                    ((x) & GENMASK(1, 0))
-#define HSIO_S6G_COMMON_CFG_IF_MODE_M                     GENMASK(1, 0)
-
-#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS(x)                  (((x) << 16) & GENMASK(17, 16))
-#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS_M                   GENMASK(17, 16)
-#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS_X(x)                (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_S6G_PLL_CFG_PLL_DIV4                         BIT(15)
-#define HSIO_S6G_PLL_CFG_PLL_ENA_ROT                      BIT(14)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA(x)             (((x) << 6) & GENMASK(13, 6))
-#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_M              GENMASK(13, 6)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_X(x)           (((x) & GENMASK(13, 6)) >> 6)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_ENA                      BIT(5)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_FORCE_SET_ENA            BIT(4)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_OOR_RECAL_ENA            BIT(3)
-#define HSIO_S6G_PLL_CFG_PLL_RB_DATA_SEL                  BIT(2)
-#define HSIO_S6G_PLL_CFG_PLL_ROT_DIR                      BIT(1)
-#define HSIO_S6G_PLL_CFG_PLL_ROT_FRQ                      BIT(0)
-
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_DATA_N            BIT(5)
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_DATA_P            BIT(4)
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_CLK               BIT(3)
-#define HSIO_S6G_ACJTAG_CFG_OB_DIRECT                     BIT(2)
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_ENA                    BIT(1)
-#define HSIO_S6G_ACJTAG_CFG_JTAG_CTRL_ENA                 BIT(0)
-
-#define HSIO_S6G_GP_CFG_GP_MSB(x)                         (((x) << 16) & GENMASK(31, 16))
-#define HSIO_S6G_GP_CFG_GP_MSB_M                          GENMASK(31, 16)
-#define HSIO_S6G_GP_CFG_GP_MSB_X(x)                       (((x) & GENMASK(31, 16)) >> 16)
-#define HSIO_S6G_GP_CFG_GP_LSB(x)                         ((x) & GENMASK(15, 0))
-#define HSIO_S6G_GP_CFG_GP_LSB_M                          GENMASK(15, 0)
-
-#define HSIO_S6G_IB_STATUS0_IB_CAL_DONE                   BIT(8)
-#define HSIO_S6G_IB_STATUS0_IB_HP_GAIN_ACT                BIT(7)
-#define HSIO_S6G_IB_STATUS0_IB_MID_GAIN_ACT               BIT(6)
-#define HSIO_S6G_IB_STATUS0_IB_LP_GAIN_ACT                BIT(5)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSET_ACT                 BIT(4)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSET_VLD                 BIT(3)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSET_ERR                 BIT(2)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSDIR                    BIT(1)
-#define HSIO_S6G_IB_STATUS0_IB_SIG_DET                    BIT(0)
-
-#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT(x)            (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT_M             GENMASK(23, 18)
-#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT_X(x)          (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT(x)           (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT_M            GENMASK(17, 12)
-#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT_X(x)         (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT(x)            (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT_M             GENMASK(11, 6)
-#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT_X(x)          (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_STATUS1_IB_OFFSET_STAT(x)             ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_STATUS1_IB_OFFSET_STAT_M              GENMASK(5, 0)
-
-#define HSIO_S6G_ACJTAG_STATUS_ACJTAG_CAPT_DATA_N         BIT(2)
-#define HSIO_S6G_ACJTAG_STATUS_ACJTAG_CAPT_DATA_P         BIT(1)
-#define HSIO_S6G_ACJTAG_STATUS_IB_DIRECT                  BIT(0)
-
-#define HSIO_S6G_PLL_STATUS_PLL_CAL_NOT_DONE              BIT(10)
-#define HSIO_S6G_PLL_STATUS_PLL_CAL_ERR                   BIT(9)
-#define HSIO_S6G_PLL_STATUS_PLL_OUT_OF_RANGE_ERR          BIT(8)
-#define HSIO_S6G_PLL_STATUS_PLL_RB_DATA(x)                ((x) & GENMASK(7, 0))
-#define HSIO_S6G_PLL_STATUS_PLL_RB_DATA_M                 GENMASK(7, 0)
-
-#define HSIO_S6G_REVID_SERDES_REV(x)                      (((x) << 26) & GENMASK(31, 26))
-#define HSIO_S6G_REVID_SERDES_REV_M                       GENMASK(31, 26)
-#define HSIO_S6G_REVID_SERDES_REV_X(x)                    (((x) & GENMASK(31, 26)) >> 26)
-#define HSIO_S6G_REVID_RCPLL_REV(x)                       (((x) << 21) & GENMASK(25, 21))
-#define HSIO_S6G_REVID_RCPLL_REV_M                        GENMASK(25, 21)
-#define HSIO_S6G_REVID_RCPLL_REV_X(x)                     (((x) & GENMASK(25, 21)) >> 21)
-#define HSIO_S6G_REVID_SER_REV(x)                         (((x) << 16) & GENMASK(20, 16))
-#define HSIO_S6G_REVID_SER_REV_M                          GENMASK(20, 16)
-#define HSIO_S6G_REVID_SER_REV_X(x)                       (((x) & GENMASK(20, 16)) >> 16)
-#define HSIO_S6G_REVID_DES_REV(x)                         (((x) << 10) & GENMASK(15, 10))
-#define HSIO_S6G_REVID_DES_REV_M                          GENMASK(15, 10)
-#define HSIO_S6G_REVID_DES_REV_X(x)                       (((x) & GENMASK(15, 10)) >> 10)
-#define HSIO_S6G_REVID_OB_REV(x)                          (((x) << 5) & GENMASK(9, 5))
-#define HSIO_S6G_REVID_OB_REV_M                           GENMASK(9, 5)
-#define HSIO_S6G_REVID_OB_REV_X(x)                        (((x) & GENMASK(9, 5)) >> 5)
-#define HSIO_S6G_REVID_IB_REV(x)                          ((x) & GENMASK(4, 0))
-#define HSIO_S6G_REVID_IB_REV_M                           GENMASK(4, 0)
-
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_WR_ONE_SHOT        BIT(31)
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_RD_ONE_SHOT        BIT(30)
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR(x)            ((x) & GENMASK(24, 0))
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR_M             GENMASK(24, 0)
-
-#define HSIO_HW_CFG_DEV2G5_10_MODE                        BIT(6)
-#define HSIO_HW_CFG_DEV1G_9_MODE                          BIT(5)
-#define HSIO_HW_CFG_DEV1G_6_MODE                          BIT(4)
-#define HSIO_HW_CFG_DEV1G_5_MODE                          BIT(3)
-#define HSIO_HW_CFG_DEV1G_4_MODE                          BIT(2)
-#define HSIO_HW_CFG_PCIE_ENA                              BIT(1)
-#define HSIO_HW_CFG_QSGMII_ENA                            BIT(0)
-
-#define HSIO_HW_QSGMII_CFG_SHYST_DIS                      BIT(3)
-#define HSIO_HW_QSGMII_CFG_E_DET_ENA                      BIT(2)
-#define HSIO_HW_QSGMII_CFG_USE_I1_ENA                     BIT(1)
-#define HSIO_HW_QSGMII_CFG_FLIP_LANES                     BIT(0)
-
-#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS(x)           (((x) << 1) & GENMASK(6, 1))
-#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS_M            GENMASK(6, 1)
-#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS_X(x)         (((x) & GENMASK(6, 1)) >> 1)
-#define HSIO_HW_QSGMII_STAT_SYNC                          BIT(0)
-
-#define HSIO_CLK_CFG_CLKDIV_PHY(x)                        (((x) << 1) & GENMASK(8, 1))
-#define HSIO_CLK_CFG_CLKDIV_PHY_M                         GENMASK(8, 1)
-#define HSIO_CLK_CFG_CLKDIV_PHY_X(x)                      (((x) & GENMASK(8, 1)) >> 1)
-#define HSIO_CLK_CFG_CLKDIV_PHY_DIS                       BIT(0)
-
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_TEMP_RD               BIT(5)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_RUN                   BIT(4)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_NO_RST                BIT(3)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_POWER_UP              BIT(2)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_CLK                   BIT(1)
-#define HSIO_TEMP_SENSOR_CTRL_SAMPLE_ENA                  BIT(0)
-
-#define HSIO_TEMP_SENSOR_CFG_RUN_WID(x)                   (((x) << 8) & GENMASK(15, 8))
-#define HSIO_TEMP_SENSOR_CFG_RUN_WID_M                    GENMASK(15, 8)
-#define HSIO_TEMP_SENSOR_CFG_RUN_WID_X(x)                 (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_TEMP_SENSOR_CFG_SAMPLE_PER(x)                ((x) & GENMASK(7, 0))
-#define HSIO_TEMP_SENSOR_CFG_SAMPLE_PER_M                 GENMASK(7, 0)
-
-#define HSIO_TEMP_SENSOR_STAT_TEMP_VALID                  BIT(8)
-#define HSIO_TEMP_SENSOR_STAT_TEMP(x)                     ((x) & GENMASK(7, 0))
-#define HSIO_TEMP_SENSOR_STAT_TEMP_M                      GENMASK(7, 0)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index e334b40..bf0c609 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2017 Microsemi Corporation
  */
 #include "ocelot.h"
+#include <soc/mscc/ocelot_hsio.h>
 
 static const u32 ocelot_ana_regmap[] = {
 	REG(ANA_ADVLEARN,                  0x009000),
diff --git a/include/soc/mscc/ocelot_hsio.h b/include/soc/mscc/ocelot_hsio.h
new file mode 100644
index 0000000..d93ddec
--- /dev/null
+++ b/include/soc/mscc/ocelot_hsio.h
@@ -0,0 +1,785 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_HSIO_H_
+#define _MSCC_OCELOT_HSIO_H_
+
+#define HSIO_PLL5G_CFG0_ENA_ROT                           BIT(31)
+#define HSIO_PLL5G_CFG0_ENA_LANE                          BIT(30)
+#define HSIO_PLL5G_CFG0_ENA_CLKTREE                       BIT(29)
+#define HSIO_PLL5G_CFG0_DIV4                              BIT(28)
+#define HSIO_PLL5G_CFG0_ENA_LOCK_FINE                     BIT(27)
+#define HSIO_PLL5G_CFG0_SELBGV820(x)                      (((x) << 23) & GENMASK(26, 23))
+#define HSIO_PLL5G_CFG0_SELBGV820_M                       GENMASK(26, 23)
+#define HSIO_PLL5G_CFG0_SELBGV820_X(x)                    (((x) & GENMASK(26, 23)) >> 23)
+#define HSIO_PLL5G_CFG0_LOOP_BW_RES(x)                    (((x) << 18) & GENMASK(22, 18))
+#define HSIO_PLL5G_CFG0_LOOP_BW_RES_M                     GENMASK(22, 18)
+#define HSIO_PLL5G_CFG0_LOOP_BW_RES_X(x)                  (((x) & GENMASK(22, 18)) >> 18)
+#define HSIO_PLL5G_CFG0_SELCPI(x)                         (((x) << 16) & GENMASK(17, 16))
+#define HSIO_PLL5G_CFG0_SELCPI_M                          GENMASK(17, 16)
+#define HSIO_PLL5G_CFG0_SELCPI_X(x)                       (((x) & GENMASK(17, 16)) >> 16)
+#define HSIO_PLL5G_CFG0_ENA_VCO_CONTRH                    BIT(15)
+#define HSIO_PLL5G_CFG0_ENA_CP1                           BIT(14)
+#define HSIO_PLL5G_CFG0_ENA_VCO_BUF                       BIT(13)
+#define HSIO_PLL5G_CFG0_ENA_BIAS                          BIT(12)
+#define HSIO_PLL5G_CFG0_CPU_CLK_DIV(x)                    (((x) << 6) & GENMASK(11, 6))
+#define HSIO_PLL5G_CFG0_CPU_CLK_DIV_M                     GENMASK(11, 6)
+#define HSIO_PLL5G_CFG0_CPU_CLK_DIV_X(x)                  (((x) & GENMASK(11, 6)) >> 6)
+#define HSIO_PLL5G_CFG0_CORE_CLK_DIV(x)                   ((x) & GENMASK(5, 0))
+#define HSIO_PLL5G_CFG0_CORE_CLK_DIV_M                    GENMASK(5, 0)
+
+#define HSIO_PLL5G_CFG1_ENA_DIRECT                        BIT(18)
+#define HSIO_PLL5G_CFG1_ROT_SPEED                         BIT(17)
+#define HSIO_PLL5G_CFG1_ROT_DIR                           BIT(16)
+#define HSIO_PLL5G_CFG1_READBACK_DATA_SEL                 BIT(15)
+#define HSIO_PLL5G_CFG1_RC_ENABLE                         BIT(14)
+#define HSIO_PLL5G_CFG1_RC_CTRL_DATA(x)                   (((x) << 6) & GENMASK(13, 6))
+#define HSIO_PLL5G_CFG1_RC_CTRL_DATA_M                    GENMASK(13, 6)
+#define HSIO_PLL5G_CFG1_RC_CTRL_DATA_X(x)                 (((x) & GENMASK(13, 6)) >> 6)
+#define HSIO_PLL5G_CFG1_QUARTER_RATE                      BIT(5)
+#define HSIO_PLL5G_CFG1_PWD_TX                            BIT(4)
+#define HSIO_PLL5G_CFG1_PWD_RX                            BIT(3)
+#define HSIO_PLL5G_CFG1_OUT_OF_RANGE_RECAL_ENA            BIT(2)
+#define HSIO_PLL5G_CFG1_HALF_RATE                         BIT(1)
+#define HSIO_PLL5G_CFG1_FORCE_SET_ENA                     BIT(0)
+
+#define HSIO_PLL5G_CFG2_ENA_TEST_MODE                     BIT(30)
+#define HSIO_PLL5G_CFG2_ENA_PFD_IN_FLIP                   BIT(29)
+#define HSIO_PLL5G_CFG2_ENA_VCO_NREF_TESTOUT              BIT(28)
+#define HSIO_PLL5G_CFG2_ENA_FBTESTOUT                     BIT(27)
+#define HSIO_PLL5G_CFG2_ENA_RCPLL                         BIT(26)
+#define HSIO_PLL5G_CFG2_ENA_CP2                           BIT(25)
+#define HSIO_PLL5G_CFG2_ENA_CLK_BYPASS1                   BIT(24)
+#define HSIO_PLL5G_CFG2_AMPC_SEL(x)                       (((x) << 16) & GENMASK(23, 16))
+#define HSIO_PLL5G_CFG2_AMPC_SEL_M                        GENMASK(23, 16)
+#define HSIO_PLL5G_CFG2_AMPC_SEL_X(x)                     (((x) & GENMASK(23, 16)) >> 16)
+#define HSIO_PLL5G_CFG2_ENA_CLK_BYPASS                    BIT(15)
+#define HSIO_PLL5G_CFG2_PWD_AMPCTRL_N                     BIT(14)
+#define HSIO_PLL5G_CFG2_ENA_AMPCTRL                       BIT(13)
+#define HSIO_PLL5G_CFG2_ENA_AMP_CTRL_FORCE                BIT(12)
+#define HSIO_PLL5G_CFG2_FRC_FSM_POR                       BIT(11)
+#define HSIO_PLL5G_CFG2_DISABLE_FSM_POR                   BIT(10)
+#define HSIO_PLL5G_CFG2_GAIN_TEST(x)                      (((x) << 5) & GENMASK(9, 5))
+#define HSIO_PLL5G_CFG2_GAIN_TEST_M                       GENMASK(9, 5)
+#define HSIO_PLL5G_CFG2_GAIN_TEST_X(x)                    (((x) & GENMASK(9, 5)) >> 5)
+#define HSIO_PLL5G_CFG2_EN_RESET_OVERRUN                  BIT(4)
+#define HSIO_PLL5G_CFG2_EN_RESET_LIM_DET                  BIT(3)
+#define HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET                  BIT(2)
+#define HSIO_PLL5G_CFG2_DISABLE_FSM                       BIT(1)
+#define HSIO_PLL5G_CFG2_ENA_GAIN_TEST                     BIT(0)
+
+#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL(x)               (((x) << 22) & GENMASK(23, 22))
+#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL_M                GENMASK(23, 22)
+#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL_X(x)             (((x) & GENMASK(23, 22)) >> 22)
+#define HSIO_PLL5G_CFG3_TESTOUT_SEL(x)                    (((x) << 19) & GENMASK(21, 19))
+#define HSIO_PLL5G_CFG3_TESTOUT_SEL_M                     GENMASK(21, 19)
+#define HSIO_PLL5G_CFG3_TESTOUT_SEL_X(x)                  (((x) & GENMASK(21, 19)) >> 19)
+#define HSIO_PLL5G_CFG3_ENA_ANA_TEST_OUT                  BIT(18)
+#define HSIO_PLL5G_CFG3_ENA_TEST_OUT                      BIT(17)
+#define HSIO_PLL5G_CFG3_SEL_FBDCLK                        BIT(16)
+#define HSIO_PLL5G_CFG3_SEL_CML_CMOS_PFD                  BIT(15)
+#define HSIO_PLL5G_CFG3_RST_FB_N                          BIT(14)
+#define HSIO_PLL5G_CFG3_FORCE_VCO_CONTRH                  BIT(13)
+#define HSIO_PLL5G_CFG3_FORCE_LO                          BIT(12)
+#define HSIO_PLL5G_CFG3_FORCE_HI                          BIT(11)
+#define HSIO_PLL5G_CFG3_FORCE_ENA                         BIT(10)
+#define HSIO_PLL5G_CFG3_FORCE_CP                          BIT(9)
+#define HSIO_PLL5G_CFG3_FBDIVSEL_TST_ENA                  BIT(8)
+#define HSIO_PLL5G_CFG3_FBDIVSEL(x)                       ((x) & GENMASK(7, 0))
+#define HSIO_PLL5G_CFG3_FBDIVSEL_M                        GENMASK(7, 0)
+
+#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL(x)                   (((x) << 16) & GENMASK(23, 16))
+#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL_M                    GENMASK(23, 16)
+#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL_X(x)                 (((x) & GENMASK(23, 16)) >> 16)
+#define HSIO_PLL5G_CFG4_IB_CTRL(x)                        ((x) & GENMASK(15, 0))
+#define HSIO_PLL5G_CFG4_IB_CTRL_M                         GENMASK(15, 0)
+
+#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL(x)                   (((x) << 16) & GENMASK(23, 16))
+#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL_M                    GENMASK(23, 16)
+#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL_X(x)                 (((x) & GENMASK(23, 16)) >> 16)
+#define HSIO_PLL5G_CFG5_OB_CTRL(x)                        ((x) & GENMASK(15, 0))
+#define HSIO_PLL5G_CFG5_OB_CTRL_M                         GENMASK(15, 0)
+
+#define HSIO_PLL5G_CFG6_REFCLK_SEL_SRC                    BIT(23)
+#define HSIO_PLL5G_CFG6_REFCLK_SEL(x)                     (((x) << 20) & GENMASK(22, 20))
+#define HSIO_PLL5G_CFG6_REFCLK_SEL_M                      GENMASK(22, 20)
+#define HSIO_PLL5G_CFG6_REFCLK_SEL_X(x)                   (((x) & GENMASK(22, 20)) >> 20)
+#define HSIO_PLL5G_CFG6_REFCLK_SRC                        BIT(19)
+#define HSIO_PLL5G_CFG6_POR_DEL_SEL(x)                    (((x) << 16) & GENMASK(17, 16))
+#define HSIO_PLL5G_CFG6_POR_DEL_SEL_M                     GENMASK(17, 16)
+#define HSIO_PLL5G_CFG6_POR_DEL_SEL_X(x)                  (((x) & GENMASK(17, 16)) >> 16)
+#define HSIO_PLL5G_CFG6_DIV125REF_SEL(x)                  (((x) << 8) & GENMASK(15, 8))
+#define HSIO_PLL5G_CFG6_DIV125REF_SEL_M                   GENMASK(15, 8)
+#define HSIO_PLL5G_CFG6_DIV125REF_SEL_X(x)                (((x) & GENMASK(15, 8)) >> 8)
+#define HSIO_PLL5G_CFG6_ENA_REFCLKC2                      BIT(7)
+#define HSIO_PLL5G_CFG6_ENA_FBCLKC2                       BIT(6)
+#define HSIO_PLL5G_CFG6_DDR_CLK_DIV(x)                    ((x) & GENMASK(5, 0))
+#define HSIO_PLL5G_CFG6_DDR_CLK_DIV_M                     GENMASK(5, 0)
+
+#define HSIO_PLL5G_STATUS0_RANGE_LIM                      BIT(12)
+#define HSIO_PLL5G_STATUS0_OUT_OF_RANGE_ERR               BIT(11)
+#define HSIO_PLL5G_STATUS0_CALIBRATION_ERR                BIT(10)
+#define HSIO_PLL5G_STATUS0_CALIBRATION_DONE               BIT(9)
+#define HSIO_PLL5G_STATUS0_READBACK_DATA(x)               (((x) << 1) & GENMASK(8, 1))
+#define HSIO_PLL5G_STATUS0_READBACK_DATA_M                GENMASK(8, 1)
+#define HSIO_PLL5G_STATUS0_READBACK_DATA_X(x)             (((x) & GENMASK(8, 1)) >> 1)
+#define HSIO_PLL5G_STATUS0_LOCK_STATUS                    BIT(0)
+
+#define HSIO_PLL5G_STATUS1_SIG_DEL(x)                     (((x) << 21) & GENMASK(28, 21))
+#define HSIO_PLL5G_STATUS1_SIG_DEL_M                      GENMASK(28, 21)
+#define HSIO_PLL5G_STATUS1_SIG_DEL_X(x)                   (((x) & GENMASK(28, 21)) >> 21)
+#define HSIO_PLL5G_STATUS1_GAIN_STAT(x)                   (((x) << 16) & GENMASK(20, 16))
+#define HSIO_PLL5G_STATUS1_GAIN_STAT_M                    GENMASK(20, 16)
+#define HSIO_PLL5G_STATUS1_GAIN_STAT_X(x)                 (((x) & GENMASK(20, 16)) >> 16)
+#define HSIO_PLL5G_STATUS1_FBCNT_DIF(x)                   (((x) << 4) & GENMASK(13, 4))
+#define HSIO_PLL5G_STATUS1_FBCNT_DIF_M                    GENMASK(13, 4)
+#define HSIO_PLL5G_STATUS1_FBCNT_DIF_X(x)                 (((x) & GENMASK(13, 4)) >> 4)
+#define HSIO_PLL5G_STATUS1_FSM_STAT(x)                    (((x) << 1) & GENMASK(3, 1))
+#define HSIO_PLL5G_STATUS1_FSM_STAT_M                     GENMASK(3, 1)
+#define HSIO_PLL5G_STATUS1_FSM_STAT_X(x)                  (((x) & GENMASK(3, 1)) >> 1)
+#define HSIO_PLL5G_STATUS1_FSM_LOCK                       BIT(0)
+
+#define HSIO_PLL5G_BIST_CFG0_PLLB_START_BIST              BIT(31)
+#define HSIO_PLL5G_BIST_CFG0_PLLB_MEAS_MODE               BIT(30)
+#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT(x)          (((x) << 20) & GENMASK(23, 20))
+#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT_M           GENMASK(23, 20)
+#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT_X(x)        (((x) & GENMASK(23, 20)) >> 20)
+#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT(x)          (((x) << 16) & GENMASK(19, 16))
+#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT_M           GENMASK(19, 16)
+#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT_X(x)        (((x) & GENMASK(19, 16)) >> 16)
+#define HSIO_PLL5G_BIST_CFG0_PLLB_DIV_FACTOR_PRE(x)       ((x) & GENMASK(15, 0))
+#define HSIO_PLL5G_BIST_CFG0_PLLB_DIV_FACTOR_PRE_M        GENMASK(15, 0)
+
+#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT(x)            (((x) << 4) & GENMASK(7, 4))
+#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT_M             GENMASK(7, 4)
+#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT_X(x)          (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_PLL5G_BIST_STAT0_PLLB_BUSY                   BIT(2)
+#define HSIO_PLL5G_BIST_STAT0_PLLB_DONE_N                 BIT(1)
+#define HSIO_PLL5G_BIST_STAT0_PLLB_FAIL                   BIT(0)
+
+#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT(x)             (((x) << 16) & GENMASK(31, 16))
+#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT_M              GENMASK(31, 16)
+#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT_X(x)           (((x) & GENMASK(31, 16)) >> 16)
+#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_REF_DIFF(x)        ((x) & GENMASK(15, 0))
+#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_REF_DIFF_M         GENMASK(15, 0)
+
+#define HSIO_RCOMP_CFG0_PWD_ENA                           BIT(13)
+#define HSIO_RCOMP_CFG0_RUN_CAL                           BIT(12)
+#define HSIO_RCOMP_CFG0_SPEED_SEL(x)                      (((x) << 10) & GENMASK(11, 10))
+#define HSIO_RCOMP_CFG0_SPEED_SEL_M                       GENMASK(11, 10)
+#define HSIO_RCOMP_CFG0_SPEED_SEL_X(x)                    (((x) & GENMASK(11, 10)) >> 10)
+#define HSIO_RCOMP_CFG0_MODE_SEL(x)                       (((x) << 8) & GENMASK(9, 8))
+#define HSIO_RCOMP_CFG0_MODE_SEL_M                        GENMASK(9, 8)
+#define HSIO_RCOMP_CFG0_MODE_SEL_X(x)                     (((x) & GENMASK(9, 8)) >> 8)
+#define HSIO_RCOMP_CFG0_FORCE_ENA                         BIT(4)
+#define HSIO_RCOMP_CFG0_RCOMP_VAL(x)                      ((x) & GENMASK(3, 0))
+#define HSIO_RCOMP_CFG0_RCOMP_VAL_M                       GENMASK(3, 0)
+
+#define HSIO_RCOMP_STATUS_BUSY                            BIT(12)
+#define HSIO_RCOMP_STATUS_DELTA_ALERT                     BIT(7)
+#define HSIO_RCOMP_STATUS_RCOMP(x)                        ((x) & GENMASK(3, 0))
+#define HSIO_RCOMP_STATUS_RCOMP_M                         GENMASK(3, 0)
+
+#define HSIO_SYNC_ETH_CFG_RSZ                             0x4
+
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC(x)             (((x) << 4) & GENMASK(7, 4))
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_M              GENMASK(7, 4)
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_X(x)           (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV(x)             (((x) << 1) & GENMASK(3, 1))
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_M              GENMASK(3, 1)
+#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_X(x)           (((x) & GENMASK(3, 1)) >> 1)
+#define HSIO_SYNC_ETH_CFG_RECO_CLK_ENA                    BIT(0)
+
+#define HSIO_SYNC_ETH_PLL_CFG_PLL_AUTO_SQUELCH_ENA        BIT(0)
+
+#define HSIO_S1G_DES_CFG_DES_PHS_CTRL(x)                  (((x) << 13) & GENMASK(16, 13))
+#define HSIO_S1G_DES_CFG_DES_PHS_CTRL_M                   GENMASK(16, 13)
+#define HSIO_S1G_DES_CFG_DES_PHS_CTRL_X(x)                (((x) & GENMASK(16, 13)) >> 13)
+#define HSIO_S1G_DES_CFG_DES_CPMD_SEL(x)                  (((x) << 11) & GENMASK(12, 11))
+#define HSIO_S1G_DES_CFG_DES_CPMD_SEL_M                   GENMASK(12, 11)
+#define HSIO_S1G_DES_CFG_DES_CPMD_SEL_X(x)                (((x) & GENMASK(12, 11)) >> 11)
+#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL(x)                 (((x) << 8) & GENMASK(10, 8))
+#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL_M                  GENMASK(10, 8)
+#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL_X(x)               (((x) & GENMASK(10, 8)) >> 8)
+#define HSIO_S1G_DES_CFG_DES_BW_ANA(x)                    (((x) << 5) & GENMASK(7, 5))
+#define HSIO_S1G_DES_CFG_DES_BW_ANA_M                     GENMASK(7, 5)
+#define HSIO_S1G_DES_CFG_DES_BW_ANA_X(x)                  (((x) & GENMASK(7, 5)) >> 5)
+#define HSIO_S1G_DES_CFG_DES_SWAP_ANA                     BIT(4)
+#define HSIO_S1G_DES_CFG_DES_BW_HYST(x)                   (((x) << 1) & GENMASK(3, 1))
+#define HSIO_S1G_DES_CFG_DES_BW_HYST_M                    GENMASK(3, 1)
+#define HSIO_S1G_DES_CFG_DES_BW_HYST_X(x)                 (((x) & GENMASK(3, 1)) >> 1)
+#define HSIO_S1G_DES_CFG_DES_SWAP_HYST                    BIT(0)
+
+#define HSIO_S1G_IB_CFG_IB_FX100_ENA                      BIT(27)
+#define HSIO_S1G_IB_CFG_ACJTAG_HYST(x)                    (((x) << 24) & GENMASK(26, 24))
+#define HSIO_S1G_IB_CFG_ACJTAG_HYST_M                     GENMASK(26, 24)
+#define HSIO_S1G_IB_CFG_ACJTAG_HYST_X(x)                  (((x) & GENMASK(26, 24)) >> 24)
+#define HSIO_S1G_IB_CFG_IB_DET_LEV(x)                     (((x) << 19) & GENMASK(21, 19))
+#define HSIO_S1G_IB_CFG_IB_DET_LEV_M                      GENMASK(21, 19)
+#define HSIO_S1G_IB_CFG_IB_DET_LEV_X(x)                   (((x) & GENMASK(21, 19)) >> 19)
+#define HSIO_S1G_IB_CFG_IB_HYST_LEV                       BIT(14)
+#define HSIO_S1G_IB_CFG_IB_ENA_CMV_TERM                   BIT(13)
+#define HSIO_S1G_IB_CFG_IB_ENA_DC_COUPLING                BIT(12)
+#define HSIO_S1G_IB_CFG_IB_ENA_DETLEV                     BIT(11)
+#define HSIO_S1G_IB_CFG_IB_ENA_HYST                       BIT(10)
+#define HSIO_S1G_IB_CFG_IB_ENA_OFFSET_COMP                BIT(9)
+#define HSIO_S1G_IB_CFG_IB_EQ_GAIN(x)                     (((x) << 6) & GENMASK(8, 6))
+#define HSIO_S1G_IB_CFG_IB_EQ_GAIN_M                      GENMASK(8, 6)
+#define HSIO_S1G_IB_CFG_IB_EQ_GAIN_X(x)                   (((x) & GENMASK(8, 6)) >> 6)
+#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ(x)             (((x) << 4) & GENMASK(5, 4))
+#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ_M              GENMASK(5, 4)
+#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ_X(x)           (((x) & GENMASK(5, 4)) >> 4)
+#define HSIO_S1G_IB_CFG_IB_RESISTOR_CTRL(x)               ((x) & GENMASK(3, 0))
+#define HSIO_S1G_IB_CFG_IB_RESISTOR_CTRL_M                GENMASK(3, 0)
+
+#define HSIO_S1G_OB_CFG_OB_SLP(x)                         (((x) << 17) & GENMASK(18, 17))
+#define HSIO_S1G_OB_CFG_OB_SLP_M                          GENMASK(18, 17)
+#define HSIO_S1G_OB_CFG_OB_SLP_X(x)                       (((x) & GENMASK(18, 17)) >> 17)
+#define HSIO_S1G_OB_CFG_OB_AMP_CTRL(x)                    (((x) << 13) & GENMASK(16, 13))
+#define HSIO_S1G_OB_CFG_OB_AMP_CTRL_M                     GENMASK(16, 13)
+#define HSIO_S1G_OB_CFG_OB_AMP_CTRL_X(x)                  (((x) & GENMASK(16, 13)) >> 13)
+#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL(x)               (((x) << 10) & GENMASK(12, 10))
+#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL_M                GENMASK(12, 10)
+#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL_X(x)             (((x) & GENMASK(12, 10)) >> 10)
+#define HSIO_S1G_OB_CFG_OB_DIS_VCM_CTRL                   BIT(9)
+#define HSIO_S1G_OB_CFG_OB_EN_MEAS_VREG                   BIT(8)
+#define HSIO_S1G_OB_CFG_OB_VCM_CTRL(x)                    (((x) << 4) & GENMASK(7, 4))
+#define HSIO_S1G_OB_CFG_OB_VCM_CTRL_M                     GENMASK(7, 4)
+#define HSIO_S1G_OB_CFG_OB_VCM_CTRL_X(x)                  (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_S1G_OB_CFG_OB_RESISTOR_CTRL(x)               ((x) & GENMASK(3, 0))
+#define HSIO_S1G_OB_CFG_OB_RESISTOR_CTRL_M                GENMASK(3, 0)
+
+#define HSIO_S1G_SER_CFG_SER_IDLE                         BIT(9)
+#define HSIO_S1G_SER_CFG_SER_DEEMPH                       BIT(8)
+#define HSIO_S1G_SER_CFG_SER_CPMD_SEL                     BIT(7)
+#define HSIO_S1G_SER_CFG_SER_SWAP_CPMD                    BIT(6)
+#define HSIO_S1G_SER_CFG_SER_ALISEL(x)                    (((x) << 4) & GENMASK(5, 4))
+#define HSIO_S1G_SER_CFG_SER_ALISEL_M                     GENMASK(5, 4)
+#define HSIO_S1G_SER_CFG_SER_ALISEL_X(x)                  (((x) & GENMASK(5, 4)) >> 4)
+#define HSIO_S1G_SER_CFG_SER_ENHYS                        BIT(3)
+#define HSIO_S1G_SER_CFG_SER_BIG_WIN                      BIT(2)
+#define HSIO_S1G_SER_CFG_SER_EN_WIN                       BIT(1)
+#define HSIO_S1G_SER_CFG_SER_ENALI                        BIT(0)
+
+#define HSIO_S1G_COMMON_CFG_SYS_RST                       BIT(31)
+#define HSIO_S1G_COMMON_CFG_SE_AUTO_SQUELCH_ENA           BIT(21)
+#define HSIO_S1G_COMMON_CFG_ENA_LANE                      BIT(18)
+#define HSIO_S1G_COMMON_CFG_PWD_RX                        BIT(17)
+#define HSIO_S1G_COMMON_CFG_PWD_TX                        BIT(16)
+#define HSIO_S1G_COMMON_CFG_LANE_CTRL(x)                  (((x) << 13) & GENMASK(15, 13))
+#define HSIO_S1G_COMMON_CFG_LANE_CTRL_M                   GENMASK(15, 13)
+#define HSIO_S1G_COMMON_CFG_LANE_CTRL_X(x)                (((x) & GENMASK(15, 13)) >> 13)
+#define HSIO_S1G_COMMON_CFG_ENA_DIRECT                    BIT(12)
+#define HSIO_S1G_COMMON_CFG_ENA_ELOOP                     BIT(11)
+#define HSIO_S1G_COMMON_CFG_ENA_FLOOP                     BIT(10)
+#define HSIO_S1G_COMMON_CFG_ENA_ILOOP                     BIT(9)
+#define HSIO_S1G_COMMON_CFG_ENA_PLOOP                     BIT(8)
+#define HSIO_S1G_COMMON_CFG_HRATE                         BIT(7)
+#define HSIO_S1G_COMMON_CFG_IF_MODE                       BIT(0)
+
+#define HSIO_S1G_PLL_CFG_PLL_ENA_FB_DIV2                  BIT(22)
+#define HSIO_S1G_PLL_CFG_PLL_ENA_RC_DIV2                  BIT(21)
+#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(x)             (((x) << 8) & GENMASK(15, 8))
+#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M              GENMASK(15, 8)
+#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_X(x)           (((x) & GENMASK(15, 8)) >> 8)
+#define HSIO_S1G_PLL_CFG_PLL_FSM_ENA                      BIT(7)
+#define HSIO_S1G_PLL_CFG_PLL_FSM_FORCE_SET_ENA            BIT(6)
+#define HSIO_S1G_PLL_CFG_PLL_FSM_OOR_RECAL_ENA            BIT(5)
+#define HSIO_S1G_PLL_CFG_PLL_RB_DATA_SEL                  BIT(3)
+
+#define HSIO_S1G_PLL_STATUS_PLL_CAL_NOT_DONE              BIT(12)
+#define HSIO_S1G_PLL_STATUS_PLL_CAL_ERR                   BIT(11)
+#define HSIO_S1G_PLL_STATUS_PLL_OUT_OF_RANGE_ERR          BIT(10)
+#define HSIO_S1G_PLL_STATUS_PLL_RB_DATA(x)                ((x) & GENMASK(7, 0))
+#define HSIO_S1G_PLL_STATUS_PLL_RB_DATA_M                 GENMASK(7, 0)
+
+#define HSIO_S1G_DFT_CFG0_LAZYBIT                         BIT(31)
+#define HSIO_S1G_DFT_CFG0_INV_DIS                         BIT(23)
+#define HSIO_S1G_DFT_CFG0_PRBS_SEL(x)                     (((x) << 20) & GENMASK(21, 20))
+#define HSIO_S1G_DFT_CFG0_PRBS_SEL_M                      GENMASK(21, 20)
+#define HSIO_S1G_DFT_CFG0_PRBS_SEL_X(x)                   (((x) & GENMASK(21, 20)) >> 20)
+#define HSIO_S1G_DFT_CFG0_TEST_MODE(x)                    (((x) << 16) & GENMASK(18, 16))
+#define HSIO_S1G_DFT_CFG0_TEST_MODE_M                     GENMASK(18, 16)
+#define HSIO_S1G_DFT_CFG0_TEST_MODE_X(x)                  (((x) & GENMASK(18, 16)) >> 16)
+#define HSIO_S1G_DFT_CFG0_RX_PHS_CORR_DIS                 BIT(4)
+#define HSIO_S1G_DFT_CFG0_RX_PDSENS_ENA                   BIT(3)
+#define HSIO_S1G_DFT_CFG0_RX_DFT_ENA                      BIT(2)
+#define HSIO_S1G_DFT_CFG0_TX_DFT_ENA                      BIT(0)
+
+#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
+#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL_M                GENMASK(17, 8)
+#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
+#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
+#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ_M                  GENMASK(7, 4)
+#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_S1G_DFT_CFG1_TX_JI_ENA                       BIT(3)
+#define HSIO_S1G_DFT_CFG1_TX_WAVEFORM_SEL                 BIT(2)
+#define HSIO_S1G_DFT_CFG1_TX_FREQOFF_DIR                  BIT(1)
+#define HSIO_S1G_DFT_CFG1_TX_FREQOFF_ENA                  BIT(0)
+
+#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
+#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL_M                GENMASK(17, 8)
+#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
+#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
+#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ_M                  GENMASK(7, 4)
+#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_S1G_DFT_CFG2_RX_JI_ENA                       BIT(3)
+#define HSIO_S1G_DFT_CFG2_RX_WAVEFORM_SEL                 BIT(2)
+#define HSIO_S1G_DFT_CFG2_RX_FREQOFF_DIR                  BIT(1)
+#define HSIO_S1G_DFT_CFG2_RX_FREQOFF_ENA                  BIT(0)
+
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_ENA             BIT(20)
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH(x)     (((x) << 16) & GENMASK(17, 16))
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_M      GENMASK(17, 16)
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_X(x)   (((x) & GENMASK(17, 16)) >> 16)
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH(x)         (((x) << 8) & GENMASK(15, 8))
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_M          GENMASK(15, 8)
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_X(x)       (((x) & GENMASK(15, 8)) >> 8)
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_LOW(x)          ((x) & GENMASK(7, 0))
+#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_LOW_M           GENMASK(7, 0)
+
+#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE(x)          (((x) << 11) & GENMASK(12, 11))
+#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE_M           GENMASK(12, 11)
+#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE_X(x)        (((x) & GENMASK(12, 11)) >> 11)
+#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_SWAP             BIT(10)
+#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_MODE             BIT(9)
+#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA              BIT(8)
+#define HSIO_S1G_MISC_CFG_RX_LPI_MODE_ENA                 BIT(5)
+#define HSIO_S1G_MISC_CFG_TX_LPI_MODE_ENA                 BIT(4)
+#define HSIO_S1G_MISC_CFG_RX_DATA_INV_ENA                 BIT(3)
+#define HSIO_S1G_MISC_CFG_TX_DATA_INV_ENA                 BIT(2)
+#define HSIO_S1G_MISC_CFG_LANE_RST                        BIT(0)
+
+#define HSIO_S1G_DFT_STATUS_PLL_BIST_NOT_DONE             BIT(7)
+#define HSIO_S1G_DFT_STATUS_PLL_BIST_FAILED               BIT(6)
+#define HSIO_S1G_DFT_STATUS_PLL_BIST_TIMEOUT_ERR          BIT(5)
+#define HSIO_S1G_DFT_STATUS_BIST_ACTIVE                   BIT(3)
+#define HSIO_S1G_DFT_STATUS_BIST_NOSYNC                   BIT(2)
+#define HSIO_S1G_DFT_STATUS_BIST_COMPLETE_N               BIT(1)
+#define HSIO_S1G_DFT_STATUS_BIST_ERROR                    BIT(0)
+
+#define HSIO_S1G_MISC_STATUS_DES_100FX_PHASE_SEL          BIT(0)
+
+#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT        BIT(31)
+#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT        BIT(30)
+#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(x)            ((x) & GENMASK(8, 0))
+#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR_M             GENMASK(8, 0)
+
+#define HSIO_S6G_DIG_CFG_GP(x)                            (((x) << 16) & GENMASK(18, 16))
+#define HSIO_S6G_DIG_CFG_GP_M                             GENMASK(18, 16)
+#define HSIO_S6G_DIG_CFG_GP_X(x)                          (((x) & GENMASK(18, 16)) >> 16)
+#define HSIO_S6G_DIG_CFG_TX_BIT_DOUBLING_MODE_ENA         BIT(7)
+#define HSIO_S6G_DIG_CFG_SIGDET_TESTMODE                  BIT(6)
+#define HSIO_S6G_DIG_CFG_SIGDET_AST(x)                    (((x) << 3) & GENMASK(5, 3))
+#define HSIO_S6G_DIG_CFG_SIGDET_AST_M                     GENMASK(5, 3)
+#define HSIO_S6G_DIG_CFG_SIGDET_AST_X(x)                  (((x) & GENMASK(5, 3)) >> 3)
+#define HSIO_S6G_DIG_CFG_SIGDET_DST(x)                    ((x) & GENMASK(2, 0))
+#define HSIO_S6G_DIG_CFG_SIGDET_DST_M                     GENMASK(2, 0)
+
+#define HSIO_S6G_DFT_CFG0_LAZYBIT                         BIT(31)
+#define HSIO_S6G_DFT_CFG0_INV_DIS                         BIT(23)
+#define HSIO_S6G_DFT_CFG0_PRBS_SEL(x)                     (((x) << 20) & GENMASK(21, 20))
+#define HSIO_S6G_DFT_CFG0_PRBS_SEL_M                      GENMASK(21, 20)
+#define HSIO_S6G_DFT_CFG0_PRBS_SEL_X(x)                   (((x) & GENMASK(21, 20)) >> 20)
+#define HSIO_S6G_DFT_CFG0_TEST_MODE(x)                    (((x) << 16) & GENMASK(18, 16))
+#define HSIO_S6G_DFT_CFG0_TEST_MODE_M                     GENMASK(18, 16)
+#define HSIO_S6G_DFT_CFG0_TEST_MODE_X(x)                  (((x) & GENMASK(18, 16)) >> 16)
+#define HSIO_S6G_DFT_CFG0_RX_PHS_CORR_DIS                 BIT(4)
+#define HSIO_S6G_DFT_CFG0_RX_PDSENS_ENA                   BIT(3)
+#define HSIO_S6G_DFT_CFG0_RX_DFT_ENA                      BIT(2)
+#define HSIO_S6G_DFT_CFG0_TX_DFT_ENA                      BIT(0)
+
+#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
+#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL_M                GENMASK(17, 8)
+#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
+#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
+#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ_M                  GENMASK(7, 4)
+#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_S6G_DFT_CFG1_TX_JI_ENA                       BIT(3)
+#define HSIO_S6G_DFT_CFG1_TX_WAVEFORM_SEL                 BIT(2)
+#define HSIO_S6G_DFT_CFG1_TX_FREQOFF_DIR                  BIT(1)
+#define HSIO_S6G_DFT_CFG1_TX_FREQOFF_ENA                  BIT(0)
+
+#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL(x)               (((x) << 8) & GENMASK(17, 8))
+#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL_M                GENMASK(17, 8)
+#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL_X(x)             (((x) & GENMASK(17, 8)) >> 8)
+#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ(x)                 (((x) << 4) & GENMASK(7, 4))
+#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ_M                  GENMASK(7, 4)
+#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ_X(x)               (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_S6G_DFT_CFG2_RX_JI_ENA                       BIT(3)
+#define HSIO_S6G_DFT_CFG2_RX_WAVEFORM_SEL                 BIT(2)
+#define HSIO_S6G_DFT_CFG2_RX_FREQOFF_DIR                  BIT(1)
+#define HSIO_S6G_DFT_CFG2_RX_FREQOFF_ENA                  BIT(0)
+
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_ENA             BIT(20)
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH(x)     (((x) << 16) & GENMASK(19, 16))
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_M      GENMASK(19, 16)
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_X(x)   (((x) & GENMASK(19, 16)) >> 16)
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH(x)         (((x) << 8) & GENMASK(15, 8))
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_M          GENMASK(15, 8)
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_X(x)       (((x) & GENMASK(15, 8)) >> 8)
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_LOW(x)          ((x) & GENMASK(7, 0))
+#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_LOW_M           GENMASK(7, 0)
+
+#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK(x)                 (((x) << 13) & GENMASK(14, 13))
+#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK_M                  GENMASK(14, 13)
+#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK_X(x)               (((x) & GENMASK(14, 13)) >> 13)
+#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE(x)          (((x) << 11) & GENMASK(12, 11))
+#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE_M           GENMASK(12, 11)
+#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE_X(x)        (((x) & GENMASK(12, 11)) >> 11)
+#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_SWAP             BIT(10)
+#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_MODE             BIT(9)
+#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_ENA              BIT(8)
+#define HSIO_S6G_MISC_CFG_RX_BUS_FLIP_ENA                 BIT(7)
+#define HSIO_S6G_MISC_CFG_TX_BUS_FLIP_ENA                 BIT(6)
+#define HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA                 BIT(5)
+#define HSIO_S6G_MISC_CFG_TX_LPI_MODE_ENA                 BIT(4)
+#define HSIO_S6G_MISC_CFG_RX_DATA_INV_ENA                 BIT(3)
+#define HSIO_S6G_MISC_CFG_TX_DATA_INV_ENA                 BIT(2)
+#define HSIO_S6G_MISC_CFG_LANE_RST                        BIT(0)
+
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0(x)               (((x) << 23) & GENMASK(28, 23))
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0_M                GENMASK(28, 23)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0_X(x)             (((x) & GENMASK(28, 23)) >> 23)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1(x)               (((x) << 18) & GENMASK(22, 18))
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1_M                GENMASK(22, 18)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1_X(x)             (((x) & GENMASK(22, 18)) >> 18)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC(x)                (((x) << 13) & GENMASK(17, 13))
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC_M                 GENMASK(17, 13)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC_X(x)              (((x) & GENMASK(17, 13)) >> 13)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS(x)             (((x) << 6) & GENMASK(8, 6))
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS_M              GENMASK(8, 6)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS_X(x)           (((x) & GENMASK(8, 6)) >> 6)
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_LEV(x)                 ((x) & GENMASK(5, 0))
+#define HSIO_S6G_OB_ANEG_CFG_AN_OB_LEV_M                  GENMASK(5, 0)
+
+#define HSIO_S6G_DFT_STATUS_PRBS_SYNC_STAT                BIT(8)
+#define HSIO_S6G_DFT_STATUS_PLL_BIST_NOT_DONE             BIT(7)
+#define HSIO_S6G_DFT_STATUS_PLL_BIST_FAILED               BIT(6)
+#define HSIO_S6G_DFT_STATUS_PLL_BIST_TIMEOUT_ERR          BIT(5)
+#define HSIO_S6G_DFT_STATUS_BIST_ACTIVE                   BIT(3)
+#define HSIO_S6G_DFT_STATUS_BIST_NOSYNC                   BIT(2)
+#define HSIO_S6G_DFT_STATUS_BIST_COMPLETE_N               BIT(1)
+#define HSIO_S6G_DFT_STATUS_BIST_ERROR                    BIT(0)
+
+#define HSIO_S6G_MISC_STATUS_DES_100FX_PHASE_SEL          BIT(0)
+
+#define HSIO_S6G_DES_CFG_DES_PHS_CTRL(x)                  (((x) << 13) & GENMASK(16, 13))
+#define HSIO_S6G_DES_CFG_DES_PHS_CTRL_M                   GENMASK(16, 13)
+#define HSIO_S6G_DES_CFG_DES_PHS_CTRL_X(x)                (((x) & GENMASK(16, 13)) >> 13)
+#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL(x)                 (((x) << 10) & GENMASK(12, 10))
+#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL_M                  GENMASK(12, 10)
+#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL_X(x)               (((x) & GENMASK(12, 10)) >> 10)
+#define HSIO_S6G_DES_CFG_DES_CPMD_SEL(x)                  (((x) << 8) & GENMASK(9, 8))
+#define HSIO_S6G_DES_CFG_DES_CPMD_SEL_M                   GENMASK(9, 8)
+#define HSIO_S6G_DES_CFG_DES_CPMD_SEL_X(x)                (((x) & GENMASK(9, 8)) >> 8)
+#define HSIO_S6G_DES_CFG_DES_BW_HYST(x)                   (((x) << 5) & GENMASK(7, 5))
+#define HSIO_S6G_DES_CFG_DES_BW_HYST_M                    GENMASK(7, 5)
+#define HSIO_S6G_DES_CFG_DES_BW_HYST_X(x)                 (((x) & GENMASK(7, 5)) >> 5)
+#define HSIO_S6G_DES_CFG_DES_SWAP_HYST                    BIT(4)
+#define HSIO_S6G_DES_CFG_DES_BW_ANA(x)                    (((x) << 1) & GENMASK(3, 1))
+#define HSIO_S6G_DES_CFG_DES_BW_ANA_M                     GENMASK(3, 1)
+#define HSIO_S6G_DES_CFG_DES_BW_ANA_X(x)                  (((x) & GENMASK(3, 1)) >> 1)
+#define HSIO_S6G_DES_CFG_DES_SWAP_ANA                     BIT(0)
+
+#define HSIO_S6G_IB_CFG_IB_SOFSI(x)                       (((x) << 29) & GENMASK(30, 29))
+#define HSIO_S6G_IB_CFG_IB_SOFSI_M                        GENMASK(30, 29)
+#define HSIO_S6G_IB_CFG_IB_SOFSI_X(x)                     (((x) & GENMASK(30, 29)) >> 29)
+#define HSIO_S6G_IB_CFG_IB_VBULK_SEL                      BIT(28)
+#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ(x)                    (((x) << 24) & GENMASK(27, 24))
+#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ_M                     GENMASK(27, 24)
+#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ_X(x)                  (((x) & GENMASK(27, 24)) >> 24)
+#define HSIO_S6G_IB_CFG_IB_ICML_ADJ(x)                    (((x) << 20) & GENMASK(23, 20))
+#define HSIO_S6G_IB_CFG_IB_ICML_ADJ_M                     GENMASK(23, 20)
+#define HSIO_S6G_IB_CFG_IB_ICML_ADJ_X(x)                  (((x) & GENMASK(23, 20)) >> 20)
+#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL(x)               (((x) << 18) & GENMASK(19, 18))
+#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL_M                GENMASK(19, 18)
+#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL_X(x)             (((x) & GENMASK(19, 18)) >> 18)
+#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(x)             (((x) << 15) & GENMASK(17, 15))
+#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M              GENMASK(17, 15)
+#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_X(x)           (((x) & GENMASK(17, 15)) >> 15)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP(x)              (((x) << 13) & GENMASK(14, 13))
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP_M               GENMASK(14, 13)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP_X(x)            (((x) & GENMASK(14, 13)) >> 13)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID(x)             (((x) << 11) & GENMASK(12, 11))
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID_M              GENMASK(12, 11)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID_X(x)           (((x) & GENMASK(12, 11)) >> 11)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP(x)              (((x) << 9) & GENMASK(10, 9))
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP_M               GENMASK(10, 9)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP_X(x)            (((x) & GENMASK(10, 9)) >> 9)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(x)          (((x) << 7) & GENMASK(8, 7))
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M           GENMASK(8, 7)
+#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_X(x)        (((x) & GENMASK(8, 7)) >> 7)
+#define HSIO_S6G_IB_CFG_IB_ANA_TEST_ENA                   BIT(6)
+#define HSIO_S6G_IB_CFG_IB_SIG_DET_ENA                    BIT(5)
+#define HSIO_S6G_IB_CFG_IB_CONCUR                         BIT(4)
+#define HSIO_S6G_IB_CFG_IB_CAL_ENA                        BIT(3)
+#define HSIO_S6G_IB_CFG_IB_SAM_ENA                        BIT(2)
+#define HSIO_S6G_IB_CFG_IB_EQZ_ENA                        BIT(1)
+#define HSIO_S6G_IB_CFG_IB_REG_ENA                        BIT(0)
+
+#define HSIO_S6G_IB_CFG1_IB_TJTAG(x)                      (((x) << 17) & GENMASK(21, 17))
+#define HSIO_S6G_IB_CFG1_IB_TJTAG_M                       GENMASK(21, 17)
+#define HSIO_S6G_IB_CFG1_IB_TJTAG_X(x)                    (((x) & GENMASK(21, 17)) >> 17)
+#define HSIO_S6G_IB_CFG1_IB_TSDET(x)                      (((x) << 12) & GENMASK(16, 12))
+#define HSIO_S6G_IB_CFG1_IB_TSDET_M                       GENMASK(16, 12)
+#define HSIO_S6G_IB_CFG1_IB_TSDET_X(x)                    (((x) & GENMASK(16, 12)) >> 12)
+#define HSIO_S6G_IB_CFG1_IB_SCALY(x)                      (((x) << 8) & GENMASK(11, 8))
+#define HSIO_S6G_IB_CFG1_IB_SCALY_M                       GENMASK(11, 8)
+#define HSIO_S6G_IB_CFG1_IB_SCALY_X(x)                    (((x) & GENMASK(11, 8)) >> 8)
+#define HSIO_S6G_IB_CFG1_IB_FILT_HP                       BIT(7)
+#define HSIO_S6G_IB_CFG1_IB_FILT_MID                      BIT(6)
+#define HSIO_S6G_IB_CFG1_IB_FILT_LP                       BIT(5)
+#define HSIO_S6G_IB_CFG1_IB_FILT_OFFSET                   BIT(4)
+#define HSIO_S6G_IB_CFG1_IB_FRC_HP                        BIT(3)
+#define HSIO_S6G_IB_CFG1_IB_FRC_MID                       BIT(2)
+#define HSIO_S6G_IB_CFG1_IB_FRC_LP                        BIT(1)
+#define HSIO_S6G_IB_CFG1_IB_FRC_OFFSET                    BIT(0)
+
+#define HSIO_S6G_IB_CFG2_IB_TINFV(x)                      (((x) << 27) & GENMASK(29, 27))
+#define HSIO_S6G_IB_CFG2_IB_TINFV_M                       GENMASK(29, 27)
+#define HSIO_S6G_IB_CFG2_IB_TINFV_X(x)                    (((x) & GENMASK(29, 27)) >> 27)
+#define HSIO_S6G_IB_CFG2_IB_OINFI(x)                      (((x) << 22) & GENMASK(26, 22))
+#define HSIO_S6G_IB_CFG2_IB_OINFI_M                       GENMASK(26, 22)
+#define HSIO_S6G_IB_CFG2_IB_OINFI_X(x)                    (((x) & GENMASK(26, 22)) >> 22)
+#define HSIO_S6G_IB_CFG2_IB_TAUX(x)                       (((x) << 19) & GENMASK(21, 19))
+#define HSIO_S6G_IB_CFG2_IB_TAUX_M                        GENMASK(21, 19)
+#define HSIO_S6G_IB_CFG2_IB_TAUX_X(x)                     (((x) & GENMASK(21, 19)) >> 19)
+#define HSIO_S6G_IB_CFG2_IB_OINFS(x)                      (((x) << 16) & GENMASK(18, 16))
+#define HSIO_S6G_IB_CFG2_IB_OINFS_M                       GENMASK(18, 16)
+#define HSIO_S6G_IB_CFG2_IB_OINFS_X(x)                    (((x) & GENMASK(18, 16)) >> 16)
+#define HSIO_S6G_IB_CFG2_IB_OCALS(x)                      (((x) << 10) & GENMASK(15, 10))
+#define HSIO_S6G_IB_CFG2_IB_OCALS_M                       GENMASK(15, 10)
+#define HSIO_S6G_IB_CFG2_IB_OCALS_X(x)                    (((x) & GENMASK(15, 10)) >> 10)
+#define HSIO_S6G_IB_CFG2_IB_TCALV(x)                      (((x) << 5) & GENMASK(9, 5))
+#define HSIO_S6G_IB_CFG2_IB_TCALV_M                       GENMASK(9, 5)
+#define HSIO_S6G_IB_CFG2_IB_TCALV_X(x)                    (((x) & GENMASK(9, 5)) >> 5)
+#define HSIO_S6G_IB_CFG2_IB_UMAX(x)                       (((x) << 3) & GENMASK(4, 3))
+#define HSIO_S6G_IB_CFG2_IB_UMAX_M                        GENMASK(4, 3)
+#define HSIO_S6G_IB_CFG2_IB_UMAX_X(x)                     (((x) & GENMASK(4, 3)) >> 3)
+#define HSIO_S6G_IB_CFG2_IB_UREG(x)                       ((x) & GENMASK(2, 0))
+#define HSIO_S6G_IB_CFG2_IB_UREG_M                        GENMASK(2, 0)
+
+#define HSIO_S6G_IB_CFG3_IB_INI_HP(x)                     (((x) << 18) & GENMASK(23, 18))
+#define HSIO_S6G_IB_CFG3_IB_INI_HP_M                      GENMASK(23, 18)
+#define HSIO_S6G_IB_CFG3_IB_INI_HP_X(x)                   (((x) & GENMASK(23, 18)) >> 18)
+#define HSIO_S6G_IB_CFG3_IB_INI_MID(x)                    (((x) << 12) & GENMASK(17, 12))
+#define HSIO_S6G_IB_CFG3_IB_INI_MID_M                     GENMASK(17, 12)
+#define HSIO_S6G_IB_CFG3_IB_INI_MID_X(x)                  (((x) & GENMASK(17, 12)) >> 12)
+#define HSIO_S6G_IB_CFG3_IB_INI_LP(x)                     (((x) << 6) & GENMASK(11, 6))
+#define HSIO_S6G_IB_CFG3_IB_INI_LP_M                      GENMASK(11, 6)
+#define HSIO_S6G_IB_CFG3_IB_INI_LP_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
+#define HSIO_S6G_IB_CFG3_IB_INI_OFFSET(x)                 ((x) & GENMASK(5, 0))
+#define HSIO_S6G_IB_CFG3_IB_INI_OFFSET_M                  GENMASK(5, 0)
+
+#define HSIO_S6G_IB_CFG4_IB_MAX_HP(x)                     (((x) << 18) & GENMASK(23, 18))
+#define HSIO_S6G_IB_CFG4_IB_MAX_HP_M                      GENMASK(23, 18)
+#define HSIO_S6G_IB_CFG4_IB_MAX_HP_X(x)                   (((x) & GENMASK(23, 18)) >> 18)
+#define HSIO_S6G_IB_CFG4_IB_MAX_MID(x)                    (((x) << 12) & GENMASK(17, 12))
+#define HSIO_S6G_IB_CFG4_IB_MAX_MID_M                     GENMASK(17, 12)
+#define HSIO_S6G_IB_CFG4_IB_MAX_MID_X(x)                  (((x) & GENMASK(17, 12)) >> 12)
+#define HSIO_S6G_IB_CFG4_IB_MAX_LP(x)                     (((x) << 6) & GENMASK(11, 6))
+#define HSIO_S6G_IB_CFG4_IB_MAX_LP_M                      GENMASK(11, 6)
+#define HSIO_S6G_IB_CFG4_IB_MAX_LP_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
+#define HSIO_S6G_IB_CFG4_IB_MAX_OFFSET(x)                 ((x) & GENMASK(5, 0))
+#define HSIO_S6G_IB_CFG4_IB_MAX_OFFSET_M                  GENMASK(5, 0)
+
+#define HSIO_S6G_IB_CFG5_IB_MIN_HP(x)                     (((x) << 18) & GENMASK(23, 18))
+#define HSIO_S6G_IB_CFG5_IB_MIN_HP_M                      GENMASK(23, 18)
+#define HSIO_S6G_IB_CFG5_IB_MIN_HP_X(x)                   (((x) & GENMASK(23, 18)) >> 18)
+#define HSIO_S6G_IB_CFG5_IB_MIN_MID(x)                    (((x) << 12) & GENMASK(17, 12))
+#define HSIO_S6G_IB_CFG5_IB_MIN_MID_M                     GENMASK(17, 12)
+#define HSIO_S6G_IB_CFG5_IB_MIN_MID_X(x)                  (((x) & GENMASK(17, 12)) >> 12)
+#define HSIO_S6G_IB_CFG5_IB_MIN_LP(x)                     (((x) << 6) & GENMASK(11, 6))
+#define HSIO_S6G_IB_CFG5_IB_MIN_LP_M                      GENMASK(11, 6)
+#define HSIO_S6G_IB_CFG5_IB_MIN_LP_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
+#define HSIO_S6G_IB_CFG5_IB_MIN_OFFSET(x)                 ((x) & GENMASK(5, 0))
+#define HSIO_S6G_IB_CFG5_IB_MIN_OFFSET_M                  GENMASK(5, 0)
+
+#define HSIO_S6G_OB_CFG_OB_IDLE                           BIT(31)
+#define HSIO_S6G_OB_CFG_OB_ENA1V_MODE                     BIT(30)
+#define HSIO_S6G_OB_CFG_OB_POL                            BIT(29)
+#define HSIO_S6G_OB_CFG_OB_POST0(x)                       (((x) << 23) & GENMASK(28, 23))
+#define HSIO_S6G_OB_CFG_OB_POST0_M                        GENMASK(28, 23)
+#define HSIO_S6G_OB_CFG_OB_POST0_X(x)                     (((x) & GENMASK(28, 23)) >> 23)
+#define HSIO_S6G_OB_CFG_OB_PREC(x)                        (((x) << 18) & GENMASK(22, 18))
+#define HSIO_S6G_OB_CFG_OB_PREC_M                         GENMASK(22, 18)
+#define HSIO_S6G_OB_CFG_OB_PREC_X(x)                      (((x) & GENMASK(22, 18)) >> 18)
+#define HSIO_S6G_OB_CFG_OB_R_ADJ_MUX                      BIT(17)
+#define HSIO_S6G_OB_CFG_OB_R_ADJ_PDR                      BIT(16)
+#define HSIO_S6G_OB_CFG_OB_POST1(x)                       (((x) << 11) & GENMASK(15, 11))
+#define HSIO_S6G_OB_CFG_OB_POST1_M                        GENMASK(15, 11)
+#define HSIO_S6G_OB_CFG_OB_POST1_X(x)                     (((x) & GENMASK(15, 11)) >> 11)
+#define HSIO_S6G_OB_CFG_OB_R_COR                          BIT(10)
+#define HSIO_S6G_OB_CFG_OB_SEL_RCTRL                      BIT(9)
+#define HSIO_S6G_OB_CFG_OB_SR_H                           BIT(8)
+#define HSIO_S6G_OB_CFG_OB_SR(x)                          (((x) << 4) & GENMASK(7, 4))
+#define HSIO_S6G_OB_CFG_OB_SR_M                           GENMASK(7, 4)
+#define HSIO_S6G_OB_CFG_OB_SR_X(x)                        (((x) & GENMASK(7, 4)) >> 4)
+#define HSIO_S6G_OB_CFG_OB_RESISTOR_CTRL(x)               ((x) & GENMASK(3, 0))
+#define HSIO_S6G_OB_CFG_OB_RESISTOR_CTRL_M                GENMASK(3, 0)
+
+#define HSIO_S6G_OB_CFG1_OB_ENA_CAS(x)                    (((x) << 6) & GENMASK(8, 6))
+#define HSIO_S6G_OB_CFG1_OB_ENA_CAS_M                     GENMASK(8, 6)
+#define HSIO_S6G_OB_CFG1_OB_ENA_CAS_X(x)                  (((x) & GENMASK(8, 6)) >> 6)
+#define HSIO_S6G_OB_CFG1_OB_LEV(x)                        ((x) & GENMASK(5, 0))
+#define HSIO_S6G_OB_CFG1_OB_LEV_M                         GENMASK(5, 0)
+
+#define HSIO_S6G_SER_CFG_SER_4TAP_ENA                     BIT(8)
+#define HSIO_S6G_SER_CFG_SER_CPMD_SEL                     BIT(7)
+#define HSIO_S6G_SER_CFG_SER_SWAP_CPMD                    BIT(6)
+#define HSIO_S6G_SER_CFG_SER_ALISEL(x)                    (((x) << 4) & GENMASK(5, 4))
+#define HSIO_S6G_SER_CFG_SER_ALISEL_M                     GENMASK(5, 4)
+#define HSIO_S6G_SER_CFG_SER_ALISEL_X(x)                  (((x) & GENMASK(5, 4)) >> 4)
+#define HSIO_S6G_SER_CFG_SER_ENHYS                        BIT(3)
+#define HSIO_S6G_SER_CFG_SER_BIG_WIN                      BIT(2)
+#define HSIO_S6G_SER_CFG_SER_EN_WIN                       BIT(1)
+#define HSIO_S6G_SER_CFG_SER_ENALI                        BIT(0)
+
+#define HSIO_S6G_COMMON_CFG_SYS_RST                       BIT(17)
+#define HSIO_S6G_COMMON_CFG_SE_DIV2_ENA                   BIT(16)
+#define HSIO_S6G_COMMON_CFG_SE_AUTO_SQUELCH_ENA           BIT(15)
+#define HSIO_S6G_COMMON_CFG_ENA_LANE                      BIT(14)
+#define HSIO_S6G_COMMON_CFG_PWD_RX                        BIT(13)
+#define HSIO_S6G_COMMON_CFG_PWD_TX                        BIT(12)
+#define HSIO_S6G_COMMON_CFG_LANE_CTRL(x)                  (((x) << 9) & GENMASK(11, 9))
+#define HSIO_S6G_COMMON_CFG_LANE_CTRL_M                   GENMASK(11, 9)
+#define HSIO_S6G_COMMON_CFG_LANE_CTRL_X(x)                (((x) & GENMASK(11, 9)) >> 9)
+#define HSIO_S6G_COMMON_CFG_ENA_DIRECT                    BIT(8)
+#define HSIO_S6G_COMMON_CFG_ENA_ELOOP                     BIT(7)
+#define HSIO_S6G_COMMON_CFG_ENA_FLOOP                     BIT(6)
+#define HSIO_S6G_COMMON_CFG_ENA_ILOOP                     BIT(5)
+#define HSIO_S6G_COMMON_CFG_ENA_PLOOP                     BIT(4)
+#define HSIO_S6G_COMMON_CFG_HRATE                         BIT(3)
+#define HSIO_S6G_COMMON_CFG_QRATE                         BIT(2)
+#define HSIO_S6G_COMMON_CFG_IF_MODE(x)                    ((x) & GENMASK(1, 0))
+#define HSIO_S6G_COMMON_CFG_IF_MODE_M                     GENMASK(1, 0)
+
+#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS(x)                  (((x) << 16) & GENMASK(17, 16))
+#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS_M                   GENMASK(17, 16)
+#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS_X(x)                (((x) & GENMASK(17, 16)) >> 16)
+#define HSIO_S6G_PLL_CFG_PLL_DIV4                         BIT(15)
+#define HSIO_S6G_PLL_CFG_PLL_ENA_ROT                      BIT(14)
+#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA(x)             (((x) << 6) & GENMASK(13, 6))
+#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_M              GENMASK(13, 6)
+#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_X(x)           (((x) & GENMASK(13, 6)) >> 6)
+#define HSIO_S6G_PLL_CFG_PLL_FSM_ENA                      BIT(5)
+#define HSIO_S6G_PLL_CFG_PLL_FSM_FORCE_SET_ENA            BIT(4)
+#define HSIO_S6G_PLL_CFG_PLL_FSM_OOR_RECAL_ENA            BIT(3)
+#define HSIO_S6G_PLL_CFG_PLL_RB_DATA_SEL                  BIT(2)
+#define HSIO_S6G_PLL_CFG_PLL_ROT_DIR                      BIT(1)
+#define HSIO_S6G_PLL_CFG_PLL_ROT_FRQ                      BIT(0)
+
+#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_DATA_N            BIT(5)
+#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_DATA_P            BIT(4)
+#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_CLK               BIT(3)
+#define HSIO_S6G_ACJTAG_CFG_OB_DIRECT                     BIT(2)
+#define HSIO_S6G_ACJTAG_CFG_ACJTAG_ENA                    BIT(1)
+#define HSIO_S6G_ACJTAG_CFG_JTAG_CTRL_ENA                 BIT(0)
+
+#define HSIO_S6G_GP_CFG_GP_MSB(x)                         (((x) << 16) & GENMASK(31, 16))
+#define HSIO_S6G_GP_CFG_GP_MSB_M                          GENMASK(31, 16)
+#define HSIO_S6G_GP_CFG_GP_MSB_X(x)                       (((x) & GENMASK(31, 16)) >> 16)
+#define HSIO_S6G_GP_CFG_GP_LSB(x)                         ((x) & GENMASK(15, 0))
+#define HSIO_S6G_GP_CFG_GP_LSB_M                          GENMASK(15, 0)
+
+#define HSIO_S6G_IB_STATUS0_IB_CAL_DONE                   BIT(8)
+#define HSIO_S6G_IB_STATUS0_IB_HP_GAIN_ACT                BIT(7)
+#define HSIO_S6G_IB_STATUS0_IB_MID_GAIN_ACT               BIT(6)
+#define HSIO_S6G_IB_STATUS0_IB_LP_GAIN_ACT                BIT(5)
+#define HSIO_S6G_IB_STATUS0_IB_OFFSET_ACT                 BIT(4)
+#define HSIO_S6G_IB_STATUS0_IB_OFFSET_VLD                 BIT(3)
+#define HSIO_S6G_IB_STATUS0_IB_OFFSET_ERR                 BIT(2)
+#define HSIO_S6G_IB_STATUS0_IB_OFFSDIR                    BIT(1)
+#define HSIO_S6G_IB_STATUS0_IB_SIG_DET                    BIT(0)
+
+#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT(x)            (((x) << 18) & GENMASK(23, 18))
+#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT_M             GENMASK(23, 18)
+#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT_X(x)          (((x) & GENMASK(23, 18)) >> 18)
+#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT(x)           (((x) << 12) & GENMASK(17, 12))
+#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT_M            GENMASK(17, 12)
+#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT_X(x)         (((x) & GENMASK(17, 12)) >> 12)
+#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT(x)            (((x) << 6) & GENMASK(11, 6))
+#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT_M             GENMASK(11, 6)
+#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT_X(x)          (((x) & GENMASK(11, 6)) >> 6)
+#define HSIO_S6G_IB_STATUS1_IB_OFFSET_STAT(x)             ((x) & GENMASK(5, 0))
+#define HSIO_S6G_IB_STATUS1_IB_OFFSET_STAT_M              GENMASK(5, 0)
+
+#define HSIO_S6G_ACJTAG_STATUS_ACJTAG_CAPT_DATA_N         BIT(2)
+#define HSIO_S6G_ACJTAG_STATUS_ACJTAG_CAPT_DATA_P         BIT(1)
+#define HSIO_S6G_ACJTAG_STATUS_IB_DIRECT                  BIT(0)
+
+#define HSIO_S6G_PLL_STATUS_PLL_CAL_NOT_DONE              BIT(10)
+#define HSIO_S6G_PLL_STATUS_PLL_CAL_ERR                   BIT(9)
+#define HSIO_S6G_PLL_STATUS_PLL_OUT_OF_RANGE_ERR          BIT(8)
+#define HSIO_S6G_PLL_STATUS_PLL_RB_DATA(x)                ((x) & GENMASK(7, 0))
+#define HSIO_S6G_PLL_STATUS_PLL_RB_DATA_M                 GENMASK(7, 0)
+
+#define HSIO_S6G_REVID_SERDES_REV(x)                      (((x) << 26) & GENMASK(31, 26))
+#define HSIO_S6G_REVID_SERDES_REV_M                       GENMASK(31, 26)
+#define HSIO_S6G_REVID_SERDES_REV_X(x)                    (((x) & GENMASK(31, 26)) >> 26)
+#define HSIO_S6G_REVID_RCPLL_REV(x)                       (((x) << 21) & GENMASK(25, 21))
+#define HSIO_S6G_REVID_RCPLL_REV_M                        GENMASK(25, 21)
+#define HSIO_S6G_REVID_RCPLL_REV_X(x)                     (((x) & GENMASK(25, 21)) >> 21)
+#define HSIO_S6G_REVID_SER_REV(x)                         (((x) << 16) & GENMASK(20, 16))
+#define HSIO_S6G_REVID_SER_REV_M                          GENMASK(20, 16)
+#define HSIO_S6G_REVID_SER_REV_X(x)                       (((x) & GENMASK(20, 16)) >> 16)
+#define HSIO_S6G_REVID_DES_REV(x)                         (((x) << 10) & GENMASK(15, 10))
+#define HSIO_S6G_REVID_DES_REV_M                          GENMASK(15, 10)
+#define HSIO_S6G_REVID_DES_REV_X(x)                       (((x) & GENMASK(15, 10)) >> 10)
+#define HSIO_S6G_REVID_OB_REV(x)                          (((x) << 5) & GENMASK(9, 5))
+#define HSIO_S6G_REVID_OB_REV_M                           GENMASK(9, 5)
+#define HSIO_S6G_REVID_OB_REV_X(x)                        (((x) & GENMASK(9, 5)) >> 5)
+#define HSIO_S6G_REVID_IB_REV(x)                          ((x) & GENMASK(4, 0))
+#define HSIO_S6G_REVID_IB_REV_M                           GENMASK(4, 0)
+
+#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_WR_ONE_SHOT        BIT(31)
+#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_RD_ONE_SHOT        BIT(30)
+#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR(x)            ((x) & GENMASK(24, 0))
+#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR_M             GENMASK(24, 0)
+
+#define HSIO_HW_CFG_DEV2G5_10_MODE                        BIT(6)
+#define HSIO_HW_CFG_DEV1G_9_MODE                          BIT(5)
+#define HSIO_HW_CFG_DEV1G_6_MODE                          BIT(4)
+#define HSIO_HW_CFG_DEV1G_5_MODE                          BIT(3)
+#define HSIO_HW_CFG_DEV1G_4_MODE                          BIT(2)
+#define HSIO_HW_CFG_PCIE_ENA                              BIT(1)
+#define HSIO_HW_CFG_QSGMII_ENA                            BIT(0)
+
+#define HSIO_HW_QSGMII_CFG_SHYST_DIS                      BIT(3)
+#define HSIO_HW_QSGMII_CFG_E_DET_ENA                      BIT(2)
+#define HSIO_HW_QSGMII_CFG_USE_I1_ENA                     BIT(1)
+#define HSIO_HW_QSGMII_CFG_FLIP_LANES                     BIT(0)
+
+#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS(x)           (((x) << 1) & GENMASK(6, 1))
+#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS_M            GENMASK(6, 1)
+#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS_X(x)         (((x) & GENMASK(6, 1)) >> 1)
+#define HSIO_HW_QSGMII_STAT_SYNC                          BIT(0)
+
+#define HSIO_CLK_CFG_CLKDIV_PHY(x)                        (((x) << 1) & GENMASK(8, 1))
+#define HSIO_CLK_CFG_CLKDIV_PHY_M                         GENMASK(8, 1)
+#define HSIO_CLK_CFG_CLKDIV_PHY_X(x)                      (((x) & GENMASK(8, 1)) >> 1)
+#define HSIO_CLK_CFG_CLKDIV_PHY_DIS                       BIT(0)
+
+#define HSIO_TEMP_SENSOR_CTRL_FORCE_TEMP_RD               BIT(5)
+#define HSIO_TEMP_SENSOR_CTRL_FORCE_RUN                   BIT(4)
+#define HSIO_TEMP_SENSOR_CTRL_FORCE_NO_RST                BIT(3)
+#define HSIO_TEMP_SENSOR_CTRL_FORCE_POWER_UP              BIT(2)
+#define HSIO_TEMP_SENSOR_CTRL_FORCE_CLK                   BIT(1)
+#define HSIO_TEMP_SENSOR_CTRL_SAMPLE_ENA                  BIT(0)
+
+#define HSIO_TEMP_SENSOR_CFG_RUN_WID(x)                   (((x) << 8) & GENMASK(15, 8))
+#define HSIO_TEMP_SENSOR_CFG_RUN_WID_M                    GENMASK(15, 8)
+#define HSIO_TEMP_SENSOR_CFG_RUN_WID_X(x)                 (((x) & GENMASK(15, 8)) >> 8)
+#define HSIO_TEMP_SENSOR_CFG_SAMPLE_PER(x)                ((x) & GENMASK(7, 0))
+#define HSIO_TEMP_SENSOR_CFG_SAMPLE_PER_M                 GENMASK(7, 0)
+
+#define HSIO_TEMP_SENSOR_STAT_TEMP_VALID                  BIT(8)
+#define HSIO_TEMP_SENSOR_STAT_TEMP(x)                     ((x) & GENMASK(7, 0))
+#define HSIO_TEMP_SENSOR_STAT_TEMP_M                      GENMASK(7, 0)
+
+#endif
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH net-next 03/10] net: mscc: ocelot: get HSIO regmap from syscon
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

HSIO address space was moved to a syscon, hence we need to get the
regmap of this address space from there and no more from the device
node.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/net/ethernet/mscc/ocelot_board.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index 26bb3b1..b7d755b 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -9,6 +9,7 @@
 #include <linux/netdevice.h>
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
 #include <linux/skbuff.h>
 
 #include "ocelot.h"
@@ -162,6 +163,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *ports, *portnp;
 	struct ocelot *ocelot;
+	struct regmap *hsio;
 	u32 val;
 
 	struct {
@@ -173,7 +175,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 		{ QSYS, "qsys" },
 		{ ANA, "ana" },
 		{ QS, "qs" },
-		{ HSIO, "hsio" },
 	};
 
 	if (!np && !pdev->dev.platform_data)
@@ -196,6 +197,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 		ocelot->targets[res[i].id] = target;
 	}
 
+	hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
+	if (IS_ERR(hsio)) {
+		dev_err(&pdev->dev, "missing hsio syscon\n");
+		return PTR_ERR(hsio);
+	}
+
+	ocelot->targets[HSIO] = hsio;
+
 	err = ocelot_chip_init(ocelot);
 	if (err)
 		return err;
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH net-next 02/10] dt-bindings: net: ocelot: remove hsio from the list of register address spaces
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

HSIO register address space should be handled outside of the MAC
controller as there are some registers for PLL5 configuring,
SerDes/switch port muxing and a thermal sensor IP, so let's remove it.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 Documentation/devicetree/bindings/mips/mscc.txt       | 16 ++++++++++++-
 Documentation/devicetree/bindings/net/mscc-ocelot.txt |  9 ++-----
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/mips/mscc.txt b/Documentation/devicetree/bindings/mips/mscc.txt
index ae15ec3..bc817e9 100644
--- a/Documentation/devicetree/bindings/mips/mscc.txt
+++ b/Documentation/devicetree/bindings/mips/mscc.txt
@@ -41,3 +41,19 @@ Example:
 		compatible = "mscc,ocelot-cpu-syscon", "syscon";
 		reg = <0x70000000 0x2c>;
 	};
+
+o HSIO regs:
+
+The SoC has a few registers (HSIO) handling miscellaneous functionalities:
+configuration and status of PLL5, RCOMP, SyncE, SerDes configurations and
+status, SerDes muxing and a thermal sensor.
+
+Required properties:
+- compatible: Should be "mscc,ocelot-hsio", "syscon", "simple-mfd"
+- reg : Should contain registers location and length
+
+Example:
+	syscon@10d0000 {
+		compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd";
+		reg = <0x10d0000 0x10000>;
+	};
diff --git a/Documentation/devicetree/bindings/net/mscc-ocelot.txt b/Documentation/devicetree/bindings/net/mscc-ocelot.txt
index 0a84711..9e5c17d 100644
--- a/Documentation/devicetree/bindings/net/mscc-ocelot.txt
+++ b/Documentation/devicetree/bindings/net/mscc-ocelot.txt
@@ -12,7 +12,6 @@ Required properties:
   - "sys"
   - "rew"
   - "qs"
-  - "hsio"
   - "qsys"
   - "ana"
   - "portX" with X from 0 to the number of last port index available on that
@@ -45,7 +44,6 @@ Example:
 		reg = <0x1010000 0x10000>,
 		      <0x1030000 0x10000>,
 		      <0x1080000 0x100>,
-		      <0x10d0000 0x10000>,
 		      <0x11e0000 0x100>,
 		      <0x11f0000 0x100>,
 		      <0x1200000 0x100>,
@@ -59,10 +57,9 @@ Example:
 		      <0x1280000 0x100>,
 		      <0x1800000 0x80000>,
 		      <0x1880000 0x10000>;
-		reg-names = "sys", "rew", "qs", "hsio", "port0",
-			    "port1", "port2", "port3", "port4", "port5",
-			    "port6", "port7", "port8", "port9", "port10",
-			    "qsys", "ana";
+		reg-names = "sys", "rew", "qs", "port0", "port1", "port2",
+			    "port3", "port4", "port5", "port6", "port7",
+			    "port8", "port9", "port10", "qsys", "ana";
 		interrupts = <21 22>;
 		interrupt-names = "xtr", "inj";
 
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH net-next 01/10] MIPS: mscc: ocelot: make HSIO registers address range a syscon
From: Quentin Schulz @ 2018-07-30 12:43 UTC (permalink / raw)
  To: alexandre.belloni, ralf, paul.burton, jhogan, robh+dt,
	mark.rutland, davem
  Cc: kishon, andrew, f.fainelli, linux-mips, devicetree, linux-kernel,
	netdev, allan.nielsen, thomas.petazzoni, Quentin Schulz
In-Reply-To: <cover.aa759035f6eefdd0bb2a5ae335dab5bd5399bd46.1532954208.git-series.quentin.schulz@bootlin.com>

HSIO contains registers for PLL5 configuration, SerDes/switch port
muxing and a thermal sensor, hence we can't keep it in the switch DT
node.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 arch/mips/boot/dts/mscc/ocelot.dtsi | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi
index afe8fc9..c51663a 100644
--- a/arch/mips/boot/dts/mscc/ocelot.dtsi
+++ b/arch/mips/boot/dts/mscc/ocelot.dtsi
@@ -96,7 +96,6 @@
 			reg = <0x1010000 0x10000>,
 			      <0x1030000 0x10000>,
 			      <0x1080000 0x100>,
-			      <0x10d0000 0x10000>,
 			      <0x11e0000 0x100>,
 			      <0x11f0000 0x100>,
 			      <0x1200000 0x100>,
@@ -110,10 +109,10 @@
 			      <0x1280000 0x100>,
 			      <0x1800000 0x80000>,
 			      <0x1880000 0x10000>;
-			reg-names = "sys", "rew", "qs", "hsio", "port0",
-				    "port1", "port2", "port3", "port4", "port5",
-				    "port6", "port7", "port8", "port9", "port10",
-				    "qsys", "ana";
+			reg-names = "sys", "rew", "qs", "port0", "port1",
+				    "port2", "port3", "port4", "port5", "port6",
+				    "port7", "port8", "port9", "port10", "qsys",
+				    "ana";
 			interrupts = <21 22>;
 			interrupt-names = "xtr", "inj";
 
@@ -220,5 +219,10 @@
 			pinctrl-0 = <&miim1>;
 			status = "disabled";
 		};
+
+		hsio: syscon@10d0000 {
+			compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd";
+			reg = <0x10d0000 0x10000>;
+		};
 	};
 };
-- 
git-series 0.9.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox