mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04:00 
			
		
		
		
	Manually rebase: pending-5.15/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch ath79/patches-5.15/910-unaligned_access_hacks.patch All other patches automatically rebased Build system: x86_64 Build-tested: bcm2711/RPi4B Run-tested: bcm2711/RPi4B Signed-off-by: John Audia <therealgraysky@proton.me>
		
			
				
	
	
		
			255 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 295ab96f478d0fa56393e85406f19a867e26ce22 Mon Sep 17 00:00:00 2001
 | |
| From: Vladimir Oltean <vladimir.oltean@nxp.com>
 | |
| Date: Wed, 2 Feb 2022 01:03:20 +0100
 | |
| Subject: [PATCH 01/16] net: dsa: provide switch operations for tracking the
 | |
|  master state
 | |
| 
 | |
| 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.
 | |
| 
 | |
| An helper is added dsa_port_master_is_operational() to check if a master
 | |
| port is operational.
 | |
| 
 | |
| 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>
 | |
| Signed-off-by: David S. Miller <davem@davemloft.net>
 | |
| ---
 | |
|  include/net/dsa.h  | 17 +++++++++++++++++
 | |
|  net/dsa/dsa2.c     | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 | |
|  net/dsa/dsa_priv.h | 13 +++++++++++++
 | |
|  net/dsa/slave.c    | 32 ++++++++++++++++++++++++++++++++
 | |
|  net/dsa/switch.c   | 15 +++++++++++++++
 | |
|  5 files changed, 123 insertions(+)
 | |
| 
 | |
| --- a/include/net/dsa.h
 | |
| +++ b/include/net/dsa.h
 | |
| @@ -291,6 +291,10 @@ struct dsa_port {
 | |
|  	struct list_head	mdbs;
 | |
|  
 | |
|  	bool setup;
 | |
| +	/* Master state bits, valid only on CPU ports */
 | |
| +	u8			master_admin_up:1;
 | |
| +	u8			master_oper_up:1;
 | |
| +
 | |
|  };
 | |
|  
 | |
|  /* TODO: ideally DSA ports would have a single dp->link_dp member,
 | |
| @@ -456,6 +460,12 @@ static inline bool dsa_port_is_unused(st
 | |
|  	return dp->type == DSA_PORT_TYPE_UNUSED;
 | |
|  }
 | |
|  
 | |
| +static inline bool dsa_port_master_is_operational(struct dsa_port *dp)
 | |
| +{
 | |
| +	return dsa_port_is_cpu(dp) && dp->master_admin_up &&
 | |
| +	       dp->master_oper_up;
 | |
| +}
 | |
| +
 | |
|  static inline bool dsa_is_unused_port(struct dsa_switch *ds, int p)
 | |
|  {
 | |
|  	return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_UNUSED;
 | |
| @@ -949,6 +959,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)		\
 | |
| --- a/net/dsa/dsa2.c
 | |
| +++ b/net/dsa/dsa2.c
 | |
| @@ -1275,6 +1275,52 @@ out_unlock:
 | |
|  	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 = dsa_port_master_is_operational(cpu_dp);
 | |
| +
 | |
| +	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 ((dsa_port_master_is_operational(cpu_dp)) !=
 | |
| +	    (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 ((dsa_port_master_is_operational(cpu_dp)) !=
 | |
| +	    (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;
 | |
| --- a/net/dsa/dsa_priv.h
 | |
| +++ b/net/dsa/dsa_priv.h
 | |
| @@ -45,6 +45,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;
 | |
| @@ -549,6 +556,12 @@ int dsa_tree_change_tag_proto(struct dsa
 | |
|  			      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);
 | |
|  int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
 | |
|  void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num);
 | |
|  
 | |
| --- a/net/dsa/slave.c
 | |
| +++ b/net/dsa/slave.c
 | |
| @@ -2311,6 +2311,36 @@ static int dsa_slave_netdevice_event(str
 | |
|  		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;
 | |
| @@ -2322,6 +2352,8 @@ static int dsa_slave_netdevice_event(str
 | |
|  		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_is_user_port(dp->ds, dp->index))
 | |
|  				continue;
 | |
| --- a/net/dsa/switch.c
 | |
| +++ b/net/dsa/switch.c
 | |
| @@ -722,6 +722,18 @@ dsa_switch_mrp_del_ring_role(struct dsa_
 | |
|  	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)
 | |
|  {
 | |
| @@ -813,6 +825,9 @@ static int dsa_switch_event(struct notif
 | |
|  	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;
 |