Skip to content

Commit

Permalink
net: dsa: mv88e6xxx: handle multiple ports in ATU
Browse files Browse the repository at this point in the history
An address can be loaded in the ATU with multiple ports, for instance
when adding multiple ports to a Multicast group with "bridge mdb".

The current code doesn't allow that. Add an helper to get a single entry
from the ATU, then set or clear the requested port, before loading the
entry back in the ATU.

Note that the required _mv88e6xxx_atu_getnext function is defined below
mv88e6xxx_port_db_load_purge, so forward-declare it for the moment. The
ATU code will be isolated in future patches.

Fixes: 83dabd1 ("net: dsa: mv88e6xxx: make switchdev DB ops generic")
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
vivien authored and davem330 committed Sep 21, 2016
1 parent aecc5ce commit 8847293
Showing 1 changed file with 49 additions and 7 deletions.
56 changes: 49 additions & 7 deletions drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -2091,12 +2091,48 @@ static int _mv88e6xxx_atu_load(struct mv88e6xxx_chip *chip,
return _mv88e6xxx_atu_cmd(chip, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
}

static int _mv88e6xxx_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
struct mv88e6xxx_atu_entry *entry);

static int mv88e6xxx_atu_get(struct mv88e6xxx_chip *chip, int fid,
const u8 *addr, struct mv88e6xxx_atu_entry *entry)
{
struct mv88e6xxx_atu_entry next;
int err;

eth_broadcast_addr(next.mac);

err = _mv88e6xxx_atu_mac_write(chip, next.mac);
if (err)
return err;

do {
err = _mv88e6xxx_atu_getnext(chip, fid, &next);
if (err)
return err;

if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
break;

if (ether_addr_equal(next.mac, addr)) {
*entry = next;
return 0;
}
} while (!is_broadcast_ether_addr(next.mac));

memset(entry, 0, sizeof(*entry));
entry->fid = fid;
ether_addr_copy(entry->mac, addr);

return 0;
}

static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
const unsigned char *addr, u16 vid,
u8 state)
{
struct mv88e6xxx_atu_entry entry = { 0 };
struct mv88e6xxx_vtu_stu_entry vlan;
struct mv88e6xxx_atu_entry entry;
int err;

/* Null VLAN ID corresponds to the port private database */
Expand All @@ -2107,12 +2143,18 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
if (err)
return err;

entry.fid = vlan.fid;
entry.state = state;
ether_addr_copy(entry.mac, addr);
if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
entry.trunk = false;
entry.portv_trunkid = BIT(port);
err = mv88e6xxx_atu_get(chip, vlan.fid, addr, &entry);
if (err)
return err;

/* Purge the ATU entry only if no port is using it anymore */
if (state == GLOBAL_ATU_DATA_STATE_UNUSED) {
entry.portv_trunkid &= ~BIT(port);
if (!entry.portv_trunkid)
entry.state = GLOBAL_ATU_DATA_STATE_UNUSED;
} else {
entry.portv_trunkid |= BIT(port);
entry.state = state;
}

return _mv88e6xxx_atu_load(chip, &entry);
Expand Down

0 comments on commit 8847293

Please sign in to comment.