mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: dsa: bcm_sf2: add suspend/resume callbacks
Implement the suspend/resume callbacks for the Broadcom Starfighter 2 switch driver. Suspending the switch requires masking interrupts and shutting down ports. Resuming the switch requires a software reset since we do not know which power-sate we might be coming from, and re-enabling the physical ports that are used. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									2446254915
								
							
						
					
					
						commit
						8cfa94984c
					
				
					 1 changed files with 85 additions and 0 deletions
				
			
		| 
						 | 
					@ -606,6 +606,89 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
 | 
				
			||||||
		status->pause = 1;
 | 
							status->pause = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						unsigned int port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable all ports physically present including the IMP
 | 
				
			||||||
 | 
						 * port, the other ones have already been disabled during
 | 
				
			||||||
 | 
						 * bcm_sf2_sw_setup
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for (port = 0; port < DSA_MAX_PORTS; port++) {
 | 
				
			||||||
 | 
							if ((1 << port) & ds->phys_port_mask ||
 | 
				
			||||||
 | 
							    dsa_is_cpu_port(ds, port))
 | 
				
			||||||
 | 
								bcm_sf2_port_disable(ds, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int timeout = 1000;
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_WATCHDOG_CTRL);
 | 
				
			||||||
 | 
						reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_WATCHDOG_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							reg = core_readl(priv, CORE_WATCHDOG_CTRL);
 | 
				
			||||||
 | 
							if (!(reg & SOFTWARE_RESET))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							usleep_range(1000, 2000);
 | 
				
			||||||
 | 
						} while (timeout-- > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (timeout == 0)
 | 
				
			||||||
 | 
							return -ETIMEDOUT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_resume(struct dsa_switch *ds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						unsigned int port;
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = bcm_sf2_sw_rst(priv);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							pr_err("%s: failed to software reset switch\n", __func__);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reinitialize the single GPHY */
 | 
				
			||||||
 | 
						if (priv->hw_params.num_gphy == 1) {
 | 
				
			||||||
 | 
							reg = reg_readl(priv, REG_SPHY_CNTRL);
 | 
				
			||||||
 | 
							reg |= PHY_RESET;
 | 
				
			||||||
 | 
							reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS);
 | 
				
			||||||
 | 
							reg_writel(priv, reg, REG_SPHY_CNTRL);
 | 
				
			||||||
 | 
							udelay(21);
 | 
				
			||||||
 | 
							reg = reg_readl(priv, REG_SPHY_CNTRL);
 | 
				
			||||||
 | 
							reg &= ~PHY_RESET;
 | 
				
			||||||
 | 
							reg_writel(priv, reg, REG_SPHY_CNTRL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (port = 0; port < DSA_MAX_PORTS; port++) {
 | 
				
			||||||
 | 
							if ((1 << port) & ds->phys_port_mask)
 | 
				
			||||||
 | 
								bcm_sf2_port_setup(ds, port);
 | 
				
			||||||
 | 
							else if (dsa_is_cpu_port(ds, port))
 | 
				
			||||||
 | 
								bcm_sf2_imp_setup(ds, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dsa_switch_driver bcm_sf2_switch_driver = {
 | 
					static struct dsa_switch_driver bcm_sf2_switch_driver = {
 | 
				
			||||||
	.tag_protocol		= DSA_TAG_PROTO_BRCM,
 | 
						.tag_protocol		= DSA_TAG_PROTO_BRCM,
 | 
				
			||||||
	.priv_size		= sizeof(struct bcm_sf2_priv),
 | 
						.priv_size		= sizeof(struct bcm_sf2_priv),
 | 
				
			||||||
| 
						 | 
					@ -620,6 +703,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
 | 
				
			||||||
	.get_sset_count		= bcm_sf2_sw_get_sset_count,
 | 
						.get_sset_count		= bcm_sf2_sw_get_sset_count,
 | 
				
			||||||
	.adjust_link		= bcm_sf2_sw_adjust_link,
 | 
						.adjust_link		= bcm_sf2_sw_adjust_link,
 | 
				
			||||||
	.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
 | 
						.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
 | 
				
			||||||
 | 
						.suspend		= bcm_sf2_sw_suspend,
 | 
				
			||||||
 | 
						.resume			= bcm_sf2_sw_resume,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init bcm_sf2_init(void)
 | 
					static int __init bcm_sf2_init(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue