diff options
author | David S. Miller <davem@davemloft.net> | 2016-02-25 15:20:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-02-25 15:20:22 -0500 |
commit | 1fc7261b16cb00db4e547f3407f81383be8d068e (patch) | |
tree | 5504d8512f44c09beea3bb6809ec17e20ddce60f | |
parent | 2a04c7baded1cb2717ef8d02759e2ce13ae28602 (diff) | |
parent | 477b184526a7f44164029eea720da0e0c888cac6 (diff) |
Merge branch 'dsa-port-vlan-dump'
Vivien Didelot says:
====================
net: dsa: add port VLAN dump operation
The VLAN GetNext approach is specific to some switches and thus hard to
implement for others. This patchset replaces it with a simpler port VLAN dump
operation, similar to the corresponding FDB operation.
The mv88e6xxx driver is the only one currently affected by the change.
The documentation is updated accordingly.
Note: this patchset uses http://www.spinics.net/lists/kernel/msg2186705.html
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/networking/dsa/dsa.txt | 11 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6171.c | 3 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6352.c | 3 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 110 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.h | 6 | ||||
-rw-r--r-- | include/net/dsa.h | 6 | ||||
-rw-r--r-- | net/dsa/slave.c | 36 |
7 files changed, 65 insertions, 110 deletions
diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index ebf21530471f..974e9c387d1e 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -542,20 +542,15 @@ Bridge layer Bridge VLAN filtering --------------------- -- port_pvid_get: bridge layer function invoked when a Port-based VLAN ID is - queried for the given switch port - -- port_pvid_set: bridge layer function invoked when a Port-based VLAN ID needs - to be configured on the given switch port - - port_vlan_add: bridge layer function invoked when a VLAN is configured (tagged or untagged) for the given switch port - port_vlan_del: bridge layer function invoked when a VLAN is removed from the given switch port -- vlan_getnext: bridge layer function invoked to query the next configured VLAN - in the switch, i.e. returns the bitmaps of members and untagged ports +- port_vlan_dump: bridge layer function invoked with a switchdev callback + function that the driver has to call for each VLAN the given port is a member + of. A switchdev object is used to carry the VID and bridge flags. - port_fdb_add: bridge layer function invoked when the bridge wants to install a Forwarding Database entry, the switch hardware should be programmed with the diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 6e18213b9c04..dd1ebaf48077 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -106,11 +106,10 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .port_join_bridge = mv88e6xxx_port_bridge_join, .port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_stp_update = mv88e6xxx_port_stp_update, - .port_pvid_get = mv88e6xxx_port_pvid_get, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, .port_vlan_add = mv88e6xxx_port_vlan_add, .port_vlan_del = mv88e6xxx_port_vlan_del, - .vlan_getnext = mv88e6xxx_vlan_getnext, + .port_vlan_dump = mv88e6xxx_port_vlan_dump, .port_fdb_prepare = mv88e6xxx_port_fdb_prepare, .port_fdb_add = mv88e6xxx_port_fdb_add, .port_fdb_del = mv88e6xxx_port_fdb_del, diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index a47f52f44b0d..bbca36ac4f77 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -327,11 +327,10 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .port_join_bridge = mv88e6xxx_port_bridge_join, .port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_stp_update = mv88e6xxx_port_stp_update, - .port_pvid_get = mv88e6xxx_port_pvid_get, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, .port_vlan_add = mv88e6xxx_port_vlan_add, .port_vlan_del = mv88e6xxx_port_vlan_del, - .vlan_getnext = mv88e6xxx_vlan_getnext, + .port_vlan_dump = mv88e6xxx_port_vlan_dump, .port_fdb_prepare = mv88e6xxx_port_fdb_prepare, .port_fdb_add = mv88e6xxx_port_fdb_add, .port_fdb_del = mv88e6xxx_port_fdb_del, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 685dcb047979..d98dc635b00b 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1151,19 +1151,6 @@ static int _mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid) return 0; } -int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid) -{ - int ret; - - ret = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN); - if (ret < 0) - return ret; - - *pvid = ret & PORT_DEFAULT_VLAN_MASK; - - return 0; -} - static int _mv88e6xxx_port_pvid_set(struct dsa_switch *ds, int port, u16 pvid) { return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN, @@ -1306,6 +1293,57 @@ static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, return 0; } +int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + int (*cb)(struct switchdev_obj *obj)) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + struct mv88e6xxx_vtu_stu_entry next; + u16 pvid; + int err; + + mutex_lock(&ps->smi_mutex); + + err = _mv88e6xxx_port_pvid_get(ds, port, &pvid); + if (err) + goto unlock; + + err = _mv88e6xxx_vtu_vid_write(ds, GLOBAL_VTU_VID_MASK); + if (err) + goto unlock; + + do { + err = _mv88e6xxx_vtu_getnext(ds, &next); + if (err) + break; + + if (!next.valid) + break; + + if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + continue; + + /* reinit and dump this VLAN obj */ + vlan->vid_begin = vlan->vid_end = next.vid; + vlan->flags = 0; + + if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) + vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; + + if (next.vid == pvid) + vlan->flags |= BRIDGE_VLAN_INFO_PVID; + + err = cb(&vlan->obj); + if (err) + break; + } while (next.vid < GLOBAL_VTU_VID_MASK); + +unlock: + mutex_unlock(&ps->smi_mutex); + + return err; +} + static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds, struct mv88e6xxx_vtu_stu_entry *entry) { @@ -1675,52 +1713,6 @@ unlock: return err; } -int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid, - unsigned long *ports, unsigned long *untagged) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - struct mv88e6xxx_vtu_stu_entry next; - int port; - int err; - - if (*vid == 4095) - return -ENOENT; - - mutex_lock(&ps->smi_mutex); - 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) - return err; - - if (!next.valid) - return -ENOENT; - - *vid = next.vid; - - for (port = 0; port < ps->num_ports; ++port) { - clear_bit(port, ports); - clear_bit(port, untagged); - - if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) - continue; - - if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED || - next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) - set_bit(port, ports); - - if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) - set_bit(port, untagged); - } - - return 0; -} - static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds, const unsigned char *addr) { diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 260b4918e427..6a30bda63a2f 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -494,9 +494,9 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, struct switchdev_trans *trans); int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); -int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *vid); -int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid, - unsigned long *ports, unsigned long *untagged); +int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + int (*cb)(struct switchdev_obj *obj)); int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans); diff --git a/include/net/dsa.h b/include/net/dsa.h index 1c845d7bf0b2..3dd54867174a 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -313,9 +313,9 @@ struct dsa_switch_driver { struct switchdev_trans *trans); int (*port_vlan_del)(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); - int (*port_pvid_get)(struct dsa_switch *ds, int port, u16 *pvid); - int (*vlan_getnext)(struct dsa_switch *ds, u16 *vid, - unsigned long *ports, unsigned long *untagged); + int (*port_vlan_dump)(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + int (*cb)(struct switchdev_obj *obj)); /* * Forwarding database diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 14ca9784ec0c..cde29239b60d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -243,41 +243,11 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; - DECLARE_BITMAP(members, DSA_MAX_PORTS); - DECLARE_BITMAP(untagged, DSA_MAX_PORTS); - u16 pvid, vid = 0; - int err; - - if (!ds->drv->vlan_getnext || !ds->drv->port_pvid_get) - return -EOPNOTSUPP; - - err = ds->drv->port_pvid_get(ds, p->port, &pvid); - if (err) - return err; - - for (;;) { - err = ds->drv->vlan_getnext(ds, &vid, members, untagged); - if (err) - break; - - if (!test_bit(p->port, members)) - continue; - memset(vlan, 0, sizeof(*vlan)); - vlan->vid_begin = vlan->vid_end = vid; + if (ds->drv->port_vlan_dump) + return ds->drv->port_vlan_dump(ds, p->port, vlan, cb); - if (vid == pvid) - vlan->flags |= BRIDGE_VLAN_INFO_PVID; - - if (test_bit(p->port, untagged)) - vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - - err = cb(&vlan->obj); - if (err) - break; - } - - return err == -ENOENT ? 0 : err; + return -EOPNOTSUPP; } static int dsa_slave_port_fdb_add(struct net_device *dev, |