/* * B53 switch driver main logic * * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
if (is5325(dev) || is5365(dev)) { /* enable the high 8 bit vid check on 5325 */ if (is5325(dev) && enable)
b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3,
VC3_HIGH_8BIT_EN); else
b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
/* BCM5325 CPU port is at 8 */ if ((is5325(dev) || is5365(dev)) && cpu_port == B53_CPU_PORT_25)
cpu_port = B53_CPU_PORT;
/* 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.
*/
b53_for_each_port(dev, i) {
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), &pvlan);
pvlan |= BIT(cpu_port);
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), pvlan);
}
}
EXPORT_SYMBOL(b53_imp_vlan_setup);
/* Force all traffic to go to the CPU port to prevent the ASIC from * trying to forward to bridged ports on matching FDB entries, then * dropping frames because it isn't allowed to forward there.
*/ if (dsa_is_user_port(ds, port))
b53_set_eap_mode(dev, port, EAP_MODE_SIMPLIFIED);
if (is5325(dev) &&
in_range(port, 1, 4)) {
u8 reg;
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
{ struct b53_device *dev = ds->priv; unsignedint cpu_port; int ret = 0;
u16 pvlan;
if (!dsa_is_user_port(ds, port)) return 0;
cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
if (dev->ops->phy_enable)
dev->ops->phy_enable(dev, port);
if (dev->ops->irq_enable)
ret = dev->ops->irq_enable(dev, port); if (ret) return ret;
/* Clear the Rx and Tx disable bits and set to no spanning tree */
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0);
/* 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.
*/
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
pvlan &= ~0x1ff;
pvlan |= BIT(port);
pvlan |= dev->ports[port].vlan_ctl_mask;
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
b53_imp_vlan_setup(ds, cpu_port);
/* If EEE was enabled, restore it */ if (dev->ports[port].eee.eee_enabled)
b53_eee_enable_set(ds, port, true);
/* Resolve which bit controls the Broadcom tag */ switch (port) { case 8:
val = BRCM_HDR_P8_EN; break; case 7:
val = BRCM_HDR_P7_EN; break; case 5:
val = BRCM_HDR_P5_EN; break; default:
val = 0; break;
}
/* Enable management mode if tagging is requested */
b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &hdr_ctl); if (tag_en)
hdr_ctl |= SM_SW_FWD_MODE; else
hdr_ctl &= ~SM_SW_FWD_MODE;
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, hdr_ctl);
/* Configure the appropriate IMP port */
b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &hdr_ctl); if (port == 8)
hdr_ctl |= GC_FRM_MGMT_PORT_MII; elseif (port == 5)
hdr_ctl |= GC_FRM_MGMT_PORT_M;
b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, hdr_ctl);
/* B53_BRCM_HDR not present on devices with legacy tags */ if (dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY ||
dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY_FCS) return;
/* Enable Broadcom tags for IMP port */
b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl); if (tag_en)
hdr_ctl |= val; else
hdr_ctl &= ~val;
b53_write8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, hdr_ctl);
/* Registers below are only accessible on newer devices */ if (!is58xx(dev)) return;
/* Enable reception Broadcom tag for CPU TX (switch RX) to * allow us to tag outgoing frames
*/
b53_read16(dev, B53_MGMT_PAGE, B53_BRCM_HDR_RX_DIS, ®); if (tag_en)
reg &= ~BIT(port); else
reg |= BIT(port);
b53_write16(dev, B53_MGMT_PAGE, B53_BRCM_HDR_RX_DIS, reg);
/* Enable transmission of Broadcom tags from the switch (CPU RX) to * allow delivering frames to the per-port net_devices
*/
b53_read16(dev, B53_MGMT_PAGE, B53_BRCM_HDR_TX_DIS, ®); if (tag_en)
reg &= ~BIT(port); else
reg |= BIT(port);
b53_write16(dev, B53_MGMT_PAGE, B53_BRCM_HDR_TX_DIS, reg);
}
EXPORT_SYMBOL(b53_brcm_hdr_setup);
staticvoid b53_enable_cpu_port(struct b53_device *dev, int port)
{
u8 port_ctrl;
/* BCM5325 CPU port is at 8 */ if ((is5325(dev) || is5365(dev)) && port == B53_CPU_PORT_25)
port = B53_CPU_PORT;
int b53_configure_vlan(struct dsa_switch *ds)
{ struct b53_device *dev = ds->priv; struct b53_vlan vl = { 0 }; struct b53_vlan *v; int i, def_vid;
u16 vid;
def_vid = b53_default_pvid(dev);
/* clear all vlan entries */ if (is5325(dev) || is5365(dev)) { for (i = def_vid; i < dev->num_vlans; i++)
b53_set_vlan_entry(dev, i, &vl);
} else {
b53_do_vlan_op(dev, VTA_CMD_CLEAR);
}
/* Create an untagged VLAN entry for the default PVID in case * CONFIG_VLAN_8021Q is disabled and there are no calls to * dsa_user_vlan_rx_add_vid() to create the default VLAN * entry. Do this only when the tagging protocol is not * DSA_TAG_PROTO_NONE
*/
v = &dev->vlans[def_vid];
b53_for_each_port(dev, i) { if (!b53_vlan_port_may_join_untagged(ds, i)) continue;
if (dev->vlan_filtering) { /* Upon initial call we have not set-up any VLANs, but upon * system resume, we need to restore all VLAN entries.
*/ for (vid = def_vid + 1; vid < dev->num_vlans; vid++) {
v = &dev->vlans[vid];
/* This is specific to 58xx devices here, do not use is58xx() which * covers the larger Starfigther 2 family, including 7445/7278 which * still use this driver as a library and need to perform the reset * earlier.
*/ if (dev->chip_id == BCM58XX_DEVICE_ID ||
dev->chip_id == BCM583XX_DEVICE_ID) {
b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, ®);
reg |= SW_RST | EN_SW_RST | EN_CH_RST;
b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, reg);
do {
b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, ®); if (!(reg & SW_RST)) break;
usleep_range(1000, 2000);
} while (timeout-- > 0);
if (timeout == 0) {
dev_err(dev->dev, "Timeout waiting for SW_RST to clear!\n"); return -ETIMEDOUT;
}
}
staticstruct phy_device *b53_get_phy_device(struct dsa_switch *ds, int port)
{ /* These ports typically do not have built-in PHYs */ switch (port) { case B53_CPU_PORT_25: case 7: case B53_CPU_PORT: return NULL;
}
/* Request bridge PVID untagged when DSA_TAG_PROTO_NONE is set * which forces the CPU port to be tagged in all VLANs.
*/
ds->untag_bridge_pvid = dev->tag_protocol == DSA_TAG_PROTO_NONE;
/* The switch does not tell us the original VLAN for untagged * packets, so keep the CPU port always tagged.
*/
ds->untag_vlan_aware_bridge_pvid = true;
ret = b53_apply_config(dev); if (ret) {
dev_err(ds->dev, "failed to apply configuration\n"); return ret;
}
/* Configure IMP/CPU port, disable all other ports. Enabled * ports will be configured with .port_enable
*/ for (port = 0; port < dev->num_ports; port++) { if (dsa_is_cpu_port(ds, port))
b53_enable_cpu_port(dev, port); else
b53_disable_port(ds, port);
}
staticvoid b53_force_link(struct b53_device *dev, int port, int link)
{
u8 reg, val, off;
/* Override the port settings */ if (port == dev->imp_port) {
off = B53_PORT_OVERRIDE_CTRL;
val = PORT_OVERRIDE_EN;
} elseif (is5325(dev)) { return;
} else {
off = B53_GMII_PORT_OVERRIDE_CTRL(port);
val = GMII_PO_EN;
}
staticvoid b53_force_port_config(struct b53_device *dev, int port, int speed, int duplex, bool tx_pause, bool rx_pause)
{
u8 reg, val, off;
/* Override the port settings */ if (port == dev->imp_port) {
off = B53_PORT_OVERRIDE_CTRL;
val = PORT_OVERRIDE_EN;
} elseif (is5325(dev)) { return;
} else {
off = B53_GMII_PORT_OVERRIDE_CTRL(port);
val = GMII_PO_EN;
}
if (port == dev->imp_port)
off = B53_RGMII_CTRL_IMP; else
off = B53_RGMII_CTRL_P(port);
/* Configure the port RGMII clock delay by DLL disabled and * tx_clk aligned timing (restoring to reset defaults)
*/
b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
/* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make * sure that we enable the port TX clock internal delay to * account for this internal delay that is inserted, otherwise * the switch won't be able to receive correctly. * * PHY_INTERFACE_MODE_RGMII means that we are not introducing * any delay neither on transmission nor reception, so the * BCM53125 must also be configured accordingly to account for * the lack of delay and introduce * * The BCM53125 switch has its RX clock and TX clock control * swapped, hence the reason why we modify the TX clock path in * the "RGMII" case
*/ if (interface == PHY_INTERFACE_MODE_RGMII_TXID)
rgmii_ctrl |= RGMII_CTRL_DLL_TXC; if (interface == PHY_INTERFACE_MODE_RGMII)
rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC;
if (dev->chip_id != BCM53115_DEVICE_ID)
rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
dev_info(ds->dev, "Configured port %d for %s\n", port,
phy_modes(interface));
}
/* Internal ports need GMII for PHYLIB */
__set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces);
/* These switches appear to support MII and RevMII too, but beyond * this, the code gives very few clues. FIXME: We probably need more * interface modes here. * * According to b53_srab_mux_init(), ports 3..5 can support: * SGMII, MII, GMII, RGMII or INTERNAL depending on the MUX setting. * However, the interface mode read from the MUX configuration is * not passed back to DSA, so phylink uses NA. * DT can specify RGMII for ports 0, 1. * For MDIO, port 8 can be RGMII_TXID.
*/
__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_REVMII, config->supported_interfaces);
/* BCM63xx RGMII ports support RGMII */ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
phy_interface_set_rgmii(config->supported_interfaces);
/* 5325/5365 are not capable of gigabit speeds, everything else is. * Note: the original code also exclulded Gigagbit for MII, RevMII * and 802.3z modes. MII and RevMII are not able to work above 100M, * so will be excluded by the generic validator implementation. * However, the exclusion of Gigabit for 802.3z just seems wrong.
*/ if (!(is5325(dev) || is5365(dev)))
config->mac_capabilities |= MAC_1000;
/* Get the implementation specific capabilities */ if (dev->ops->phylink_get_caps)
dev->ops->phylink_get_caps(dev, port, config);
}
if ((is5325(dev) || is5365(dev)) && vlan->vid == 0) return -EOPNOTSUPP;
/* Port 7 on 7278 connects to the ASP's UniMAC which is not capable of * receiving VLAN tagged frames at all, we can still allow the port to * be configured for egress untagged.
*/ if (dev->chip_id == BCM7278_DEVICE_ID && port == 7 &&
!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED)) return -EINVAL;
/* Convert the array into a 64-bit MAC */
mac = ether_addr_to_u64(addr);
/* Perform a read for the given MAC and VID */
b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac); if (!is5325m(dev))
b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid);
/* Issue a read operation for this MAC */
ret = b53_arl_rw_op(dev, 1); if (ret) return ret;
if (is5325(dev) || is5365(dev))
ret = b53_arl_read_25(dev, mac, vid, &ent, &idx); else
ret = b53_arl_read(dev, mac, vid, &ent, &idx);
/* If this is a read, just finish now */ if (op) return ret;
switch (ret) { case -ETIMEDOUT: return ret; case -ENOSPC:
dev_dbg(dev->dev, "{%pM,%.4d} no space left in ARL\n",
addr, vid); return is_valid ? ret : 0; case -ENOENT: /* We could not find a matching MAC, so reset to a new entry */
dev_dbg(dev->dev, "{%pM,%.4d} not found, using idx: %d\n",
addr, vid, idx);
fwd_entry = 0; break; default:
dev_dbg(dev->dev, "{%pM,%.4d} found, using idx: %d\n",
addr, vid, idx); break;
}
/* For multicast address, the port is a bitmask and the validity * is determined by having at least one port being still active
*/ if (!is_multicast_ether_addr(addr)) {
ent.port = port;
ent.is_valid = is_valid;
} else { if (is_valid)
ent.port |= BIT(port); else
ent.port &= ~BIT(port);
/* On 7278, port 7 which connects to the ASP should only receive * traffic from matching CFP rules.
*/ if (dev->chip_id == BCM7278_DEVICE_ID && port == 7) return -EINVAL;
if (dev->vlan_filtering) { /* Make this port leave the all VLANs join since we will have * proper VLAN entries from now on
*/ if (is58xx(dev)) {
b53_read16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN,
®);
reg &= ~BIT(port); if ((reg & BIT(cpu_port)) == BIT(cpu_port))
reg &= ~BIT(cpu_port);
b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN,
reg);
}
b53_for_each_port(dev, i) { if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge)) continue;
/* Add this local port to the remote port VLAN control * membership and update the remote port bitmask
*/
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), ®);
reg |= BIT(port);
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), reg);
dev->ports[i].vlan_ctl_mask = reg;
pvlan |= BIT(i);
}
/* Disable redirection of unknown SA to the CPU port */
b53_set_eap_mode(dev, port, EAP_MODE_BASIC);
/* Configure the local port VLAN control membership to include * remote ports and update the local port bitmask
*/
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
dev->ports[port].vlan_ctl_mask = pvlan;
if (dev->vlan_filtering) { /* Make this port join all VLANs without VLAN entries */ if (is58xx(dev)) {
b53_read16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, ®);
reg |= BIT(port); if (!(reg & BIT(cpu_port)))
reg |= BIT(cpu_port);
b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg);
}
int b53_br_flags(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack)
{ if (flags.mask & BR_FLOOD)
b53_port_set_ucast_flood(ds->priv, port,
!!(flags.val & BR_FLOOD)); if (flags.mask & BR_MCAST_FLOOD)
b53_port_set_mcast_flood(ds->priv, port,
!!(flags.val & BR_MCAST_FLOOD)); if (flags.mask & BR_LEARNING)
b53_port_set_learning(ds->priv, port,
!!(flags.val & BR_LEARNING));
return 0;
}
EXPORT_SYMBOL(b53_br_flags);
staticbool b53_possible_cpu_port(struct dsa_switch *ds, int port)
{ /* Broadcom switches will accept enabling Broadcom tags on the * following ports: 5, 7 and 8, any other port is not supported
*/ switch (port) { case B53_CPU_PORT_25: case 7: case B53_CPU_PORT: returntrue;
}
returnfalse;
}
staticbool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port, enum dsa_tag_protocol tag_protocol)
{ bool ret = b53_possible_cpu_port(ds, port);
if (!ret) {
dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n",
port); return ret;
}
switch (tag_protocol) { case DSA_TAG_PROTO_BRCM: case DSA_TAG_PROTO_BRCM_PREPEND:
dev_warn(ds->dev, "Port %d is stacked to Broadcom tag switch\n", port);
ret = false; break; default:
ret = true; break;
}
/* Broadcom BCM58xx chips have a flow accelerator on Port 8 * which requires us to use the prepended Broadcom tag type
*/ if (dev->chip_id == BCM58XX_DEVICE_ID && port == B53_CPU_PORT) {
dev->tag_protocol = DSA_TAG_PROTO_BRCM_PREPEND; goto out;
}
/* Now look at the other one to know if we can disable mirroring * entirely
*/ if (mirror->ingress)
b53_read16(dev, B53_MGMT_PAGE, B53_EG_MIR_CTL, ®); else
b53_read16(dev, B53_MGMT_PAGE, B53_IG_MIR_CTL, ®); if (!(reg & MIRROR_MASK))
other_loc_disable = true;
b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, ®); /* Both no longer have ports, let's disable mirroring */ if (loc_disable && other_loc_disable) {
reg &= ~MIRROR_EN;
reg &= ~mirror->to_local_port;
}
b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg);
}
EXPORT_SYMBOL(b53_mirror_del);
/* Returns 0 if EEE was not enabled, or 1 otherwise
*/ int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy)
{ int ret;
if (!b53_support_eee(ds, port)) return 0;
ret = phy_init_eee(phy, false); if (ret) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.