forked from mirrors/linux
		
	net: mscc: ocelot: remove struct ocelot_mm_state :: lock
Unfortunately, the workarounds for the hardware bugs make it pointless to keep fine-grained locking for the MAC Merge state of each port. Our vsc9959_cut_through_fwd() implementation requires ocelot->fwd_domain_lock to be held, in order to serialize with changes to the bridging domains and to port speed changes (which affect which ports can be cut-through). Simultaneously, the traffic classes which can be cut-through cannot be preemptible at the same time, and this will depend on the MAC Merge layer state (which changes from threaded interrupt context). Since vsc9959_cut_through_fwd() would have to hold the mm->lock of all ports for a correct and race-free implementation with respect to ocelot_mm_irq(), in practice it means that any time a port's mm->lock is held, it would potentially block holders of ocelot->fwd_domain_lock. In the interest of simple locking rules, make all MAC Merge layer state changes (and preemptible traffic class changes) be serialized by the ocelot->fwd_domain_lock. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									15f93f46f3
								
							
						
					
					
						commit
						3ff468ef98
					
				
					 2 changed files with 8 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -56,8 +56,6 @@ static void ocelot_mm_update_port_status(struct ocelot *ocelot, int port)
 | 
			
		|||
	enum ethtool_mm_verify_status verify_status;
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&mm->lock);
 | 
			
		||||
 | 
			
		||||
	val = ocelot_port_readl(ocelot_port, DEV_MM_STATUS);
 | 
			
		||||
 | 
			
		||||
	verify_status = ocelot_mm_verify_status(val);
 | 
			
		||||
| 
						 | 
				
			
			@ -88,16 +86,18 @@ static void ocelot_mm_update_port_status(struct ocelot *ocelot, int port)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	ocelot_port_writel(ocelot_port, val, DEV_MM_STATUS);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&mm->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ocelot_mm_irq(struct ocelot *ocelot)
 | 
			
		||||
{
 | 
			
		||||
	int port;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ocelot->fwd_domain_lock);
 | 
			
		||||
 | 
			
		||||
	for (port = 0; port < ocelot->num_phys_ports; port++)
 | 
			
		||||
		ocelot_mm_update_port_status(ocelot, port);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&ocelot->fwd_domain_lock);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ocelot_mm_irq);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -107,14 +107,11 @@ int ocelot_port_set_mm(struct ocelot *ocelot, int port,
 | 
			
		|||
{
 | 
			
		||||
	struct ocelot_port *ocelot_port = ocelot->ports[port];
 | 
			
		||||
	u32 mm_enable = 0, verify_disable = 0, add_frag_size;
 | 
			
		||||
	struct ocelot_mm_state *mm;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (!ocelot->mm_supported)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	mm = &ocelot->mm[port];
 | 
			
		||||
 | 
			
		||||
	err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size,
 | 
			
		||||
					      &add_frag_size, extack);
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +126,7 @@ int ocelot_port_set_mm(struct ocelot *ocelot, int port,
 | 
			
		|||
	if (!cfg->verify_enabled)
 | 
			
		||||
		verify_disable = DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&mm->lock);
 | 
			
		||||
	mutex_lock(&ocelot->fwd_domain_lock);
 | 
			
		||||
 | 
			
		||||
	ocelot_port_rmwl(ocelot_port, mm_enable,
 | 
			
		||||
			 DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA |
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +145,7 @@ int ocelot_port_set_mm(struct ocelot *ocelot, int port,
 | 
			
		|||
		       QSYS_PREEMPTION_CFG,
 | 
			
		||||
		       port);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&mm->lock);
 | 
			
		||||
	mutex_unlock(&ocelot->fwd_domain_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +163,7 @@ int ocelot_port_get_mm(struct ocelot *ocelot, int port,
 | 
			
		|||
 | 
			
		||||
	mm = &ocelot->mm[port];
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&mm->lock);
 | 
			
		||||
	mutex_lock(&ocelot->fwd_domain_lock);
 | 
			
		||||
 | 
			
		||||
	val = ocelot_port_readl(ocelot_port, DEV_MM_ENABLE_CONFIG);
 | 
			
		||||
	state->pmac_enabled = !!(val & DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA);
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +182,7 @@ int ocelot_port_get_mm(struct ocelot *ocelot, int port,
 | 
			
		|||
	state->verify_status = mm->verify_status;
 | 
			
		||||
	state->tx_active = mm->tx_active;
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&mm->lock);
 | 
			
		||||
	mutex_unlock(&ocelot->fwd_domain_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +206,6 @@ int ocelot_mm_init(struct ocelot *ocelot)
 | 
			
		|||
		u32 val;
 | 
			
		||||
 | 
			
		||||
		mm = &ocelot->mm[port];
 | 
			
		||||
		mutex_init(&mm->lock);
 | 
			
		||||
		ocelot_port = ocelot->ports[port];
 | 
			
		||||
 | 
			
		||||
		/* Update initial status variable for the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -744,7 +744,6 @@ struct ocelot_mirror {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
struct ocelot_mm_state {
 | 
			
		||||
	struct mutex lock;
 | 
			
		||||
	enum ethtool_mm_verify_status verify_status;
 | 
			
		||||
	bool tx_active;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue