forked from mirrors/linux
		
	net: dsa: bcm_sf2: Make it a real platform device driver
The Broadcom Starfighter 2 switch driver should be a proper platform driver, now that the DSA code has been updated to allow that, register a switch device, feed it with the proper configuration data coming from Device Tree and register our switch device with DSA. The bulk of the changes consist in moving what bcm_sf2_sw_setup() did into the platform driver probe function. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									a85fad1436
								
							
						
					
					
						commit
						d9338023fb
					
				
					 2 changed files with 118 additions and 61 deletions
				
			
		| 
						 | 
					@ -1571,23 +1571,84 @@ static int bcm_sf2_sw_vlan_dump(struct dsa_switch *ds, int port,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
					static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
 | 
					 | 
				
			||||||
	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
	struct device_node *dn;
 | 
					 | 
				
			||||||
	void __iomem **base;
 | 
					 | 
				
			||||||
	unsigned int port;
 | 
						unsigned int port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable all valid ports and disable those unused */
 | 
				
			||||||
 | 
						for (port = 0; port < priv->hw_params.num_ports; port++) {
 | 
				
			||||||
 | 
							/* IMP port receives special treatment */
 | 
				
			||||||
 | 
							if ((1 << port) & ds->enabled_port_mask)
 | 
				
			||||||
 | 
								bcm_sf2_port_setup(ds, port, NULL);
 | 
				
			||||||
 | 
							else if (dsa_is_cpu_port(ds, port))
 | 
				
			||||||
 | 
								bcm_sf2_imp_setup(ds, port);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								bcm_sf2_port_disable(ds, port, NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bcm_sf2_sw_configure_vlan(ds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dsa_switch_driver bcm_sf2_switch_driver = {
 | 
				
			||||||
 | 
						.tag_protocol		= DSA_TAG_PROTO_BRCM,
 | 
				
			||||||
 | 
						.probe			= bcm_sf2_sw_drv_probe,
 | 
				
			||||||
 | 
						.setup			= bcm_sf2_sw_setup,
 | 
				
			||||||
 | 
						.set_addr		= bcm_sf2_sw_set_addr,
 | 
				
			||||||
 | 
						.get_phy_flags		= bcm_sf2_sw_get_phy_flags,
 | 
				
			||||||
 | 
						.get_strings		= bcm_sf2_sw_get_strings,
 | 
				
			||||||
 | 
						.get_ethtool_stats	= bcm_sf2_sw_get_ethtool_stats,
 | 
				
			||||||
 | 
						.get_sset_count		= bcm_sf2_sw_get_sset_count,
 | 
				
			||||||
 | 
						.adjust_link		= bcm_sf2_sw_adjust_link,
 | 
				
			||||||
 | 
						.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
 | 
				
			||||||
 | 
						.suspend		= bcm_sf2_sw_suspend,
 | 
				
			||||||
 | 
						.resume			= bcm_sf2_sw_resume,
 | 
				
			||||||
 | 
						.get_wol		= bcm_sf2_sw_get_wol,
 | 
				
			||||||
 | 
						.set_wol		= bcm_sf2_sw_set_wol,
 | 
				
			||||||
 | 
						.port_enable		= bcm_sf2_port_setup,
 | 
				
			||||||
 | 
						.port_disable		= bcm_sf2_port_disable,
 | 
				
			||||||
 | 
						.get_eee		= bcm_sf2_sw_get_eee,
 | 
				
			||||||
 | 
						.set_eee		= bcm_sf2_sw_set_eee,
 | 
				
			||||||
 | 
						.port_bridge_join	= bcm_sf2_sw_br_join,
 | 
				
			||||||
 | 
						.port_bridge_leave	= bcm_sf2_sw_br_leave,
 | 
				
			||||||
 | 
						.port_stp_state_set	= bcm_sf2_sw_br_set_stp_state,
 | 
				
			||||||
 | 
						.port_fdb_prepare	= bcm_sf2_sw_fdb_prepare,
 | 
				
			||||||
 | 
						.port_fdb_add		= bcm_sf2_sw_fdb_add,
 | 
				
			||||||
 | 
						.port_fdb_del		= bcm_sf2_sw_fdb_del,
 | 
				
			||||||
 | 
						.port_fdb_dump		= bcm_sf2_sw_fdb_dump,
 | 
				
			||||||
 | 
						.port_vlan_filtering	= bcm_sf2_sw_vlan_filtering,
 | 
				
			||||||
 | 
						.port_vlan_prepare	= bcm_sf2_sw_vlan_prepare,
 | 
				
			||||||
 | 
						.port_vlan_add		= bcm_sf2_sw_vlan_add,
 | 
				
			||||||
 | 
						.port_vlan_del		= bcm_sf2_sw_vlan_del,
 | 
				
			||||||
 | 
						.port_vlan_dump		= bcm_sf2_sw_vlan_dump,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
 | 
				
			||||||
 | 
						struct device_node *dn = pdev->dev.of_node;
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv;
 | 
				
			||||||
 | 
						struct dsa_switch *ds;
 | 
				
			||||||
 | 
						void __iomem **base;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	u32 reg, rev;
 | 
						u32 reg, rev;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ds = devm_kzalloc(&pdev->dev, sizeof(*ds) + sizeof(*priv), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!ds)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv = (struct bcm_sf2_priv *)(ds + 1);
 | 
				
			||||||
 | 
						ds->priv = priv;
 | 
				
			||||||
 | 
						ds->dev = &pdev->dev;
 | 
				
			||||||
 | 
						ds->drv = &bcm_sf2_switch_driver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_set_drvdata(&pdev->dev, ds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_init(&priv->indir_lock);
 | 
						spin_lock_init(&priv->indir_lock);
 | 
				
			||||||
	mutex_init(&priv->stats_mutex);
 | 
						mutex_init(&priv->stats_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* All the interesting properties are at the parent device_node
 | 
						bcm_sf2_identify_ports(priv, dn->child);
 | 
				
			||||||
	 * level
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	dn = ds->cd->of_node->parent;
 | 
					 | 
				
			||||||
	bcm_sf2_identify_ports(priv, ds->cd->of_node);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv->irq0 = irq_of_parse_and_map(dn, 0);
 | 
						priv->irq0 = irq_of_parse_and_map(dn, 0);
 | 
				
			||||||
	priv->irq1 = irq_of_parse_and_map(dn, 1);
 | 
						priv->irq1 = irq_of_parse_and_map(dn, 1);
 | 
				
			||||||
| 
						 | 
					@ -1649,19 +1710,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
				
			||||||
				 &priv->hw_params.num_gphy))
 | 
									 &priv->hw_params.num_gphy))
 | 
				
			||||||
		priv->hw_params.num_gphy = 1;
 | 
							priv->hw_params.num_gphy = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Enable all valid ports and disable those unused */
 | 
					 | 
				
			||||||
	for (port = 0; port < priv->hw_params.num_ports; port++) {
 | 
					 | 
				
			||||||
		/* IMP port receives special treatment */
 | 
					 | 
				
			||||||
		if ((1 << port) & ds->enabled_port_mask)
 | 
					 | 
				
			||||||
			bcm_sf2_port_setup(ds, port, NULL);
 | 
					 | 
				
			||||||
		else if (dsa_is_cpu_port(ds, port))
 | 
					 | 
				
			||||||
			bcm_sf2_imp_setup(ds, port);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			bcm_sf2_port_disable(ds, port, NULL);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bcm_sf2_sw_configure_vlan(ds);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rev = reg_readl(priv, REG_SWITCH_REVISION);
 | 
						rev = reg_readl(priv, REG_SWITCH_REVISION);
 | 
				
			||||||
	priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
 | 
						priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
 | 
				
			||||||
					SWITCH_TOP_REV_MASK;
 | 
										SWITCH_TOP_REV_MASK;
 | 
				
			||||||
| 
						 | 
					@ -1670,6 +1718,10 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
				
			||||||
	rev = reg_readl(priv, REG_PHY_REVISION);
 | 
						rev = reg_readl(priv, REG_PHY_REVISION);
 | 
				
			||||||
	priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
 | 
						priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = dsa_register_switch(ds, dn);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto out_free_irq1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
 | 
						pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
 | 
				
			||||||
		priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
 | 
							priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
 | 
				
			||||||
		priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
 | 
							priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
 | 
				
			||||||
| 
						 | 
					@ -1677,6 +1729,8 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_free_irq1:
 | 
				
			||||||
 | 
						free_irq(priv->irq1, priv);
 | 
				
			||||||
out_free_irq0:
 | 
					out_free_irq0:
 | 
				
			||||||
	free_irq(priv->irq0, priv);
 | 
						free_irq(priv->irq0, priv);
 | 
				
			||||||
out_mdio:
 | 
					out_mdio:
 | 
				
			||||||
| 
						 | 
					@ -1691,52 +1745,56 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dsa_switch_driver bcm_sf2_switch_driver = {
 | 
					static int bcm_sf2_sw_remove(struct platform_device *pdev)
 | 
				
			||||||
	.tag_protocol		= DSA_TAG_PROTO_BRCM,
 | 
					 | 
				
			||||||
	.probe			= bcm_sf2_sw_drv_probe,
 | 
					 | 
				
			||||||
	.setup			= bcm_sf2_sw_setup,
 | 
					 | 
				
			||||||
	.set_addr		= bcm_sf2_sw_set_addr,
 | 
					 | 
				
			||||||
	.get_phy_flags		= bcm_sf2_sw_get_phy_flags,
 | 
					 | 
				
			||||||
	.get_strings		= bcm_sf2_sw_get_strings,
 | 
					 | 
				
			||||||
	.get_ethtool_stats	= bcm_sf2_sw_get_ethtool_stats,
 | 
					 | 
				
			||||||
	.get_sset_count		= bcm_sf2_sw_get_sset_count,
 | 
					 | 
				
			||||||
	.adjust_link		= bcm_sf2_sw_adjust_link,
 | 
					 | 
				
			||||||
	.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
 | 
					 | 
				
			||||||
	.suspend		= bcm_sf2_sw_suspend,
 | 
					 | 
				
			||||||
	.resume			= bcm_sf2_sw_resume,
 | 
					 | 
				
			||||||
	.get_wol		= bcm_sf2_sw_get_wol,
 | 
					 | 
				
			||||||
	.set_wol		= bcm_sf2_sw_set_wol,
 | 
					 | 
				
			||||||
	.port_enable		= bcm_sf2_port_setup,
 | 
					 | 
				
			||||||
	.port_disable		= bcm_sf2_port_disable,
 | 
					 | 
				
			||||||
	.get_eee		= bcm_sf2_sw_get_eee,
 | 
					 | 
				
			||||||
	.set_eee		= bcm_sf2_sw_set_eee,
 | 
					 | 
				
			||||||
	.port_bridge_join	= bcm_sf2_sw_br_join,
 | 
					 | 
				
			||||||
	.port_bridge_leave	= bcm_sf2_sw_br_leave,
 | 
					 | 
				
			||||||
	.port_stp_state_set	= bcm_sf2_sw_br_set_stp_state,
 | 
					 | 
				
			||||||
	.port_fdb_prepare	= bcm_sf2_sw_fdb_prepare,
 | 
					 | 
				
			||||||
	.port_fdb_add		= bcm_sf2_sw_fdb_add,
 | 
					 | 
				
			||||||
	.port_fdb_del		= bcm_sf2_sw_fdb_del,
 | 
					 | 
				
			||||||
	.port_fdb_dump		= bcm_sf2_sw_fdb_dump,
 | 
					 | 
				
			||||||
	.port_vlan_filtering	= bcm_sf2_sw_vlan_filtering,
 | 
					 | 
				
			||||||
	.port_vlan_prepare	= bcm_sf2_sw_vlan_prepare,
 | 
					 | 
				
			||||||
	.port_vlan_add		= bcm_sf2_sw_vlan_add,
 | 
					 | 
				
			||||||
	.port_vlan_del		= bcm_sf2_sw_vlan_del,
 | 
					 | 
				
			||||||
	.port_vlan_dump		= bcm_sf2_sw_vlan_dump,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init bcm_sf2_init(void)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	register_switch_driver(&bcm_sf2_switch_driver);
 | 
						struct dsa_switch *ds = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable all ports and interrupts */
 | 
				
			||||||
 | 
						priv->wol_ports_mask = 0;
 | 
				
			||||||
 | 
						bcm_sf2_sw_suspend(ds);
 | 
				
			||||||
 | 
						dsa_unregister_switch(ds);
 | 
				
			||||||
 | 
						bcm_sf2_mdio_unregister(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module_init(bcm_sf2_init);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit bcm_sf2_exit(void)
 | 
					#ifdef CONFIG_PM_SLEEP
 | 
				
			||||||
 | 
					static int bcm_sf2_suspend(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unregister_switch_driver(&bcm_sf2_switch_driver);
 | 
						struct platform_device *pdev = to_platform_device(dev);
 | 
				
			||||||
 | 
						struct dsa_switch *ds = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dsa_switch_suspend(ds);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module_exit(bcm_sf2_exit);
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_resume(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct platform_device *pdev = to_platform_device(dev);
 | 
				
			||||||
 | 
						struct dsa_switch *ds = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dsa_switch_resume(ds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* CONFIG_PM_SLEEP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,
 | 
				
			||||||
 | 
								 bcm_sf2_suspend, bcm_sf2_resume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id bcm_sf2_of_match[] = {
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm7445-switch-v4.0" },
 | 
				
			||||||
 | 
						{ /* sentinel */ },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct platform_driver bcm_sf2_driver = {
 | 
				
			||||||
 | 
						.probe	= bcm_sf2_sw_probe,
 | 
				
			||||||
 | 
						.remove	= bcm_sf2_sw_remove,
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name = "brcm-sf2",
 | 
				
			||||||
 | 
							.of_match_table = bcm_sf2_of_match,
 | 
				
			||||||
 | 
							.pm = &bcm_sf2_pm_ops,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					module_platform_driver(bcm_sf2_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Broadcom Corporation");
 | 
					MODULE_AUTHOR("Broadcom Corporation");
 | 
				
			||||||
MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
 | 
					MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1088,7 +1088,6 @@ static int dsa_resume(struct device *d)
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(dsa_pm_ops, dsa_suspend, dsa_resume);
 | 
					static SIMPLE_DEV_PM_OPS(dsa_pm_ops, dsa_suspend, dsa_resume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct of_device_id dsa_of_match_table[] = {
 | 
					static const struct of_device_id dsa_of_match_table[] = {
 | 
				
			||||||
	{ .compatible = "brcm,bcm7445-switch-v4.0" },
 | 
					 | 
				
			||||||
	{ .compatible = "marvell,dsa", },
 | 
						{ .compatible = "marvell,dsa", },
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue