diff options
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 568 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global1.h | 14 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global1_vtu.c | 511 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 31 |
5 files changed, 690 insertions, 435 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index 31d37a90cec7..6edd869c8d6f 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o mv88e6xxx-objs := chip.o mv88e6xxx-objs += global1.o mv88e6xxx-objs += global1_atu.o +mv88e6xxx-objs += global1_vtu.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o mv88e6xxx-objs += port.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 44ba8cff5631..19581d783d8e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3,9 +3,6 @@ * * Copyright (c) 2008 Marvell Semiconductor * - * Copyright (c) 2015 CMC Electronics, Inc. - * Added support for VLAN Table Unit operations - * * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> * * Copyright (c) 2016-2017 Savoir-faire Linux Inc. @@ -680,31 +677,6 @@ static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, return err; } -static bool mv88e6xxx_6097_family(struct mv88e6xxx_chip *chip) -{ - return chip->info->family == MV88E6XXX_FAMILY_6097; -} - -static bool mv88e6xxx_6165_family(struct mv88e6xxx_chip *chip) -{ - return chip->info->family == MV88E6XXX_FAMILY_6165; -} - -static bool mv88e6xxx_6341_family(struct mv88e6xxx_chip *chip) -{ - return chip->info->family == MV88E6XXX_FAMILY_6341; -} - -static bool mv88e6xxx_6351_family(struct mv88e6xxx_chip *chip) -{ - return chip->info->family == MV88E6XXX_FAMILY_6351; -} - -static bool mv88e6xxx_6352_family(struct mv88e6xxx_chip *chip) -{ - return chip->info->family == MV88E6XXX_FAMILY_6352; -} - static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, int speed, int duplex, phy_interface_t mode) @@ -1266,169 +1238,30 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) netdev_err(ds->ports[port].netdev, "failed to flush ATU\n"); } -static int _mv88e6xxx_vtu_wait(struct mv88e6xxx_chip *chip) -{ - return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY); -} - -static int _mv88e6xxx_vtu_cmd(struct mv88e6xxx_chip *chip, u16 op) +static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) { - int err; - - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op); - if (err) - return err; - - return _mv88e6xxx_vtu_wait(chip); -} - -static int _mv88e6xxx_vtu_stu_flush(struct mv88e6xxx_chip *chip) -{ - int ret; - - ret = _mv88e6xxx_vtu_wait(chip); - if (ret < 0) - return ret; + if (!chip->info->max_vid) + return 0; - return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_FLUSH_ALL); + return mv88e6xxx_g1_vtu_flush(chip); } -static int _mv88e6xxx_vtu_stu_data_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry, - unsigned int nibble_offset) +static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) { - u16 regs[3]; - int i, err; - - for (i = 0; i < 3; ++i) { - u16 *reg = ®s[i]; - - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg); - if (err) - return err; - } - - for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { - unsigned int shift = (i % 4) * 4 + nibble_offset; - u16 reg = regs[i / 4]; - - entry->data[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK; - } - - return 0; -} + if (!chip->info->ops->vtu_getnext) + return -EOPNOTSUPP; -static int mv88e6xxx_vtu_data_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - return _mv88e6xxx_vtu_stu_data_read(chip, entry, 0); + return chip->info->ops->vtu_getnext(chip, entry); } -static int mv88e6xxx_stu_data_read(struct mv88e6xxx_chip *chip, +static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { - return _mv88e6xxx_vtu_stu_data_read(chip, entry, 2); -} - -static int _mv88e6xxx_vtu_stu_data_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry, - unsigned int nibble_offset) -{ - u16 regs[3] = { 0 }; - int i, err; - - for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { - unsigned int shift = (i % 4) * 4 + nibble_offset; - u8 data = entry->data[i]; - - regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift; - } - - for (i = 0; i < 3; ++i) { - u16 reg = regs[i]; - - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg); - if (err) - return err; - } - - return 0; -} - -static int mv88e6xxx_vtu_data_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - return _mv88e6xxx_vtu_stu_data_write(chip, entry, 0); -} - -static int mv88e6xxx_stu_data_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - return _mv88e6xxx_vtu_stu_data_write(chip, entry, 2); -} - -static int _mv88e6xxx_vtu_vid_write(struct mv88e6xxx_chip *chip, u16 vid) -{ - return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, - vid & GLOBAL_VTU_VID_MASK); -} - -static int _mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - struct mv88e6xxx_vtu_entry next = { 0 }; - u16 val; - int err; - - err = _mv88e6xxx_vtu_wait(chip); - if (err) - return err; - - err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_VTU_GET_NEXT); - if (err) - return err; - - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val); - if (err) - return err; - - next.vid = val & GLOBAL_VTU_VID_MASK; - next.valid = !!(val & GLOBAL_VTU_VID_VALID); - - if (next.valid) { - err = mv88e6xxx_vtu_data_read(chip, &next); - if (err) - return err; - - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) { - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val); - if (err) - return err; - - next.fid = val & GLOBAL_VTU_FID_MASK; - } else if (mv88e6xxx_num_databases(chip) == 256) { - /* VTU DBNum[7:4] are located in VTU Operation 11:8, and - * VTU DBNum[3:0] are located in VTU Operation 3:0 - */ - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val); - if (err) - return err; - - next.fid = (val & 0xf00) >> 4; - next.fid |= val & 0xf; - } - - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) { - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val); - if (err) - return err; - - next.sid = val & GLOBAL_VTU_SID_MASK; - } - } + if (!chip->info->ops->vtu_loadpurge) + return -EOPNOTSUPP; - *entry = next; - return 0; + return chip->info->ops->vtu_loadpurge(chip, entry); } static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, @@ -1436,11 +1269,13 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, int (*cb)(struct switchdev_obj *obj)) { struct mv88e6xxx_chip *chip = ds->priv; - struct mv88e6xxx_vtu_entry next; + struct mv88e6xxx_vtu_entry next = { + .vid = chip->info->max_vid, + }; u16 pvid; int err; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU)) + if (!chip->info->max_vid) return -EOPNOTSUPP; mutex_lock(&chip->reg_lock); @@ -1449,19 +1284,15 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, if (err) goto unlock; - err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK); - if (err) - goto unlock; - do { - err = _mv88e6xxx_vtu_getnext(chip, &next); + err = mv88e6xxx_vtu_getnext(chip, &next); if (err) break; if (!next.valid) break; - if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) continue; /* reinit and dump this VLAN obj */ @@ -1469,7 +1300,7 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, vlan->vid_end = next.vid; vlan->flags = 0; - if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) + if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; if (next.vid == pvid) @@ -1478,7 +1309,7 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, err = cb(&vlan->obj); if (err) break; - } while (next.vid < GLOBAL_VTU_VID_MASK); + } while (next.vid < chip->info->max_vid); unlock: mutex_unlock(&chip->reg_lock); @@ -1486,133 +1317,12 @@ unlock: return err; } -static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE; - u16 reg = 0; - int err; - - err = _mv88e6xxx_vtu_wait(chip); - if (err) - return err; - - if (!entry->valid) - goto loadpurge; - - /* Write port member tags */ - err = mv88e6xxx_vtu_data_write(chip, entry); - if (err) - return err; - - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) { - reg = entry->sid & GLOBAL_VTU_SID_MASK; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg); - if (err) - return err; - } - - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) { - reg = entry->fid & GLOBAL_VTU_FID_MASK; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, reg); - if (err) - return err; - } else if (mv88e6xxx_num_databases(chip) == 256) { - /* VTU DBNum[7:4] are located in VTU Operation 11:8, and - * VTU DBNum[3:0] are located in VTU Operation 3:0 - */ - op |= (entry->fid & 0xf0) << 8; - op |= entry->fid & 0xf; - } - - reg = GLOBAL_VTU_VID_VALID; -loadpurge: - reg |= entry->vid & GLOBAL_VTU_VID_MASK; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg); - if (err) - return err; - - return _mv88e6xxx_vtu_cmd(chip, op); -} - -static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip *chip, u8 sid, - struct mv88e6xxx_vtu_entry *entry) -{ - struct mv88e6xxx_vtu_entry next = { 0 }; - u16 val; - int err; - - err = _mv88e6xxx_vtu_wait(chip); - if (err) - return err; - - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, - sid & GLOBAL_VTU_SID_MASK); - if (err) - return err; - - err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_GET_NEXT); - if (err) - return err; - - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val); - if (err) - return err; - - next.sid = val & GLOBAL_VTU_SID_MASK; - - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val); - if (err) - return err; - - next.valid = !!(val & GLOBAL_VTU_VID_VALID); - - if (next.valid) { - err = mv88e6xxx_stu_data_read(chip, &next); - if (err) - return err; - } - - *entry = next; - return 0; -} - -static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - u16 reg = 0; - int err; - - err = _mv88e6xxx_vtu_wait(chip); - if (err) - return err; - - if (!entry->valid) - goto loadpurge; - - /* Write port states */ - err = mv88e6xxx_stu_data_write(chip, entry); - if (err) - return err; - - reg = GLOBAL_VTU_VID_VALID; -loadpurge: - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg); - if (err) - return err; - - reg = entry->sid & GLOBAL_VTU_SID_MASK; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg); - if (err) - return err; - - return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE); -} - static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) { DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); - struct mv88e6xxx_vtu_entry vlan; + struct mv88e6xxx_vtu_entry vlan = { + .vid = chip->info->max_vid, + }; int i, err; bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); @@ -1627,12 +1337,8 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) } /* Set every FID bit used by the VLAN entries */ - err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK); - if (err) - return err; - do { - err = _mv88e6xxx_vtu_getnext(chip, &vlan); + err = mv88e6xxx_vtu_getnext(chip, &vlan); if (err) return err; @@ -1640,7 +1346,7 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) break; set_bit(vlan.fid, fid_bitmap); - } while (vlan.vid < GLOBAL_VTU_VID_MASK); + } while (vlan.vid < chip->info->max_vid); /* The reset value 0x000 is used to indicate that multiple address * databases are not needed. Return the next positive available. @@ -1653,89 +1359,52 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) return mv88e6xxx_g1_atu_flush(chip, *fid, true); } -static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid, - struct mv88e6xxx_vtu_entry *entry) -{ - struct dsa_switch *ds = chip->ds; - struct mv88e6xxx_vtu_entry vlan = { - .valid = true, - .vid = vid, - }; - int i, err; - - err = mv88e6xxx_atu_new(chip, &vlan.fid); - if (err) - return err; - - /* exclude all ports except the CPU and DSA ports */ - for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) - vlan.data[i] = dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i) - ? GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED - : GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; - - if (mv88e6xxx_6097_family(chip) || mv88e6xxx_6165_family(chip) || - mv88e6xxx_6351_family(chip) || mv88e6xxx_6352_family(chip) || - mv88e6xxx_6341_family(chip)) { - struct mv88e6xxx_vtu_entry vstp; - - /* Adding a VTU entry requires a valid STU entry. As VSTP is not - * implemented, only one STU entry is needed to cover all VTU - * entries. Thus, validate the SID 0. - */ - vlan.sid = 0; - err = _mv88e6xxx_stu_getnext(chip, GLOBAL_VTU_SID_MASK, &vstp); - if (err) - return err; - - if (vstp.sid != vlan.sid || !vstp.valid) { - memset(&vstp, 0, sizeof(vstp)); - vstp.valid = true; - vstp.sid = vlan.sid; - - err = _mv88e6xxx_stu_loadpurge(chip, &vstp); - if (err) - return err; - } - } - - *entry = vlan; - return 0; -} - -static int _mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, - struct mv88e6xxx_vtu_entry *entry, bool creat) +static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, + struct mv88e6xxx_vtu_entry *entry, bool new) { int err; if (!vid) return -EINVAL; - err = _mv88e6xxx_vtu_vid_write(chip, vid - 1); - if (err) - return err; + entry->vid = vid - 1; + entry->valid = false; - err = _mv88e6xxx_vtu_getnext(chip, entry); + err = mv88e6xxx_vtu_getnext(chip, 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. - */ + if (entry->vid == vid && entry->valid) + return 0; + + if (new) { + int i; - err = _mv88e6xxx_vtu_new(chip, vid, entry); + /* Initialize a fresh VLAN entry */ + memset(entry, 0, sizeof(*entry)); + entry->valid = true; + entry->vid = vid; + + /* Include only CPU and DSA ports */ + for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) + entry->member[i] = dsa_is_normal_port(chip->ds, i) ? + GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER : + GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED; + + return mv88e6xxx_atu_new(chip, &entry->fid); } - return err; + /* switchdev expects -EOPNOTSUPP to honor software VLANs */ + return -EOPNOTSUPP; } static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, u16 vid_begin, u16 vid_end) { struct mv88e6xxx_chip *chip = ds->priv; - struct mv88e6xxx_vtu_entry vlan; + struct mv88e6xxx_vtu_entry vlan = { + .vid = vid_begin - 1, + }; int i, err; if (!vid_begin) @@ -1743,12 +1412,8 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); - err = _mv88e6xxx_vtu_vid_write(chip, vid_begin - 1); - if (err) - goto unlock; - do { - err = _mv88e6xxx_vtu_getnext(chip, &vlan); + err = mv88e6xxx_vtu_getnext(chip, &vlan); if (err) goto unlock; @@ -1765,7 +1430,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, if (!ds->ports[port].netdev) continue; - if (vlan.data[i] == + if (vlan.member[i] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) continue; @@ -1799,7 +1464,7 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, PORT_CONTROL_2_8021Q_DISABLED; int err; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU)) + if (!chip->info->max_vid) return -EOPNOTSUPP; mutex_lock(&chip->reg_lock); @@ -1817,7 +1482,7 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds->priv; int err; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU)) + if (!chip->info->max_vid) return -EOPNOTSUPP; /* If the requested port doesn't belong to the same bridge as the VLAN @@ -1840,15 +1505,15 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, struct mv88e6xxx_vtu_entry vlan; int err; - err = _mv88e6xxx_vtu_get(chip, vid, &vlan, true); + err = mv88e6xxx_vtu_get(chip, vid, &vlan, true); if (err) return err; - vlan.data[port] = untagged ? + vlan.member[port] = untagged ? GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED : GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; - return _mv88e6xxx_vtu_loadpurge(chip, &vlan); + return mv88e6xxx_vtu_loadpurge(chip, &vlan); } static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, @@ -1860,7 +1525,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; u16 vid; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU)) + if (!chip->info->max_vid) return; mutex_lock(&chip->reg_lock); @@ -1885,15 +1550,15 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry vlan; int i, err; - err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false); + err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); if (err) return err; /* Tell switchdev if this VLAN is handled in software */ - if (vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + if (vlan.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) return -EOPNOTSUPP; - vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; + vlan.member[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; /* keep the VLAN unless all ports are excluded */ vlan.valid = false; @@ -1901,13 +1566,13 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)) continue; - if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) { + if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) { vlan.valid = true; break; } } - err = _mv88e6xxx_vtu_loadpurge(chip, &vlan); + err = mv88e6xxx_vtu_loadpurge(chip, &vlan); if (err) return err; @@ -1921,7 +1586,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 pvid, vid; int err = 0; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU)) + if (!chip->info->max_vid) return -EOPNOTSUPP; mutex_lock(&chip->reg_lock); @@ -1960,7 +1625,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, if (vid == 0) err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid); else - err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false); + err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); if (err) return err; @@ -2090,7 +1755,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, int (*cb)(struct switchdev_obj *obj)) { struct mv88e6xxx_vtu_entry vlan = { - .vid = GLOBAL_VTU_VID_MASK, /* all ones */ + .vid = chip->info->max_vid, }; u16 fid; int err; @@ -2105,12 +1770,8 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, return err; /* Dump VLANs' Filtering Information Databases */ - err = _mv88e6xxx_vtu_vid_write(chip, vlan.vid); - if (err) - return err; - do { - err = _mv88e6xxx_vtu_getnext(chip, &vlan); + err = mv88e6xxx_vtu_getnext(chip, &vlan); if (err) return err; @@ -2121,7 +1782,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, obj, cb); if (err) return err; - } while (vlan.vid < GLOBAL_VTU_VID_MASK); + } while (vlan.vid < chip->info->max_vid); return err; } @@ -2617,11 +2278,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) if (err) return err; - /* Clear all the VTU and STU entries */ - err = _mv88e6xxx_vtu_stu_flush(chip); - if (err < 0) - return err; - /* Configure the IP ToS mapping registers. */ err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000); if (err) @@ -2702,6 +2358,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) goto unlock; } + err = mv88e6xxx_vtu_setup(chip); + if (err) + goto unlock; + err = mv88e6xxx_pvt_setup(chip); if (err) goto unlock; @@ -2956,6 +2616,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .ppu_enable = mv88e6185_g1_ppu_enable, .ppu_disable = mv88e6185_g1_ppu_disable, .reset = mv88e6185_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6095_ops = { @@ -2977,6 +2639,8 @@ static const struct mv88e6xxx_ops mv88e6095_ops = { .ppu_enable = mv88e6185_g1_ppu_enable, .ppu_disable = mv88e6185_g1_ppu_disable, .reset = mv88e6185_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6097_ops = { @@ -3005,6 +2669,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6123_ops = { @@ -3028,6 +2694,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6131_ops = { @@ -3057,6 +2725,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .ppu_enable = mv88e6185_g1_ppu_enable, .ppu_disable = mv88e6185_g1_ppu_disable, .reset = mv88e6185_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6141_ops = { @@ -3088,6 +2758,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6161_ops = { @@ -3116,6 +2788,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6165_ops = { @@ -3137,6 +2811,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6171_ops = { @@ -3166,6 +2842,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6172_ops = { @@ -3197,6 +2875,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6175_ops = { @@ -3226,6 +2906,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6176_ops = { @@ -3257,6 +2939,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6185_ops = { @@ -3282,6 +2966,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { .ppu_enable = mv88e6185_g1_ppu_enable, .ppu_disable = mv88e6185_g1_ppu_disable, .reset = mv88e6185_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6190_ops = { @@ -3312,6 +2998,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6190x_ops = { @@ -3342,6 +3030,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6191_ops = { @@ -3372,6 +3062,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6240_ops = { @@ -3403,6 +3095,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6290_ops = { @@ -3434,6 +3128,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6320_ops = { @@ -3463,6 +3159,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .g1_set_egress_port = mv88e6095_g1_set_egress_port, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6321_ops = { @@ -3491,6 +3189,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, .g1_set_egress_port = mv88e6095_g1_set_egress_port, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6341_ops = { @@ -3522,6 +3222,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6350_ops = { @@ -3551,6 +3253,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6351_ops = { @@ -3580,6 +3284,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6352_ops = { @@ -3611,6 +3317,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6352_g1_vtu_getnext, + .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6390_ops = { @@ -3644,6 +3352,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, }; static const struct mv88e6xxx_ops mv88e6390x_ops = { @@ -3676,6 +3386,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, }; static const struct mv88e6xxx_info mv88e6xxx_table[] = { @@ -3685,6 +3397,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6085", .num_databases = 4096, .num_ports = 10, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3702,6 +3415,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6095/88E6095F", .num_databases = 256, .num_ports = 11, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3718,6 +3432,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6097/88E6097F", .num_databases = 4096, .num_ports = 11, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3735,6 +3450,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6123", .num_databases = 4096, .num_ports = 3, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3752,6 +3468,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6131", .num_databases = 256, .num_ports = 8, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3768,6 +3485,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6341", .num_databases = 4096, .num_ports = 6, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 3750, @@ -3784,6 +3502,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6161", .num_databases = 4096, .num_ports = 6, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3801,6 +3520,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6165", .num_databases = 4096, .num_ports = 6, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3818,6 +3538,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6171", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3835,6 +3556,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6172", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3852,6 +3574,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6175", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3869,6 +3592,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6176", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3886,6 +3610,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6185", .num_databases = 256, .num_ports = 10, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3902,6 +3627,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6190", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ + .max_vid = 8191, .port_base_addr = 0x0, .global1_addr = 0x1b, .tag_protocol = DSA_TAG_PROTO_DSA, @@ -3919,6 +3645,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6190X", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ + .max_vid = 8191, .port_base_addr = 0x0, .global1_addr = 0x1b, .age_time_coeff = 3750, @@ -3936,6 +3663,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6191", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ + .max_vid = 8191, .port_base_addr = 0x0, .global1_addr = 0x1b, .age_time_coeff = 3750, @@ -3953,6 +3681,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6240", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -3970,6 +3699,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6290", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ + .max_vid = 8191, .port_base_addr = 0x0, .global1_addr = 0x1b, .age_time_coeff = 3750, @@ -3987,6 +3717,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6320", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -4004,6 +3735,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6321", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -4020,6 +3752,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6341", .num_databases = 4096, .num_ports = 6, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 3750, @@ -4036,6 +3769,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6350", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -4053,6 +3787,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6351", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -4070,6 +3805,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6352", .num_databases = 4096, .num_ports = 7, + .max_vid = 4095, .port_base_addr = 0x10, .global1_addr = 0x1b, .age_time_coeff = 15000, @@ -4086,6 +3822,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6390", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ + .max_vid = 8191, .port_base_addr = 0x0, .global1_addr = 0x1b, .age_time_coeff = 3750, @@ -4102,6 +3839,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6390X", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ + .max_vid = 8191, .port_base_addr = 0x0, .global1_addr = 0x1b, .age_time_coeff = 3750, diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index e30cbe480d5b..46a4ea0f8c47 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -50,4 +50,18 @@ int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all); int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port, bool all); +int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip); + #endif /* _MV88E6XXX_GLOBAL1_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c new file mode 100644 index 000000000000..9aea22d4c9e2 --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -0,0 +1,511 @@ +/* + * Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support + * + * Copyright (c) 2008 Marvell Semiconductor + * Copyright (c) 2015 CMC Electronics, Inc. + * Copyright (c) 2017 Savoir-faire Linux, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "mv88e6xxx.h" +#include "global1.h" + +/* Offset 0x02: VTU FID Register */ + +static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val; + int err; + + err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val); + if (err) + return err; + + entry->fid = val & GLOBAL_VTU_FID_MASK; + + return 0; +} + +static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val = entry->fid & GLOBAL_VTU_FID_MASK; + + return mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, val); +} + +/* Offset 0x03: VTU SID Register */ + +static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val; + int err; + + err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val); + if (err) + return err; + + entry->sid = val & GLOBAL_VTU_SID_MASK; + + return 0; +} + +static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val = entry->sid & GLOBAL_VTU_SID_MASK; + + return mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, val); +} + +/* Offset 0x05: VTU Operation Register */ + +static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY); +} + +static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op) +{ + int err; + + err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op); + if (err) + return err; + + return mv88e6xxx_g1_vtu_op_wait(chip); +} + +/* Offset 0x06: VTU VID Register */ + +static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val; + int err; + + err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val); + if (err) + return err; + + entry->vid = val & 0xfff; + + if (val & GLOBAL_VTU_VID_PAGE) + entry->vid |= 0x1000; + + entry->valid = !!(val & GLOBAL_VTU_VID_VALID); + + return 0; +} + +static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val = entry->vid & 0xfff; + + if (entry->vid & 0x1000) + val |= GLOBAL_VTU_VID_PAGE; + + if (entry->valid) + val |= GLOBAL_VTU_VID_VALID; + + return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, val); +} + +/* Offset 0x07: VTU/STU Data Register 1 + * Offset 0x08: VTU/STU Data Register 2 + * Offset 0x09: VTU/STU Data Register 3 + */ + +static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 regs[3]; + int i; + + /* Read all 3 VTU/STU Data registers */ + for (i = 0; i < 3; ++i) { + u16 *reg = ®s[i]; + int err; + + err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + if (err) + return err; + } + + /* Extract MemberTag and PortState data */ + for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { + unsigned int member_offset = (i % 4) * 4; + unsigned int state_offset = member_offset + 2; + + entry->member[i] = (regs[i / 4] >> member_offset) & 0x3; + entry->state[i] = (regs[i / 4] >> state_offset) & 0x3; + } + + return 0; +} + +static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 regs[3] = { 0 }; + int i; + + /* Insert MemberTag and PortState data */ + for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { + unsigned int member_offset = (i % 4) * 4; + unsigned int state_offset = member_offset + 2; + + regs[i / 4] |= (entry->member[i] & 0x3) << member_offset; + regs[i / 4] |= (entry->state[i] & 0x3) << state_offset; + } + + /* Write all 3 VTU/STU Data registers */ + for (i = 0; i < 3; ++i) { + u16 reg = regs[i]; + int err; + + err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + if (err) + return err; + } + + return 0; +} + +static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data) +{ + u16 regs[2]; + int i; + + /* Read the 2 VTU/STU Data registers */ + for (i = 0; i < 2; ++i) { + u16 *reg = ®s[i]; + int err; + + err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + if (err) + return err; + } + + /* Extract data */ + for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { + unsigned int offset = (i % 8) * 2; + + data[i] = (regs[i / 8] >> offset) & 0x3; + } + + return 0; +} + +static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data) +{ + u16 regs[2] = { 0 }; + int i; + + /* Insert data */ + for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { + unsigned int offset = (i % 8) * 2; + + regs[i / 8] |= (data[i] & 0x3) << offset; + } + + /* Write the 2 VTU/STU Data registers */ + for (i = 0; i < 2; ++i) { + u16 reg = regs[i]; + int err; + + err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + if (err) + return err; + } + + return 0; +} + +/* VLAN Translation Unit Operations */ + +static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_GET_NEXT); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_read(chip, entry); + if (err) + return err; + + return mv88e6xxx_g1_vtu_vid_read(chip, entry); +} + +static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *vtu) +{ + struct mv88e6xxx_vtu_entry stu; + int err; + + err = mv88e6xxx_g1_vtu_sid_read(chip, vtu); + if (err) + return err; + + stu.sid = vtu->sid - 1; + + err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu); + if (err) + return err; + + if (stu.sid != vtu->sid || !stu.valid) + return -EINVAL; + + return 0; +} + +static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + /* To get the next higher active VID, the VTU GetNext operation can be + * started again without setting the VID registers since it already + * contains the last VID. + * + * To save a few hardware accesses and abstract this to the caller, + * write the VID only once, when the entry is given as invalid. + */ + if (!entry->valid) { + err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + if (err) + return err; + } + + err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_GET_NEXT); + if (err) + return err; + + return mv88e6xxx_g1_vtu_vid_read(chip, entry); +} + +int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 val; + int err; + + err = mv88e6xxx_g1_vtu_getnext(chip, entry); + if (err) + return err; + + if (entry->valid) { + err = mv88e6185_g1_vtu_data_read(chip, entry); + if (err) + return err; + + /* VTU DBNum[3:0] are located in VTU Operation 3:0 + * VTU DBNum[7:4] are located in VTU Operation 11:8 + */ + err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val); + if (err) + return err; + + entry->fid = val & 0x000f; + entry->fid |= (val & 0x0f00) >> 4; + } + + return 0; +} + +int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + int err; + + /* Fetch VLAN MemberTag data from the VTU */ + err = mv88e6xxx_g1_vtu_getnext(chip, entry); + if (err) + return err; + + if (entry->valid) { + /* Fetch (and mask) VLAN PortState data from the STU */ + err = mv88e6xxx_g1_vtu_stu_get(chip, entry); + if (err) + return err; + + err = mv88e6185_g1_vtu_data_read(chip, entry); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_fid_read(chip, entry); + if (err) + return err; + } + + return 0; +} + +int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + int err; + + /* Fetch VLAN MemberTag data from the VTU */ + err = mv88e6xxx_g1_vtu_getnext(chip, entry); + if (err) + return err; + + if (entry->valid) { + err = mv88e6390_g1_vtu_data_read(chip, entry->member); + if (err) + return err; + + /* Fetch VLAN PortState data from the STU */ + err = mv88e6xxx_g1_vtu_stu_get(chip, entry); + if (err) + return err; + + err = mv88e6390_g1_vtu_data_read(chip, entry->state); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_fid_read(chip, entry); + if (err) + return err; + } + + return 0; +} + +int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE; + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + if (err) + return err; + + if (entry->valid) { + err = mv88e6185_g1_vtu_data_write(chip, entry); + if (err) + return err; + + /* VTU DBNum[3:0] are located in VTU Operation 3:0 + * VTU DBNum[7:4] are located in VTU Operation 11:8 + */ + op |= entry->fid & 0x000f; + op |= (entry->fid & 0x00f0) << 8; + } + + return mv88e6xxx_g1_vtu_op(chip, op); +} + +int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + if (err) + return err; + + if (entry->valid) { + /* Write MemberTag and PortState data */ + err = mv88e6185_g1_vtu_data_write(chip, entry); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry); + if (err) + return err; + + /* Load STU entry */ + err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + if (err) + return err; + } + + /* Load/Purge VTU entry */ + return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_LOAD_PURGE); +} + +int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + if (err) + return err; + + if (entry->valid) { + /* Write PortState data */ + err = mv88e6390_g1_vtu_data_write(chip, entry->state); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry); + if (err) + return err; + + /* Load STU entry */ + err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE); + if (err) + return err; + + /* Write MemberTag data */ + err = mv88e6390_g1_vtu_data_write(chip, entry->member); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + if (err) + return err; + } + + /* Load/Purge VTU entry */ + return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_LOAD_PURGE); +} + +int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) +{ + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_FLUSH_ALL); +} diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index c8f54986996b..77236cd72df2 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -249,6 +249,7 @@ #define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) #define GLOBAL_VTU_VID 0x06 #define GLOBAL_VTU_VID_MASK 0xfff +#define GLOBAL_VTU_VID_PAGE BIT(13) #define GLOBAL_VTU_VID_VALID BIT(12) #define GLOBAL_VTU_DATA_0_3 0x07 #define GLOBAL_VTU_DATA_4_7 0x08 @@ -566,9 +567,6 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA) #define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) -#define MV88E6XXX_FLAG_STU BIT_ULL(MV88E6XXX_CAP_STU) -#define MV88E6XXX_FLAG_VTU BIT_ULL(MV88E6XXX_CAP_VTU) - /* Ingress Rate Limit unit */ #define MV88E6XXX_FLAGS_IRL \ (MV88E6XXX_FLAG_G2_IRL_CMD | \ @@ -587,7 +585,6 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6095 \ (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6097 \ @@ -597,8 +594,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) @@ -609,8 +604,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) @@ -618,8 +611,7 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_INT | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAGS_MULTI_CHIP | \ - MV88E6XXX_FLAG_VTU) + MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6320 \ (MV88E6XXX_FLAG_EEE | \ @@ -627,7 +619,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) @@ -637,8 +628,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_INT | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ MV88E6XXX_FLAGS_SERDES) @@ -650,8 +639,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) @@ -663,8 +650,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ MV88E6XXX_FLAGS_SERDES) @@ -673,8 +658,6 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) @@ -686,6 +669,7 @@ struct mv88e6xxx_info { const char *name; unsigned int num_databases; unsigned int num_ports; + unsigned int max_vid; unsigned int port_base_addr; unsigned int global1_addr; unsigned int age_time_coeff; @@ -713,7 +697,8 @@ struct mv88e6xxx_vtu_entry { u16 fid; u8 sid; bool valid; - u8 data[DSA_MAX_PORTS]; + u8 member[DSA_MAX_PORTS]; + u8 state[DSA_MAX_PORTS]; }; struct mv88e6xxx_bus_ops; @@ -898,6 +883,12 @@ struct mv88e6xxx_ops { /* Can be either in g1 or g2, so don't use a prefix */ int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); + + /* VLAN Translation Unit operations */ + int (*vtu_getnext)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); + int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); }; struct mv88e6xxx_irq_ops { |