Commit aaf1be31 authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-mv88e6xxx-802.1s-and-88E6390-VTU'

Vivien Didelot says:

====================
net: dsa: mv88e6xxx: 802.1s and 88E6390 VTU

This patch series adds support for the VLAN Table Unit (a.k.a. the VTU)
to the 88E6390 family of Marvell Ethernet switch chips. The plumbing for
the per VLAN Spanning Tree support is added as a side effect of the
necessary refactoring.

The patchset is split up so that no duplication of code is introduced.
With this patchset applied, the mv88e6xxx driver has 2 new function
pointers for the VTU GetNext and VTU Load/Purge operations (with 3
implementations), both handling programmation of 802.1q and 802.1s.

On a ZII Rev C board (featuring 2 88E6390X chips) with all ports bridged
together, we obtain the following hardware VLAN configuration:

    # cat /sys/class/net/br0/bridge/vlan_filtering
    1
    # cat /sys/class/net/br0/bridge/default_pvid
    42
    # bridge vlan add dev lan3 vid 666
    # bridge vlan show
    port    vlan ids
    lan1     42 PVID Egress Untagged

    lan1     42 PVID Egress Untagged

    lan2     42 PVID Egress Untagged

    lan2     42 PVID Egress Untagged

    lan3     42 PVID Egress Untagged
             666

    lan3     42 PVID Egress Untagged
             666

    lan4     42 PVID Egress Untagged

    lan4     42 PVID Egress Untagged

    lan5     42 PVID Egress Untagged

    lan5     42 PVID Egress Untagged

    lan6     42 PVID Egress Untagged

    lan6     42 PVID Egress Untagged

    lan7     42 PVID Egress Untagged

    lan7     42 PVID Egress Untagged

    lan8     42 PVID Egress Untagged

    lan8     42 PVID Egress Untagged

    br0      42 PVID Egress Untagged

Below are the technical details for the different implementations.

All switch families have up to 3 dedicated VTU Data registers used to
program 802.1q and 802.1s, both using 2-bit values.

On 88E6185 and 88E6352 families, port membership and state are adjacent,
while the 88E6390 family share the same bits:

    Bits        88E6185/88E6352         88E6390
    -----       -----------------       --------------------------
    0-1         Port 0 membership       Port 0 membership or state
    2-3         Port 0 state            Port 1 membership or state
    4-5         Port 1 membership       Port 2 membership or state
    6-7         Port 1 state            Port 3 membership or state
    8-9         Port 2 membership       Port 4 membership or state
    10-11       Port 2 state            Port 5 membership or state
    ...         ...                     ...

The 88E6185 family programs all ports membership and state in a single
VTU GetNext or Load/Purge operation.

The 88E6352 family introduced an indirect Spanning Tree Unit table
(a.k.a. STU) which requires additional STU GetNext and Load/Purge
operations to read and write the ports state bits.

The 88E6390 family also has an STU and requires data bits to be accessed
before and after every single VTU or STU operation.

Finally, the 88E6390 family introduced a 13th bit for the VLAN ID, which
must be taken care of regardless the VTU operating mode. This means that
iterating over the VTU now starts or ends with value 8191, not 4095.

Patch 1 adds a max_vid field to the chip info structure.
Patch 2 adds 802.1q and 802.1s data to the generic VTU entry structure.
Patches 3 to 10 move helpers to a dedicated file (later made static).
Patches 11 and 12 abstract handling of the STU behind VTU operations.
Patches 13 and 14 add the new function pointers for VTU operations.
Patches 15 and 18 polish the VTU code and add VTU support for 88E6390.

Changes in v2:
  - add Reviewed-by tags
  - fix comments in 8/18
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 152afb9b 931d1822
......@@ -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
......@@ -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 = &regs[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 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
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,
......
......@@ -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 */
/*
* 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 = &regs[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 = &regs[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);
}
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment