From d51c542b782fac35a9f37a23391f3bee884b7401 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:29 -0400 Subject: net: dsa: mv88e6xxx: remove basic function flags All 88E6xxx Marvell switches (even the old not supported yet 88E6060) have at least an ATU, per-port STP states and VLAN map, to run basic switch functions such as Spanning Tree and port based VLANs. Get rid of the related MV88E6XXX_FLAG_{ATU,PORTSTATE,VLANTABLE} flags, as they are defaults to every chip. This enables STP on 6185 and removes many inconsistencies on others. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5cb06f7..3feb842 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1460,9 +1460,6 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, int stp_state; int err; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PORTSTATE)) - return; - switch (state) { case BR_STATE_DISABLED: stp_state = PORT_CONTROL_STATE_DISABLED; @@ -2398,11 +2395,6 @@ static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans) { - struct mv88e6xxx_chip *chip = ds_to_priv(ds); - - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_ATU)) - return -EOPNOTSUPP; - /* We don't need any dynamic resource from the kernel (yet), * so skip the prepare phase. */ @@ -2418,9 +2410,6 @@ static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, GLOBAL_ATU_DATA_STATE_UC_STATIC; struct mv88e6xxx_chip *chip = ds_to_priv(ds); - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_ATU)) - return; - mutex_lock(&chip->reg_lock); if (_mv88e6xxx_port_fdb_load(chip, port, fdb->addr, fdb->vid, state)) netdev_err(ds->ports[port].netdev, @@ -2434,9 +2423,6 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds_to_priv(ds); int ret; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_ATU)) - return -EOPNOTSUPP; - mutex_lock(&chip->reg_lock); ret = _mv88e6xxx_port_fdb_load(chip, port, fdb->addr, fdb->vid, GLOBAL_ATU_DATA_STATE_UNUSED); @@ -2542,9 +2528,6 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, u16 fid; int err; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_ATU)) - return -EOPNOTSUPP; - mutex_lock(&chip->reg_lock); /* Dump port's default Filtering Information Database (VLAN ID 0) */ @@ -2587,9 +2570,6 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds_to_priv(ds); int i, err = 0; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VLANTABLE)) - return -EOPNOTSUPP; - mutex_lock(&chip->reg_lock); /* Assign the bridge and remap each port's VLANTable */ @@ -2614,9 +2594,6 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port) struct net_device *bridge = chip->ports[port].bridge_dev; int i; - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VLANTABLE)) - return; - mutex_lock(&chip->reg_lock); /* Unassign the bridge and remap each port's VLANTable */ diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 83f0662..2ff62f4 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -374,11 +374,6 @@ enum mv88e6xxx_family { }; enum mv88e6xxx_cap { - /* Address Translation Unit. - * The ATU is used to lookup and learn MAC addresses. See GLOBAL_ATU_OP. - */ - MV88E6XXX_CAP_ATU, - /* Energy Efficient Ethernet. */ MV88E6XXX_CAP_EEE, @@ -394,11 +389,6 @@ enum mv88e6xxx_cap { */ MV88E6XXX_CAP_MULTI_CHIP, - /* Port State Filtering for 802.1D Spanning Tree. - * See PORT_CONTROL_STATE_* values in the PORT_CONTROL register. - */ - MV88E6XXX_CAP_PORTSTATE, - /* PHY Polling Unit. * See GLOBAL_CONTROL_PPU_ENABLE and GLOBAL_STATUS_PPU_POLLING. */ @@ -430,12 +420,6 @@ enum mv88e6xxx_cap { MV88E6XXX_CAP_TEMP, MV88E6XXX_CAP_TEMP_LIMIT, - /* In-chip Port Based VLANs. - * Each port VLANTable register (see PORT_BASE_VLAN) is used to restrict - * the output (or egress) ports to which it is allowed to send frames. - */ - MV88E6XXX_CAP_VLANTABLE, - /* VLAN Table Unit. * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. */ @@ -443,11 +427,9 @@ enum mv88e6xxx_cap { }; /* Bitmask of capabilities */ -#define MV88E6XXX_FLAG_ATU BIT(MV88E6XXX_CAP_ATU) #define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE) #define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM) #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) -#define MV88E6XXX_FLAG_PORTSTATE BIT(MV88E6XXX_CAP_PORTSTATE) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) #define MV88E6XXX_FLAG_SMI_PHY BIT(MV88E6XXX_CAP_SMI_PHY) @@ -455,22 +437,17 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_SWITCH_MAC BIT(MV88E6XXX_CAP_SWITCH_MAC_WOL_WOF) #define MV88E6XXX_FLAG_TEMP BIT(MV88E6XXX_CAP_TEMP) #define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT) -#define MV88E6XXX_FLAG_VLANTABLE BIT(MV88E6XXX_CAP_VLANTABLE) #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) #define MV88E6XXX_FLAGS_FAMILY_6095 \ - (MV88E6XXX_FLAG_ATU | \ - MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ - MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6097 \ - (MV88E6XXX_FLAG_ATU | \ - MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6165 \ @@ -481,51 +458,40 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6185 \ - (MV88E6XXX_FLAG_ATU | \ - MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ - MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6320 \ - (MV88E6XXX_FLAG_ATU | \ - MV88E6XXX_FLAG_EEE | \ + (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ MV88E6XXX_FLAG_MULTI_CHIP | \ - MV88E6XXX_FLAG_PORTSTATE | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ - MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6351 \ - (MV88E6XXX_FLAG_ATU | \ - MV88E6XXX_FLAG_MULTI_CHIP | \ - MV88E6XXX_FLAG_PORTSTATE | \ + (MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ - MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6352 \ - (MV88E6XXX_FLAG_ATU | \ - MV88E6XXX_FLAG_EEE | \ + (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ MV88E6XXX_FLAG_MULTI_CHIP | \ - MV88E6XXX_FLAG_PORTSTATE | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ - MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) struct mv88e6xxx_info { -- cgit v0.10.2 From 9729934c4ff6893456e9a885718b75856e1a42ae Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:30 -0400 Subject: net: dsa: mv88e6xxx: split setup of Global 1 and 2 Separate the setup of Global 1 and Global 2 internal SMI devices and add a flag to describe the presence of this second registers set. Also rearrange the G1 setup in the registers order. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 3feb842..1e39fa6 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2993,13 +2993,12 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return 0; } -static int mv88e6xxx_setup_global(struct mv88e6xxx_chip *chip) +static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) { struct dsa_switch *ds = chip->ds; u32 upstream_port = dsa_upstream_port(ds); u16 reg; int err; - int i; /* Enable the PHY Polling Unit if present, don't discard any packets, * and mask all interrupt sources. @@ -3040,6 +3039,16 @@ static int mv88e6xxx_setup_global(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; + + /* Clear all ATU entries */ + err = _mv88e6xxx_atu_flush(chip, 0, true); + if (err) + return err; + /* Configure the IP ToS mapping registers. */ err = _mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000); if (err) @@ -3071,6 +3080,26 @@ static int mv88e6xxx_setup_global(struct mv88e6xxx_chip *chip) if (err) return err; + /* Clear the statistics counters for all ports */ + err = _mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_STATS_OP, + GLOBAL_STATS_OP_FLUSH_ALL); + if (err) + return err; + + /* Wait for the flush to complete. */ + err = _mv88e6xxx_stats_wait(chip); + if (err) + return err; + + return 0; +} + +static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) +{ + struct dsa_switch *ds = chip->ds; + int err; + int i; + /* Send all frames with destination addresses matching * 01:80:c2:00:00:0x to the CPU port. */ @@ -3174,28 +3203,7 @@ static int mv88e6xxx_setup_global(struct mv88e6xxx_chip *chip) } } - /* Clear the statistics counters for all ports */ - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_FLUSH_ALL); - if (err) - return err; - - /* Wait for the flush to complete. */ - err = _mv88e6xxx_stats_wait(chip); - if (err) - return err; - - /* Clear all ATU entries */ - err = _mv88e6xxx_atu_flush(chip, 0, true); - if (err) - return err; - - /* Clear all the VTU and STU entries */ - err = _mv88e6xxx_vtu_stu_flush(chip); - if (err < 0) - return err; - - return err; + return 0; } static int mv88e6xxx_setup(struct dsa_switch *ds) @@ -3216,12 +3224,21 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) if (err) goto unlock; - err = mv88e6xxx_setup_global(chip); + /* Setup Switch Port Registers */ + for (i = 0; i < chip->info->num_ports; i++) { + err = mv88e6xxx_setup_port(chip, i); + if (err) + goto unlock; + } + + /* Setup Switch Global 1 Registers */ + err = mv88e6xxx_g1_setup(chip); if (err) goto unlock; - for (i = 0; i < chip->info->num_ports; i++) { - err = mv88e6xxx_setup_port(chip, i); + /* Setup Switch Global 2 Registers */ + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) { + err = mv88e6xxx_g2_setup(chip); if (err) goto unlock; } diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 2ff62f4..390dac5 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -383,6 +383,11 @@ enum mv88e6xxx_cap { */ MV88E6XXX_CAP_EEPROM, + /* Switch Global 2 Registers. + * The device contains a second set of global 16-bit registers. + */ + MV88E6XXX_CAP_GLOBAL2, + /* Multi-chip Addressing Mode. * Some chips require an indirect SMI access when their SMI device * address is not zero. See SMI_CMD and SMI_DATA. @@ -429,6 +434,7 @@ enum mv88e6xxx_cap { /* Bitmask of capabilities */ #define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE) #define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM) +#define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) @@ -440,31 +446,36 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) #define MV88E6XXX_FLAGS_FAMILY_6095 \ - (MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6097 \ - (MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6165 \ - (MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6185 \ - (MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6320 \ (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ + MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -474,7 +485,8 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6351 \ - (MV88E6XXX_FLAG_MULTI_CHIP | \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_STU | \ @@ -485,6 +497,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6352 \ (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ + MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ -- cgit v0.10.2 From f22ab64123da18b96bf8b3d0801c802c73797a9f Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:31 -0400 Subject: net: dsa: mv88e6xxx: extract device mapping The Device Mapping register is an indirect table access. Provide helpers to access this table and explicit the checking of the new DSA_RTABLE_NONE routing table value. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 1e39fa6..9b2525a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -216,6 +216,32 @@ static int mv88e6xxx_write(struct mv88e6xxx_chip *chip, return 0; } +/* Indirect write to single pointer-data register with an Update bit */ +static int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, + u16 update) +{ + u16 val; + int i, err; + + /* Wait until the previous operation is completed */ + for (i = 0; i < 16; ++i) { + err = mv88e6xxx_read(chip, addr, reg, &val); + if (err) + return err; + + if (!(val & BIT(15))) + break; + } + + if (i == 16) + return -ETIMEDOUT; + + /* Set the Update bit to trigger a write operation */ + val = BIT(15) | update; + + return mv88e6xxx_write(chip, addr, reg, val); +} + static int _mv88e6xxx_reg_read(struct mv88e6xxx_chip *chip, int addr, int reg) { u16 val; @@ -3094,9 +3120,39 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) return 0; } +static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, + int target, int port) +{ + u16 val = (target << 8) | (port & 0xf); + + return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING, val); +} + +static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip) +{ + int target, port; + int err; + + /* Initialize the routing port to the 32 possible target devices */ + for (target = 0; target < 32; ++target) { + port = 0xf; + + if (target < DSA_MAX_SWITCHES) { + port = chip->ds->rtable[target]; + if (port == DSA_RTABLE_NONE) + port = 0xf; + } + + err = mv88e6xxx_g2_device_mapping_write(chip, target, port); + if (err) + break; + } + + return err; +} + static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) { - struct dsa_switch *ds = chip->ds; int err; int i; @@ -3120,20 +3176,9 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) return err; /* Program the DSA routing table. */ - for (i = 0; i < 32; i++) { - int nexthop = 0x1f; - - if (i != ds->index && i < DSA_MAX_SWITCHES) - nexthop = ds->rtable[i] & 0x1f; - - err = _mv88e6xxx_reg_write( - chip, REG_GLOBAL2, - GLOBAL2_DEVICE_MAPPING, - GLOBAL2_DEVICE_MAPPING_UPDATE | - (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) | nexthop); - if (err) - return err; - } + err = mv88e6xxx_g2_set_device_mapping(chip); + if (err) + return err; /* Clear all trunk masks. */ for (i = 0; i < 8; i++) { -- cgit v0.10.2 From 5154041fa717fd8e4ef8c8144c6eaba9392bdaec Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:32 -0400 Subject: net: dsa: mv88e6xxx: extract trunk mapping The Trunk Mask and Trunk Mapping registers are two Global 2 indirect accesses to trunking configuration. Add helpers for these tables and simplify the Global 2 setup. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 9b2525a..d18e5c8 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3151,6 +3151,49 @@ static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip) return err; } +static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num, + bool hask, u16 mask) +{ + const u16 port_mask = BIT(chip->info->num_ports) - 1; + u16 val = (num << 12) | (mask & port_mask); + + if (hask) + val |= GLOBAL2_TRUNK_MASK_HASK; + + return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_TRUNK_MASK, val); +} + +static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id, + u16 map) +{ + const u16 port_mask = BIT(chip->info->num_ports) - 1; + u16 val = (id << 11) | (map & port_mask); + + return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING, val); +} + +static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip) +{ + const u16 port_mask = BIT(chip->info->num_ports) - 1; + int i, err; + + /* Clear all eight possible Trunk Mask vectors */ + for (i = 0; i < 8; ++i) { + err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask); + if (err) + return err; + } + + /* Clear all sixteen possible Trunk ID routing vectors */ + for (i = 0; i < 16; ++i) { + err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0); + if (err) + return err; + } + + return 0; +} + static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) { int err; @@ -3180,27 +3223,10 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) if (err) return err; - /* Clear all trunk masks. */ - for (i = 0; i < 8; i++) { - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, - GLOBAL2_TRUNK_MASK, - 0x8000 | - (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) | - ((1 << chip->info->num_ports) - 1)); - if (err) - return err; - } - - /* Clear all trunk mappings. */ - for (i = 0; i < 16; i++) { - err = _mv88e6xxx_reg_write( - chip, REG_GLOBAL2, - GLOBAL2_TRUNK_MAPPING, - GLOBAL2_TRUNK_MAPPING_UPDATE | - (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT)); - if (err) - return err; - } + /* Clear all trunk masks and mapping. */ + err = mv88e6xxx_g2_clear_trunk(chip); + if (err) + return err; if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 390dac5..876d9ea 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -294,6 +294,7 @@ #define GLOBAL2_TRUNK_MASK 0x07 #define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) #define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 +#define GLOBAL2_TRUNK_MASK_HASK BIT(11) #define GLOBAL2_TRUNK_MAPPING 0x08 #define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) #define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 -- cgit v0.10.2 From 47395ed28056a7ac7fbd9e7ff06bbbd66d01e256 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:33 -0400 Subject: net: dsa: mv88e6xxx: add cap for MGMT Enables bits Some switches provide a Rsvd2CPU mechanism used to choose which of the 16 reserved multicast destination addresses matching 01:80:c2:00:00:0x should be considered as MGMT and thus forwarded to the CPU port. Other switches extend this mechanism to also configure as MGMT the additional 16 reserved multicast addresses matching 01:80:c2:00:00:2x. This mechanism is exposed via two registers in Global 2, and an Rsvd2CPU enable bit in the management register. Newer chip (such as 88E6390) has replaced these registers with a new indirect MGMT mechanism in Global 1. The patch adds two MV88E6XXX_FLAG_G2_MGMT_EN_{0,2}X flags to describe the presence of these Global 2 registers. If 88E6390 support is added, a MV88E6XXX_FLAG_G1_MGMT_CTRL flag will be needed to setup Rsvd2CPU. Note: all switches still support in parallel the ATU Load operation with an MGMT Entry State to forward such frames in a less convenient way. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d18e5c8..cf98884 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3196,25 +3196,40 @@ static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip) static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) { + u16 reg; int err; int i; - /* Send all frames with destination addresses matching - * 01:80:c2:00:00:0x to the CPU port. - */ - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, - 0xffff); - if (err) - return err; + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) { + /* Consider the frames with reserved multicast destination + * addresses matching 01:80:c2:00:00:2x as MGMT. + */ + err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, + 0xffff); + if (err) + return err; + } + + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X)) { + /* Consider the frames with reserved multicast destination + * addresses matching 01:80:c2:00:00:0x as MGMT. + */ + err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, + 0xffff); + if (err) + return err; + } /* Ignore removed tag data on doubly tagged packets, disable * flow control messages, force flow control priority to the * highest, and send all special multicast frames to the CPU * port at the highest priority. */ - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_SWITCH_MGMT, - 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 | - GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI); + reg = GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI | (0x7 << 4); + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) || + mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) + reg |= GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x7; + err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_SWITCH_MGMT, reg); if (err) return err; @@ -3231,14 +3246,6 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || mv88e6xxx_6320_family(chip)) { - /* Send all frames with destination addresses matching - * 01:80:c2:00:00:2x to the CPU port. - */ - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, - GLOBAL2_MGMT_EN_2X, 0xffff); - if (err) - return err; - /* Initialise cross-chip port VLAN table to reset * defaults. */ diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 876d9ea..d13b0b5 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -388,6 +388,8 @@ enum mv88e6xxx_cap { * The device contains a second set of global 16-bit registers. */ MV88E6XXX_CAP_GLOBAL2, + MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ + MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ /* Multi-chip Addressing Mode. * Some chips require an indirect SMI access when their SMI device @@ -436,6 +438,8 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE) #define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM) #define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) +#define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X) +#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X) #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) @@ -448,12 +452,15 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6095 \ (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6097 \ (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ @@ -461,6 +468,8 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6165 \ (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_SWITCH_MAC | \ @@ -469,6 +478,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6185 \ (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_VTU) @@ -477,6 +487,8 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -487,6 +499,8 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6351 \ (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -499,6 +513,8 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ -- cgit v0.10.2 From 3b4caa1b1ce95eaa405c8a27443fe7ddafb563a0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:34 -0400 Subject: net: dsa: mv88e6xxx: rework Switch MAC setter Switches such as 88E6185 as 3 Switch MAC registers in Global 1. Newer chips such as 88E6352 have freed these registers in favor of an indirect access in a Switch MAC/WoL/WoF register in Global 2. Explicit this difference with G1 and G2 helpers and flags. Also, note that this indirect access is a single-register which doesn't require to wait for the operation to complete (like Switch MAC, Trunk Mapping, etc.), in contrary to multi-registers indirect accesses with several operations and a busy bit. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index cf98884..d1b4a7a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -283,68 +283,6 @@ static int mv88e6xxx_reg_write(struct mv88e6xxx_chip *chip, int addr, return ret; } -static int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr) -{ - struct mv88e6xxx_chip *chip = ds_to_priv(ds); - int err; - - err = mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_MAC_01, - (addr[0] << 8) | addr[1]); - if (err) - return err; - - err = mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_MAC_23, - (addr[2] << 8) | addr[3]); - if (err) - return err; - - return mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_MAC_45, - (addr[4] << 8) | addr[5]); -} - -static int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) -{ - struct mv88e6xxx_chip *chip = ds_to_priv(ds); - int ret; - int i; - - for (i = 0; i < 6; i++) { - int j; - - /* Write the MAC address byte. */ - ret = mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_SWITCH_MAC, - GLOBAL2_SWITCH_MAC_BUSY | - (i << 8) | addr[i]); - if (ret) - return ret; - - /* Wait for the write to complete. */ - for (j = 0; j < 16; j++) { - ret = mv88e6xxx_reg_read(chip, REG_GLOBAL2, - GLOBAL2_SWITCH_MAC); - if (ret < 0) - return ret; - - if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0) - break; - } - if (j == 16) - return -ETIMEDOUT; - } - - return 0; -} - -static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr) -{ - struct mv88e6xxx_chip *chip = ds_to_priv(ds); - - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_SWITCH_MAC)) - return mv88e6xxx_set_addr_indirect(ds, addr); - else - return mv88e6xxx_set_addr_direct(ds, addr); -} - static int mv88e6xxx_mdio_read_direct(struct mv88e6xxx_chip *chip, int addr, int regnum) { @@ -3019,6 +2957,24 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return 0; } +static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) +{ + int err; + + err = mv88e6xxx_write(chip, REG_GLOBAL, GLOBAL_MAC_01, + (addr[0] << 8) | addr[1]); + if (err) + return err; + + err = mv88e6xxx_write(chip, REG_GLOBAL, GLOBAL_MAC_23, + (addr[2] << 8) | addr[3]); + if (err) + return err; + + return mv88e6xxx_write(chip, REG_GLOBAL, GLOBAL_MAC_45, + (addr[4] << 8) | addr[5]); +} + static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) { struct dsa_switch *ds = chip->ds; @@ -3194,6 +3150,28 @@ static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip) return 0; } +/* Indirect write to the Switch MAC/WoL/WoF register */ +static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip, + unsigned int pointer, u8 data) +{ + u16 val = (pointer << 8) | data; + + return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_SWITCH_MAC, val); +} + +static int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) +{ + int i, err; + + for (i = 0; i < 6; i++) { + err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]); + if (err) + break; + } + + return err; +} + static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) { u16 reg; @@ -3327,6 +3305,24 @@ unlock: return err; } +static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr) +{ + struct mv88e6xxx_chip *chip = ds_to_priv(ds); + int err; + + mutex_lock(&chip->reg_lock); + + /* Has an indirect Switch MAC/WoL/WoF register in Global 2? */ + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_SWITCH_MAC)) + err = mv88e6xxx_g2_set_switch_mac(chip, addr); + else + err = mv88e6xxx_g1_set_switch_mac(chip, addr); + + mutex_unlock(&chip->reg_lock); + + return err; +} + static int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page, int reg) { diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index d13b0b5..da61db4 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -303,7 +303,6 @@ #define GLOBAL2_PVT_ADDR 0x0b #define GLOBAL2_PVT_DATA 0x0c #define GLOBAL2_SWITCH_MAC 0x0d -#define GLOBAL2_SWITCH_MAC_BUSY BIT(15) #define GLOBAL2_ATU_STATS 0x0e #define GLOBAL2_PRIO_OVERRIDE 0x0f #define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) @@ -390,6 +389,7 @@ enum mv88e6xxx_cap { MV88E6XXX_CAP_GLOBAL2, MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ + MV88E6XXX_CAP_G2_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */ /* Multi-chip Addressing Mode. * Some chips require an indirect SMI access when their SMI device @@ -415,13 +415,6 @@ enum mv88e6xxx_cap { */ MV88E6XXX_CAP_STU, - /* Switch MAC/WoL/WoF register. - * This requires an indirect access to set the switch MAC address - * through GLOBAL2_SWITCH_MAC, otherwise GLOBAL_MAC_01, GLOBAL_MAC_23, - * and GLOBAL_MAC_45 are used with a direct access. - */ - MV88E6XXX_CAP_SWITCH_MAC_WOL_WOF, - /* Internal temperature sensor. * Available from any enabled port's PHY register 26, page 6. */ @@ -440,12 +433,12 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) #define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X) #define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X) +#define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC) #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) #define MV88E6XXX_FLAG_SMI_PHY BIT(MV88E6XXX_CAP_SMI_PHY) #define MV88E6XXX_FLAG_STU BIT(MV88E6XXX_CAP_STU) -#define MV88E6XXX_FLAG_SWITCH_MAC BIT(MV88E6XXX_CAP_SWITCH_MAC_WOL_WOF) #define MV88E6XXX_FLAG_TEMP BIT(MV88E6XXX_CAP_TEMP) #define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT) #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) @@ -470,9 +463,9 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_SWITCH_MAC | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU) @@ -489,10 +482,10 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_SWITCH_MAC | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ - MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU) @@ -501,11 +494,11 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_SWITCH_MAC | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU) @@ -515,11 +508,11 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_SWITCH_MAC | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU) -- cgit v0.10.2 From 63ed880dea23ddbe4a98c8f7c13ea5ad42635987 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:35 -0400 Subject: net: dsa: mv88e6xxx: add cap for PVT Add flags to describe the presence of Cross-chip Port VLAN Table (PVT) related registers and simplify the setup of Global 2. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d1b4a7a..f346ad7 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3221,17 +3221,17 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) if (err) return err; - if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || - mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || - mv88e6xxx_6320_family(chip)) { - /* Initialise cross-chip port VLAN table to reset - * defaults. - */ - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, - GLOBAL2_PVT_ADDR, 0x9000); + if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_PVT)) { + /* Initialize Cross-chip Port VLAN Table to reset defaults */ + err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_PVT_ADDR, + GLOBAL2_PVT_ADDR_OP_INIT_ONES); if (err) return err; + } + if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || + mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || + mv88e6xxx_6320_family(chip)) { /* Clear the priority override table. */ for (i = 0; i < 16; i++) { err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index da61db4..4e03650 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -301,6 +301,10 @@ #define GLOBAL2_INGRESS_OP 0x09 #define GLOBAL2_INGRESS_DATA 0x0a #define GLOBAL2_PVT_ADDR 0x0b +#define GLOBAL2_PVT_ADDR_BUSY BIT(15) +#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) #define GLOBAL2_PVT_DATA 0x0c #define GLOBAL2_SWITCH_MAC 0x0d #define GLOBAL2_ATU_STATS 0x0e @@ -389,6 +393,8 @@ enum mv88e6xxx_cap { MV88E6XXX_CAP_GLOBAL2, MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ + 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_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */ /* Multi-chip Addressing Mode. @@ -433,6 +439,8 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) #define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X) #define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X) +#define MV88E6XXX_FLAG_G2_PVT_ADDR BIT(MV88E6XXX_CAP_G2_PVT_ADDR) +#define MV88E6XXX_FLAG_G2_PVT_DATA BIT(MV88E6XXX_CAP_G2_PVT_DATA) #define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC) #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) @@ -443,6 +451,11 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT) #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) +/* Cross-chip Port VLAN Table */ +#define MV88E6XXX_FLAGS_PVT \ + (MV88E6XXX_FLAG_G2_PVT_ADDR | \ + MV88E6XXX_FLAG_G2_PVT_DATA) + #define MV88E6XXX_FLAGS_FAMILY_6095 \ (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ @@ -457,7 +470,8 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_VTU) + MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6165 \ (MV88E6XXX_FLAG_GLOBAL2 | \ @@ -467,7 +481,8 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_TEMP | \ - MV88E6XXX_FLAG_VTU) + MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6185 \ (MV88E6XXX_FLAG_GLOBAL2 | \ @@ -488,7 +503,8 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ - MV88E6XXX_FLAG_VTU) + MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6351 \ (MV88E6XXX_FLAG_GLOBAL2 | \ @@ -500,7 +516,8 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_TEMP | \ - MV88E6XXX_FLAG_VTU) + MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6352 \ (MV88E6XXX_FLAG_EEE | \ @@ -515,7 +532,8 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ - MV88E6XXX_FLAG_VTU) + MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_PVT) struct mv88e6xxx_info { enum mv88e6xxx_family family; -- cgit v0.10.2 From 9bda889faed61c2b2f7c2356b6a9e577c9812cf0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:36 -0400 Subject: net: dsa: mv88e6xxx: add cap for Priority Override Add flags and helpers to describe the presence of Priority Override Table (POT) related registers and simplify the setup of Global 2. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index f346ad7..3422792 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3172,6 +3172,28 @@ static int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) return err; } +static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer, + u8 data) +{ + u16 val = (pointer << 8) | (data & 0x7); + + return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE, val); +} + +static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip) +{ + int i, err; + + /* Clear all sixteen possible Priority Override entries */ + for (i = 0; i < 16; i++) { + err = mv88e6xxx_g2_pot_write(chip, i, 0); + if (err) + break; + } + + return err; +} + static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) { u16 reg; @@ -3229,17 +3251,11 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) return err; } - if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || - mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || - mv88e6xxx_6320_family(chip)) { + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) { /* Clear the priority override table. */ - for (i = 0; i < 16; i++) { - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, - GLOBAL2_PRIO_OVERRIDE, - 0x8000 | (i << 8)); - if (err) - return err; - } + err = mv88e6xxx_g2_clear_pot(chip); + if (err) + return err; } if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 4e03650..06b11fb 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -396,6 +396,7 @@ enum mv88e6xxx_cap { 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_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */ + MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ /* Multi-chip Addressing Mode. * Some chips require an indirect SMI access when their SMI device @@ -442,6 +443,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_G2_PVT_ADDR BIT(MV88E6XXX_CAP_G2_PVT_ADDR) #define MV88E6XXX_FLAG_G2_PVT_DATA BIT(MV88E6XXX_CAP_G2_PVT_DATA) #define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC) +#define MV88E6XXX_FLAG_G2_POT BIT(MV88E6XXX_CAP_G2_POT) #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) @@ -467,6 +469,7 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ @@ -478,6 +481,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_SWITCH_MAC | \ + MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_TEMP | \ @@ -498,6 +502,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_SWITCH_MAC | \ + MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -511,6 +516,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_SWITCH_MAC | \ + MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -526,6 +532,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_SWITCH_MAC | \ + MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ -- cgit v0.10.2 From 8ec61c7f7c6c75943e8c785729bd8de3440d158c Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:37 -0400 Subject: net: dsa: mv88e6xxx: add cap for IRL Add capability flags to describe the presence of Ingress Rate Limit unit registers and an helper function to clear it. In the meantime, fix a few harmless issues: - 6185 and 6095 don't have such registers (reserved) - the previous code didn't wait for the IRL operation to complete Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 3422792..bc26b4f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3150,6 +3150,29 @@ static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip) return 0; } +static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip) +{ + int port, err; + + /* Init all Ingress Rate Limit resources of all ports */ + for (port = 0; port < chip->info->num_ports; ++port) { + /* XXX newer chips (like 88E6390) have different 2-bit ops */ + err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_IRL_CMD, + GLOBAL2_IRL_CMD_OP_INIT_ALL | + (port << 8)); + if (err) + break; + + /* Wait for the operation to complete */ + err = _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_IRL_CMD, + GLOBAL2_IRL_CMD_BUSY); + if (err) + break; + } + + return err; +} + /* Indirect write to the Switch MAC/WoL/WoF register */ static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip, unsigned int pointer, u8 data) @@ -3198,7 +3221,6 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) { u16 reg; int err; - int i; if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) { /* Consider the frames with reserved multicast destination @@ -3243,6 +3265,15 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) if (err) return err; + if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_IRL)) { + /* Disable ingress rate limiting by resetting all per port + * ingress rate limit resources to their initial state. + */ + err = mv88e6xxx_g2_clear_irl(chip); + if (err) + return err; + } + if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_PVT)) { /* Initialize Cross-chip Port VLAN Table to reset defaults */ err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_PVT_ADDR, @@ -3258,23 +3289,6 @@ static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) return err; } - if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || - mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || - mv88e6xxx_6185_family(chip) || mv88e6xxx_6095_family(chip) || - mv88e6xxx_6320_family(chip)) { - /* Disable ingress rate limiting by resetting all - * ingress rate limit registers to their initial - * state. - */ - for (i = 0; i < chip->info->num_ports; i++) { - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, - GLOBAL2_INGRESS_OP, - 0x9000 | (i << 8)); - if (err) - return err; - } - } - return 0; } diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 06b11fb..9ea5363 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -298,8 +298,13 @@ #define GLOBAL2_TRUNK_MAPPING 0x08 #define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) #define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 -#define GLOBAL2_INGRESS_OP 0x09 -#define GLOBAL2_INGRESS_DATA 0x0a +#define GLOBAL2_IRL_CMD 0x09 +#define GLOBAL2_IRL_CMD_BUSY BIT(15) +#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_DATA 0x0a #define GLOBAL2_PVT_ADDR 0x0b #define GLOBAL2_PVT_ADDR_BUSY BIT(15) #define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) @@ -393,6 +398,8 @@ enum mv88e6xxx_cap { MV88E6XXX_CAP_GLOBAL2, MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ 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_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */ @@ -440,6 +447,8 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) #define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X) #define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X) +#define MV88E6XXX_FLAG_G2_IRL_CMD BIT(MV88E6XXX_CAP_G2_IRL_CMD) +#define MV88E6XXX_FLAG_G2_IRL_DATA BIT(MV88E6XXX_CAP_G2_IRL_DATA) #define MV88E6XXX_FLAG_G2_PVT_ADDR BIT(MV88E6XXX_CAP_G2_PVT_ADDR) #define MV88E6XXX_FLAG_G2_PVT_DATA BIT(MV88E6XXX_CAP_G2_PVT_DATA) #define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC) @@ -453,6 +462,11 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT) #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) +/* Ingress Rate Limit unit */ +#define MV88E6XXX_FLAGS_IRL \ + (MV88E6XXX_FLAG_G2_IRL_CMD | \ + MV88E6XXX_FLAG_G2_IRL_DATA) + /* Cross-chip Port VLAN Table */ #define MV88E6XXX_FLAGS_PVT \ (MV88E6XXX_FLAG_G2_PVT_ADDR | \ @@ -474,6 +488,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6165 \ @@ -486,6 +501,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6185 \ @@ -509,6 +525,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6351 \ @@ -523,6 +540,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_PVT) #define MV88E6XXX_FLAGS_FAMILY_6352 \ @@ -540,6 +558,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU | \ + MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_PVT) struct mv88e6xxx_info { -- cgit v0.10.2 From 34a79f63bbe49c888f95e75dd759685a238556b6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:38 -0400 Subject: net: dsa: support switchdev ageing time attr Add a new function for DSA drivers to handle the switchdev SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME attribute. The ageing time is passed as milliseconds. Also because we can have multiple logical bridges on top of a physical switch and ageing time are switch-wide, call the driver function with the fastest ageing time in use on the chip instead of the requested one. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/include/net/dsa.h b/include/net/dsa.h index 52ab18b..2217a3f 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -141,6 +141,7 @@ struct dsa_switch_tree { struct dsa_port { struct net_device *netdev; struct device_node *dn; + unsigned int ageing_time; }; struct dsa_switch { @@ -329,6 +330,7 @@ struct dsa_switch_driver { /* * Bridge integration */ + int (*set_ageing_time)(struct dsa_switch *ds, unsigned int msecs); int (*port_bridge_join)(struct dsa_switch *ds, int port, struct net_device *bridge); void (*port_bridge_leave)(struct dsa_switch *ds, int port); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 7236eb2..fc91967 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -333,6 +333,44 @@ static int dsa_slave_vlan_filtering(struct net_device *dev, return 0; } +static int dsa_fastest_ageing_time(struct dsa_switch *ds, + unsigned int ageing_time) +{ + int i; + + for (i = 0; i < DSA_MAX_PORTS; ++i) { + struct dsa_port *dp = &ds->ports[i]; + + if (dp && dp->ageing_time && dp->ageing_time < ageing_time) + ageing_time = dp->ageing_time; + } + + return ageing_time; +} + +static int dsa_slave_ageing_time(struct net_device *dev, + const struct switchdev_attr *attr, + struct switchdev_trans *trans) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + unsigned long ageing_jiffies = clock_t_to_jiffies(attr->u.ageing_time); + unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); + + /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ + if (switchdev_trans_ph_prepare(trans)) + return 0; + + /* Keep the fastest ageing time in case of multiple bridges */ + ds->ports[p->port].ageing_time = ageing_time; + ageing_time = dsa_fastest_ageing_time(ds, ageing_time); + + if (ds->drv->set_ageing_time) + return ds->drv->set_ageing_time(ds, ageing_time); + + return 0; +} + static int dsa_slave_port_attr_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) @@ -346,6 +384,9 @@ static int dsa_slave_port_attr_set(struct net_device *dev, case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: ret = dsa_slave_vlan_filtering(dev, attr, trans); break; + case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: + ret = dsa_slave_ageing_time(dev, attr, trans); + break; default: ret = -EOPNOTSUPP; break; -- cgit v0.10.2 From acddbd21477efc3da9ab414b2bc72cd580cf6fdb Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:39 -0400 Subject: net: dsa: mv88e6xxx: add G1 helper for ageing time All Marvell switch chips from (88E6060 to 88E6390) have a ATU Control register containing bits 11:4 to configure an ATU Age Time quotient. However the coefficient used to calculate the ATU Age Time vary with the models. E.g. 88E6060, 88E6352 and 88E6390 use respectively 16, 15 and 3.75 seconds. Add a age_time_coeff to the info structure to handle this and a Global 1 helper to set the default age time of 5 minutes in the setup code. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index bc26b4f..8e24c65 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2975,6 +2975,33 @@ static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) (addr[4] << 8) | addr[5]); } +static int mv88e6xxx_g1_set_age_time(struct mv88e6xxx_chip *chip, + unsigned int msecs) +{ + const unsigned int coeff = chip->info->age_time_coeff; + const unsigned int min = 0x01 * coeff; + const unsigned int max = 0xff * coeff; + u8 age_time; + u16 val; + int err; + + if (msecs < min || msecs > max) + return -ERANGE; + + /* Round to nearest multiple of coeff */ + age_time = (msecs + coeff / 2) / coeff; + + err = mv88e6xxx_read(chip, REG_GLOBAL, GLOBAL_ATU_CONTROL, &val); + if (err) + return err; + + /* AgeTime is 11:4 bits */ + val &= ~0xff0; + val |= age_time << 4; + + return mv88e6xxx_write(chip, REG_GLOBAL, GLOBAL_ATU_CONTROL, val); +} + static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) { struct dsa_switch *ds = chip->ds; @@ -3012,18 +3039,22 @@ 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; + /* Set the default address aging time to 5 minutes, and * enable address learn messages to be sent to all message * ports. */ - err = _mv88e6xxx_reg_write(chip, REG_GLOBAL, GLOBAL_ATU_CONTROL, - 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL); + err = mv88e6xxx_write(chip, REG_GLOBAL, GLOBAL_ATU_CONTROL, + GLOBAL_ATU_CONTROL_LEARN2ALL); if (err) return err; - /* Clear all the VTU and STU entries */ - err = _mv88e6xxx_vtu_stu_flush(chip); - if (err < 0) + err = mv88e6xxx_g1_set_age_time(chip, 300000); + if (err) return err; /* Clear all ATU entries */ @@ -3634,6 +3665,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 10, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6097, }, @@ -3644,6 +3676,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 256, .num_ports = 11, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6095, }, @@ -3654,6 +3687,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 3, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6165, }, @@ -3664,6 +3698,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 256, .num_ports = 8, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6185, }, @@ -3674,6 +3709,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 6, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6165, }, @@ -3684,6 +3720,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 6, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6165, }, @@ -3694,6 +3731,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3704,6 +3742,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, @@ -3714,6 +3753,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3724,6 +3764,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, @@ -3734,6 +3775,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 256, .num_ports = 10, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6185, }, @@ -3744,6 +3786,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, @@ -3754,6 +3797,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6320, }, @@ -3764,6 +3808,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6320, }, @@ -3774,6 +3819,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3784,6 +3830,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3794,6 +3841,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_databases = 4096, .num_ports = 7, .port_base_addr = 0x10, + .age_time_coeff = 15000, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, }; diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 9ea5363..899ca1d 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -568,6 +568,7 @@ struct mv88e6xxx_info { unsigned int num_databases; unsigned int num_ports; unsigned int port_base_addr; + unsigned int age_time_coeff; unsigned long flags; }; -- cgit v0.10.2 From 2cfcd9641618e71a1b823324aa4737e18662c25e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 20:45:40 -0400 Subject: net: dsa: mv88e6xxx: add support for DSA ageing time Implement the DSA driver function to configure the bridge ageing time. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8e24c65..9ba2173 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3002,6 +3002,19 @@ static int mv88e6xxx_g1_set_age_time(struct mv88e6xxx_chip *chip, return mv88e6xxx_write(chip, REG_GLOBAL, GLOBAL_ATU_CONTROL, val); } +static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, + unsigned int ageing_time) +{ + struct mv88e6xxx_chip *chip = ds_to_priv(ds); + int err; + + mutex_lock(&chip->reg_lock); + err = mv88e6xxx_g1_set_age_time(chip, ageing_time); + mutex_unlock(&chip->reg_lock); + + return err; +} + static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) { struct dsa_switch *ds = chip->ds; @@ -3980,6 +3993,7 @@ static struct dsa_switch_driver mv88e6xxx_switch_driver = { .set_eeprom = mv88e6xxx_set_eeprom, .get_regs_len = mv88e6xxx_get_regs_len, .get_regs = mv88e6xxx_get_regs, + .set_ageing_time = mv88e6xxx_set_ageing_time, .port_bridge_join = mv88e6xxx_port_bridge_join, .port_bridge_leave = mv88e6xxx_port_bridge_leave, .port_stp_state_set = mv88e6xxx_port_stp_state_set, -- cgit v0.10.2