net: dsa: sja1105: Add P/Q/R/S management route support via dynamic interface
authorVladimir Oltean <olteanv@gmail.com>
Sun, 2 Jun 2019 21:15:33 +0000 (00:15 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 4 Jun 2019 18:49:20 +0000 (11:49 -0700)
Management routes are one-shot FDB rules installed on the CPU port for
sending link-local traffic.  They are a prerequisite for STP, PTP etc to
work.

Also make a note that removing a management route was not supported on
the previous generation of switches.

Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/sja1105/sja1105_dynamic_config.c
drivers/net/dsa/sja1105/sja1105_main.c

index 02a67df..352bb6e 100644 (file)
@@ -161,6 +161,36 @@ static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
        return size;
 }
 
+static void
+sja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+                                  enum packing_op op)
+{
+       u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+       u64 mgmtroute = 1;
+
+       sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
+       if (op == PACK)
+               sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
+}
+
+static size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
+                                                  enum packing_op op)
+{
+       const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+       struct sja1105_mgmt_entry *entry = entry_ptr;
+
+       /* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
+        * is the same (driver uses it to confirm that frame was sent).
+        * So just keep the name from E/T.
+        */
+       sja1105_packing(buf, &entry->tsreg,     71, 71, size, op);
+       sja1105_packing(buf, &entry->takets,    70, 70, size, op);
+       sja1105_packing(buf, &entry->macaddr,   69, 22, size, op);
+       sja1105_packing(buf, &entry->destports, 21, 17, size, op);
+       sja1105_packing(buf, &entry->enfport,   16, 16, size, op);
+       return size;
+}
+
 /* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
  * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
  * between entry (0x2d, 0x2e) and command (0x30).
@@ -359,7 +389,7 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
        [BLK_IDX_XMII_PARAMS] = {0},
 };
 
-/* SJA1105P/Q/R/S: Second generation: TODO */
+/* SJA1105P/Q/R/S: Second generation */
 struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
        [BLK_IDX_L2_LOOKUP] = {
                .entry_packing = sja1105pqrs_l2_lookup_entry_packing,
@@ -369,6 +399,14 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
                .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
                .addr = 0x24,
        },
+       [BLK_IDX_MGMT_ROUTE] = {
+               .entry_packing = sja1105pqrs_mgmt_route_entry_packing,
+               .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
+               .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
+               .max_entry_count = SJA1105_NUM_PORTS,
+               .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
+               .addr = 0x24,
+       },
        [BLK_IDX_L2_POLICING] = {0},
        [BLK_IDX_VLAN_LOOKUP] = {
                .entry_packing = sja1105_vlan_lookup_entry_packing,
index dc9803e..f9bbc78 100644 (file)
@@ -1475,6 +1475,8 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
        if (!timeout) {
                /* Clean up the management route so that a follow-up
                 * frame may not match on it by mistake.
+                * This is only hardware supported on P/Q/R/S - on E/T it is
+                * a no-op and we are silently discarding the -EOPNOTSUPP.
                 */
                sja1105_dynamic_config_write(priv, BLK_IDX_MGMT_ROUTE,
                                             slot, &mgmt_route, false);