diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2016-02-26 13:16:01 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-01 16:24:51 -0500 |
commit | 2fb5ef09de7c8ab30f7aa315e700a46f51ac4b98 (patch) | |
tree | f43e865c235a452022f472522ee40f57eabcf906 /drivers/net/dsa | |
parent | fb2dabad69f099fb9c03a44276778911da50ba29 (diff) |
net: dsa: mv88e6xxx: extract single VLAN retrieval
Rename _mv88e6xxx_vlan_init in _mv88e6xxx_vtu_new, eventually called
from a new _mv88e6xxx_vtu_get function, which abstracts the VTU GetNext
VID-1 trick to retrieve a single entry.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 55 |
1 files changed, 35 insertions, 20 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index d98dc635b00b..e9e99222399a 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1458,8 +1458,8 @@ loadpurge: return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE); } -static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid, - struct mv88e6xxx_vtu_stu_entry *entry) +static int _mv88e6xxx_vtu_new(struct dsa_switch *ds, u16 vid, + struct mv88e6xxx_vtu_stu_entry *entry) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); struct mv88e6xxx_vtu_stu_entry vlan = { @@ -1509,6 +1509,35 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid, return 0; } +static int _mv88e6xxx_vtu_get(struct dsa_switch *ds, u16 vid, + struct mv88e6xxx_vtu_stu_entry *entry, bool creat) +{ + int err; + + if (!vid) + return -EINVAL; + + err = _mv88e6xxx_vtu_vid_write(ds, vid - 1); + if (err) + return err; + + err = _mv88e6xxx_vtu_getnext(ds, entry); + if (err) + return err; + + if (entry->vid != vid || !entry->valid) { + if (!creat) + return -EOPNOTSUPP; + /* -ENOENT would've been more appropriate, but switchdev expects + * -EOPNOTSUPP to inform bridge about an eventual software VLAN. + */ + + err = _mv88e6xxx_vtu_new(ds, vid, entry); + } + + return err; +} + static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, u16 vid_begin, u16 vid_end) { @@ -1593,20 +1622,10 @@ static int _mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid, struct mv88e6xxx_vtu_stu_entry vlan; int err; - err = _mv88e6xxx_vtu_vid_write(ds, vid - 1); - if (err) - return err; - - err = _mv88e6xxx_vtu_getnext(ds, &vlan); + err = _mv88e6xxx_vtu_get(ds, vid, &vlan, true); if (err) return err; - if (vlan.vid != vid || !vlan.valid) { - err = _mv88e6xxx_vlan_init(ds, vid, &vlan); - if (err) - return err; - } - vlan.data[port] = untagged ? GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED : GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; @@ -1647,16 +1666,12 @@ static int _mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid) struct mv88e6xxx_vtu_stu_entry vlan; int i, err; - err = _mv88e6xxx_vtu_vid_write(ds, vid - 1); - if (err) - return err; - - err = _mv88e6xxx_vtu_getnext(ds, &vlan); + err = _mv88e6xxx_vtu_get(ds, vid, &vlan, false); if (err) return err; - if (vlan.vid != vid || !vlan.valid || - vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + /* Tell switchdev if this VLAN is handled in software */ + if (vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) return -EOPNOTSUPP; vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; |