diff options
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 325 |
1 files changed, 16 insertions, 309 deletions
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 62e486652e622..3b073e1522373 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -564,8 +564,7 @@ static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum) return mdiobus_read_nested(priv->bus, port, regnum); } -static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, - u16 val) +int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) { struct mt7530_priv *priv = ds->priv; @@ -573,14 +572,10 @@ static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, } static void -mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset, - uint8_t *data) +mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data) { int i; - if (stringset != ETH_SS_STATS) - return; - for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name, ETH_GSTRING_LEN); @@ -608,11 +603,8 @@ mt7530_get_ethtool_stats(struct dsa_switch *ds, int port, } static int -mt7530_get_sset_count(struct dsa_switch *ds, int port, int sset) +mt7530_get_sset_count(struct dsa_switch *ds) { - if (sset != ETH_SS_STATS) - return 0; - return ARRAY_SIZE(mt7530_mib); } @@ -695,7 +687,7 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv, * the switch */ mt7530_write(priv, MT7530_PCR_P(port), - PCR_MATRIX(dsa_user_ports(priv->ds))); + PCR_MATRIX(priv->ds->enabled_port_mask)); return 0; } @@ -788,8 +780,8 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port, * same bridge. If the port is disabled, port matrix is kept * and not being setup until the port becomes enabled. */ - if (dsa_is_user_port(ds, i) && i != port) { - if (dsa_to_port(ds, i)->bridge_dev != bridge) + if (ds->enabled_port_mask & BIT(i) && i != port) { + if (ds->ports[i].bridge_dev != bridge) continue; if (priv->ports[i].enable) mt7530_set(priv, MT7530_PCR_P(i), @@ -812,69 +804,6 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port, } static void -mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port) -{ - struct mt7530_priv *priv = ds->priv; - bool all_user_ports_removed = true; - int i; - - /* When a port is removed from the bridge, the port would be set up - * back to the default as is at initial boot which is a VLAN-unaware - * port. - */ - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, - MT7530_PORT_MATRIX_MODE); - mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, - VLAN_ATTR(MT7530_VLAN_TRANSPARENT)); - - priv->ports[port].vlan_filtering = false; - - for (i = 0; i < MT7530_NUM_PORTS; i++) { - if (dsa_is_user_port(ds, i) && - priv->ports[i].vlan_filtering) { - all_user_ports_removed = false; - break; - } - } - - /* CPU port also does the same thing until all user ports belonging to - * the CPU port get out of VLAN filtering mode. - */ - if (all_user_ports_removed) { - mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT), - PCR_MATRIX(dsa_user_ports(priv->ds))); - mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), - PORT_SPEC_TAG); - } -} - -static void -mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port) -{ - struct mt7530_priv *priv = ds->priv; - - /* The real fabric path would be decided on the membership in the - * entry of VLAN table. PCR_MATRIX set up here with ALL_MEMBERS - * means potential VLAN can be consisting of certain subset of all - * ports. - */ - mt7530_rmw(priv, MT7530_PCR_P(port), - PCR_MATRIX_MASK, PCR_MATRIX(MT7530_ALL_MEMBERS)); - - /* Trapped into security mode allows packet forwarding through VLAN - * table lookup. - */ - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, - MT7530_PORT_SECURITY_MODE); - - /* Set the port as a user port which is to be able to recognize VID - * from incoming packets before fetching entry within the VLAN table. - */ - mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, - VLAN_ATTR(MT7530_VLAN_USER)); -} - -static void mt7530_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { @@ -887,12 +816,9 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, /* Remove this port from the port matrix of the other ports * in the same bridge. If the port is disabled, port matrix * is kept and not being setup until the port becomes enabled. - * And the other port's port matrix cannot be broken when the - * other port is still a VLAN-aware port. */ - if (!priv->ports[i].vlan_filtering && - dsa_is_user_port(ds, i) && i != port) { - if (dsa_to_port(ds, i)->bridge_dev != bridge) + if (ds->enabled_port_mask & BIT(i) && i != port) { + if (ds->ports[i].bridge_dev != bridge) continue; if (priv->ports[i].enable) mt7530_clear(priv, MT7530_PCR_P(i), @@ -909,8 +835,6 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, PCR_MATRIX(BIT(MT7530_CPU_PORT))); priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); - mt7530_port_set_vlan_unaware(ds, port); - mutex_unlock(&priv->reg_mutex); } @@ -924,7 +848,7 @@ mt7530_port_fdb_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT); - ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL); + ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); mutex_unlock(&priv->reg_mutex); return ret; @@ -940,7 +864,7 @@ mt7530_port_fdb_del(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_EMP); - ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL); + ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); mutex_unlock(&priv->reg_mutex); return ret; @@ -981,226 +905,12 @@ err: return 0; } -static int -mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid) -{ - struct mt7530_dummy_poll p; - u32 val; - int ret; - - val = VTCR_BUSY | VTCR_FUNC(cmd) | vid; - mt7530_write(priv, MT7530_VTCR, val); - - INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR); - ret = readx_poll_timeout(_mt7530_read, &p, val, - !(val & VTCR_BUSY), 20, 20000); - if (ret < 0) { - dev_err(priv->dev, "poll timeout\n"); - return ret; - } - - val = mt7530_read(priv, MT7530_VTCR); - if (val & VTCR_INVALID) { - dev_err(priv->dev, "read VTCR invalid\n"); - return -EINVAL; - } - - return 0; -} - -static int -mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, - bool vlan_filtering) -{ - struct mt7530_priv *priv = ds->priv; - - priv->ports[port].vlan_filtering = vlan_filtering; - - if (vlan_filtering) { - /* The port is being kept as VLAN-unaware port when bridge is - * set up with vlan_filtering not being set, Otherwise, the - * port and the corresponding CPU port is required the setup - * for becoming a VLAN-aware port. - */ - mt7530_port_set_vlan_aware(ds, port); - mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT); - } - - return 0; -} - -static int -mt7530_port_vlan_prepare(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -{ - /* nothing needed */ - - return 0; -} - -static void -mt7530_hw_vlan_add(struct mt7530_priv *priv, - struct mt7530_hw_vlan_entry *entry) -{ - u8 new_members; - u32 val; - - new_members = entry->old_members | BIT(entry->port) | - BIT(MT7530_CPU_PORT); - - /* Validate the entry with independent learning, create egress tag per - * VLAN and joining the port as one of the port members. - */ - val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID; - mt7530_write(priv, MT7530_VAWD1, val); - - /* Decide whether adding tag or not for those outgoing packets from the - * port inside the VLAN. - */ - val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG : - MT7530_VLAN_EGRESS_TAG; - mt7530_rmw(priv, MT7530_VAWD2, - ETAG_CTRL_P_MASK(entry->port), - ETAG_CTRL_P(entry->port, val)); - - /* CPU port is always taken as a tagged port for serving more than one - * VLANs across and also being applied with egress type stack mode for - * that VLAN tags would be appended after hardware special tag used as - * DSA tag. - */ - mt7530_rmw(priv, MT7530_VAWD2, - ETAG_CTRL_P_MASK(MT7530_CPU_PORT), - ETAG_CTRL_P(MT7530_CPU_PORT, - MT7530_VLAN_EGRESS_STACK)); -} - -static void -mt7530_hw_vlan_del(struct mt7530_priv *priv, - struct mt7530_hw_vlan_entry *entry) -{ - u8 new_members; - u32 val; - - new_members = entry->old_members & ~BIT(entry->port); - - val = mt7530_read(priv, MT7530_VAWD1); - if (!(val & VLAN_VALID)) { - dev_err(priv->dev, - "Cannot be deleted due to invalid entry\n"); - return; - } - - /* If certain member apart from CPU port is still alive in the VLAN, - * the entry would be kept valid. Otherwise, the entry is got to be - * disabled. - */ - if (new_members && new_members != BIT(MT7530_CPU_PORT)) { - val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | - VLAN_VALID; - mt7530_write(priv, MT7530_VAWD1, val); - } else { - mt7530_write(priv, MT7530_VAWD1, 0); - mt7530_write(priv, MT7530_VAWD2, 0); - } -} - -static void -mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid, - struct mt7530_hw_vlan_entry *entry, - mt7530_vlan_op vlan_op) -{ - u32 val; - - /* Fetch entry */ - mt7530_vlan_cmd(priv, MT7530_VTCR_RD_VID, vid); - - val = mt7530_read(priv, MT7530_VAWD1); - - entry->old_members = (val >> PORT_MEM_SHFT) & PORT_MEM_MASK; - - /* Manipulate entry */ - vlan_op(priv, entry); - - /* Flush result to hardware */ - mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, vid); -} - -static void -mt7530_port_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -{ - bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; - bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; - struct mt7530_hw_vlan_entry new_entry; - struct mt7530_priv *priv = ds->priv; - u16 vid; - - /* The port is kept as VLAN-unaware if bridge with vlan_filtering not - * being set. - */ - if (!priv->ports[port].vlan_filtering) - return; - - mutex_lock(&priv->reg_mutex); - - for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { - mt7530_hw_vlan_entry_init(&new_entry, port, untagged); - mt7530_hw_vlan_update(priv, vid, &new_entry, - mt7530_hw_vlan_add); - } - - if (pvid) { - mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, - G0_PORT_VID(vlan->vid_end)); - priv->ports[port].pvid = vlan->vid_end; - } - - mutex_unlock(&priv->reg_mutex); -} - -static int -mt7530_port_vlan_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -{ - struct mt7530_hw_vlan_entry target_entry; - struct mt7530_priv *priv = ds->priv; - u16 vid, pvid; - - /* The port is kept as VLAN-unaware if bridge with vlan_filtering not - * being set. - */ - if (!priv->ports[port].vlan_filtering) - return 0; - - mutex_lock(&priv->reg_mutex); - - pvid = priv->ports[port].pvid; - for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { - mt7530_hw_vlan_entry_init(&target_entry, port, 0); - mt7530_hw_vlan_update(priv, vid, &target_entry, - mt7530_hw_vlan_del); - - /* PVID is being restored to the default whenever the PVID port - * is being removed from the VLAN. - */ - if (pvid == vid) - pvid = G0_PORT_VID_DEF; - } - - mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid); - priv->ports[port].pvid = pvid; - - mutex_unlock(&priv->reg_mutex); - - return 0; -} - static enum dsa_tag_protocol -mtk_get_tag_protocol(struct dsa_switch *ds, int port) +mtk_get_tag_protocol(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; - if (port != MT7530_CPU_PORT) { + if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { dev_warn(priv->dev, "port not matched with tagging CPU port\n"); return DSA_TAG_PROTO_NONE; @@ -1218,11 +928,11 @@ mt7530_setup(struct dsa_switch *ds) struct device_node *dn; struct mt7530_dummy_poll p; - /* The parent node of master netdev which holds the common system + /* The parent node of cpu_dp->netdev which holds the common system * controller also is the container for two GMACs nodes representing * as two netdev instances. */ - dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent; + dn = ds->dst->cpu_dp->netdev->dev.of_node->parent; priv->ethernet = syscon_node_to_regmap(dn); if (IS_ERR(priv->ethernet)) return PTR_ERR(priv->ethernet); @@ -1300,7 +1010,7 @@ mt7530_setup(struct dsa_switch *ds) } /* Flush the FDB table */ - ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); + ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0); if (ret < 0) return ret; @@ -1324,10 +1034,6 @@ static const struct dsa_switch_ops mt7530_switch_ops = { .port_fdb_add = mt7530_port_fdb_add, .port_fdb_del = mt7530_port_fdb_del, .port_fdb_dump = mt7530_port_fdb_dump, - .port_vlan_filtering = mt7530_port_vlan_filtering, - .port_vlan_prepare = mt7530_port_vlan_prepare, - .port_vlan_add = mt7530_port_vlan_add, - .port_vlan_del = mt7530_port_vlan_del, }; static int @@ -1432,3 +1138,4 @@ mdio_module_driver(mt7530_mdio_driver); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mediatek-mt7530"); |
