mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 00:21:32 +00:00
Merge branch 'mv88e6xxx-broadcast-flooding-in-hardware'
Andrew Lunn says: ==================== mv88e6xxx broadcast flooding in hardware This patchset makes the mv88e6xxx driver perform flooding in hardware, rather than let the software bridge perform the flooding. This is a prerequisite for IGMP snooping on the bridge interface. In order to make hardware broadcasting work, a few other issues need fixing or improving. SWITCHDEV_ATTR_ID_PORT_PARENT_ID is broken, which is apparent when testing on the ZII devel board with multiple switches. Some of these patches are taken from a previous RFC patchset of IGMP support. Rebased onto net-next, with fixup for Vivien's refactoring. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c311db92af
@ -1137,7 +1137,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
|
||||
if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
|
||||
continue;
|
||||
|
||||
if (!ds->ports[port].slave)
|
||||
if (!ds->ports[i].slave)
|
||||
continue;
|
||||
|
||||
if (vlan.member[i] ==
|
||||
@ -1151,8 +1151,8 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
|
||||
if (!dsa_to_port(ds, i)->bridge_dev)
|
||||
continue;
|
||||
|
||||
dev_err(ds->dev, "p%d: hw VLAN %d already used by %s\n",
|
||||
port, vlan.vid,
|
||||
dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
|
||||
port, vlan.vid, i,
|
||||
netdev_name(dsa_to_port(ds, i)->bridge_dev));
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
@ -1208,6 +1208,73 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
|
||||
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_vtu_entry vlan;
|
||||
struct mv88e6xxx_atu_entry entry;
|
||||
int err;
|
||||
|
||||
/* Null VLAN ID corresponds to the port private database */
|
||||
if (vid == 0)
|
||||
err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
|
||||
else
|
||||
err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
ether_addr_copy(entry.mac, addr);
|
||||
eth_addr_dec(entry.mac);
|
||||
|
||||
err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Initialize a fresh ATU entry if it isn't found */
|
||||
if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
|
||||
!ether_addr_equal(entry.mac, addr)) {
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
ether_addr_copy(entry.mac, addr);
|
||||
}
|
||||
|
||||
/* Purge the ATU entry only if no port is using it anymore */
|
||||
if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
|
||||
entry.portvec &= ~BIT(port);
|
||||
if (!entry.portvec)
|
||||
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
} else {
|
||||
entry.portvec |= BIT(port);
|
||||
entry.state = state;
|
||||
}
|
||||
|
||||
return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
|
||||
u16 vid)
|
||||
{
|
||||
const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
|
||||
|
||||
return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
|
||||
{
|
||||
int port;
|
||||
int err;
|
||||
|
||||
for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
|
||||
err = mv88e6xxx_port_add_broadcast(chip, port, vid);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
|
||||
u16 vid, u8 member)
|
||||
{
|
||||
@ -1220,7 +1287,11 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
|
||||
|
||||
vlan.member[port] = member;
|
||||
|
||||
return mv88e6xxx_vtu_loadpurge(chip, &vlan);
|
||||
err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mv88e6xxx_broadcast_setup(chip, vid);
|
||||
}
|
||||
|
||||
static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
|
||||
@ -1324,50 +1395,6 @@ unlock:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
|
||||
const unsigned char *addr, u16 vid,
|
||||
u8 state)
|
||||
{
|
||||
struct mv88e6xxx_vtu_entry vlan;
|
||||
struct mv88e6xxx_atu_entry entry;
|
||||
int err;
|
||||
|
||||
/* Null VLAN ID corresponds to the port private database */
|
||||
if (vid == 0)
|
||||
err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
|
||||
else
|
||||
err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
ether_addr_copy(entry.mac, addr);
|
||||
eth_addr_dec(entry.mac);
|
||||
|
||||
err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Initialize a fresh ATU entry if it isn't found */
|
||||
if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
|
||||
!ether_addr_equal(entry.mac, addr)) {
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
ether_addr_copy(entry.mac, addr);
|
||||
}
|
||||
|
||||
/* Purge the ATU entry only if no port is using it anymore */
|
||||
if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
|
||||
entry.portvec &= ~BIT(port);
|
||||
if (!entry.portvec)
|
||||
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
} else {
|
||||
entry.portvec |= BIT(port);
|
||||
entry.state = state;
|
||||
}
|
||||
|
||||
return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
@ -2049,6 +2076,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
err = mv88e6xxx_broadcast_setup(chip, 0);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
err = mv88e6xxx_pot_setup(chip);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
@ -355,11 +355,12 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
|
||||
{
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
struct dsa_switch_tree *dst = ds->dst;
|
||||
|
||||
switch (attr->id) {
|
||||
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
|
||||
attr->u.ppid.id_len = sizeof(ds->index);
|
||||
memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len);
|
||||
attr->u.ppid.id_len = sizeof(dst->index);
|
||||
memcpy(&attr->u.ppid.id, &dst->index, attr->u.ppid.id_len);
|
||||
break;
|
||||
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:
|
||||
attr->u.brport_flags_support = 0;
|
||||
|
@ -141,6 +141,8 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
2 * ETH_ALEN);
|
||||
}
|
||||
|
||||
skb->offload_fwd_mark = 1;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,8 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
2 * ETH_ALEN);
|
||||
}
|
||||
|
||||
skb->offload_fwd_mark = 1;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user