All of lore.kernel.org
 help / color / mirror / Atom feed
* [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet
@ 2021-12-11 19:57 Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state Ansuel Smith
                   ` (14 more replies)
  0 siblings, 15 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

This require the "Replace DSA dp->priv with tagger-owned storage" series
https://patchwork.kernel.org/project/netdevbpf/cover/20211209233447.336331-1-vladimir.oltean@nxp.com/
This require specifically
https://patchwork.kernel.org/project/netdevbpf/patch/20211209233447.336331-2-vladimir.oltean@nxp.com/
of Vladimir series to correctly compile and work.



Hi, this is still WIP and currently has some problem but I would love if
someone can give this a superficial review and answer to some problem
with this.

The main reason for this is that we notice some routing problem in the
switch and it seems assisted learning is needed. Considering mdio is
quite slow due to the indirect write using this Ethernet alternative way
seems to be quicker.

The qca8k switch supports a special way to pass mdio read/write request
using specially crafted Ethernet packet.
This works by putting some defined data in the Ethernet header where the
mac source and dst should be placed. The Ethernet type header is set to qca
header and is set to a mdio read/write type.
This is used to communicate to the switch that this is a special packet
and should be parsed differently.

Current implementation of this use completion API to wait for the packet
to be processed by the tagger and has a timeout that fallback to the
legacy mdio way and mutex to enforce one transaction at time.

Here I list the main concern I have about this:
- Is the changes done to the tagger acceptable? (moving stuff to global
  include)
- Is it correct to put the skb generation code in the qca8k source?
- Is the changes generally correct? (referring to how this is
  implemented with part of the implementation split between the tagger
  and the driver)

I still have to find a solution to a slowdown problem and this is where
I would love to get some hint.
Currently I still didn't find a good way to understand when the tagger
starts to accept packets and because of this the initial setup is slow
as every completion timeouts. Am I missing something or is there a way
to check for this?
After the initial slowdown, as soon as the cpu port is ready and starts
to accept packet, every transaction is near instant and no completion
timeouts.

As I said this is still WIP but it does work correctly aside from the
initial slowdown problem. (the slowdown is in the first port init and at
the first port init... from port 2 the tagger starts to accept packet
and this starts to work)

Additional changes to the original implementation:

We now have connect()/disconnect() ops for the tagger. They are used to
allocate priv data in the dsa priv. The header still has to be put in
global include to make it usable by a dsa driver.
They are called when the tag is connect to the dst and the data is freed
using discconect on tagger change.

(if someone wonder why the bind function is put at in the general setup
function it's because tag is set in the cpu port where the notifier is
still not available and we require the notifier to sen the
tag_proto_connect() event.

We now have a tag_proto_connect() for the dsa driver used to put
additional data in the tagger priv (that is actually the dsa priv).
This is called using a switch event DSA_NOTIFIER_TAG_PROTO_CONNECT.
Current use for this is adding handler for the Ethernet packet to keep
the tagger code as dumb as possible.

From what I read in the old series we probably need to drop the priv and
move to a more specific use to prevent any abuse... (or actually just
add an additional priv just for the tagger to prevent any breakage by
removing priv from dsa_port)

I still didn't investigate the slowdown problem that is still present in
some part when the port are actually init.

Hope Andrew is not too angry about this implementation but it seems
flexible and not that bad.

(also in the current code I assume a tagger is always present. This
should be the case or a check if the tagger is not present is needed?)

Also still have to work on the autocast handler but it's really a
function to add with the current implementation. Tagger is already have
support to handle them.



Additional changes to current implementation v3:

The tagger priv has changed to only implement the handler. All the
other stuff is now placed in the qca8k_priv and the tagger has to access
it under lock.
We also add MIB in Ethernet packet with an additional handler.
We also use mdio Ethernet for phy read/write but that is still dubious.
We use the new API from Vladimir to track if the master port is
operational or not. We had to track many thing to reach a usable state.
Checking if the port is UP is not enough and tracking a NETDEV_CHANGE is
also not enough since it use also for other task. The correct way was
both track for interface UP and if a qdisc was assigned to the
interface. That tells us the port (and the tagger indirectly) is ready
to accept and process packet.



Current concern are:
- Any hint about the naming? Is calling this mdio Ethernet correct?
  Should we use a more ""standard""/significant name? (considering also
  other switch will implement this)
- Should we use Ethernet packet also for phy read/write? From my test it
  works right but wonder if we should use mdio for phy and Ethernet for
  config/other task? It looks like the switch can work with both mdio
  mdio used for reg and Ethernet. (probably a locking internally)
  Also from CPU load, what is heavier? mdio or ethernet handling?
  Considering how phy works we require 3 skb allocation while for
  mdio we need at worst 9+ write.

Aside from these minor concern this should be ready for review.

v4:
- Remove duplicate patch sent by mistake.
v3:
- Include MIB with Ethernet packet.
- Include phy read/write with Ethernet packet.
- Reorganize code with new API.
- Introuce master tracking by Vladimir
v2:
- Address all suggestion from Vladimir.
  Try to generilize this with connect/disconnect function from the
  tagger and tag_proto_connect for the driver.

Ansuel Smith (11):
  net: dsa: tag_qca: convert to FIELD macro
  net: dsa: tag_qca: move define to include linux/dsa
  net: da: tag_qca: enable promisc_on_master flag
  net: dsa: tag_qca: add define for handling mdio Ethernet packet
  net: dsa: tag_qca: add define for handling MIB packet
  net: dsa: tag_qca: add support for handling mdio Ethernet and MIB
    packet
  net: dsa: qca8k: add tracking state of master port
  net: dsa: qca8k: add support for mdio read/write in Ethernet packet
  net: dsa: qca8k: add support for mib autocast in Ethernet packet
  net: dsa: qca8k: add support for phy read/write with mdio Ethernet
  net: dsa: qca8k: cache lo and hi for mdio write

Vladimir Oltean (4):
  net: dsa: provide switch operations for tracking the master state
  net: dsa: stop updating master MTU from master.c
  net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown}
  net: dsa: replay master state events in
    dsa_tree_{setup,teardown}_master

 drivers/net/dsa/qca8k.c     | 501 +++++++++++++++++++++++++++++++++++-
 drivers/net/dsa/qca8k.h     |  31 ++-
 include/linux/dsa/tag_qca.h |  79 ++++++
 include/net/dsa.h           |  11 +
 net/dsa/dsa2.c              |  81 +++++-
 net/dsa/dsa_priv.h          |  13 +
 net/dsa/master.c            |  29 +--
 net/dsa/slave.c             |  32 +++
 net/dsa/switch.c            |  15 ++
 net/dsa/tag_qca.c           |  94 +++++--
 10 files changed, 820 insertions(+), 66 deletions(-)
 create mode 100644 include/linux/dsa/tag_qca.h

-- 
2.32.0


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-12  4:22   ` Florian Fainelli
  2021-12-11 19:57 ` [net-next RFC PATCH v4 02/15] net: dsa: stop updating master MTU from master.c Ansuel Smith
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean, Ansuel Smith

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Certain drivers may need to send management traffic to the switch for
things like register access, FDB dump, etc, to accelerate what their
slow bus (SPI, I2C, MDIO) can already do.

Ethernet is faster (especially in bulk transactions) but is also more
unreliable, since the user may decide to bring the DSA master down (or
not bring it up), therefore severing the link between the host and the
attached switch.

Drivers needing Ethernet-based register access already should have
fallback logic to the slow bus if the Ethernet method fails, but that
fallback may be based on a timeout, and the I/O to the switch may slow
down to a halt if the master is down, because every Ethernet packet will
have to time out. The driver also doesn't have the option to turn off
Ethernet-based I/O momentarily, because it wouldn't know when to turn it
back on.

Which is where this change comes in. By tracking NETDEV_CHANGE,
NETDEV_UP and NETDEV_GOING_DOWN events on the DSA master, we should know
the exact interval of time during which this interface is reliably
available for traffic. Provide this information to switches so they can
use it as they wish.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 include/net/dsa.h  | 11 +++++++++++
 net/dsa/dsa2.c     | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 net/dsa/dsa_priv.h | 13 +++++++++++++
 net/dsa/slave.c    | 32 ++++++++++++++++++++++++++++++++
 net/dsa/switch.c   | 15 +++++++++++++++
 5 files changed, 117 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 8b496c7e62ef..12352aafe1cf 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -299,6 +299,10 @@ struct dsa_port {
 	struct list_head	fdbs;
 	struct list_head	mdbs;
 
+	/* Master state bits, valid only on CPU ports */
+	u8 master_admin_up:1,
+	   master_oper_up:1;
+
 	bool setup;
 };
 
@@ -1023,6 +1027,13 @@ struct dsa_switch_ops {
 	int	(*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid,
 				      u16 flags);
 	int	(*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid);
+
+	/*
+	 * DSA master tracking operations
+	 */
+	void	(*master_state_change)(struct dsa_switch *ds,
+				       const struct net_device *master,
+				       bool operational);
 };
 
 #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes)		\
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index cf6566168620..86b1e2f11469 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1245,6 +1245,52 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
 	return err;
 }
 
+static void dsa_tree_master_state_change(struct dsa_switch_tree *dst,
+					 struct net_device *master)
+{
+	struct dsa_notifier_master_state_info info;
+	struct dsa_port *cpu_dp = master->dsa_ptr;
+
+	info.master = master;
+	info.operational = cpu_dp->master_admin_up && cpu_dp->master_oper_up;
+
+	dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info);
+}
+
+void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
+					struct net_device *master,
+					bool up)
+{
+	struct dsa_port *cpu_dp = master->dsa_ptr;
+	bool notify = false;
+
+	if ((cpu_dp->master_admin_up && cpu_dp->master_oper_up) !=
+	    (up && cpu_dp->master_oper_up))
+		notify = true;
+
+	cpu_dp->master_admin_up = up;
+
+	if (notify)
+		dsa_tree_master_state_change(dst, master);
+}
+
+void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
+				       struct net_device *master,
+				       bool up)
+{
+	struct dsa_port *cpu_dp = master->dsa_ptr;
+	bool notify = false;
+
+	if ((cpu_dp->master_admin_up && cpu_dp->master_oper_up) !=
+	    (cpu_dp->master_admin_up && up))
+		notify = true;
+
+	cpu_dp->master_oper_up = up;
+
+	if (notify)
+		dsa_tree_master_state_change(dst, master);
+}
+
 static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
 {
 	struct dsa_switch_tree *dst = ds->dst;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 0db2b26b0c83..d2f2bce2391b 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -44,6 +44,7 @@ enum {
 	DSA_NOTIFIER_MRP_DEL_RING_ROLE,
 	DSA_NOTIFIER_TAG_8021Q_VLAN_ADD,
 	DSA_NOTIFIER_TAG_8021Q_VLAN_DEL,
+	DSA_NOTIFIER_MASTER_STATE_CHANGE,
 };
 
 /* DSA_NOTIFIER_AGEING_TIME */
@@ -127,6 +128,12 @@ struct dsa_notifier_tag_8021q_vlan_info {
 	u16 vid;
 };
 
+/* DSA_NOTIFIER_MASTER_STATE_CHANGE */
+struct dsa_notifier_master_state_info {
+	const struct net_device *master;
+	bool operational;
+};
+
 struct dsa_switchdev_event_work {
 	struct dsa_switch *ds;
 	int port;
@@ -507,6 +514,12 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
 			      struct net_device *master,
 			      const struct dsa_device_ops *tag_ops,
 			      const struct dsa_device_ops *old_tag_ops);
+void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
+					struct net_device *master,
+					bool up);
+void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
+				       struct net_device *master,
+				       bool up);
 unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
 void dsa_bridge_num_put(const struct net_device *bridge_dev,
 			unsigned int bridge_num);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 88f7b8686dac..5ccb0616022d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2348,6 +2348,36 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		err = dsa_port_lag_change(dp, info->lower_state_info);
 		return notifier_from_errno(err);
 	}
+	case NETDEV_CHANGE:
+	case NETDEV_UP: {
+		/* Track state of master port.
+		 * DSA driver may require the master port (and indirectly
+		 * the tagger) to be available for some special operation.
+		 */
+		if (netdev_uses_dsa(dev)) {
+			struct dsa_port *cpu_dp = dev->dsa_ptr;
+			struct dsa_switch_tree *dst = cpu_dp->ds->dst;
+
+			/* Track when the master port is UP */
+			dsa_tree_master_oper_state_change(dst, dev,
+							  netif_oper_up(dev));
+
+			/* Track when the master port is ready and can accept
+			 * packet.
+			 * NETDEV_UP event is not enough to flag a port as ready.
+			 * We also have to wait for linkwatch_do_dev to dev_activate
+			 * and emit a NETDEV_CHANGE event.
+			 * We check if a master port is ready by checking if the dev
+			 * have a qdisc assigned and is not noop.
+			 */
+			dsa_tree_master_admin_state_change(dst, dev,
+							   qdisc_tx_is_noop(dev));
+
+			return NOTIFY_OK;
+		}
+
+		return NOTIFY_DONE;
+	}
 	case NETDEV_GOING_DOWN: {
 		struct dsa_port *dp, *cpu_dp;
 		struct dsa_switch_tree *dst;
@@ -2359,6 +2389,8 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		cpu_dp = dev->dsa_ptr;
 		dst = cpu_dp->ds->dst;
 
+		dsa_tree_master_admin_state_change(dst, dev, false);
+
 		list_for_each_entry(dp, &dst->ports, list) {
 			if (!dsa_port_is_user(dp))
 				continue;
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 06948f536829..321972b85857 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -710,6 +710,18 @@ dsa_switch_mrp_del_ring_role(struct dsa_switch *ds,
 	return 0;
 }
 
+static int
+dsa_switch_master_state_change(struct dsa_switch *ds,
+			       struct dsa_notifier_master_state_info *info)
+{
+	if (!ds->ops->master_state_change)
+		return 0;
+
+	ds->ops->master_state_change(ds, info->master, info->operational);
+
+	return 0;
+}
+
 static int dsa_switch_event(struct notifier_block *nb,
 			    unsigned long event, void *info)
 {
@@ -798,6 +810,9 @@ static int dsa_switch_event(struct notifier_block *nb,
 	case DSA_NOTIFIER_TAG_8021Q_VLAN_DEL:
 		err = dsa_switch_tag_8021q_vlan_del(ds, info);
 		break;
+	case DSA_NOTIFIER_MASTER_STATE_CHANGE:
+		err = dsa_switch_master_state_change(ds, info);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		break;
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 02/15] net: dsa: stop updating master MTU from master.c
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-12  4:23   ` Florian Fainelli
  2021-12-11 19:57 ` [net-next RFC PATCH v4 03/15] net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown} Ansuel Smith
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

The dev_set_mtu() call from dsa_master_setup() has been effectively
superseded by the dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN) that is
done from dsa_slave_create() for each user port. This function also
updates the master MTU according to the largest user port MTU from the
tree. Therefore, updating the master MTU through a separate code path
isn't needed.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/master.c | 25 +------------------------
 1 file changed, 1 insertion(+), 24 deletions(-)

diff --git a/net/dsa/master.c b/net/dsa/master.c
index e8e19857621b..f4efb244f91d 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -330,28 +330,13 @@ static const struct attribute_group dsa_group = {
 	.attrs	= dsa_slave_attrs,
 };
 
-static void dsa_master_reset_mtu(struct net_device *dev)
-{
-	int err;
-
-	rtnl_lock();
-	err = dev_set_mtu(dev, ETH_DATA_LEN);
-	if (err)
-		netdev_dbg(dev,
-			   "Unable to reset MTU to exclude DSA overheads\n");
-	rtnl_unlock();
-}
-
 static struct lock_class_key dsa_master_addr_list_lock_key;
 
 int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
 {
-	const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops;
 	struct dsa_switch *ds = cpu_dp->ds;
 	struct device_link *consumer_link;
-	int mtu, ret;
-
-	mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops);
+	int ret;
 
 	/* The DSA master must use SET_NETDEV_DEV for this to work. */
 	consumer_link = device_link_add(ds->dev, dev->dev.parent,
@@ -361,13 +346,6 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
 			   "Failed to create a device link to DSA switch %s\n",
 			   dev_name(ds->dev));
 
-	rtnl_lock();
-	ret = dev_set_mtu(dev, mtu);
-	rtnl_unlock();
-	if (ret)
-		netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n",
-			    ret, mtu);
-
 	/* If we use a tagging format that doesn't have an ethertype
 	 * field, make sure that all packets from this point on get
 	 * sent to the tag format's receive function.
@@ -405,7 +383,6 @@ void dsa_master_teardown(struct net_device *dev)
 	sysfs_remove_group(&dev->dev.kobj, &dsa_group);
 	dsa_netdev_ops_set(dev, NULL);
 	dsa_master_ethtool_teardown(dev);
-	dsa_master_reset_mtu(dev);
 	dsa_master_set_promiscuity(dev, -1);
 
 	dev->dsa_ptr = NULL;
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 03/15] net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown}
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 02/15] net: dsa: stop updating master MTU from master.c Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-12  4:24   ` Florian Fainelli
  2021-12-11 19:57 ` [net-next RFC PATCH v4 04/15] net: dsa: replay master state events in dsa_tree_{setup,teardown}_master Ansuel Smith
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean, Ansuel Smith

From: Vladimir Oltean <vladimir.oltean@nxp.com>

DSA needs to simulate master tracking events when a binding is first
with a DSA master established and torn down, in order to give drivers
the simplifying guarantee that ->master_state_change calls are made
only when the master's readiness state to pass traffic changes.
master_state_change() provide a operational bool that DSA driver can use
to understand if DSA master is operational or not.
To avoid races, we need to block the reception of
NETDEV_UP/NETDEV_CHANGE/NETDEV_GOING_DOWN events in the netdev notifier
chain while we are changing the master's dev->dsa_ptr (this changes what
netdev_uses_dsa(dev) reports).

The dsa_master_setup() and dsa_master_teardown() functions optionally
require the rtnl_mutex to be held, if the tagger needs the master to be
promiscuous, these functions call dev_set_promiscuity(). Move the
rtnl_lock() from that function and make it top-level.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 net/dsa/dsa2.c   | 8 ++++++++
 net/dsa/master.c | 4 ++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 86b1e2f11469..90e29dd42d3d 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1030,6 +1030,8 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
 	struct dsa_port *dp;
 	int err;
 
+	rtnl_lock();
+
 	list_for_each_entry(dp, &dst->ports, list) {
 		if (dsa_port_is_cpu(dp)) {
 			err = dsa_master_setup(dp->master, dp);
@@ -1038,6 +1040,8 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
 		}
 	}
 
+	rtnl_unlock();
+
 	return 0;
 }
 
@@ -1045,9 +1049,13 @@ static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
 {
 	struct dsa_port *dp;
 
+	rtnl_lock();
+
 	list_for_each_entry(dp, &dst->ports, list)
 		if (dsa_port_is_cpu(dp))
 			dsa_master_teardown(dp->master);
+
+	rtnl_unlock();
 }
 
 static int dsa_tree_setup_lags(struct dsa_switch_tree *dst)
diff --git a/net/dsa/master.c b/net/dsa/master.c
index f4efb244f91d..2199104ca7df 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -267,9 +267,9 @@ static void dsa_master_set_promiscuity(struct net_device *dev, int inc)
 	if (!ops->promisc_on_master)
 		return;
 
-	rtnl_lock();
+	ASSERT_RTNL();
+
 	dev_set_promiscuity(dev, inc);
-	rtnl_unlock();
 }
 
 static ssize_t tagging_show(struct device *d, struct device_attribute *attr,
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 04/15] net: dsa: replay master state events in dsa_tree_{setup,teardown}_master
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (2 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 03/15] net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown} Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-12  4:25   ` Florian Fainelli
  2021-12-11 19:57 ` [net-next RFC PATCH v4 05/15] net: dsa: tag_qca: convert to FIELD macro Ansuel Smith
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean, Ansuel Smith

From: Vladimir Oltean <vladimir.oltean@nxp.com>

In order for switch driver to be able to make simple and reliable use of
the master tracking operations, they must also be notified of the
initial state of the DSA master, not just of the changes. This is
because they might enable certain features only during the time when
they know that the DSA master is up and running.

Therefore, this change explicitly checks the state of the DSA master
under the same rtnl_mutex as we were holding during the
dsa_master_setup() and dsa_master_teardown() call. The idea being that
if the DSA master became operational in between the moment in which it
became a DSA master (dsa_master_setup set dev->dsa_ptr) and the moment
when we checked for the master being up, there is a chance that we
would emit a ->master_state_change() call with no actual state change.
We need to avoid that by serializing the concurrent netdevice event with
us. If the netdevice event started before, we force it to finish before
we begin, because we take rtnl_lock before making netdev_uses_dsa()
return true. So we also handle that early event and do nothing on it.
Similarly, if the dev_open() attempt is concurrent with us, it will
attempt to take the rtnl_mutex, but we're holding it. We'll see that
the master flag IFF_UP isn't set, then when we release the rtnl_mutex
we'll process the NETDEV_UP notifier.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 net/dsa/dsa2.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 90e29dd42d3d..76cf9ee1153c 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1034,9 +1034,18 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
 
 	list_for_each_entry(dp, &dst->ports, list) {
 		if (dsa_port_is_cpu(dp)) {
-			err = dsa_master_setup(dp->master, dp);
+			struct net_device *master = dp->master;
+			bool admin_up = (master->flags & IFF_UP) &&
+					!qdisc_tx_is_noop(master);
+
+			err = dsa_master_setup(master, dp);
 			if (err)
 				return err;
+
+			/* Replay master state event */
+			dsa_tree_master_admin_state_change(dst, master, admin_up);
+			dsa_tree_master_oper_state_change(dst, master,
+							  netif_oper_up(master));
 		}
 	}
 
@@ -1051,9 +1060,19 @@ static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
 
 	rtnl_lock();
 
-	list_for_each_entry(dp, &dst->ports, list)
-		if (dsa_port_is_cpu(dp))
-			dsa_master_teardown(dp->master);
+	list_for_each_entry(dp, &dst->ports, list) {
+		if (dsa_port_is_cpu(dp)) {
+			struct net_device *master = dp->master;
+
+			/* Synthesizing an "admin down" state is sufficient for
+			 * the switches to get a notification if the master is
+			 * currently up and running.
+			 */
+			dsa_tree_master_admin_state_change(dst, master, false);
+
+			dsa_master_teardown(master);
+		}
+	}
 
 	rtnl_unlock();
 }
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 05/15] net: dsa: tag_qca: convert to FIELD macro
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (3 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 04/15] net: dsa: replay master state events in dsa_tree_{setup,teardown}_master Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 06/15] net: dsa: tag_qca: move define to include linux/dsa Ansuel Smith
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Convert driver to FIELD macro to drop redundant define.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 net/dsa/tag_qca.c | 34 +++++++++++++++-------------------
 1 file changed, 15 insertions(+), 19 deletions(-)

diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 1ea9401b8ace..55fa6b96b4eb 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -4,29 +4,24 @@
  */
 
 #include <linux/etherdevice.h>
+#include <linux/bitfield.h>
 
 #include "dsa_priv.h"
 
 #define QCA_HDR_LEN	2
 #define QCA_HDR_VERSION	0x2
 
-#define QCA_HDR_RECV_VERSION_MASK	GENMASK(15, 14)
-#define QCA_HDR_RECV_VERSION_S		14
-#define QCA_HDR_RECV_PRIORITY_MASK	GENMASK(13, 11)
-#define QCA_HDR_RECV_PRIORITY_S		11
-#define QCA_HDR_RECV_TYPE_MASK		GENMASK(10, 6)
-#define QCA_HDR_RECV_TYPE_S		6
+#define QCA_HDR_RECV_VERSION		GENMASK(15, 14)
+#define QCA_HDR_RECV_PRIORITY		GENMASK(13, 11)
+#define QCA_HDR_RECV_TYPE		GENMASK(10, 6)
 #define QCA_HDR_RECV_FRAME_IS_TAGGED	BIT(3)
-#define QCA_HDR_RECV_SOURCE_PORT_MASK	GENMASK(2, 0)
-
-#define QCA_HDR_XMIT_VERSION_MASK	GENMASK(15, 14)
-#define QCA_HDR_XMIT_VERSION_S		14
-#define QCA_HDR_XMIT_PRIORITY_MASK	GENMASK(13, 11)
-#define QCA_HDR_XMIT_PRIORITY_S		11
-#define QCA_HDR_XMIT_CONTROL_MASK	GENMASK(10, 8)
-#define QCA_HDR_XMIT_CONTROL_S		8
+#define QCA_HDR_RECV_SOURCE_PORT	GENMASK(2, 0)
+
+#define QCA_HDR_XMIT_VERSION		GENMASK(15, 14)
+#define QCA_HDR_XMIT_PRIORITY		GENMASK(13, 11)
+#define QCA_HDR_XMIT_CONTROL		GENMASK(10, 8)
 #define QCA_HDR_XMIT_FROM_CPU		BIT(7)
-#define QCA_HDR_XMIT_DP_BIT_MASK	GENMASK(6, 0)
+#define QCA_HDR_XMIT_DP_BIT		GENMASK(6, 0)
 
 static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -40,8 +35,9 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
 	phdr = dsa_etype_header_pos_tx(skb);
 
 	/* Set the version field, and set destination port information */
-	hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S |
-		QCA_HDR_XMIT_FROM_CPU | BIT(dp->index);
+	hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
+	hdr |= QCA_HDR_XMIT_FROM_CPU;
+	hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(dp->index));
 
 	*phdr = htons(hdr);
 
@@ -62,7 +58,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 	hdr = ntohs(*phdr);
 
 	/* Make sure the version is correct */
-	ver = (hdr & QCA_HDR_RECV_VERSION_MASK) >> QCA_HDR_RECV_VERSION_S;
+	ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
 	if (unlikely(ver != QCA_HDR_VERSION))
 		return NULL;
 
@@ -71,7 +67,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 	dsa_strip_etype_header(skb, QCA_HDR_LEN);
 
 	/* Get source port information */
-	port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK);
+	port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr);
 
 	skb->dev = dsa_master_find_slave(dev, 0, port);
 	if (!skb->dev)
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 06/15] net: dsa: tag_qca: move define to include linux/dsa
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (4 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 05/15] net: dsa: tag_qca: convert to FIELD macro Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 07/15] net: da: tag_qca: enable promisc_on_master flag Ansuel Smith
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Move tag_qca define to include dir linux/dsa as the qca8k require access
to the tagger define to support in-band mdio read/write using ethernet
packet.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 include/linux/dsa/tag_qca.h | 21 +++++++++++++++++++++
 net/dsa/tag_qca.c           | 16 +---------------
 2 files changed, 22 insertions(+), 15 deletions(-)
 create mode 100644 include/linux/dsa/tag_qca.h

diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h
new file mode 100644
index 000000000000..c02d2d39ff4a
--- /dev/null
+++ b/include/linux/dsa/tag_qca.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __TAG_QCA_H
+#define __TAG_QCA_H
+
+#define QCA_HDR_LEN	2
+#define QCA_HDR_VERSION	0x2
+
+#define QCA_HDR_RECV_VERSION		GENMASK(15, 14)
+#define QCA_HDR_RECV_PRIORITY		GENMASK(13, 11)
+#define QCA_HDR_RECV_TYPE		GENMASK(10, 6)
+#define QCA_HDR_RECV_FRAME_IS_TAGGED	BIT(3)
+#define QCA_HDR_RECV_SOURCE_PORT	GENMASK(2, 0)
+
+#define QCA_HDR_XMIT_VERSION		GENMASK(15, 14)
+#define QCA_HDR_XMIT_PRIORITY		GENMASK(13, 11)
+#define QCA_HDR_XMIT_CONTROL		GENMASK(10, 8)
+#define QCA_HDR_XMIT_FROM_CPU		BIT(7)
+#define QCA_HDR_XMIT_DP_BIT		GENMASK(6, 0)
+
+#endif /* __TAG_QCA_H */
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 55fa6b96b4eb..34e565e00ece 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -5,24 +5,10 @@
 
 #include <linux/etherdevice.h>
 #include <linux/bitfield.h>
+#include <linux/dsa/tag_qca.h>
 
 #include "dsa_priv.h"
 
-#define QCA_HDR_LEN	2
-#define QCA_HDR_VERSION	0x2
-
-#define QCA_HDR_RECV_VERSION		GENMASK(15, 14)
-#define QCA_HDR_RECV_PRIORITY		GENMASK(13, 11)
-#define QCA_HDR_RECV_TYPE		GENMASK(10, 6)
-#define QCA_HDR_RECV_FRAME_IS_TAGGED	BIT(3)
-#define QCA_HDR_RECV_SOURCE_PORT	GENMASK(2, 0)
-
-#define QCA_HDR_XMIT_VERSION		GENMASK(15, 14)
-#define QCA_HDR_XMIT_PRIORITY		GENMASK(13, 11)
-#define QCA_HDR_XMIT_CONTROL		GENMASK(10, 8)
-#define QCA_HDR_XMIT_FROM_CPU		BIT(7)
-#define QCA_HDR_XMIT_DP_BIT		GENMASK(6, 0)
-
 static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dsa_port *dp = dsa_slave_to_port(dev);
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 07/15] net: da: tag_qca: enable promisc_on_master flag
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (5 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 06/15] net: dsa: tag_qca: move define to include linux/dsa Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 08/15] net: dsa: tag_qca: add define for handling mdio Ethernet packet Ansuel Smith
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Ethernet MDIO packets are non-standard and DSA master expects the first
6 octets to be the MAC DA. To address these kind of packet, enable
promisc_on_master flag for the tagger.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 net/dsa/tag_qca.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 34e565e00ece..f8df49d5956f 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -68,6 +68,7 @@ static const struct dsa_device_ops qca_netdev_ops = {
 	.xmit	= qca_tag_xmit,
 	.rcv	= qca_tag_rcv,
 	.needed_headroom = QCA_HDR_LEN,
+	.promisc_on_master = true,
 };
 
 MODULE_LICENSE("GPL");
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 08/15] net: dsa: tag_qca: add define for handling mdio Ethernet packet
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (6 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 07/15] net: da: tag_qca: enable promisc_on_master flag Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 09/15] net: dsa: tag_qca: add define for handling MIB packet Ansuel Smith
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Add all the required define to prepare support for mdio read/write in
Ethernet packet. Any packet of this type has to be dropped as the only
use of these special packet is receive ack for an mdio write request or
receive data for an mdio read request.
A struct is used that emulates the Ethernet header but is used for a
different purpose.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 include/linux/dsa/tag_qca.h | 41 +++++++++++++++++++++++++++++++++++++
 net/dsa/tag_qca.c           | 13 +++++++++---
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h
index c02d2d39ff4a..578a4aeafd92 100644
--- a/include/linux/dsa/tag_qca.h
+++ b/include/linux/dsa/tag_qca.h
@@ -12,10 +12,51 @@
 #define QCA_HDR_RECV_FRAME_IS_TAGGED	BIT(3)
 #define QCA_HDR_RECV_SOURCE_PORT	GENMASK(2, 0)
 
+/* Packet type for recv */
+#define QCA_HDR_RECV_TYPE_NORMAL	0x0
+#define QCA_HDR_RECV_TYPE_MIB		0x1
+#define QCA_HDR_RECV_TYPE_RW_REG_ACK	0x2
+
 #define QCA_HDR_XMIT_VERSION		GENMASK(15, 14)
 #define QCA_HDR_XMIT_PRIORITY		GENMASK(13, 11)
 #define QCA_HDR_XMIT_CONTROL		GENMASK(10, 8)
 #define QCA_HDR_XMIT_FROM_CPU		BIT(7)
 #define QCA_HDR_XMIT_DP_BIT		GENMASK(6, 0)
 
+/* Packet type for xmit */
+#define QCA_HDR_XMIT_TYPE_NORMAL	0x0
+#define QCA_HDR_XMIT_TYPE_RW_REG	0x1
+
+#define MDIO_CHECK_CODE_VAL		0x5
+
+/* Specific define for in-band MDIO read/write with Ethernet packet */
+#define QCA_HDR_MDIO_SEQ_LEN		4 /* 4 byte for the seq */
+#define QCA_HDR_MDIO_COMMAND_LEN	4 /* 4 byte for the command */
+#define QCA_HDR_MDIO_DATA1_LEN		4 /* First 4 byte for the mdio data */
+#define QCA_HDR_MDIO_HEADER_LEN		(QCA_HDR_MDIO_SEQ_LEN + \
+					QCA_HDR_MDIO_COMMAND_LEN + \
+					QCA_HDR_MDIO_DATA1_LEN)
+
+#define QCA_HDR_MDIO_DATA2_LEN		12 /* Other 12 byte for the mdio data */
+#define QCA_HDR_MDIO_PADDING_LEN	34 /* Padding to reach the min Ethernet packet */
+
+#define QCA_HDR_MDIO_PKG_LEN		(QCA_HDR_MDIO_HEADER_LEN + \
+					QCA_HDR_LEN + \
+					QCA_HDR_MDIO_DATA2_LEN + \
+					QCA_HDR_MDIO_PADDING_LEN)
+
+#define QCA_HDR_MDIO_SEQ_NUM		GENMASK(31, 0)  /* 63, 32 */
+#define QCA_HDR_MDIO_CHECK_CODE		GENMASK(31, 29) /* 31, 29 */
+#define QCA_HDR_MDIO_CMD		BIT(28)		/* 28 */
+#define QCA_HDR_MDIO_LENGTH		GENMASK(23, 20) /* 23, 20 */
+#define QCA_HDR_MDIO_ADDR		GENMASK(18, 0)  /* 18, 0 */
+
+/* Special struct emulating a Ethernet header */
+struct mdio_ethhdr {
+	u32 command;		/* command bit 31:0 */
+	u32 seq;		/* seq 63:32 */
+	u32 mdio_data;		/* first 4byte mdio */
+	u16 hdr;		/* qca hdr */
+} __packed;
+
 #endif /* __TAG_QCA_H */
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index f8df49d5956f..b91f9f1b2deb 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -32,10 +32,10 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 {
-	u8 ver;
-	u16  hdr;
-	int port;
+	u16  hdr, pk_type;
 	__be16 *phdr;
+	int port;
+	u8 ver;
 
 	if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
 		return NULL;
@@ -48,6 +48,13 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 	if (unlikely(ver != QCA_HDR_VERSION))
 		return NULL;
 
+	/* Get pk type */
+	pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
+
+	/* MDIO read/write packet */
+	if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK)
+		return NULL;
+
 	/* Remove QCA tag and recalculate checksum */
 	skb_pull_rcsum(skb, QCA_HDR_LEN);
 	dsa_strip_etype_header(skb, QCA_HDR_LEN);
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 09/15] net: dsa: tag_qca: add define for handling MIB packet
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (7 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 08/15] net: dsa: tag_qca: add define for handling mdio Ethernet packet Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 10/15] net: dsa: tag_qca: add support for handling mdio Ethernet and " Ansuel Smith
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Add struct to correctly parse a mib Ethernet packet.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 include/linux/dsa/tag_qca.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h
index 578a4aeafd92..f3369b939107 100644
--- a/include/linux/dsa/tag_qca.h
+++ b/include/linux/dsa/tag_qca.h
@@ -59,4 +59,21 @@ struct mdio_ethhdr {
 	u16 hdr;		/* qca hdr */
 } __packed;
 
+enum mdio_cmd {
+	MDIO_WRITE = 0x0,
+	MDIO_READ
+};
+
+struct mib_ethhdr {
+	u32 data[3];		/* first 3 mib counter */
+	__be16 hdr;		/* qca hdr */
+} __packed;
+
+struct tag_qca_priv {
+	void (*rw_reg_ack_handler)(struct dsa_port *dp,
+				   struct sk_buff *skb);
+	void (*mib_autocast_handler)(struct dsa_port *dp,
+				     struct sk_buff *skb);
+};
+
 #endif /* __TAG_QCA_H */
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 10/15] net: dsa: tag_qca: add support for handling mdio Ethernet and MIB packet
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (8 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 09/15] net: dsa: tag_qca: add define for handling MIB packet Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 11/15] net: dsa: qca8k: add tracking state of master port Ansuel Smith
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Add connect/disconnect helper to assign private struct to the cpu port
dsa priv.
Add support for Ethernet mdio packet and MIB packet if the dsa driver
provide an handler to correctly parse and elaborate the data.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 net/dsa/tag_qca.c | 52 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index b91f9f1b2deb..7edc198fdb60 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -32,11 +32,15 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 {
+	struct dsa_port *dp = dev->dsa_ptr;
+	struct tag_qca_priv *priv;
 	u16  hdr, pk_type;
 	__be16 *phdr;
 	int port;
 	u8 ver;
 
+	priv = dp->ds->tagger_data;
+
 	if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
 		return NULL;
 
@@ -51,9 +55,19 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 	/* Get pk type */
 	pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
 
-	/* MDIO read/write packet */
-	if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK)
+	/* Ethernet MDIO read/write packet */
+	if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) {
+		if (priv->rw_reg_ack_handler)
+			priv->rw_reg_ack_handler(dp, skb);
+		return NULL;
+	}
+
+	/* Ethernet MIB counter packet */
+	if (pk_type == QCA_HDR_RECV_TYPE_MIB) {
+		if (priv->mib_autocast_handler)
+			priv->mib_autocast_handler(dp, skb);
 		return NULL;
+	}
 
 	/* Remove QCA tag and recalculate checksum */
 	skb_pull_rcsum(skb, QCA_HDR_LEN);
@@ -69,9 +83,43 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
 	return skb;
 }
 
+static int qca_tag_connect(struct dsa_switch_tree *dst)
+{
+	struct tag_qca_priv *priv;
+	struct dsa_port *dp;
+
+	list_for_each_entry(dp, &dst->ports, list) {
+		if (dp->ds->tagger_data)
+			continue;
+
+		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+		if (!priv)
+			return -ENOMEM;
+
+		dp->ds->tagger_data = priv;
+	}
+
+	return 0;
+}
+
+static void qca_tag_disconnect(struct dsa_switch_tree *dst)
+{
+	struct dsa_port *dp;
+
+	list_for_each_entry(dp, &dst->ports, list) {
+		if (dp->ds->tagger_data)
+			continue;
+
+		kfree(dp->ds->tagger_data);
+		dp->ds->tagger_data = NULL;
+	}
+}
+
 static const struct dsa_device_ops qca_netdev_ops = {
 	.name	= "qca",
 	.proto	= DSA_TAG_PROTO_QCA,
+	.connect = qca_tag_connect,
+	.disconnect = qca_tag_disconnect,
 	.xmit	= qca_tag_xmit,
 	.rcv	= qca_tag_rcv,
 	.needed_headroom = QCA_HDR_LEN,
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 11/15] net: dsa: qca8k: add tracking state of master port
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (9 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 10/15] net: dsa: tag_qca: add support for handling mdio Ethernet and " Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet Ansuel Smith
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

MDIO/MIB Ethernet require the master port and the tagger availabale to
correctly work. Use the new api master_state_change to track when master
is operational or not and set a bool in qca8k_priv.
This bool will later be used by mdio read/write and mib request to
correctly use the working function.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca8k.c | 13 +++++++++++++
 drivers/net/dsa/qca8k.h |  1 +
 2 files changed, 14 insertions(+)

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 039694518788..905fae26e05b 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -2383,6 +2383,18 @@ qca8k_port_lag_leave(struct dsa_switch *ds, int port,
 	return qca8k_lag_refresh_portmap(ds, port, lag, true);
 }
 
+static void
+qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
+		    bool operational)
+{
+	struct qca8k_priv *priv = ds->priv;
+
+	if (operational)
+		priv->master_oper = true;
+	else
+		priv->master_oper = false;
+}
+
 static const struct dsa_switch_ops qca8k_switch_ops = {
 	.get_tag_protocol	= qca8k_get_tag_protocol,
 	.setup			= qca8k_setup,
@@ -2418,6 +2430,7 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
 	.get_phy_flags		= qca8k_get_phy_flags,
 	.port_lag_join		= qca8k_port_lag_join,
 	.port_lag_leave		= qca8k_port_lag_leave,
+	.master_state_change	= qca8k_master_change,
 };
 
 static int qca8k_read_switch_id(struct qca8k_priv *priv)
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index ab4a417b25a9..fb98536bf3e8 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -342,6 +342,7 @@ struct qca8k_priv {
 	u8 mirror_rx;
 	u8 mirror_tx;
 	u8 lag_hash_mode;
+	bool master_oper; /* Track if mdio/mib Ethernet is available */
 	bool legacy_phy_port_mapping;
 	struct qca8k_ports_config ports_config;
 	struct regmap *regmap;
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (10 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 11/15] net: dsa: qca8k: add tracking state of master port Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-12  4:12   ` Florian Fainelli
  2021-12-11 19:57 ` [net-next RFC PATCH v4 13/15] net: dsa: qca8k: add support for mib autocast " Ansuel Smith
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Add qca8k side support for mdio read/write in Ethernet packet.
qca8k supports some specially crafted Ethernet packet that can be used
for mdio read/write instead of the legacy method uart/internal mdio.
This add support for the qca8k side to craft the packet and enqueue it.
Each port and the qca8k_priv have a special struct to put data in it.
The completion API is used to wait for the packet to be received back
with the requested data.

The various steps are:
1. Craft the special packet with the qca hdr set to mdio read/write
   mode.
2. Set the lock in the dedicated mdio struct.
3. Reinit the completion.
4. Enqueue the packet.
5. Wait the packet to be received.
6. Use the data set by the tagger to complete the mdio operation.

If the completion timeouts or the ack value is not true, the legacy
mdio way is used.

It has to be considered that in the initial setup mdio is still used and
mdio is still used until DSA is ready to accept and tag packet.

tag_proto_connect() is used to fill the required handler for the tagger
to correctly parse and elaborate the special Ethernet mdio packet.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca8k.c     | 189 +++++++++++++++++++++++++++++++++++-
 drivers/net/dsa/qca8k.h     |  12 +++
 include/linux/dsa/tag_qca.h |   2 +-
 3 files changed, 201 insertions(+), 2 deletions(-)

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 905fae26e05b..0f1a604f015e 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -20,6 +20,7 @@
 #include <linux/phylink.h>
 #include <linux/gpio/consumer.h>
 #include <linux/etherdevice.h>
+#include <linux/dsa/tag_qca.h>
 
 #include "qca8k.h"
 
@@ -170,6 +171,157 @@ qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
 	return regmap_update_bits(priv->regmap, reg, mask, write_val);
 }
 
+static void qca8k_rw_reg_ack_handler(struct dsa_port *dp, struct sk_buff *skb)
+{
+	struct qca8k_mdio_hdr_data *mdio_hdr_data;
+	struct qca8k_priv *priv = dp->ds->priv;
+	struct mdio_ethhdr *mdio_ethhdr;
+	u8 len, cmd;
+
+	mdio_ethhdr = (struct mdio_ethhdr *)skb_mac_header(skb);
+	mdio_hdr_data = &priv->mdio_hdr_data;
+
+	cmd = FIELD_GET(QCA_HDR_MDIO_CMD, mdio_ethhdr->command);
+	len = FIELD_GET(QCA_HDR_MDIO_LENGTH, mdio_ethhdr->command);
+
+	/* Make sure the seq match the requested packet */
+	if (mdio_ethhdr->seq == mdio_hdr_data->seq)
+		mdio_hdr_data->ack = true;
+
+	if (cmd == MDIO_READ) {
+		mdio_hdr_data->data[0] = mdio_ethhdr->mdio_data;
+
+		/* Get the rest of the 12 byte of data */
+		if (len > QCA_HDR_MDIO_DATA1_LEN)
+			memcpy(mdio_hdr_data->data + 1, skb->data,
+			       QCA_HDR_MDIO_DATA2_LEN);
+	}
+
+	complete(&mdio_hdr_data->rw_done);
+}
+
+static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
+					       int seq_num)
+{
+	struct mdio_ethhdr *mdio_ethhdr;
+	struct sk_buff *skb;
+	u16 hdr;
+
+	skb = dev_alloc_skb(QCA_HDR_MDIO_PKG_LEN);
+
+	prefetchw(skb->data);
+
+	skb_reset_mac_header(skb);
+	skb_set_network_header(skb, skb->len);
+
+	mdio_ethhdr = skb_push(skb, QCA_HDR_MDIO_HEADER_LEN + QCA_HDR_LEN);
+
+	hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
+	hdr |= QCA_HDR_XMIT_FROM_CPU;
+	hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0));
+	hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
+
+	mdio_ethhdr->seq = FIELD_PREP(QCA_HDR_MDIO_SEQ_NUM, seq_num);
+
+	mdio_ethhdr->command = FIELD_PREP(QCA_HDR_MDIO_ADDR, reg);
+	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_LENGTH, 4);
+	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_CMD, cmd);
+	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_CHECK_CODE, MDIO_CHECK_CODE_VAL);
+
+	if (cmd == MDIO_WRITE)
+		mdio_ethhdr->mdio_data = *val;
+
+	mdio_ethhdr->hdr = htons(hdr);
+
+	skb_put_zero(skb, QCA_HDR_MDIO_DATA2_LEN);
+	skb_put_zero(skb, QCA_HDR_MDIO_PADDING_LEN);
+
+	return skb;
+}
+
+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
+{
+	struct qca8k_mdio_hdr_data *mdio_hdr_data = &priv->mdio_hdr_data;
+	struct sk_buff *skb;
+	bool ack;
+	int ret;
+
+	skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, 200);
+	skb->dev = dsa_to_port(priv->ds, 0)->master;
+
+	mutex_lock(&mdio_hdr_data->mutex);
+
+	reinit_completion(&mdio_hdr_data->rw_done);
+	mdio_hdr_data->seq = 200;
+	mdio_hdr_data->ack = false;
+
+	dev_queue_xmit(skb);
+
+	ret = wait_for_completion_timeout(&mdio_hdr_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
+
+	*val = mdio_hdr_data->data[0];
+	ack = mdio_hdr_data->ack;
+
+	mutex_unlock(&mdio_hdr_data->mutex);
+
+	if (ret <= 0)
+		return -ETIMEDOUT;
+
+	if (!ack)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val)
+{
+	struct qca8k_mdio_hdr_data *mdio_hdr_data = &priv->mdio_hdr_data;
+	struct sk_buff *skb;
+	bool ack;
+	int ret;
+
+	skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val, 200);
+	skb->dev = dsa_to_port(priv->ds, 0)->master;
+
+	mutex_lock(&mdio_hdr_data->mutex);
+
+	reinit_completion(&mdio_hdr_data->rw_done);
+	mdio_hdr_data->ack = false;
+	mdio_hdr_data->seq = 200;
+
+	dev_queue_xmit(skb);
+
+	ret = wait_for_completion_timeout(&mdio_hdr_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
+
+	ack = mdio_hdr_data->ack;
+
+	mutex_unlock(&mdio_hdr_data->mutex);
+
+	if (ret <= 0)
+		return -ETIMEDOUT;
+
+	if (!ack)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
+{
+	u32 val = 0;
+	int ret;
+
+	ret = qca8k_read_eth(priv, reg, &val);
+	if (ret)
+		return ret;
+
+	val &= ~mask;
+	val |= write_val;
+
+	return qca8k_write_eth(priv, reg, val);
+}
+
 static int
 qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
 {
@@ -178,6 +330,9 @@ qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
 	u16 r1, r2, page;
 	int ret;
 
+	if (priv->master_oper && !qca8k_read_eth(priv, reg, val))
+		return 0;
+
 	qca8k_split_addr(reg, &r1, &r2, &page);
 
 	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
@@ -201,6 +356,9 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
 	u16 r1, r2, page;
 	int ret;
 
+	if (priv->master_oper && !qca8k_write_eth(priv, reg, val))
+		return 0;
+
 	qca8k_split_addr(reg, &r1, &r2, &page);
 
 	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
@@ -225,6 +383,10 @@ qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_
 	u32 val;
 	int ret;
 
+	if (priv->master_oper &&
+	    !qca8k_regmap_update_bits_eth(priv, reg, mask, write_val))
+		return 0;
+
 	qca8k_split_addr(reg, &r1, &r2, &page);
 
 	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
@@ -1232,7 +1394,7 @@ qca8k_setup(struct dsa_switch *ds)
 		}
 
 		/* Individual user ports get connected to CPU port only */
-		if (dsa_is_user_port(ds, i)) {
+		if (dsa_is_dsa_port(ds, i)) {
 			ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
 					QCA8K_PORT_LOOKUP_MEMBER,
 					BIT(cpu_port));
@@ -2395,6 +2557,30 @@ qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
 		priv->master_oper = false;
 }
 
+static int qca8k_connect_tag_protocol(struct dsa_switch *ds,
+				      enum dsa_tag_protocol proto)
+{
+	struct qca8k_priv *qca8k_priv = ds->priv;
+
+	switch (proto) {
+	case DSA_TAG_PROTO_QCA:
+		struct tag_qca_priv *priv;
+
+		priv = ds->tagger_data;
+
+		mutex_init(&qca8k_priv->mdio_hdr_data.mutex);
+		init_completion(&qca8k_priv->mdio_hdr_data.rw_done);
+
+		priv->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
+
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static const struct dsa_switch_ops qca8k_switch_ops = {
 	.get_tag_protocol	= qca8k_get_tag_protocol,
 	.setup			= qca8k_setup,
@@ -2431,6 +2617,7 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
 	.port_lag_join		= qca8k_port_lag_join,
 	.port_lag_leave		= qca8k_port_lag_leave,
 	.master_state_change	= qca8k_master_change,
+	.connect_tag_protocol	= qca8k_connect_tag_protocol,
 };
 
 static int qca8k_read_switch_id(struct qca8k_priv *priv)
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index fb98536bf3e8..307c56466082 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -11,6 +11,9 @@
 #include <linux/delay.h>
 #include <linux/regmap.h>
 #include <linux/gpio.h>
+#include <linux/dsa/tag_qca.h>
+
+#define QCA8K_ETHERNET_TIMEOUT				100
 
 #define QCA8K_NUM_PORTS					7
 #define QCA8K_NUM_CPU_PORTS				2
@@ -328,6 +331,14 @@ enum {
 	QCA8K_CPU_PORT6,
 };
 
+struct qca8k_mdio_hdr_data {
+	struct completion rw_done;
+	struct mutex mutex; /* Enforce one mdio read/write at time */
+	bool ack;
+	u32 seq;
+	u32 data[4];
+};
+
 struct qca8k_ports_config {
 	bool sgmii_rx_clk_falling_edge;
 	bool sgmii_tx_clk_falling_edge;
@@ -354,6 +365,7 @@ struct qca8k_priv {
 	struct dsa_switch_ops ops;
 	struct gpio_desc *reset_gpio;
 	unsigned int port_mtu[QCA8K_NUM_PORTS];
+	struct qca8k_mdio_hdr_data mdio_hdr_data;
 };
 
 struct qca8k_mib_desc {
diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h
index f3369b939107..203e72dad9bb 100644
--- a/include/linux/dsa/tag_qca.h
+++ b/include/linux/dsa/tag_qca.h
@@ -56,7 +56,7 @@ struct mdio_ethhdr {
 	u32 command;		/* command bit 31:0 */
 	u32 seq;		/* seq 63:32 */
 	u32 mdio_data;		/* first 4byte mdio */
-	u16 hdr;		/* qca hdr */
+	__be16 hdr;		/* qca hdr */
 } __packed;
 
 enum mdio_cmd {
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 13/15] net: dsa: qca8k: add support for mib autocast in Ethernet packet
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (11 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 14/15] net: dsa: qca8k: add support for phy read/write with mdio Ethernet Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write Ansuel Smith
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

The switch can autocast MIB counter using Ethernet packet.
Add support for this and provide a handler for the tagger.
The switch will send packet with MIB counter for each port, the switch
will use completion API to wait for the correct packet to be received
and will complete the task only when each packet is received.
Although the handler will drop all the other packet, we still have to
consume each MIB packet to complete the request. This is done to prevent
mixed data with concurrent ethtool request.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca8k.c | 102 +++++++++++++++++++++++++++++++++++++++-
 drivers/net/dsa/qca8k.h |  18 ++++++-
 2 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 0f1a604f015e..624df3b0fd9f 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -794,7 +794,10 @@ qca8k_mib_init(struct qca8k_priv *priv)
 	int ret;
 
 	mutex_lock(&priv->reg_mutex);
-	ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
+	ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
+				 QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
+				 FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
+				 QCA8K_MIB_BUSY);
 	if (ret)
 		goto exit;
 
@@ -1865,6 +1868,97 @@ qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
 			ETH_GSTRING_LEN);
 }
 
+static void qca8k_mib_autocast_handler(struct dsa_port *dp, struct sk_buff *skb)
+{
+	const struct qca8k_match_data *match_data;
+	struct qca8k_mib_hdr_data *mib_hdr_data;
+	struct qca8k_priv *priv = dp->ds->priv;
+	const struct qca8k_mib_desc *mib;
+	struct mib_ethhdr *mib_ethhdr;
+	int i, mib_len, offset = 0;
+	u64 *data;
+	u8 port;
+
+	mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb);
+	mib_hdr_data = &priv->mib_hdr_data;
+
+	/* The switch autocast every port. Ignore other packet and
+	 * parse only the requested one.
+	 */
+	port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr));
+	if (port != mib_hdr_data->req_port)
+		goto exit;
+
+	match_data = device_get_match_data(priv->dev);
+	data = mib_hdr_data->data;
+
+	for (i = 0; i < match_data->mib_count; i++) {
+		mib = &ar8327_mib[i];
+
+		/* First 3 mib are present in the skb head */
+		if (i < 3) {
+			data[i] = mib_ethhdr->data[i];
+			continue;
+		}
+
+		mib_len = sizeof(uint32_t);
+
+		/* Some mib are 64 bit wide */
+		if (mib->size == 2)
+			mib_len = sizeof(uint64_t);
+
+		/* Copy the mib value from packet to the */
+		memcpy(data + i, skb->data + offset, mib_len);
+
+		/* Set the offset for the next mib */
+		offset += mib_len;
+	}
+
+exit:
+	/* Complete on receiving all the mib packet */
+	if (refcount_dec_and_test(&mib_hdr_data->port_parsed))
+		complete(&mib_hdr_data->rw_done);
+}
+
+static int
+qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct qca8k_mib_hdr_data *mib_hdr_data;
+	struct qca8k_priv *priv = ds->priv;
+	int ret;
+
+	mib_hdr_data = &priv->mib_hdr_data;
+
+	mutex_lock(&mib_hdr_data->mutex);
+
+	reinit_completion(&mib_hdr_data->rw_done);
+
+	mib_hdr_data->req_port = dp->index;
+	mib_hdr_data->data = data;
+	refcount_set(&mib_hdr_data->port_parsed, QCA8K_NUM_PORTS);
+
+	mutex_lock(&priv->reg_mutex);
+
+	/* Send mib autocast request */
+	ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
+				 QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
+				 FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) |
+				 QCA8K_MIB_BUSY);
+
+	mutex_unlock(&priv->reg_mutex);
+
+	if (ret)
+		goto exit;
+
+	ret = wait_for_completion_timeout(&mib_hdr_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
+
+	mutex_unlock(&mib_hdr_data->mutex);
+
+exit:
+	return ret;
+}
+
 static void
 qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
 			uint64_t *data)
@@ -1876,6 +1970,10 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
 	u32 hi = 0;
 	int ret;
 
+	if (priv->master_oper &&
+	    qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
+		return;
+
 	match_data = of_device_get_match_data(priv->dev);
 
 	for (i = 0; i < match_data->mib_count; i++) {
@@ -2572,7 +2670,7 @@ static int qca8k_connect_tag_protocol(struct dsa_switch *ds,
 		init_completion(&qca8k_priv->mdio_hdr_data.rw_done);
 
 		priv->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
-
+		priv->mib_autocast_handler = qca8k_mib_autocast_handler;
 		break;
 	default:
 		return -EOPNOTSUPP;
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 307c56466082..e46320487834 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -66,7 +66,7 @@
 #define QCA8K_REG_MODULE_EN				0x030
 #define   QCA8K_MODULE_EN_MIB				BIT(0)
 #define QCA8K_REG_MIB					0x034
-#define   QCA8K_MIB_FLUSH				BIT(24)
+#define   QCA8K_MIB_FUNC				GENMASK(26, 24)
 #define   QCA8K_MIB_CPU_KEEP				BIT(20)
 #define   QCA8K_MIB_BUSY				BIT(17)
 #define QCA8K_MDIO_MASTER_CTRL				0x3c
@@ -316,6 +316,12 @@ enum qca8k_vlan_cmd {
 	QCA8K_VLAN_READ = 6,
 };
 
+enum qca8k_mid_cmd {
+	QCA8K_MIB_FLUSH = 1,
+	QCA8K_MIB_FLUSH_PORT = 2,
+	QCA8K_MIB_CAST = 3,
+};
+
 struct ar8xxx_port_status {
 	int enabled;
 };
@@ -339,6 +345,15 @@ struct qca8k_mdio_hdr_data {
 	u32 data[4];
 };
 
+struct qca8k_mib_hdr_data {
+	struct completion rw_done;
+	struct mutex mutex; /* Process one command at time */
+	refcount_t port_parsed; /* Counter to track parsed port */
+	u8 req_port;
+	u64 *data; /* pointer to ethtool data */
+	bool ready;
+};
+
 struct qca8k_ports_config {
 	bool sgmii_rx_clk_falling_edge;
 	bool sgmii_tx_clk_falling_edge;
@@ -366,6 +381,7 @@ struct qca8k_priv {
 	struct gpio_desc *reset_gpio;
 	unsigned int port_mtu[QCA8K_NUM_PORTS];
 	struct qca8k_mdio_hdr_data mdio_hdr_data;
+	struct qca8k_mib_hdr_data mib_hdr_data;
 };
 
 struct qca8k_mib_desc {
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 14/15] net: dsa: qca8k: add support for phy read/write with mdio Ethernet
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (12 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 13/15] net: dsa: qca8k: add support for mib autocast " Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-11 19:57 ` [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write Ansuel Smith
  14 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

Use mdio Ethernet also for phy read/write if availabale. Use a different
seq number to make sure we receive the correct packet.
On any error, we fallback to the legacy mdio read/write.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca8k.c | 150 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 150 insertions(+)

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 624df3b0fd9f..375a1d34e46f 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -831,6 +831,125 @@ qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
 		regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
 }
 
+static int
+qca8k_mdio_eth_busy_wait(struct qca8k_mdio_hdr_data *phy_hdr_data,
+			 struct sk_buff *read_skb, u32 *val)
+{
+	struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL);
+	bool ack;
+	int ret;
+
+	reinit_completion(&phy_hdr_data->rw_done);
+	phy_hdr_data->seq = 400;
+	phy_hdr_data->ack = false;
+
+	dev_queue_xmit(skb);
+
+	ret = wait_for_completion_timeout(&phy_hdr_data->rw_done,
+					  QCA8K_ETHERNET_TIMEOUT);
+
+	ack = phy_hdr_data->ack;
+
+	if (ret <= 0)
+		return -ETIMEDOUT;
+
+	if (!ack)
+		return -EINVAL;
+
+	*val = phy_hdr_data->data[0];
+
+	return 0;
+}
+
+static int
+qca8k_mdio_eth_command(struct qca8k_priv *priv, bool read, int phy,
+		       int regnum, u16 data)
+{
+	struct net_device *dev = dsa_to_port(priv->ds, 0)->master;
+	struct sk_buff *write_skb, *clear_skb, *read_skb;
+	struct qca8k_mdio_hdr_data *phy_hdr_data;
+	u32 write_val, clear_val = 0, val;
+	int seq_num = 400;
+	int ret, ret1;
+	bool ack;
+
+	if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
+		return -EINVAL;
+
+	phy_hdr_data = &priv->mdio_hdr_data;
+
+	write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
+		    QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
+		    QCA8K_MDIO_MASTER_REG_ADDR(regnum);
+
+	if (read) {
+		write_val |= QCA8K_MDIO_MASTER_READ;
+	} else {
+		write_val |= QCA8K_MDIO_MASTER_WRITE;
+		write_val |= QCA8K_MDIO_MASTER_DATA(data);
+	}
+
+	/* Prealloc all the needed skb before the lock */
+	write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
+					    &write_val, seq_num);
+	write_skb->dev = dev;
+	clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
+					    &clear_val, seq_num);
+	clear_skb->dev = dev;
+	read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL,
+					   &clear_val, seq_num);
+	read_skb->dev = dev;
+
+	/* Actually start the request:
+	 * 1. Send mdio master packet
+	 * 2. Busy Wait for mdio master command
+	 * 3. Get the data if we are reading
+	 * 4. Reset the mdio master (even with error)
+	 */
+	mutex_lock(&phy_hdr_data->mutex);
+
+	reinit_completion(&phy_hdr_data->rw_done);
+	phy_hdr_data->ack = false;
+	phy_hdr_data->seq = seq_num;
+
+	dev_queue_xmit(write_skb);
+
+	ret = wait_for_completion_timeout(&phy_hdr_data->rw_done,
+					  QCA8K_ETHERNET_TIMEOUT);
+
+	ack = phy_hdr_data->ack;
+
+	if (ret <= 0) {
+		ret = -ETIMEDOUT;
+		goto exit;
+	}
+
+	if (!ack) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ret = read_poll_timeout(qca8k_mdio_eth_busy_wait, ret1,
+				!(val & QCA8K_MDIO_MASTER_BUSY), 0,
+				QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
+				phy_hdr_data, read_skb, &val);
+
+	if (ret < 0 && ret1 < 0)
+		ret = ret1;
+
+	if (read)
+		ret = phy_hdr_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK;
+
+exit:
+	dev_queue_xmit(clear_skb);
+
+	mutex_unlock(&phy_hdr_data->mutex);
+
+	kfree_skb(read_skb);
+
+	return ret;
+}
+
 static u32
 qca8k_port_to_phy(int port)
 {
@@ -953,6 +1072,14 @@ qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 da
 {
 	struct qca8k_priv *priv = slave_bus->priv;
 	struct mii_bus *bus = priv->bus;
+	int ret;
+
+	/* Use mdio Ethernet when available, fallback to legacy one on error */
+	if (priv->master_oper) {
+		ret = qca8k_mdio_eth_command(priv, false, phy, regnum, data);
+		if (!ret)
+			return 0;
+	}
 
 	return qca8k_mdio_write(bus, phy, regnum, data);
 }
@@ -962,6 +1089,14 @@ qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum)
 {
 	struct qca8k_priv *priv = slave_bus->priv;
 	struct mii_bus *bus = priv->bus;
+	int ret;
+
+	/* Use mdio Ethernet when available, fallback to legacy one on error */
+	if (priv->master_oper) {
+		ret = qca8k_mdio_eth_command(priv, true, phy, regnum, 0);
+		if (ret >= 0)
+			return ret;
+	}
 
 	return qca8k_mdio_read(bus, phy, regnum);
 }
@@ -970,6 +1105,7 @@ static int
 qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data)
 {
 	struct qca8k_priv *priv = ds->priv;
+	int ret;
 
 	/* Check if the legacy mapping should be used and the
 	 * port is not correctly mapped to the right PHY in the
@@ -978,6 +1114,13 @@ qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data)
 	if (priv->legacy_phy_port_mapping)
 		port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
 
+	/* Use mdio Ethernet when available, fallback to legacy one on error */
+	if (priv->master_oper) {
+		ret = qca8k_mdio_eth_command(priv, true, port, regnum, 0);
+		if (!ret)
+			return ret;
+	}
+
 	return qca8k_mdio_write(priv->bus, port, regnum, data);
 }
 
@@ -994,6 +1137,13 @@ qca8k_phy_read(struct dsa_switch *ds, int port, int regnum)
 	if (priv->legacy_phy_port_mapping)
 		port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
 
+	/* Use mdio Ethernet when available, fallback to legacy one on error */
+	if (priv->master_oper) {
+		ret = qca8k_mdio_eth_command(priv, true, port, regnum, 0);
+		if (ret >= 0)
+			return ret;
+	}
+
 	ret = qca8k_mdio_read(priv->bus, port, regnum);
 
 	if (ret < 0)
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write
  2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
                   ` (13 preceding siblings ...)
  2021-12-11 19:57 ` [net-next RFC PATCH v4 14/15] net: dsa: qca8k: add support for phy read/write with mdio Ethernet Ansuel Smith
@ 2021-12-11 19:57 ` Ansuel Smith
  2021-12-12  4:04   ` Florian Fainelli
  14 siblings, 1 reply; 26+ messages in thread
From: Ansuel Smith @ 2021-12-11 19:57 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Ansuel Smith

From Documentation, we can cache lo and hi the same way we do with the
page. This massively reduce the mdio write as 3/4 of the time we only
require to write the lo or hi part for a mdio write.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca8k.c | 49 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 44 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 375a1d34e46f..b109a74031c6 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -94,6 +94,48 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
 	*page = regaddr & 0x3ff;
 }
 
+static u16 qca8k_current_lo = 0xffff;
+
+static int
+qca8k_set_lo(struct mii_bus *bus, int phy_id, u32 regnum, u16 lo)
+{
+	int ret;
+
+	if (lo == qca8k_current_lo) {
+		// pr_info("SAME LOW");
+		return 0;
+	}
+
+	ret = bus->write(bus, phy_id, regnum, lo);
+	if (ret < 0)
+		dev_err_ratelimited(&bus->dev,
+				    "failed to write qca8k 32bit lo register\n");
+
+	qca8k_current_lo = lo;
+	return 0;
+}
+
+static u16 qca8k_current_hi = 0xffff;
+
+static int
+qca8k_set_hi(struct mii_bus *bus, int phy_id, u32 regnum, u16 hi)
+{
+	int ret;
+
+	if (hi == qca8k_current_hi) {
+		// pr_info("SAME HI");
+		return 0;
+	}
+
+	ret = bus->write(bus, phy_id, regnum, hi);
+	if (ret < 0)
+		dev_err_ratelimited(&bus->dev,
+				    "failed to write qca8k 32bit hi register\n");
+
+	qca8k_current_hi = hi;
+	return 0;
+}
+
 static int
 qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)
 {
@@ -125,12 +167,9 @@ qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
 	lo = val & 0xffff;
 	hi = (u16)(val >> 16);
 
-	ret = bus->write(bus, phy_id, regnum, lo);
+	ret = qca8k_set_lo(bus, phy_id, regnum, lo);
 	if (ret >= 0)
-		ret = bus->write(bus, phy_id, regnum + 1, hi);
-	if (ret < 0)
-		dev_err_ratelimited(&bus->dev,
-				    "failed to write qca8k 32bit register\n");
+		ret = qca8k_set_hi(bus, phy_id, regnum + 1, hi);
 }
 
 static int
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write
  2021-12-11 19:57 ` [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write Ansuel Smith
@ 2021-12-12  4:04   ` Florian Fainelli
  2021-12-12 17:43     ` Ansuel Smith
  0 siblings, 1 reply; 26+ messages in thread
From: Florian Fainelli @ 2021-12-12  4:04 UTC (permalink / raw)
  To: Ansuel Smith, Andrew Lunn, Vivien Didelot, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev



On 12/11/2021 11:57 AM, Ansuel Smith wrote:
>  From Documentation, we can cache lo and hi the same way we do with the
> page. This massively reduce the mdio write as 3/4 of the time we only
> require to write the lo or hi part for a mdio write.
> 
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> ---
>   drivers/net/dsa/qca8k.c | 49 ++++++++++++++++++++++++++++++++++++-----
>   1 file changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> index 375a1d34e46f..b109a74031c6 100644
> --- a/drivers/net/dsa/qca8k.c
> +++ b/drivers/net/dsa/qca8k.c
> @@ -94,6 +94,48 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
>   	*page = regaddr & 0x3ff;
>   }
>   
> +static u16 qca8k_current_lo = 0xffff;

Let's assume I have two qca8k switches in my system on the same or a 
different MDIO bus, is not the caching supposed to be a per-qca8k switch 
instance thing?

> +
> +static int
> +qca8k_set_lo(struct mii_bus *bus, int phy_id, u32 regnum, u16 lo)
> +{
> +	int ret;
> +
> +	if (lo == qca8k_current_lo) {
> +		// pr_info("SAME LOW");

Stray debugging left.

> +		return 0;
> +	}
> +
> +	ret = bus->write(bus, phy_id, regnum, lo);
> +	if (ret < 0)
> +		dev_err_ratelimited(&bus->dev,
> +				    "failed to write qca8k 32bit lo register\n");
> +
> +	qca8k_current_lo = lo;
> +	return 0;
> +}
> +
> +static u16 qca8k_current_hi = 0xffff;
> +
> +static int
> +qca8k_set_hi(struct mii_bus *bus, int phy_id, u32 regnum, u16 hi)
> +{
> +	int ret;
> +
> +	if (hi == qca8k_current_hi) {
> +		// pr_info("SAME HI");

Likewise
-- 
Florian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet
  2021-12-11 19:57 ` [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet Ansuel Smith
@ 2021-12-12  4:12   ` Florian Fainelli
  2021-12-12 17:41     ` Ansuel Smith
  0 siblings, 1 reply; 26+ messages in thread
From: Florian Fainelli @ 2021-12-12  4:12 UTC (permalink / raw)
  To: Ansuel Smith, Andrew Lunn, Vivien Didelot, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev



On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> Add qca8k side support for mdio read/write in Ethernet packet.
> qca8k supports some specially crafted Ethernet packet that can be used
> for mdio read/write instead of the legacy method uart/internal mdio.
> This add support for the qca8k side to craft the packet and enqueue it.
> Each port and the qca8k_priv have a special struct to put data in it.
> The completion API is used to wait for the packet to be received back
> with the requested data.
> 
> The various steps are:
> 1. Craft the special packet with the qca hdr set to mdio read/write
>     mode.
> 2. Set the lock in the dedicated mdio struct.
> 3. Reinit the completion.
> 4. Enqueue the packet.
> 5. Wait the packet to be received.
> 6. Use the data set by the tagger to complete the mdio operation.
> 
> If the completion timeouts or the ack value is not true, the legacy
> mdio way is used.
> 
> It has to be considered that in the initial setup mdio is still used and
> mdio is still used until DSA is ready to accept and tag packet.
> 
> tag_proto_connect() is used to fill the required handler for the tagger
> to correctly parse and elaborate the special Ethernet mdio packet.
> 
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> ---

[snip]

> +
> +static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
> +					       int seq_num)
> +{
> +	struct mdio_ethhdr *mdio_ethhdr;
> +	struct sk_buff *skb;
> +	u16 hdr;
> +
> +	skb = dev_alloc_skb(QCA_HDR_MDIO_PKG_LEN);

No out of memory condition handling?

> +
> +	prefetchw(skb->data);

What's the point you are going to dirty the cache lines right below with 
your skb_push().

> +
> +	skb_reset_mac_header(skb);
> +	skb_set_network_header(skb, skb->len);
> +
> +	mdio_ethhdr = skb_push(skb, QCA_HDR_MDIO_HEADER_LEN + QCA_HDR_LEN);
> +
> +	hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
> +	hdr |= QCA_HDR_XMIT_FROM_CPU;
> +	hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0));
> +	hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
> +
> +	mdio_ethhdr->seq = FIELD_PREP(QCA_HDR_MDIO_SEQ_NUM, seq_num);
> +
> +	mdio_ethhdr->command = FIELD_PREP(QCA_HDR_MDIO_ADDR, reg);
> +	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_LENGTH, 4);
> +	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_CMD, cmd);
> +	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_CHECK_CODE, MDIO_CHECK_CODE_VAL);
> +
> +	if (cmd == MDIO_WRITE)
> +		mdio_ethhdr->mdio_data = *val;
> +
> +	mdio_ethhdr->hdr = htons(hdr);
> +
> +	skb_put_zero(skb, QCA_HDR_MDIO_DATA2_LEN);
> +	skb_put_zero(skb, QCA_HDR_MDIO_PADDING_LEN);
> +
> +	return skb;
> +}
> +
> +static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
> +{
> +	struct qca8k_mdio_hdr_data *mdio_hdr_data = &priv->mdio_hdr_data;
> +	struct sk_buff *skb;
> +	bool ack;
> +	int ret;
> +
> +	skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, 200);
> +	skb->dev = dsa_to_port(priv->ds, 0)->master;

Surely you should be checking that this is the CPU port and obtain it 
from DSA instead of hard coding it to 0.

> +
> +	mutex_lock(&mdio_hdr_data->mutex);
> +
> +	reinit_completion(&mdio_hdr_data->rw_done);
> +	mdio_hdr_data->seq = 200;
> +	mdio_hdr_data->ack = false;
> +
> +	dev_queue_xmit(skb);
> +
> +	ret = wait_for_completion_timeout(&mdio_hdr_data->rw_done, QCA8K_ETHERNET_TIMEOUT);

msec_to_jiffies(QCA8K_ETHERNET_TIMEOUT) at least?
-- 
Florian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state
  2021-12-11 19:57 ` [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state Ansuel Smith
@ 2021-12-12  4:22   ` Florian Fainelli
  2021-12-12 18:19     ` Ansuel Smith
  2021-12-12 18:19     ` Vladimir Oltean
  0 siblings, 2 replies; 26+ messages in thread
From: Florian Fainelli @ 2021-12-12  4:22 UTC (permalink / raw)
  To: Ansuel Smith, Andrew Lunn, Vivien Didelot, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean



On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Certain drivers may need to send management traffic to the switch for
> things like register access, FDB dump, etc, to accelerate what their
> slow bus (SPI, I2C, MDIO) can already do.
> 
> Ethernet is faster (especially in bulk transactions) but is also more
> unreliable, since the user may decide to bring the DSA master down (or
> not bring it up), therefore severing the link between the host and the
> attached switch.
> 
> Drivers needing Ethernet-based register access already should have
> fallback logic to the slow bus if the Ethernet method fails, but that
> fallback may be based on a timeout, and the I/O to the switch may slow
> down to a halt if the master is down, because every Ethernet packet will
> have to time out. The driver also doesn't have the option to turn off
> Ethernet-based I/O momentarily, because it wouldn't know when to turn it
> back on.
> 
> Which is where this change comes in. By tracking NETDEV_CHANGE,
> NETDEV_UP and NETDEV_GOING_DOWN events on the DSA master, we should know
> the exact interval of time during which this interface is reliably
> available for traffic. Provide this information to switches so they can
> use it as they wish.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> ---
>   include/net/dsa.h  | 11 +++++++++++
>   net/dsa/dsa2.c     | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>   net/dsa/dsa_priv.h | 13 +++++++++++++
>   net/dsa/slave.c    | 32 ++++++++++++++++++++++++++++++++
>   net/dsa/switch.c   | 15 +++++++++++++++
>   5 files changed, 117 insertions(+)
> 
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index 8b496c7e62ef..12352aafe1cf 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -299,6 +299,10 @@ struct dsa_port {
>   	struct list_head	fdbs;
>   	struct list_head	mdbs;
>   
> +	/* Master state bits, valid only on CPU ports */
> +	u8 master_admin_up:1,
> +	   master_oper_up:1;
> +
>   	bool setup;
>   };
>   
> @@ -1023,6 +1027,13 @@ struct dsa_switch_ops {
>   	int	(*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid,
>   				      u16 flags);
>   	int	(*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid);
> +
> +	/*
> +	 * DSA master tracking operations
> +	 */
> +	void	(*master_state_change)(struct dsa_switch *ds,
> +				       const struct net_device *master,
> +				       bool operational);
>   };
>   
>   #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes)		\
> diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
> index cf6566168620..86b1e2f11469 100644
> --- a/net/dsa/dsa2.c
> +++ b/net/dsa/dsa2.c
> @@ -1245,6 +1245,52 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
>   	return err;
>   }
>   
> +static void dsa_tree_master_state_change(struct dsa_switch_tree *dst,
> +					 struct net_device *master)
> +{
> +	struct dsa_notifier_master_state_info info;
> +	struct dsa_port *cpu_dp = master->dsa_ptr;
> +
> +	info.master = master;
> +	info.operational = cpu_dp->master_admin_up && cpu_dp->master_oper_up;

Since this gets tested a few times below, I would be tempted to add a:

dsa_master_is_operational() helper and use it throughout.

> +
> +	dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info);
> +}
> +
> +void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
> +					struct net_device *master,
> +					bool up)
> +{
> +	struct dsa_port *cpu_dp = master->dsa_ptr;
> +	bool notify = false;
> +
> +	if ((cpu_dp->master_admin_up && cpu_dp->master_oper_up) !=

Here

> +	    (up && cpu_dp->master_oper_up))
> +		notify = true;
> +
> +	cpu_dp->master_admin_up = up;
> +
> +	if (notify)
> +		dsa_tree_master_state_change(dst, master);
> +}
> +
> +void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
> +				       struct net_device *master,
> +				       bool up)
> +{
> +	struct dsa_port *cpu_dp = master->dsa_ptr;
> +	bool notify = false;
> +
> +	if ((cpu_dp->master_admin_up && cpu_dp->master_oper_up) !=

And here as well

> +	    (cpu_dp->master_admin_up && up))
> +		notify = true;
> +
> +	cpu_dp->master_oper_up = up;
> +
> +	if (notify)
> +		dsa_tree_master_state_change(dst, master);
> +}
> +
>   static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
>   {
>   	struct dsa_switch_tree *dst = ds->dst;
> diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
> index 0db2b26b0c83..d2f2bce2391b 100644
> --- a/net/dsa/dsa_priv.h
> +++ b/net/dsa/dsa_priv.h
> @@ -44,6 +44,7 @@ enum {
>   	DSA_NOTIFIER_MRP_DEL_RING_ROLE,
>   	DSA_NOTIFIER_TAG_8021Q_VLAN_ADD,
>   	DSA_NOTIFIER_TAG_8021Q_VLAN_DEL,
> +	DSA_NOTIFIER_MASTER_STATE_CHANGE,
>   };
>   
>   /* DSA_NOTIFIER_AGEING_TIME */
> @@ -127,6 +128,12 @@ struct dsa_notifier_tag_8021q_vlan_info {
>   	u16 vid;
>   };
>   
> +/* DSA_NOTIFIER_MASTER_STATE_CHANGE */
> +struct dsa_notifier_master_state_info {
> +	const struct net_device *master;
> +	bool operational;
> +};
> +
>   struct dsa_switchdev_event_work {
>   	struct dsa_switch *ds;
>   	int port;
> @@ -507,6 +514,12 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
>   			      struct net_device *master,
>   			      const struct dsa_device_ops *tag_ops,
>   			      const struct dsa_device_ops *old_tag_ops);
> +void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
> +					struct net_device *master,
> +					bool up);
> +void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
> +				       struct net_device *master,
> +				       bool up);
>   unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
>   void dsa_bridge_num_put(const struct net_device *bridge_dev,
>   			unsigned int bridge_num);
> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> index 88f7b8686dac..5ccb0616022d 100644
> --- a/net/dsa/slave.c
> +++ b/net/dsa/slave.c
> @@ -2348,6 +2348,36 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
>   		err = dsa_port_lag_change(dp, info->lower_state_info);
>   		return notifier_from_errno(err);
>   	}
> +	case NETDEV_CHANGE:
> +	case NETDEV_UP: {
> +		/* Track state of master port.
> +		 * DSA driver may require the master port (and indirectly
> +		 * the tagger) to be available for some special operation.
> +		 */
> +		if (netdev_uses_dsa(dev)) {
> +			struct dsa_port *cpu_dp = dev->dsa_ptr;
> +			struct dsa_switch_tree *dst = cpu_dp->ds->dst;
> +
> +			/* Track when the master port is UP */
> +			dsa_tree_master_oper_state_change(dst, dev,
> +							  netif_oper_up(dev));
> +
> +			/* Track when the master port is ready and can accept
> +			 * packet.
> +			 * NETDEV_UP event is not enough to flag a port as ready.
> +			 * We also have to wait for linkwatch_do_dev to dev_activate
> +			 * and emit a NETDEV_CHANGE event.
> +			 * We check if a master port is ready by checking if the dev
> +			 * have a qdisc assigned and is not noop.
> +			 */
> +			dsa_tree_master_admin_state_change(dst, dev,
> +							   qdisc_tx_is_noop(dev));

If my kernel is built with no packet scheduler, is not the interface 
going to be configured with noop all of the time?

Other than that LGTM!
-- 
Florian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 02/15] net: dsa: stop updating master MTU from master.c
  2021-12-11 19:57 ` [net-next RFC PATCH v4 02/15] net: dsa: stop updating master MTU from master.c Ansuel Smith
@ 2021-12-12  4:23   ` Florian Fainelli
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Fainelli @ 2021-12-12  4:23 UTC (permalink / raw)
  To: Ansuel Smith, Andrew Lunn, Vivien Didelot, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean



On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> The dev_set_mtu() call from dsa_master_setup() has been effectively
> superseded by the dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN) that is
> done from dsa_slave_create() for each user port. This function also
> updates the master MTU according to the largest user port MTU from the
> tree. Therefore, updating the master MTU through a separate code path
> isn't needed.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 03/15] net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown}
  2021-12-11 19:57 ` [net-next RFC PATCH v4 03/15] net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown} Ansuel Smith
@ 2021-12-12  4:24   ` Florian Fainelli
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Fainelli @ 2021-12-12  4:24 UTC (permalink / raw)
  To: Ansuel Smith, Andrew Lunn, Vivien Didelot, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean



On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> DSA needs to simulate master tracking events when a binding is first
> with a DSA master established and torn down, in order to give drivers
> the simplifying guarantee that ->master_state_change calls are made
> only when the master's readiness state to pass traffic changes.
> master_state_change() provide a operational bool that DSA driver can use
> to understand if DSA master is operational or not.
> To avoid races, we need to block the reception of
> NETDEV_UP/NETDEV_CHANGE/NETDEV_GOING_DOWN events in the netdev notifier
> chain while we are changing the master's dev->dsa_ptr (this changes what
> netdev_uses_dsa(dev) reports).
> 
> The dsa_master_setup() and dsa_master_teardown() functions optionally
> require the rtnl_mutex to be held, if the tagger needs the master to be
> promiscuous, these functions call dev_set_promiscuity(). Move the
> rtnl_lock() from that function and make it top-level.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 04/15] net: dsa: replay master state events in dsa_tree_{setup,teardown}_master
  2021-12-11 19:57 ` [net-next RFC PATCH v4 04/15] net: dsa: replay master state events in dsa_tree_{setup,teardown}_master Ansuel Smith
@ 2021-12-12  4:25   ` Florian Fainelli
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Fainelli @ 2021-12-12  4:25 UTC (permalink / raw)
  To: Ansuel Smith, Andrew Lunn, Vivien Didelot, Vladimir Oltean,
	David S. Miller, Jakub Kicinski, linux-kernel, netdev
  Cc: Vladimir Oltean



On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> In order for switch driver to be able to make simple and reliable use of
> the master tracking operations, they must also be notified of the
> initial state of the DSA master, not just of the changes. This is
> because they might enable certain features only during the time when
> they know that the DSA master is up and running.
> 
> Therefore, this change explicitly checks the state of the DSA master
> under the same rtnl_mutex as we were holding during the
> dsa_master_setup() and dsa_master_teardown() call. The idea being that
> if the DSA master became operational in between the moment in which it
> became a DSA master (dsa_master_setup set dev->dsa_ptr) and the moment
> when we checked for the master being up, there is a chance that we
> would emit a ->master_state_change() call with no actual state change.
> We need to avoid that by serializing the concurrent netdevice event with
> us. If the netdevice event started before, we force it to finish before
> we begin, because we take rtnl_lock before making netdev_uses_dsa()
> return true. So we also handle that early event and do nothing on it.
> Similarly, if the dev_open() attempt is concurrent with us, it will
> attempt to take the rtnl_mutex, but we're holding it. We'll see that
> the master flag IFF_UP isn't set, then when we release the rtnl_mutex
> we'll process the NETDEV_UP notifier.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>

With the caveat from patch #1 about qdisc_noop addressed:

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet
  2021-12-12  4:12   ` Florian Fainelli
@ 2021-12-12 17:41     ` Ansuel Smith
  0 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-12 17:41 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Andrew Lunn, Vivien Didelot, Vladimir Oltean, David S. Miller,
	Jakub Kicinski, linux-kernel, netdev

On Sat, Dec 11, 2021 at 08:12:51PM -0800, Florian Fainelli wrote:
> 
> 
> On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> > Add qca8k side support for mdio read/write in Ethernet packet.
> > qca8k supports some specially crafted Ethernet packet that can be used
> > for mdio read/write instead of the legacy method uart/internal mdio.
> > This add support for the qca8k side to craft the packet and enqueue it.
> > Each port and the qca8k_priv have a special struct to put data in it.
> > The completion API is used to wait for the packet to be received back
> > with the requested data.
> > 
> > The various steps are:
> > 1. Craft the special packet with the qca hdr set to mdio read/write
> >     mode.
> > 2. Set the lock in the dedicated mdio struct.
> > 3. Reinit the completion.
> > 4. Enqueue the packet.
> > 5. Wait the packet to be received.
> > 6. Use the data set by the tagger to complete the mdio operation.
> > 
> > If the completion timeouts or the ack value is not true, the legacy
> > mdio way is used.
> > 
> > It has to be considered that in the initial setup mdio is still used and
> > mdio is still used until DSA is ready to accept and tag packet.
> > 
> > tag_proto_connect() is used to fill the required handler for the tagger
> > to correctly parse and elaborate the special Ethernet mdio packet.
> > 
> > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > ---
> 
> [snip]
> 
> > +
> > +static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
> > +					       int seq_num)
> > +{
> > +	struct mdio_ethhdr *mdio_ethhdr;
> > +	struct sk_buff *skb;
> > +	u16 hdr;
> > +
> > +	skb = dev_alloc_skb(QCA_HDR_MDIO_PKG_LEN);
> 
> No out of memory condition handling?
>

Will add.

> > +
> > +	prefetchw(skb->data);
> 
> What's the point you are going to dirty the cache lines right below with
> your skb_push().
> 

Will drop.

> > +
> > +	skb_reset_mac_header(skb);
> > +	skb_set_network_header(skb, skb->len);
> > +
> > +	mdio_ethhdr = skb_push(skb, QCA_HDR_MDIO_HEADER_LEN + QCA_HDR_LEN);
> > +
> > +	hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
> > +	hdr |= QCA_HDR_XMIT_FROM_CPU;
> > +	hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0));
> > +	hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
> > +
> > +	mdio_ethhdr->seq = FIELD_PREP(QCA_HDR_MDIO_SEQ_NUM, seq_num);
> > +
> > +	mdio_ethhdr->command = FIELD_PREP(QCA_HDR_MDIO_ADDR, reg);
> > +	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_LENGTH, 4);
> > +	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_CMD, cmd);
> > +	mdio_ethhdr->command |= FIELD_PREP(QCA_HDR_MDIO_CHECK_CODE, MDIO_CHECK_CODE_VAL);
> > +
> > +	if (cmd == MDIO_WRITE)
> > +		mdio_ethhdr->mdio_data = *val;
> > +
> > +	mdio_ethhdr->hdr = htons(hdr);
> > +
> > +	skb_put_zero(skb, QCA_HDR_MDIO_DATA2_LEN);
> > +	skb_put_zero(skb, QCA_HDR_MDIO_PADDING_LEN);
> > +
> > +	return skb;
> > +}
> > +
> > +static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
> > +{
> > +	struct qca8k_mdio_hdr_data *mdio_hdr_data = &priv->mdio_hdr_data;
> > +	struct sk_buff *skb;
> > +	bool ack;
> > +	int ret;
> > +
> > +	skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, 200);
> > +	skb->dev = dsa_to_port(priv->ds, 0)->master;
> 
> Surely you should be checking that this is the CPU port and obtain it from
> DSA instead of hard coding it to 0.
> 

You are right as we can also have port6 as cpu port.

> > +
> > +	mutex_lock(&mdio_hdr_data->mutex);
> > +
> > +	reinit_completion(&mdio_hdr_data->rw_done);
> > +	mdio_hdr_data->seq = 200;
> > +	mdio_hdr_data->ack = false;
> > +
> > +	dev_queue_xmit(skb);
> > +
> > +	ret = wait_for_completion_timeout(&mdio_hdr_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
> 
> msec_to_jiffies(QCA8K_ETHERNET_TIMEOUT) at least?

Sorry got it work and misread that the conversion was implicit.

> -- 
> Florian

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write
  2021-12-12  4:04   ` Florian Fainelli
@ 2021-12-12 17:43     ` Ansuel Smith
  0 siblings, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-12 17:43 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Andrew Lunn, Vivien Didelot, Vladimir Oltean, David S. Miller,
	Jakub Kicinski, linux-kernel, netdev

On Sat, Dec 11, 2021 at 08:04:42PM -0800, Florian Fainelli wrote:
> 
> 
> On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> >  From Documentation, we can cache lo and hi the same way we do with the
> > page. This massively reduce the mdio write as 3/4 of the time we only
> > require to write the lo or hi part for a mdio write.
> > 
> > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > ---
> >   drivers/net/dsa/qca8k.c | 49 ++++++++++++++++++++++++++++++++++++-----
> >   1 file changed, 44 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> > index 375a1d34e46f..b109a74031c6 100644
> > --- a/drivers/net/dsa/qca8k.c
> > +++ b/drivers/net/dsa/qca8k.c
> > @@ -94,6 +94,48 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
> >   	*page = regaddr & 0x3ff;
> >   }
> > +static u16 qca8k_current_lo = 0xffff;
> 
> Let's assume I have two qca8k switches in my system on the same or a
> different MDIO bus, is not the caching supposed to be a per-qca8k switch
> instance thing?
>

Also another user made me notice this... This problem is present from
when the driver was implemented and I think with the assumption that
only one switch was present in the device. We actually found SoC with 2
qca8k switch.
I will add a patch to move these stuff (and the cache page variable) in
the qca8k priv.

> > +
> > +static int
> > +qca8k_set_lo(struct mii_bus *bus, int phy_id, u32 regnum, u16 lo)
> > +{
> > +	int ret;
> > +
> > +	if (lo == qca8k_current_lo) {
> > +		// pr_info("SAME LOW");
> 
> Stray debugging left.
> 

Sorry.

> > +		return 0;
> > +	}
> > +
> > +	ret = bus->write(bus, phy_id, regnum, lo);
> > +	if (ret < 0)
> > +		dev_err_ratelimited(&bus->dev,
> > +				    "failed to write qca8k 32bit lo register\n");
> > +
> > +	qca8k_current_lo = lo;
> > +	return 0;
> > +}
> > +
> > +static u16 qca8k_current_hi = 0xffff;
> > +
> > +static int
> > +qca8k_set_hi(struct mii_bus *bus, int phy_id, u32 regnum, u16 hi)
> > +{
> > +	int ret;
> > +
> > +	if (hi == qca8k_current_hi) {
> > +		// pr_info("SAME HI");
> 
> Likewise
> -- 
> Florian

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state
  2021-12-12  4:22   ` Florian Fainelli
@ 2021-12-12 18:19     ` Ansuel Smith
  2021-12-12 18:19     ` Vladimir Oltean
  1 sibling, 0 replies; 26+ messages in thread
From: Ansuel Smith @ 2021-12-12 18:19 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Andrew Lunn, Vivien Didelot, Vladimir Oltean, David S. Miller,
	Jakub Kicinski, linux-kernel, netdev, Vladimir Oltean

On Sat, Dec 11, 2021 at 08:22:39PM -0800, Florian Fainelli wrote:
> 
> 
> On 12/11/2021 11:57 AM, Ansuel Smith wrote:
> > From: Vladimir Oltean <vladimir.oltean@nxp.com>
> > 
> > Certain drivers may need to send management traffic to the switch for
> > things like register access, FDB dump, etc, to accelerate what their
> > slow bus (SPI, I2C, MDIO) can already do.
> > 
> > Ethernet is faster (especially in bulk transactions) but is also more
> > unreliable, since the user may decide to bring the DSA master down (or
> > not bring it up), therefore severing the link between the host and the
> > attached switch.
> > 
> > Drivers needing Ethernet-based register access already should have
> > fallback logic to the slow bus if the Ethernet method fails, but that
> > fallback may be based on a timeout, and the I/O to the switch may slow
> > down to a halt if the master is down, because every Ethernet packet will
> > have to time out. The driver also doesn't have the option to turn off
> > Ethernet-based I/O momentarily, because it wouldn't know when to turn it
> > back on.
> > 
> > Which is where this change comes in. By tracking NETDEV_CHANGE,
> > NETDEV_UP and NETDEV_GOING_DOWN events on the DSA master, we should know
> > the exact interval of time during which this interface is reliably
> > available for traffic. Provide this information to switches so they can
> > use it as they wish.
> > 
> > Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > ---
> >   include/net/dsa.h  | 11 +++++++++++
> >   net/dsa/dsa2.c     | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> >   net/dsa/dsa_priv.h | 13 +++++++++++++
> >   net/dsa/slave.c    | 32 ++++++++++++++++++++++++++++++++
> >   net/dsa/switch.c   | 15 +++++++++++++++
> >   5 files changed, 117 insertions(+)
> > 
> > diff --git a/include/net/dsa.h b/include/net/dsa.h
> > index 8b496c7e62ef..12352aafe1cf 100644
> > --- a/include/net/dsa.h
> > +++ b/include/net/dsa.h
> > @@ -299,6 +299,10 @@ struct dsa_port {
> >   	struct list_head	fdbs;
> >   	struct list_head	mdbs;
> > +	/* Master state bits, valid only on CPU ports */
> > +	u8 master_admin_up:1,
> > +	   master_oper_up:1;
> > +
> >   	bool setup;
> >   };
> > @@ -1023,6 +1027,13 @@ struct dsa_switch_ops {
> >   	int	(*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid,
> >   				      u16 flags);
> >   	int	(*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid);
> > +
> > +	/*
> > +	 * DSA master tracking operations
> > +	 */
> > +	void	(*master_state_change)(struct dsa_switch *ds,
> > +				       const struct net_device *master,
> > +				       bool operational);
> >   };
> >   #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes)		\
> > diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
> > index cf6566168620..86b1e2f11469 100644
> > --- a/net/dsa/dsa2.c
> > +++ b/net/dsa/dsa2.c
> > @@ -1245,6 +1245,52 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
> >   	return err;
> >   }
> > +static void dsa_tree_master_state_change(struct dsa_switch_tree *dst,
> > +					 struct net_device *master)
> > +{
> > +	struct dsa_notifier_master_state_info info;
> > +	struct dsa_port *cpu_dp = master->dsa_ptr;
> > +
> > +	info.master = master;
> > +	info.operational = cpu_dp->master_admin_up && cpu_dp->master_oper_up;
> 
> Since this gets tested a few times below, I would be tempted to add a:
> 
> dsa_master_is_operational() helper and use it throughout.
>

Isn't that a bit overkill for a check of 2 bit? Will send a patch with
the helper in v5.

> > +
> > +	dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info);
> > +}
> > +
> > +void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
> > +					struct net_device *master,
> > +					bool up)
> > +{
> > +	struct dsa_port *cpu_dp = master->dsa_ptr;
> > +	bool notify = false;
> > +
> > +	if ((cpu_dp->master_admin_up && cpu_dp->master_oper_up) !=
> 
> Here
> 
> > +	    (up && cpu_dp->master_oper_up))
> > +		notify = true;
> > +
> > +	cpu_dp->master_admin_up = up;
> > +
> > +	if (notify)
> > +		dsa_tree_master_state_change(dst, master);
> > +}
> > +
> > +void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
> > +				       struct net_device *master,
> > +				       bool up)
> > +{
> > +	struct dsa_port *cpu_dp = master->dsa_ptr;
> > +	bool notify = false;
> > +
> > +	if ((cpu_dp->master_admin_up && cpu_dp->master_oper_up) !=
> 
> And here as well
> 
> > +	    (cpu_dp->master_admin_up && up))
> > +		notify = true;
> > +
> > +	cpu_dp->master_oper_up = up;
> > +
> > +	if (notify)
> > +		dsa_tree_master_state_change(dst, master);
> > +}
> > +
> >   static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
> >   {
> >   	struct dsa_switch_tree *dst = ds->dst;
> > diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
> > index 0db2b26b0c83..d2f2bce2391b 100644
> > --- a/net/dsa/dsa_priv.h
> > +++ b/net/dsa/dsa_priv.h
> > @@ -44,6 +44,7 @@ enum {
> >   	DSA_NOTIFIER_MRP_DEL_RING_ROLE,
> >   	DSA_NOTIFIER_TAG_8021Q_VLAN_ADD,
> >   	DSA_NOTIFIER_TAG_8021Q_VLAN_DEL,
> > +	DSA_NOTIFIER_MASTER_STATE_CHANGE,
> >   };
> >   /* DSA_NOTIFIER_AGEING_TIME */
> > @@ -127,6 +128,12 @@ struct dsa_notifier_tag_8021q_vlan_info {
> >   	u16 vid;
> >   };
> > +/* DSA_NOTIFIER_MASTER_STATE_CHANGE */
> > +struct dsa_notifier_master_state_info {
> > +	const struct net_device *master;
> > +	bool operational;
> > +};
> > +
> >   struct dsa_switchdev_event_work {
> >   	struct dsa_switch *ds;
> >   	int port;
> > @@ -507,6 +514,12 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
> >   			      struct net_device *master,
> >   			      const struct dsa_device_ops *tag_ops,
> >   			      const struct dsa_device_ops *old_tag_ops);
> > +void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
> > +					struct net_device *master,
> > +					bool up);
> > +void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
> > +				       struct net_device *master,
> > +				       bool up);
> >   unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
> >   void dsa_bridge_num_put(const struct net_device *bridge_dev,
> >   			unsigned int bridge_num);
> > diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> > index 88f7b8686dac..5ccb0616022d 100644
> > --- a/net/dsa/slave.c
> > +++ b/net/dsa/slave.c
> > @@ -2348,6 +2348,36 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
> >   		err = dsa_port_lag_change(dp, info->lower_state_info);
> >   		return notifier_from_errno(err);
> >   	}
> > +	case NETDEV_CHANGE:
> > +	case NETDEV_UP: {
> > +		/* Track state of master port.
> > +		 * DSA driver may require the master port (and indirectly
> > +		 * the tagger) to be available for some special operation.
> > +		 */
> > +		if (netdev_uses_dsa(dev)) {
> > +			struct dsa_port *cpu_dp = dev->dsa_ptr;
> > +			struct dsa_switch_tree *dst = cpu_dp->ds->dst;
> > +
> > +			/* Track when the master port is UP */
> > +			dsa_tree_master_oper_state_change(dst, dev,
> > +							  netif_oper_up(dev));
> > +
> > +			/* Track when the master port is ready and can accept
> > +			 * packet.
> > +			 * NETDEV_UP event is not enough to flag a port as ready.
> > +			 * We also have to wait for linkwatch_do_dev to dev_activate
> > +			 * and emit a NETDEV_CHANGE event.
> > +			 * We check if a master port is ready by checking if the dev
> > +			 * have a qdisc assigned and is not noop.
> > +			 */
> > +			dsa_tree_master_admin_state_change(dst, dev,
> > +							   qdisc_tx_is_noop(dev));
> 
> If my kernel is built with no packet scheduler, is not the interface going
> to be configured with noop all of the time?
> 
> Other than that LGTM!

Ok I just notice, tracking attach_default_qdiscs fail is a nightmare...
Refcount is not set with noop so we can't use that.
dev->qdisc is set to noop by default.

Starting to think we need a way to add more info to the notifier or dev
activate... Unless there is a way to also check when noop is actually
activated.

(or just add a priv_flag with for dev_activated)

> -- 
> Florian

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state
  2021-12-12  4:22   ` Florian Fainelli
  2021-12-12 18:19     ` Ansuel Smith
@ 2021-12-12 18:19     ` Vladimir Oltean
  1 sibling, 0 replies; 26+ messages in thread
From: Vladimir Oltean @ 2021-12-12 18:19 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Ansuel Smith, Andrew Lunn, Vivien Didelot, David S. Miller,
	Jakub Kicinski, linux-kernel, netdev, Vladimir Oltean

Hi Florian,

On Sat, Dec 11, 2021 at 08:22:39PM -0800, Florian Fainelli wrote:
> If my kernel is built with no packet scheduler, is not the interface going
> to be configured with noop all of the time?

I made this test and it looks like interfaces that are down use noop,
normal multi-queue interfaces use mq, and stacked interfaces using LLTX
like DSA use noqueue when up:

root@debian:~# zcat /proc/config.gz | grep NET_SCHED
# CONFIG_NET_SCHED is not set
root@debian:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 02:0b:67:72:9a:d5 brd ff:ff:ff:ff:ff:ff
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
4: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1508 qdisc mq state UP group default qlen 1000
    link/ether de:79:92:89:2e:e6 brd ff:ff:ff:ff:ff:ff
    altname enp0s0f2
    inet6 fe80::dc79:92ff:fe89:2ee6/64 scope link
       valid_lft forever preferred_lft forever
5: swp0@eno2: <BROADCAST,MULTICAST> mtu 1504 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
6: swp1@eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
7: swp2@eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1504 qdisc noqueue state UP group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a4f4:afff:fefd:fc73/64 scope link
       valid_lft forever preferred_lft forever
8: sw0p0@swp0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
9: sw0p1@swp0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
10: sw0p2@swp0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
11: sw2p0@swp2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a4f4:afff:fefd:fc73/64 scope link
       valid_lft forever preferred_lft forever
12: sw2p1@swp2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
13: sw2p2@swp2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff
14: sw2p3@swp2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a6:f4:af:fd:fc:73 brd ff:ff:ff:ff:ff:ff

Would this test be sufficient or do you have a specific concern?

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2021-12-12 18:19 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-11 19:57 [net-next RFC PATCH v4 00/15] Add support for qca8k mdio rw in Ethernet packet Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 01/15] net: dsa: provide switch operations for tracking the master state Ansuel Smith
2021-12-12  4:22   ` Florian Fainelli
2021-12-12 18:19     ` Ansuel Smith
2021-12-12 18:19     ` Vladimir Oltean
2021-12-11 19:57 ` [net-next RFC PATCH v4 02/15] net: dsa: stop updating master MTU from master.c Ansuel Smith
2021-12-12  4:23   ` Florian Fainelli
2021-12-11 19:57 ` [net-next RFC PATCH v4 03/15] net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown} Ansuel Smith
2021-12-12  4:24   ` Florian Fainelli
2021-12-11 19:57 ` [net-next RFC PATCH v4 04/15] net: dsa: replay master state events in dsa_tree_{setup,teardown}_master Ansuel Smith
2021-12-12  4:25   ` Florian Fainelli
2021-12-11 19:57 ` [net-next RFC PATCH v4 05/15] net: dsa: tag_qca: convert to FIELD macro Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 06/15] net: dsa: tag_qca: move define to include linux/dsa Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 07/15] net: da: tag_qca: enable promisc_on_master flag Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 08/15] net: dsa: tag_qca: add define for handling mdio Ethernet packet Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 09/15] net: dsa: tag_qca: add define for handling MIB packet Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 10/15] net: dsa: tag_qca: add support for handling mdio Ethernet and " Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 11/15] net: dsa: qca8k: add tracking state of master port Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 12/15] net: dsa: qca8k: add support for mdio read/write in Ethernet packet Ansuel Smith
2021-12-12  4:12   ` Florian Fainelli
2021-12-12 17:41     ` Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 13/15] net: dsa: qca8k: add support for mib autocast " Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 14/15] net: dsa: qca8k: add support for phy read/write with mdio Ethernet Ansuel Smith
2021-12-11 19:57 ` [net-next RFC PATCH v4 15/15] net: dsa: qca8k: cache lo and hi for mdio write Ansuel Smith
2021-12-12  4:04   ` Florian Fainelli
2021-12-12 17:43     ` Ansuel Smith

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.