summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/dsa/mv88e6171.c2
-rw-r--r--drivers/net/dsa/mv88e6352.c2
-rw-r--r--drivers/net/dsa/mv88e6xxx.c132
-rw-r--r--drivers/net/dsa/mv88e6xxx.h5
-rw-r--r--include/net/dsa.h7
-rw-r--r--net/dsa/slave.c26
6 files changed, 83 insertions, 91 deletions
diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c
index dfca352e78e3..2c8eb6f76ebe 100644
--- a/drivers/net/dsa/mv88e6171.c
+++ b/drivers/net/dsa/mv88e6171.c
@@ -122,7 +122,7 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
.port_fdb_add = mv88e6xxx_port_fdb_add,
.port_fdb_del = mv88e6xxx_port_fdb_del,
- .port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
+ .port_fdb_dump = mv88e6xxx_port_fdb_dump,
};
MODULE_ALIAS("platform:mv88e6171");
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index 796fdcbe3c6e..cbf4dd8721a6 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -349,7 +349,7 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
.port_fdb_add = mv88e6xxx_port_fdb_add,
.port_fdb_del = mv88e6xxx_port_fdb_del,
- .port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
+ .port_fdb_dump = mv88e6xxx_port_fdb_dump,
};
MODULE_ALIAS("platform:mv88e6172");
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 4591240eb795..39664d8667af 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1259,7 +1259,13 @@ static int _mv88e6xxx_vtu_stu_data_write(struct dsa_switch *ds,
return 0;
}
-static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
+static int _mv88e6xxx_vtu_vid_write(struct dsa_switch *ds, u16 vid)
+{
+ return _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
+ vid & GLOBAL_VTU_VID_MASK);
+}
+
+static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds,
struct mv88e6xxx_vtu_stu_entry *entry)
{
struct mv88e6xxx_vtu_stu_entry next = { 0 };
@@ -1269,11 +1275,6 @@ static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
if (ret < 0)
return ret;
- ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
- vid & GLOBAL_VTU_VID_MASK);
- if (ret < 0)
- return ret;
-
ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_GET_NEXT);
if (ret < 0)
return ret;
@@ -1485,7 +1486,12 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
int err;
mutex_lock(&ps->smi_mutex);
- err = _mv88e6xxx_vtu_getnext(ds, vid - 1, &vlan);
+
+ err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
+ if (err)
+ goto unlock;
+
+ err = _mv88e6xxx_vtu_getnext(ds, &vlan);
if (err)
goto unlock;
@@ -1514,7 +1520,11 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
mutex_lock(&ps->smi_mutex);
- err = _mv88e6xxx_vtu_getnext(ds, vid - 1, &vlan);
+ err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
+ if (err)
+ goto unlock;
+
+ err = _mv88e6xxx_vtu_getnext(ds, &vlan);
if (err)
goto unlock;
@@ -1549,29 +1559,6 @@ unlock:
return err;
}
-static int _mv88e6xxx_port_vtu_getnext(struct dsa_switch *ds, int port, u16 vid,
- struct mv88e6xxx_vtu_stu_entry *entry)
-{
- int err;
-
- do {
- if (vid == 4095)
- return -ENOENT;
-
- err = _mv88e6xxx_vtu_getnext(ds, vid, entry);
- if (err)
- return err;
-
- if (!entry->valid)
- return -ENOENT;
-
- vid = entry->vid;
- } while (entry->data[port] != GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED &&
- entry->data[port] != GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED);
-
- return 0;
-}
-
int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
unsigned long *ports, unsigned long *untagged)
{
@@ -1584,7 +1571,12 @@ int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
return -ENOENT;
mutex_lock(&ps->smi_mutex);
- err = _mv88e6xxx_vtu_getnext(ds, *vid, &next);
+ err = _mv88e6xxx_vtu_vid_write(ds, *vid);
+ if (err)
+ goto unlock;
+
+ err = _mv88e6xxx_vtu_getnext(ds, &next);
+unlock:
mutex_unlock(&ps->smi_mutex);
if (err)
@@ -1732,7 +1724,6 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
}
static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
- const unsigned char *addr,
struct mv88e6xxx_atu_entry *entry)
{
struct mv88e6xxx_atu_entry next = { 0 };
@@ -1744,10 +1735,6 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
if (ret < 0)
return ret;
- ret = _mv88e6xxx_atu_mac_write(ds, addr);
- if (ret < 0)
- return ret;
-
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
if (ret < 0)
return ret;
@@ -1785,46 +1772,69 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
return 0;
}
-/* get next entry for port */
-int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
- unsigned char *addr, u16 *vid, bool *is_static)
+int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
+ struct switchdev_obj_port_fdb *fdb,
+ int (*cb)(struct switchdev_obj *obj))
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- struct mv88e6xxx_atu_entry next;
- u16 fid = *vid; /* We use one FID per VLAN */
- int ret;
+ struct mv88e6xxx_vtu_stu_entry vlan = {
+ .vid = GLOBAL_VTU_VID_MASK, /* all ones */
+ };
+ int err;
mutex_lock(&ps->smi_mutex);
+ err = _mv88e6xxx_vtu_vid_write(ds, vlan.vid);
+ if (err)
+ goto unlock;
+
do {
- if (is_broadcast_ether_addr(addr)) {
- struct mv88e6xxx_vtu_stu_entry vtu;
+ struct mv88e6xxx_atu_entry addr = {
+ .mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ };
- ret = _mv88e6xxx_port_vtu_getnext(ds, port, *vid, &vtu);
- if (ret < 0)
- goto unlock;
+ err = _mv88e6xxx_vtu_getnext(ds, &vlan);
+ if (err)
+ goto unlock;
- *vid = vtu.vid;
- fid = vtu.fid;
- }
+ if (!vlan.valid)
+ break;
- ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next);
- if (ret < 0)
+ err = _mv88e6xxx_atu_mac_write(ds, addr.mac);
+ if (err)
goto unlock;
- ether_addr_copy(addr, next.mac);
+ do {
+ err = _mv88e6xxx_atu_getnext(ds, vlan.fid, &addr);
+ if (err)
+ goto unlock;
- if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
- continue;
- } while (next.trunk || (next.portv_trunkid & BIT(port)) == 0);
+ if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
+ break;
+
+ if (!addr.trunk && addr.portv_trunkid & BIT(port)) {
+ bool is_static = addr.state ==
+ (is_multicast_ether_addr(addr.mac) ?
+ GLOBAL_ATU_DATA_STATE_MC_STATIC :
+ GLOBAL_ATU_DATA_STATE_UC_STATIC);
+
+ fdb->vid = vlan.vid;
+ ether_addr_copy(fdb->addr, addr.mac);
+ fdb->ndm_state = is_static ? NUD_NOARP :
+ NUD_REACHABLE;
+
+ err = cb(&fdb->obj);
+ if (err)
+ goto unlock;
+ }
+ } while (!is_broadcast_ether_addr(addr.mac));
+
+ } while (vlan.vid < GLOBAL_VTU_VID_MASK);
- *is_static = next.state == (is_multicast_ether_addr(addr) ?
- GLOBAL_ATU_DATA_STATE_MC_STATIC :
- GLOBAL_ATU_DATA_STATE_UC_STATIC);
unlock:
mutex_unlock(&ps->smi_mutex);
- return ret;
+ return err;
}
static void mv88e6xxx_bridge_work(struct work_struct *work)
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 4ba69f339bfe..430de4fa1fec 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -474,8 +474,9 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
struct switchdev_trans *trans);
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb);
-int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
- unsigned char *addr, u16 *vid, bool *is_static);
+int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
+ struct switchdev_obj_port_fdb *fdb,
+ int (*cb)(struct switchdev_obj *obj));
int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
int reg, int val);
diff --git a/include/net/dsa.h b/include/net/dsa.h
index e00588625bc2..98ccbdef646f 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -198,6 +198,7 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
}
struct switchdev_trans;
+struct switchdev_obj;
struct switchdev_obj_port_fdb;
struct dsa_switch_driver {
@@ -327,9 +328,9 @@ struct dsa_switch_driver {
struct switchdev_trans *trans);
int (*port_fdb_del)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb);
- int (*port_fdb_getnext)(struct dsa_switch *ds, int port,
- unsigned char *addr, u16 *vid,
- bool *is_static);
+ int (*port_fdb_dump)(struct dsa_switch *ds, int port,
+ struct switchdev_obj_port_fdb *fdb,
+ int (*cb)(struct switchdev_obj *obj));
};
void register_switch_driver(struct dsa_switch_driver *type);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index b0b8da0f5af8..481754ee062a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -378,31 +378,11 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
- unsigned char addr[ETH_ALEN] = { 0 };
- u16 vid = 0;
- int ret;
-
- if (!ds->drv->port_fdb_getnext)
- return -EOPNOTSUPP;
- for (;;) {
- bool is_static;
-
- ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid,
- &is_static);
- if (ret < 0)
- break;
+ if (ds->drv->port_fdb_dump)
+ return ds->drv->port_fdb_dump(ds, p->port, fdb, cb);
- ether_addr_copy(fdb->addr, addr);
- fdb->vid = vid;
- fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
-
- ret = cb(&fdb->obj);
- if (ret < 0)
- break;
- }
-
- return ret == -ENOENT ? 0 : ret;
+ return -EOPNOTSUPP;
}
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)