aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa/mt7530.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
-rw-r--r--drivers/net/dsa/mt7530.c325
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");