static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port, u32 br_port_mask) { struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int i; u32 reg, p_ctl; p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); for (i = 0; i < priv->hw_params.num_ports; i++) { /* Don't touch the remaining ports */ if (!((1 << i) & br_port_mask)) continue; reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); reg &= ~(1 << port); core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); priv->port_sts[port].vlan_ctl_mask = reg; /* Prevent self removal to preserve isolation */ if (port != i) p_ctl &= ~(1 << i); } core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port)); priv->port_sts[port].vlan_ctl_mask = p_ctl; return 0; }
static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port, u32 br_port_mask) { struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int i; u32 reg, p_ctl; p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); for (i = 0; i < priv->hw_params.num_ports; i++) { if (!((1 << i) & br_port_mask)) continue; /* Add this local port to the remote port VLAN control * membership and update the remote port bitmask */ reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); reg |= 1 << port; core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); priv->port_sts[i].vlan_ctl_mask = reg; p_ctl |= 1 << i; } /* Configure the local port VLAN control membership to include * remote ports and update the local port bitmask */ core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port)); priv->port_sts[port].vlan_ctl_mask = p_ctl; return 0; }
static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, struct phy_device *phy) { struct bcm_sf2_priv *priv = ds_to_priv(ds); s8 cpu_port = ds->dst[ds->index].cpu_port; u32 reg; /* Clear the memory power down */ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); reg &= ~P_TXQ_PSM_VDD(port); core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); /* Clear the Rx and Tx disable bits and set to no spanning tree */ core_writel(priv, 0, CORE_G_PCTL_PORT(port)); /* Enable port 7 interrupts to get notified */ if (port == 7) intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); /* Set this port, and only this one to be in the default VLAN */ reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); reg &= ~PORT_VLAN_CTRL_MASK; reg |= (1 << port); core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port)); bcm_sf2_imp_vlan_setup(ds, cpu_port); /* If EEE was enabled, restore it */ if (priv->port_sts[port].eee.eee_enabled) bcm_sf2_eee_enable_set(ds, port, true); return 0; }
static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, struct phy_device *phy) { struct bcm_sf2_priv *priv = ds_to_priv(ds); s8 cpu_port = ds->dst[ds->index].cpu_port; u32 reg; /* Clear the memory power down */ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); reg &= ~P_TXQ_PSM_VDD(port); core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); /* Clear the Rx and Tx disable bits and set to no spanning tree */ core_writel(priv, 0, CORE_G_PCTL_PORT(port)); /* Re-enable the GPHY and re-apply workarounds */ if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1) { bcm_sf2_gphy_enable_set(ds, true); if (phy) { /* if phy_stop() has been called before, phy * will be in halted state, and phy_start() * will call resume. * * the resume path does not configure back * autoneg settings, and since we hard reset * the phy manually here, we need to reset the * state machine also. */ phy->state = PHY_READY; phy_init_hw(phy); } } /* Enable MoCA port interrupts to get notified */ if (port == priv->moca_port) bcm_sf2_port_intr_enable(priv, port); /* Set this port, and only this one to be in the default VLAN, * if member of a bridge, restore its membership prior to * bringing down this port. */ reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); reg &= ~PORT_VLAN_CTRL_MASK; reg |= (1 << port); reg |= priv->port_sts[port].vlan_ctl_mask; core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port)); bcm_sf2_imp_vlan_setup(ds, cpu_port); /* If EEE was enabled, restore it */ if (priv->port_sts[port].eee.eee_enabled) bcm_sf2_eee_enable_set(ds, port, true); return 0; }
static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port, struct net_device *bridge) { struct bcm_sf2_priv *priv = ds_to_priv(ds); s8 cpu_port = ds->dst->cpu_port; unsigned int i; u32 reg, p_ctl; /* Make this port leave the all VLANs join since we will have proper * VLAN entries from now on */ reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN); reg &= ~BIT(port); if ((reg & BIT(cpu_port)) == BIT(cpu_port)) reg &= ~BIT(cpu_port); core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN); priv->port_sts[port].bridge_dev = bridge; p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); for (i = 0; i < priv->hw_params.num_ports; i++) { if (priv->port_sts[i].bridge_dev != bridge) continue; /* Add this local port to the remote port VLAN control * membership and update the remote port bitmask */ reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); reg |= 1 << port; core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); priv->port_sts[i].vlan_ctl_mask = reg; p_ctl |= 1 << i; } /* Configure the local port VLAN control membership to include * remote ports and update the local port bitmask */ core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port)); priv->port_sts[port].vlan_ctl_mask = p_ctl; return 0; }
static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port) { struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int i; u32 reg; /* Enable the IMP Port to be in the same VLAN as the other ports * on a per-port basis such that we only have Port i and IMP in * the same VLAN. */ for (i = 0; i < priv->hw_params.num_ports; i++) { if (!((1 << i) & ds->enabled_port_mask)) continue; reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); reg |= (1 << cpu_port); core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); } }
static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port) { struct bcm_sf2_priv *priv = ds_to_priv(ds); struct net_device *bridge = priv->port_sts[port].bridge_dev; s8 cpu_port = ds->dst->cpu_port; unsigned int i; u32 reg, p_ctl; p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); for (i = 0; i < priv->hw_params.num_ports; i++) { /* Don't touch the remaining ports */ if (priv->port_sts[i].bridge_dev != bridge) continue; reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); reg &= ~(1 << port); core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); priv->port_sts[port].vlan_ctl_mask = reg; /* Prevent self removal to preserve isolation */ if (port != i) p_ctl &= ~(1 << i); } core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port)); priv->port_sts[port].vlan_ctl_mask = p_ctl; priv->port_sts[port].bridge_dev = NULL; /* Make this port join all VLANs without VLAN entries */ reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN); reg |= BIT(port); if (!(reg & BIT(cpu_port))) reg |= BIT(cpu_port); core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN); }