ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
VSC73XX_ICPU_CTRL, &val); if (ret) {
dev_err(vsc->dev, "unable to read iCPU control\n"); return ret;
}
/* The iCPU can always be used but can boot in different ways. * If it is initially disabled and has no external memory, * we are in control and can do whatever we like, else we * are probably in trouble (we need some way to communicate * with the running firmware) so we bail out for now.
*/
icpu_pi_en = !!(val & VSC73XX_ICPU_CTRL_ICPU_PI_EN);
icpu_si_boot_en = !!(val & VSC73XX_ICPU_CTRL_BOOT_EN); if (icpu_si_boot_en && icpu_pi_en) {
dev_err(vsc->dev, "iCPU enabled boots from SI, has external memory\n");
dev_err(vsc->dev, "no idea how to deal with this\n"); return -ENODEV;
} if (icpu_si_boot_en && !icpu_pi_en) {
dev_err(vsc->dev, "iCPU enabled boots from PI/SI, no external memory\n"); return -EAGAIN;
} if (!icpu_si_boot_en && icpu_pi_en) {
dev_err(vsc->dev, "iCPU enabled, boots from PI external memory\n");
dev_err(vsc->dev, "no idea how to deal with this\n"); return -ENODEV;
} /* !icpu_si_boot_en && !cpu_pi_en */
dev_info(vsc->dev, "iCPU disabled, no external memory\n");
return 0;
}
staticint vsc73xx_mdio_busy_check(struct vsc73xx *vsc)
{ int ret, err;
u32 val;
dev_dbg(vsc->dev, "write %04x to reg %02x in phy%d\n",
val, regnum, phy); return 0;
}
staticenum dsa_tag_protocol vsc73xx_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp)
{ /* The switch internally uses a 8 byte header with length, * source port, tag, LPA and priority. This is supposedly * only accessible when operating the switch using the internal * CPU or with an external CPU mapping the device in, but not * when operating the switch over SPI and putting frames in/out * on port 6 (the CPU port). So far we must assume that we * cannot access the tag. (See "Internal frame header" section * 3.9.1 in the manual.)
*/ return DSA_TAG_PROTO_VSC73XX_8021Q;
}
staticint vsc73xx_wait_for_vlan_table_cmd(struct vsc73xx *vsc)
{ int ret, err;
u32 val;
/* Initialize memory, initialize RAM bank 0..15 except 6 and 7 * This sequence appears in the * VSC7385 SparX-G5 datasheet section 6.6.1 * VSC7395 SparX-G5e datasheet section 6.6.1 * "initialization sequence". * No explanation is given to the 0x1010400 magic number.
*/ for (i = 0; i <= 15; i++) { if (i != 6 && i != 7) {
vsc73xx_write(vsc, VSC73XX_BLOCK_MEMINIT,
2,
0, 0x1010400 + i);
mdelay(1);
}
}
mdelay(30);
/* Clear MAC table */
vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_MACACCESS,
VSC73XX_MACACCESS_CMD_CLEAR_TABLE);
/* Set VLAN table to default values */
vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_VLANACCESS,
VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE);
msleep(40);
/* Use 20KiB buffers on all ports on VSC7395 * The VSC7385 has 16KiB buffers and that is the * default if we don't set this up explicitly. * Port "31" is "all ports".
*/ if (IS_739X(vsc))
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 0x1f,
VSC73XX_Q_MISC_CONF,
VSC73XX_Q_MISC_CONF_EXTENT_MEM);
/* Put all ports into reset until enabled */ for (i = 0; i < 7; i++) { if (i == 5) continue;
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 4,
VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
}
/* Configure RGMII delay */
ret = vsc73xx_configure_rgmii_port_delay(ds); if (ret) return ret;
/* Disable preamble and use maximum allowed clock for the internal * mdio bus, used for communication with internal PHYs only.
*/
val = VSC73XX_MII_MPRES_NOPREAMBLE |
FIELD_PREP(VSC73XX_MII_MPRES_PRESCALEVAL,
VSC73XX_MII_PRESCALEVAL_MIN);
vsc73xx_write(vsc, VSC73XX_BLOCK_MII, VSC73XX_BLOCK_MII_INTERNAL,
VSC73XX_MII_MPRES, val);
/* Release reset from the internal PHYs */
vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
VSC73XX_GLORESET_PHY_RESET);
udelay(4);
/* Clear VLAN table */ for (i = 0; i < VLAN_N_VID; i++)
vsc73xx_write_vlan_table_entry(vsc, i, 0);
INIT_LIST_HEAD(&vsc->vlans);
rtnl_lock();
ret = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
rtnl_unlock();
staticvoid vsc73xx_init_port(struct vsc73xx *vsc, int port)
{
u32 val;
/* MAC configure, first reset the port and then write defaults */
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_MAC_CFG,
VSC73XX_MAC_CFG_RESET);
/* Take up the port in 1Gbit mode by default, this will be * augmented after auto-negotiation on the PHY-facing * ports.
*/ if (port == CPU_PORT)
val = VSC73XX_MAC_CFG_1000M_F_RGMII; else
val = VSC73XX_MAC_CFG_1000M_F_PHY;
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_MAC_CFG,
val |
VSC73XX_MAC_CFG_TX_EN |
VSC73XX_MAC_CFG_RX_EN);
/* Flow control for the CPU port: * Use a zero delay pause frame when pause condition is left * Obey pause control frames
*/
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_FCCONF,
VSC73XX_FCCONF_ZERO_PAUSE_EN |
VSC73XX_FCCONF_FLOW_CTRL_OBEY);
/* Issue pause control frames on PHY facing ports. * Allow early initiation of MAC transmission if the amount * of egress data is below 512 bytes on CPU port. * FIXME: enable 20KiB buffers?
*/ if (port == CPU_PORT)
val = VSC73XX_Q_MISC_CONF_EARLY_TX_512; else
val = VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE;
val |= VSC73XX_Q_MISC_CONF_EXTENT_MEM;
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_Q_MISC_CONF,
val);
/* Flow control MAC: a MAC address used in flow control frames */
val = (vsc->addr[5] << 16) | (vsc->addr[4] << 8) | (vsc->addr[3]);
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_FCMACHI,
val);
val = (vsc->addr[2] << 16) | (vsc->addr[1] << 8) | (vsc->addr[0]);
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_FCMACLO,
val);
/* Tell the categorizer to forward pause frames, not control * frame. Do not drop anything.
*/
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_CAT_DROP,
VSC73XX_CAT_DROP_FWD_PAUSE_ENA);
/* Special handling of the CPU-facing port */ if (port == CPU_PORT) { /* Other ports are already initialized but not this one */
vsc73xx_init_port(vsc, CPU_PORT); /* Select the external port for this interface (EXT_PORT) * Enable the GMII GTX external clock * Use double data rate (DDR mode)
*/
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
CPU_PORT,
VSC73XX_ADVPORTM,
VSC73XX_ADVPORTM_EXT_PORT |
VSC73XX_ADVPORTM_ENA_GTX |
VSC73XX_ADVPORTM_DDR_MODE);
}
}
/* This routine is described in the datasheet (below ARBDISC register * description)
*/
vsc73xx_reset_port(vsc, port, 0);
/* Allow backward dropping of frames from this port */
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
VSC73XX_SBACKWDROP, BIT(port), BIT(port));
}
staticvoid vsc73xx_mac_link_up(struct phylink_config *config, struct phy_device *phy, unsignedint mode,
phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause)
{ struct dsa_port *dp = dsa_phylink_to_port(config); struct vsc73xx *vsc = dp->ds->priv; int port = dp->index;
u32 val;
u8 seed;
if (speed == SPEED_1000)
val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M; else
val = VSC73XX_MAC_CFG_TX_IPG_100_10M;
if (phy_interface_mode_is_rgmii(interface))
val |= VSC73XX_MAC_CFG_CLK_SEL_1000M; else
val |= VSC73XX_MAC_CFG_CLK_SEL_EXT;
if (duplex == DUPLEX_FULL)
val |= VSC73XX_MAC_CFG_FDX; else /* In datasheet description ("Port Mode Procedure" in 5.6.2) * this bit is configured only for half duplex.
*/
val |= VSC73XX_MAC_CFG_WEXC_DIS;
/* This routine is described in the datasheet (below ARBDISC register * description)
*/
vsc73xx_reset_port(vsc, port, val);
/* Seed the port randomness with randomness */
get_random_bytes(&seed, 1);
val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET;
val |= VSC73XX_MAC_CFG_SEED_LOAD;
/* Those bits are responsible for MTU only. Kernel takes care about MTU, * let's enable +8 bytes frame length unconditionally.
*/
val |= VSC73XX_MAC_CFG_VLAN_AWR | VSC73XX_MAC_CFG_VLAN_DBLAWR;
/* Flow control for the PHY facing ports: * Use a zero delay pause frame when pause condition is left * Obey pause control frames * When generating pause frames, use 0xff as pause value
*/
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
VSC73XX_FCCONF_ZERO_PAUSE_EN |
VSC73XX_FCCONF_FLOW_CTRL_OBEY |
0xff);
/** * vsc73xx_vlan_commit_conf - Update VLAN configuration of a port * @vsc: Switch private data structure * @port: Port index on which to operate * * Update the VLAN behavior of a port to make sure that when it is under * a VLAN filtering bridge, the port is either filtering with tag * preservation, or filtering with all VLANs egress-untagged. Otherwise, * the port ignores VLAN tags from packets and applies the port-based * VID. * * Must be called when changes are made to: * - the bridge VLAN filtering state of the port * - the number or attributes of VLANs from the bridge VLAN table, * while the port is currently VLAN-aware * * Return: 0 on success, or negative errno on error.
*/ staticint vsc73xx_vlan_commit_conf(struct vsc73xx *vsc, int port)
{ enum vsc73xx_port_vlan_conf port_vlan_conf = VSC73XX_VLAN_IGNORE; struct dsa_port *dp = dsa_to_port(vsc->ds, port);
/** * vsc73xx_vlan_commit_untagged - Update native VLAN of a port * @vsc: Switch private data structure * @port: Port index on which to operate * * Update the native VLAN of a port (the one VLAN which is transmitted * as egress-tagged on a trunk port) when port is in VLAN filtering mode and * only one untagged vid is configured. * In other cases no need to configure it because switch can untag all vlans on * the port. * * Return: 0 on success, or negative errno on error.
*/ staticint vsc73xx_vlan_commit_untagged(struct vsc73xx *vsc, int port)
{ struct dsa_port *dp = dsa_to_port(vsc->ds, port); struct vsc73xx_vlan_summary summary;
u16 vid = 0; bool valid;
if (!dsa_port_is_vlan_filtering(dp)) /* Port is configured to untag all vlans in that case. * No need to commit untagged config change.
*/ return 0;
staticint
vsc73xx_vlan_change_pvid(struct vsc73xx *vsc, int port, u16 vid, bool set)
{
u32 val = 0; int ret;
val = set ? 0 : VSC73XX_CAT_DROP_UNTAGGED_ENA;
ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
VSC73XX_CAT_DROP,
VSC73XX_CAT_DROP_UNTAGGED_ENA, val); if (!set || ret) return ret;
return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
VSC73XX_CAT_PORT_VLAN,
VSC73XX_CAT_PORT_VLAN_VLAN_VID,
vid & VSC73XX_CAT_PORT_VLAN_VLAN_VID);
}
/** * vsc73xx_vlan_commit_pvid - Update port-based default VLAN of a port * @vsc: Switch private data structure * @port: Port index on which to operate * * Update the PVID of a port so that it follows either the bridge PVID * configuration, when the bridge is currently VLAN-aware, or the PVID * from tag_8021q, when the port is standalone or under a VLAN-unaware * bridge. A port with no PVID drops all untagged and VID 0 tagged * traffic. * * Must be called when changes are made to: * - the bridge VLAN filtering state of the port * - the number or attributes of VLANs from the bridge VLAN table, * while the port is currently VLAN-aware * * Return: 0 on success, or negative errno on error.
*/ staticint vsc73xx_vlan_commit_pvid(struct vsc73xx *vsc, int port)
{ struct vsc73xx_portinfo *portinfo = &vsc->portinfo[port]; bool valid = portinfo->pvid_tag_8021q_configured; struct dsa_port *dp = dsa_to_port(vsc->ds, port);
u16 vid = portinfo->pvid_tag_8021q;
if (dsa_port_is_vlan_filtering(dp)) {
vid = portinfo->pvid_vlan_filtering;
valid = portinfo->pvid_vlan_filtering_configured;
}
/* The first counters is the RX octets */
ethtool_puts(&buf, "RxEtherStatsOctets");
/* Each port supports recording 3 RX counters and 3 TX counters, * figure out what counters we use in this set-up and return the * names of them. The hardware default counters will be number of * packets on RX/TX, combined broadcast+multicast packets RX/TX and * total error packets RX/TX.
*/ for (i = 0; i < 3; i++) {
cnt = vsc73xx_find_counter(vsc, indices[i], false);
ethtool_puts(&buf, cnt ? cnt->name : "");
}
/* TX stats begins with the number of TX octets */
ethtool_puts(&buf, "TxEtherStatsOctets");
for (i = 3; i < 6; i++) {
cnt = vsc73xx_find_counter(vsc, indices[i], true);
ethtool_puts(&buf, cnt ? cnt->name : "");
}
}
staticint vsc73xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
{ /* We only support SS_STATS */ if (sset != ETH_SS_STATS) return 0; /* RX and TX packets, then 3 RX counters, 3 TX counters */ return 8;
}
/* According to application not "VSC7398 Jumbo Frames" setting * up the frame size to 9.6 KB does not affect the performance on standard * frames. It is clear from the application note that * "9.6 kilobytes" == 9600 bytes.
*/ staticint vsc73xx_get_max_mtu(struct dsa_switch *ds, int port)
{ return 9600 - ETH_HLEN - ETH_FCS_LEN;
}
/* The commit to hardware processed below is required because vsc73xx * is using tag_8021q. When vlan_filtering is disabled, tag_8021q uses * pvid/untagged vlans for port recognition. The values configured for * vlans and pvid/untagged states are stored in portinfo structure. * When vlan_filtering is enabled, we need to restore pvid/untagged from * portinfo structure. Analogous routine is processed when * vlan_filtering is disabled, but values used for tag_8021q are * restored.
*/
/* Be sure to deny alterations to the configuration done by tag_8021q.
*/ if (vid_is_dsa_8021q(vlan->vid)) {
NL_SET_ERR_MSG_MOD(extack, "Range 3072-4095 reserved for dsa_8021q operation"); return -EBUSY;
}
/* The processed vlan->vid is excluded from the search because the VLAN * can be re-added with a different set of flags, so it's easiest to * ignore its old flags from the VLAN database software copy.
*/
vsc73xx_bridge_vlan_summary(vsc, port, &summary, vlan->vid);
/* VSC73XX allows only three untagged states: none, one or all */ if ((untagged && summary.num_tagged > 0 && summary.num_untagged > 0) ||
(!untagged && summary.num_untagged > 1)) {
NL_SET_ERR_MSG_MOD(extack, "Port can have only none, one or all untagged vlan"); return -EBUSY;
}
if (state != BR_STATE_FORWARDING) { /* Ports that aren't in the forwarding state must not * forward packets anywhere.
*/
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_SRCMASKS + port,
VSC73XX_SRCMASKS_PORTS_MASK, 0);
/* Forwarding ports must forward to the CPU and to other ports * in the same bridge
*/
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_SRCMASKS + CPU_PORT, BIT(port), BIT(port));
mask = BIT(CPU_PORT);
dsa_switch_for_each_user_port(other_dp, ds) { int other_port = other_dp->index;
/* FIXME: STP frames aren't forwarded at this moment. BPDU frames are * forwarded only from and to PI/SI interface. For more info see chapter * 2.7.1 (CPU Forwarding) in datasheet. * This function is required for tag_8021q operations.
*/ staticvoid vsc73xx_port_stp_state_set(struct dsa_switch *ds, int port,
u8 state)
{ struct dsa_port *dp = dsa_to_port(ds, port); struct vsc73xx *vsc = ds->priv;
u32 val = 0;
if (state == BR_STATE_LEARNING || state == BR_STATE_FORWARDING)
val = dp->learning ? BIT(port) : 0;
val = (state == BR_STATE_BLOCKING || state == BR_STATE_DISABLED) ?
0 : BIT(port);
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_RECVMASK, BIT(port), val);
/* CPU Port should always forward packets when user ports are forwarding * so let's configure it from other ports only.
*/ if (port != CPU_PORT)
vsc73xx_refresh_fwd_map(ds, port, state);
}
if (!fdb) return -EINVAL; if (index >= VSC73XX_NUM_FDB_ROWS) return -EINVAL;
for (i = 0; i < VSC73XX_NUM_BUCKETS; i++) {
ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_MACTINDX,
(i ? 0 : VSC73XX_MACTINDX_SHADOW) |
FIELD_PREP(VSC73XX_MACTINDX_BUCKET_MSK, i) |
index); if (ret) return ret;
ret = vsc73xx_port_wait_for_mac_table_cmd(vsc); if (ret) return ret;
ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_MACACCESS,
VSC73XX_MACACCESS_CMD_MASK,
VSC73XX_MACACCESS_CMD_READ_ENTRY); if (ret) return ret;
ret = vsc73xx_port_wait_for_mac_table_cmd(vsc); if (ret) return ret;
ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_MACACCESS, &val); if (ret) return ret;
fdb[i].valid = FIELD_GET(VSC73XX_MACACCESS_VALID, val); if (!fdb[i].valid) continue;
if (!vid) { switch (db.type) { case DSA_DB_PORT:
vid = dsa_tag_8021q_standalone_vid(db.dp); break; case DSA_DB_BRIDGE:
vid = dsa_tag_8021q_bridge_vid(db.bridge.num); break; default: return -EOPNOTSUPP;
}
}
if (!vid) { switch (db.type) { case DSA_DB_PORT:
vid = dsa_tag_8021q_standalone_vid(db.dp); break; case DSA_DB_BRIDGE:
vid = dsa_tag_8021q_bridge_vid(db.bridge.num); break; default: return -EOPNOTSUPP;
}
}
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.