net: dsa: sja1105: Populate is_static for FDB entries on P/Q/R/S

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>
This commit is contained in:
Vladimir Oltean 2019-06-26 02:39:40 +03:00 committed by David S. Miller
parent 4a95078636
commit 17ae655540
3 changed files with 62 additions and 5 deletions

View 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,

View 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;
}

View 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 {