Merge branch 'mv88e6xxx-cross-chip-bridging'

Vivien Didelot says:

====================
net: dsa: mv88e6xxx: program cross-chip bridging

The purpose of this patch series is to bring hardware cross-chip
bridging configuration to the DSA layer and the mv88e6xxx DSA driver.

Most recent Marvell switch chips have a Cross-chip Port Based VLAN Table
(PVT) used to restrict to which internal destination port an arbitrary
external source port is allowed to egress frames to.

The current behavior of the mv88e6xxx driver is to program this table
table with all ones, allowing any external ports to egress frames on any
internal ports. This means that carefully crafted Ethernet frames can
potentially bypass the user bridging configuration.

Patches 1 to 7 prepare the setup of this table and factorize the common
bits of both in-chip and cross-chip Marvell bridging code.

Patch 8 adds new optional cross-chip bridging operations to DSA switch.

Patch 9 switches the current behavior to program the table according to
the user bridging configuration when (cross-chip) ports get (un)bridged.

On a ZII Rev B board, bridging together the 3 user ports of both 88E6352
will result in the following PVTs on respectively switch 0 and switch 1:

    External   Internal Ports
    Dev Port   0  1  2  3  4  5  6

     1    0    *  *  *  -  -  *  *
     1    1    *  *  *  -  -  *  *
     1    2    *  *  *  -  -  *  *
     1    3    -  -  -  -  -  *  *
     1    4    -  -  -  -  -  *  *
     1    5    *  *  *  *  *  *  *
     1    6    *  *  *  *  *  *  *

     0    0    *  *  *  -  -  *  *
     0    1    *  *  *  -  -  *  *
     0    2    *  *  *  -  -  *  *
     0    3    -  -  -  -  -  *  *
     0    4    -  -  -  -  -  *  *
     0    5    *  *  *  *  *  *  *
     0    6    *  *  *  *  *  *  *

Changes since v2:
  - Define MV88E6XXX_MAX_PVT_SWITCHES and MV88E6XXX_MAX_PVT_PORTS
  - use mv88e6xxx_g2_misc_4_bit_port instead of the 5-bit variant
  - add Andrew's tags and reword commit 6/9
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-04-01 12:22:59 -07:00
commit 772c3bdad1
6 changed files with 287 additions and 72 deletions

View File

@ -1123,27 +1123,42 @@ out:
return err;
}
static int _mv88e6xxx_port_based_vlan_map(struct mv88e6xxx_chip *chip, int port)
static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
{
struct dsa_switch *ds = chip->ds;
struct net_device *bridge = ds->ports[port].bridge_dev;
u16 output_ports = 0;
struct dsa_switch *ds = NULL;
struct net_device *br;
u16 pvlan;
int i;
/* allow CPU port or DSA link(s) to send frames to every port */
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
output_ports = ~0;
} else {
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
/* allow sending frames to every group member */
if (bridge && ds->ports[i].bridge_dev == bridge)
output_ports |= BIT(i);
if (dev < DSA_MAX_SWITCHES)
ds = chip->ds->dst->ds[dev];
/* allow sending frames to CPU port and DSA link(s) */
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
output_ports |= BIT(i);
}
}
/* Prevent frames from unknown switch or port */
if (!ds || port >= ds->num_ports)
return 0;
/* Frames from DSA links and CPU ports can egress any local port */
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
return mv88e6xxx_port_mask(chip);
br = ds->ports[port].bridge_dev;
pvlan = 0;
/* Frames from user ports can egress any local DSA links and CPU ports,
* as well as any local member of their bridge group.
*/
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
if (dsa_is_cpu_port(chip->ds, i) ||
dsa_is_dsa_port(chip->ds, i) ||
(br && chip->ds->ports[i].bridge_dev == br))
pvlan |= BIT(i);
return pvlan;
}
static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
{
u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
/* prevent frames from going back out of the port they came in on */
output_ports &= ~BIT(port);
@ -1198,6 +1213,46 @@ static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
}
static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
{
u16 pvlan = 0;
if (!mv88e6xxx_has_pvt(chip))
return -EOPNOTSUPP;
/* Skip the local source device, which uses in-chip port VLAN */
if (dev != chip->ds->index)
pvlan = mv88e6xxx_port_vlan(chip, dev, port);
return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
}
static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
{
int dev, port;
int err;
if (!mv88e6xxx_has_pvt(chip))
return 0;
/* Clear 5 Bit Port for usage with Marvell Link Street devices:
* use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
*/
err = mv88e6xxx_g2_misc_4_bit_port(chip);
if (err)
return err;
for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
err = mv88e6xxx_pvt_map(chip, dev, port);
if (err)
return err;
}
}
return 0;
}
static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@ -2085,23 +2140,52 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
return err;
}
static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
struct net_device *br)
{
struct dsa_switch *ds;
int port;
int dev;
int err;
/* Remap the Port VLAN of each local bridge group member */
for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) {
if (chip->ds->ports[port].bridge_dev == br) {
err = mv88e6xxx_port_vlan_map(chip, port);
if (err)
return err;
}
}
if (!mv88e6xxx_has_pvt(chip))
return 0;
/* Remap the Port VLAN of each cross-chip bridge group member */
for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) {
ds = chip->ds->dst->ds[dev];
if (!ds)
break;
for (port = 0; port < ds->num_ports; ++port) {
if (ds->ports[port].bridge_dev == br) {
err = mv88e6xxx_pvt_map(chip, dev, port);
if (err)
return err;
}
}
}
return 0;
}
static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
{
struct mv88e6xxx_chip *chip = ds->priv;
int i, err = 0;
int err;
mutex_lock(&chip->reg_lock);
/* Remap each port's VLANTable */
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
if (ds->ports[i].bridge_dev == br) {
err = _mv88e6xxx_port_based_vlan_map(chip, i);
if (err)
break;
}
}
err = mv88e6xxx_bridge_map(chip, br);
mutex_unlock(&chip->reg_lock);
return err;
@ -2111,17 +2195,41 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
{
struct mv88e6xxx_chip *chip = ds->priv;
int i;
mutex_lock(&chip->reg_lock);
if (mv88e6xxx_bridge_map(chip, br) ||
mv88e6xxx_port_vlan_map(chip, port))
dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
mutex_unlock(&chip->reg_lock);
}
/* Remap each port's VLANTable */
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
if (i == port || ds->ports[i].bridge_dev == br)
if (_mv88e6xxx_port_based_vlan_map(chip, i))
netdev_warn(ds->ports[i].netdev,
"failed to remap\n");
static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
int port, struct net_device *br)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
if (!mv88e6xxx_has_pvt(chip))
return 0;
mutex_lock(&chip->reg_lock);
err = mv88e6xxx_pvt_map(chip, dev, port);
mutex_unlock(&chip->reg_lock);
return err;
}
static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
int port, struct net_device *br)
{
struct mv88e6xxx_chip *chip = ds->priv;
if (!mv88e6xxx_has_pvt(chip))
return;
mutex_lock(&chip->reg_lock);
if (mv88e6xxx_pvt_map(chip, dev, port))
dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
mutex_unlock(&chip->reg_lock);
}
@ -2435,7 +2543,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
if (err)
return err;
err = _mv88e6xxx_port_based_vlan_map(chip, port);
err = mv88e6xxx_port_vlan_map(chip, port);
if (err)
return err;
@ -2594,6 +2702,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
goto unlock;
}
err = mv88e6xxx_pvt_setup(chip);
if (err)
goto unlock;
err = mv88e6xxx_atu_setup(chip);
if (err)
goto unlock;
@ -3578,6 +3690,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 8,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6097,
.ops = &mv88e6085_ops,
@ -3610,6 +3723,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 8,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6097,
.ops = &mv88e6097_ops,
@ -3626,6 +3740,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
.ops = &mv88e6123_ops,
@ -3657,6 +3772,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 3750,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6341,
.ops = &mv88e6141_ops,
@ -3673,6 +3789,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
.ops = &mv88e6161_ops,
@ -3689,6 +3806,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
.ops = &mv88e6165_ops,
@ -3705,6 +3823,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6171_ops,
@ -3721,6 +3840,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6172_ops,
@ -3737,6 +3857,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6175_ops,
@ -3753,6 +3874,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6176_ops,
@ -3785,6 +3907,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.tag_protocol = DSA_TAG_PROTO_DSA,
.age_time_coeff = 3750,
.g1_irqs = 9,
.pvt = true,
.atu_move_port_mask = 0x1f,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6190_ops,
@ -3801,6 +3924,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 3750,
.g1_irqs = 9,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6190x_ops,
@ -3817,6 +3941,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 3750,
.g1_irqs = 9,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6191_ops,
@ -3833,6 +3958,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6240_ops,
@ -3849,6 +3975,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 3750,
.g1_irqs = 9,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6290_ops,
@ -3865,6 +3992,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 8,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6320,
.ops = &mv88e6320_ops,
@ -3896,6 +4024,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 3750,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6341,
.ops = &mv88e6341_ops,
@ -3912,6 +4041,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6350_ops,
@ -3928,6 +4058,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6351_ops,
@ -3944,6 +4075,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 15000,
.g1_irqs = 9,
.atu_move_port_mask = 0xf,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6352_ops,
@ -3959,6 +4091,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 3750,
.g1_irqs = 9,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6390_ops,
@ -3974,6 +4107,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.age_time_coeff = 3750,
.g1_irqs = 9,
.atu_move_port_mask = 0x1f,
.pvt = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6390x_ops,
@ -4209,6 +4343,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.port_mdb_add = mv88e6xxx_port_mdb_add,
.port_mdb_del = mv88e6xxx_port_mdb_del,
.port_mdb_dump = mv88e6xxx_port_mdb_dump,
.crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join,
.crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave,
};
static struct dsa_switch_driver mv88e6xxx_switch_drv = {
@ -4220,7 +4356,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
struct device *dev = chip->dev;
struct dsa_switch *ds;
ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);
ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip));
if (!ds)
return -ENOMEM;

View File

@ -172,6 +172,50 @@ static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip)
return err;
}
/* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
* Offset 0x0C: Cross-chip Port VLAN Data Register
*/
static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_wait(chip, GLOBAL2_PVT_ADDR, GLOBAL2_PVT_ADDR_BUSY);
}
static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
int src_port, u16 op)
{
int err;
/* 9-bit Cross-chip PVT pointer: with GLOBAL2_MISC_5_BIT_PORT cleared,
* source device is 5-bit, source port is 4-bit.
*/
op |= (src_dev & 0x1f) << 4;
op |= (src_port & 0xf);
err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR, op);
if (err)
return err;
return mv88e6xxx_g2_pvt_op_wait(chip);
}
int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
int src_port, u16 data)
{
int err;
err = mv88e6xxx_g2_pvt_op_wait(chip);
if (err)
return err;
err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_DATA, data);
if (err)
return err;
return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN);
}
/* Offset 0x0D: Switch MAC/WoL/WoF register */
static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
@ -784,6 +828,31 @@ static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
return err;
}
/* Offset 0x1D: Misc Register */
static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
bool port_5_bit)
{
u16 val;
int err;
err = mv88e6xxx_g2_read(chip, GLOBAL2_MISC, &val);
if (err)
return err;
if (port_5_bit)
val |= GLOBAL2_MISC_5_BIT_PORT;
else
val &= ~GLOBAL2_MISC_5_BIT_PORT;
return mv88e6xxx_g2_write(chip, GLOBAL2_MISC, val);
}
int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_misc_5_bit_port(chip, false);
}
static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
{
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
@ -966,14 +1035,6 @@ int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
return err;
}
if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_PVT)) {
/* Initialize Cross-chip Port VLAN Table to reset defaults */
err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR,
GLOBAL2_PVT_ADDR_OP_INIT_ONES);
if (err)
return err;
}
if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
/* Clear the priority override table. */
err = mv88e6xxx_g2_clear_pot(chip);

View File

@ -42,6 +42,10 @@ int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
struct ethtool_eeprom *eeprom, u8 *data);
int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
int src_port, u16 data);
int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip);
@ -110,6 +114,17 @@ static inline int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
return -EOPNOTSUPP;
}
int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
int src_port, u16 data)
{
return -EOPNOTSUPP;
}
int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
{
return -EOPNOTSUPP;
}
static inline int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
{
return -EOPNOTSUPP;

View File

@ -439,9 +439,14 @@
#define GLOBAL2_WDOG_FORCE_IRQ BIT(0)
#define GLOBAL2_QOS_WEIGHT 0x1c
#define GLOBAL2_MISC 0x1d
#define GLOBAL2_MISC_5_BIT_PORT BIT(14)
#define MV88E6XXX_N_FID 4096
/* PVT limits for 4-bit port and 5-bit switch */
#define MV88E6XXX_MAX_PVT_SWITCHES 32
#define MV88E6XXX_MAX_PVT_PORTS 16
enum mv88e6xxx_frame_mode {
MV88E6XXX_FRAME_MODE_NORMAL,
MV88E6XXX_FRAME_MODE_DSA,
@ -527,8 +532,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */
MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */
MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */
MV88E6XXX_CAP_G2_PVT_ADDR, /* (0x0b) Cross Chip Port VLAN Addr */
MV88E6XXX_CAP_G2_PVT_DATA, /* (0x0c) Cross Chip Port VLAN Data */
MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */
/* Per VLAN Spanning Tree Unit (STU).
@ -561,8 +564,6 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X)
#define MV88E6XXX_FLAG_G2_IRL_CMD BIT_ULL(MV88E6XXX_CAP_G2_IRL_CMD)
#define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA)
#define MV88E6XXX_FLAG_G2_PVT_ADDR BIT_ULL(MV88E6XXX_CAP_G2_PVT_ADDR)
#define MV88E6XXX_FLAG_G2_PVT_DATA BIT_ULL(MV88E6XXX_CAP_G2_PVT_DATA)
#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT)
#define MV88E6XXX_FLAG_STU BIT_ULL(MV88E6XXX_CAP_STU)
@ -578,11 +579,6 @@ enum mv88e6xxx_cap {
(MV88E6XXX_FLAG_SMI_CMD | \
MV88E6XXX_FLAG_SMI_DATA)
/* Cross-chip Port VLAN Table */
#define MV88E6XXX_FLAGS_PVT \
(MV88E6XXX_FLAG_G2_PVT_ADDR | \
MV88E6XXX_FLAG_G2_PVT_DATA)
/* Fiber/SERDES Registers at SMI address F, page 1 */
#define MV88E6XXX_FLAGS_SERDES \
(MV88E6XXX_FLAG_PHY_PAGE | \
@ -604,8 +600,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT)
MV88E6XXX_FLAGS_MULTI_CHIP)
#define MV88E6XXX_FLAGS_FAMILY_6165 \
(MV88E6XXX_FLAG_G1_VTU_FID | \
@ -617,8 +612,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT)
MV88E6XXX_FLAGS_MULTI_CHIP)
#define MV88E6XXX_FLAGS_FAMILY_6185 \
(MV88E6XXX_FLAG_GLOBAL2 | \
@ -635,8 +629,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT)
MV88E6XXX_FLAGS_MULTI_CHIP)
#define MV88E6XXX_FLAGS_FAMILY_6341 \
(MV88E6XXX_FLAG_EEE | \
@ -648,7 +641,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT | \
MV88E6XXX_FLAGS_SERDES)
#define MV88E6XXX_FLAGS_FAMILY_6351 \
@ -661,8 +653,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT)
MV88E6XXX_FLAGS_MULTI_CHIP)
#define MV88E6XXX_FLAGS_FAMILY_6352 \
(MV88E6XXX_FLAG_EEE | \
@ -676,7 +667,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT | \
MV88E6XXX_FLAGS_SERDES)
#define MV88E6XXX_FLAGS_FAMILY_6390 \
@ -686,8 +676,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAGS_PVT)
MV88E6XXX_FLAGS_MULTI_CHIP)
struct mv88e6xxx_ops;
@ -701,6 +690,7 @@ struct mv88e6xxx_info {
unsigned int global1_addr;
unsigned int age_time_coeff;
unsigned int g1_irqs;
bool pvt;
enum dsa_tag_protocol tag_protocol;
unsigned long long flags;
@ -936,6 +926,11 @@ static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip,
return (chip->info->flags & flags) == flags;
}
static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip)
{
return chip->info->pvt;
}
static inline unsigned int mv88e6xxx_num_databases(struct mv88e6xxx_chip *chip)
{
return chip->info->num_databases;

View File

@ -456,6 +456,14 @@ struct dsa_switch_ops {
bool ingress);
void (*port_mirror_del)(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror);
/*
* Cross-chip operations
*/
int (*crosschip_bridge_join)(struct dsa_switch *ds, int sw_index,
int port, struct net_device *br);
void (*crosschip_bridge_leave)(struct dsa_switch *ds, int sw_index,
int port, struct net_device *br);
};
struct dsa_switch_driver {

View File

@ -20,9 +20,9 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds,
if (ds->index == info->sw_index && ds->ops->port_bridge_join)
return ds->ops->port_bridge_join(ds, info->port, info->br);
if (ds->index != info->sw_index)
dev_dbg(ds->dev, "crosschip DSA port %d.%d bridged to %s\n",
info->sw_index, info->port, netdev_name(info->br));
if (ds->index != info->sw_index && ds->ops->crosschip_bridge_join)
return ds->ops->crosschip_bridge_join(ds, info->sw_index,
info->port, info->br);
return 0;
}
@ -33,9 +33,9 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
if (ds->index == info->sw_index && ds->ops->port_bridge_leave)
ds->ops->port_bridge_leave(ds, info->port, info->br);
if (ds->index != info->sw_index)
dev_dbg(ds->dev, "crosschip DSA port %d.%d unbridged from %s\n",
info->sw_index, info->port, netdev_name(info->br));
if (ds->index != info->sw_index && ds->ops->crosschip_bridge_leave)
ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port,
info->br);
return 0;
}