net: dsa: sja1105: Populate is_static for FDB entries on P/Q/R/S
authorVladimir Oltean <olteanv@gmail.com>
Tue, 25 Jun 2019 23:39:40 +0000 (02:39 +0300)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Jun 2019 18:03:21 +0000 (11:03 -0700)
The reason why this wasn't tackled earlier is that I had hoped I
understood the user manual wrong.  But unfortunately hacks are required
in order to retrieve the static/dynamic nature of FDB entries on SJA1105
P/Q/R/S, since this info is stored in the writeback buffer of the
dynamic config command.

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
drivers/net/dsa/sja1105/sja1105_static_config.h

index 3acd486..6bfb169 100644 (file)
@@ -149,13 +149,11 @@ sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 {
        u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
        const int size = SJA1105_SIZE_DYN_CMD;
-       u64 lockeds = 0;
        u64 hostcmd;
 
        sja1105_packing(p, &cmd->valid,    31, 31, size, op);
        sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
        sja1105_packing(p, &cmd->errors,   29, 29, size, op);
-       sja1105_packing(p, &lockeds,       28, 28, size, op);
        sja1105_packing(p, &cmd->valident, 27, 27, size, op);
 
        /* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
@@ -205,6 +203,64 @@ sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
                        SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
 }
 
+/* The switch is so retarded that it makes our command/entry abstraction
+ * crumble apart.
+ *
+ * On P/Q/R/S, the switch tries to say whether a FDB entry
+ * is statically programmed or dynamically learned via a flag called LOCKEDS.
+ * The hardware manual says about this fiels:
+ *
+ *   On write will specify the format of ENTRY.
+ *   On read the flag will be found cleared at times the VALID flag is found
+ *   set.  The flag will also be found cleared in response to a read having the
+ *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
+ *   cleared, the flag be set if the most recent access operated on an entry
+ *   that was either loaded by configuration or through dynamic reconfiguration
+ *   (as opposed to automatically learned entries).
+ *
+ * The trouble with this flag is that it's part of the *command* to access the
+ * dynamic interface, and not part of the *entry* retrieved from it.
+ * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
+ * an output from the switch into the command buffer, and for a
+ * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
+ * (hence we can write either static, or automatically learned entries, from
+ * the core).
+ * But the manual contradicts itself in the last phrase where it says that on
+ * read, LOCKEDS will be set to 1 for all FDB entries written through the
+ * dynamic interface (therefore, the value of LOCKEDS from the
+ * sja1105_dynamic_config_write is not really used for anything, it'll store a
+ * 1 anyway).
+ * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
+ * learned) into the switch, which kind of makes sense.
+ * As for reading through the dynamic interface, it doesn't make too much sense
+ * to put LOCKEDS into the command, since the switch will inevitably have to
+ * ignore it (otherwise a command would be like "read the FDB entry 123, but
+ * only if it's dynamically learned" <- well how am I supposed to know?) and
+ * just use it as an output buffer for its findings. But guess what... that's
+ * what the entry buffer is for!
+ * Unfortunately, what really breaks this abstraction is the fact that it
+ * wasn't designed having the fact in mind that the switch can output
+ * entry-related data as writeback through the command buffer.
+ * However, whether a FDB entry is statically or dynamically learned *is* part
+ * of the entry and not the command data, no matter what the switch thinks.
+ * In order to do that, we'll need to wrap around the
+ * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
+ * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
+ * command buffer.
+ */
+static size_t
+sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
+                                       enum packing_op op)
+{
+       struct sja1105_l2_lookup_entry *entry = entry_ptr;
+       u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+       const int size = SJA1105_SIZE_DYN_CMD;
+
+       sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
+
+       return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
+}
+
 static void
 sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
                                enum packing_op op)
@@ -485,7 +541,7 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
 /* 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,
+               .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
                .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
                .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
                .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
index 80d8d2f..ed0b721 100644 (file)
@@ -1070,6 +1070,7 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
                dev_err(ds->dev, "FDB is full, cannot add entry.\n");
                return -EINVAL;
        }
+       l2_lookup.lockeds = true;
        l2_lookup.index = i;
 
 skip_finding_an_index:
@@ -1205,7 +1206,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
                 */
                if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
                        l2_lookup.vlanid = 1;
-               cb(macaddr, l2_lookup.vlanid, false, data);
+               cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
        }
        return 0;
 }
index 2a3a1a9..684465f 100644 (file)
@@ -132,7 +132,7 @@ struct sja1105_l2_lookup_entry {
        u64 mask_vlanid;
        u64 mask_macaddr;
        u64 iotag;
-       bool lockeds;
+       u64 lockeds;
        union {
                /* LOCKEDS=1: Static FDB entries */
                struct {