18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci#include "sja1105.h"
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/* In the dynamic configuration interface, the switch exposes a register-like
78c2ecf20Sopenharmony_ci * view of some of the static configuration tables.
88c2ecf20Sopenharmony_ci * Many times the field organization of the dynamic tables is abbreviated (not
98c2ecf20Sopenharmony_ci * all fields are dynamically reconfigurable) and different from the static
108c2ecf20Sopenharmony_ci * ones, but the key reason for having it is that we can spare a switch reset
118c2ecf20Sopenharmony_ci * for settings that can be changed dynamically.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * This file creates a per-switch-family abstraction called
148c2ecf20Sopenharmony_ci * struct sja1105_dynamic_table_ops and two operations that work with it:
158c2ecf20Sopenharmony_ci * - sja1105_dynamic_config_write
168c2ecf20Sopenharmony_ci * - sja1105_dynamic_config_read
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Compared to the struct sja1105_table_ops from sja1105_static_config.c,
198c2ecf20Sopenharmony_ci * the dynamic accessors work with a compound buffer:
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * packed_buf
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * |
248c2ecf20Sopenharmony_ci * V
258c2ecf20Sopenharmony_ci * +-----------------------------------------+------------------+
268c2ecf20Sopenharmony_ci * |              ENTRY BUFFER               |  COMMAND BUFFER  |
278c2ecf20Sopenharmony_ci * +-----------------------------------------+------------------+
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * <----------------------- packed_size ------------------------>
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * The ENTRY BUFFER may or may not have the same layout, or size, as its static
328c2ecf20Sopenharmony_ci * configuration table entry counterpart. When it does, the same packing
338c2ecf20Sopenharmony_ci * function is reused (bar exceptional cases - see
348c2ecf20Sopenharmony_ci * sja1105pqrs_dyn_l2_lookup_entry_packing).
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * The reason for the COMMAND BUFFER being at the end is to be able to send
378c2ecf20Sopenharmony_ci * a dynamic write command through a single SPI burst. By the time the switch
388c2ecf20Sopenharmony_ci * reacts to the command, the ENTRY BUFFER is already populated with the data
398c2ecf20Sopenharmony_ci * sent by the core.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * The COMMAND BUFFER is always SJA1105_SIZE_DYN_CMD bytes (one 32-bit word) in
428c2ecf20Sopenharmony_ci * size.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * Sometimes the ENTRY BUFFER does not really exist (when the number of fields
458c2ecf20Sopenharmony_ci * that can be reconfigured is small), then the switch repurposes some of the
468c2ecf20Sopenharmony_ci * unused 32 bits of the COMMAND BUFFER to hold ENTRY data.
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * The key members of struct sja1105_dynamic_table_ops are:
498c2ecf20Sopenharmony_ci * - .entry_packing: A function that deals with packing an ENTRY structure
508c2ecf20Sopenharmony_ci *		     into an SPI buffer, or retrieving an ENTRY structure
518c2ecf20Sopenharmony_ci *		     from one.
528c2ecf20Sopenharmony_ci *		     The @packed_buf pointer it's given does always point to
538c2ecf20Sopenharmony_ci *		     the ENTRY portion of the buffer.
548c2ecf20Sopenharmony_ci * - .cmd_packing: A function that deals with packing/unpacking the COMMAND
558c2ecf20Sopenharmony_ci *		   structure to/from the SPI buffer.
568c2ecf20Sopenharmony_ci *		   It is given the same @packed_buf pointer as .entry_packing,
578c2ecf20Sopenharmony_ci *		   so most of the time, the @packed_buf points *behind* the
588c2ecf20Sopenharmony_ci *		   COMMAND offset inside the buffer.
598c2ecf20Sopenharmony_ci *		   To access the COMMAND portion of the buffer, the function
608c2ecf20Sopenharmony_ci *		   knows its correct offset.
618c2ecf20Sopenharmony_ci *		   Giving both functions the same pointer is handy because in
628c2ecf20Sopenharmony_ci *		   extreme cases (see sja1105pqrs_dyn_l2_lookup_entry_packing)
638c2ecf20Sopenharmony_ci *		   the .entry_packing is able to jump to the COMMAND portion,
648c2ecf20Sopenharmony_ci *		   or vice-versa (sja1105pqrs_l2_lookup_cmd_packing).
658c2ecf20Sopenharmony_ci * - .access: A bitmap of:
668c2ecf20Sopenharmony_ci *	OP_READ: Set if the hardware manual marks the ENTRY portion of the
678c2ecf20Sopenharmony_ci *		 dynamic configuration table buffer as R (readable) after
688c2ecf20Sopenharmony_ci *		 an SPI read command (the switch will populate the buffer).
698c2ecf20Sopenharmony_ci *	OP_WRITE: Set if the manual marks the ENTRY portion of the dynamic
708c2ecf20Sopenharmony_ci *		  table buffer as W (writable) after an SPI write command
718c2ecf20Sopenharmony_ci *		  (the switch will read the fields provided in the buffer).
728c2ecf20Sopenharmony_ci *	OP_DEL: Set if the manual says the VALIDENT bit is supported in the
738c2ecf20Sopenharmony_ci *		COMMAND portion of this dynamic config buffer (i.e. the
748c2ecf20Sopenharmony_ci *		specified entry can be invalidated through a SPI write
758c2ecf20Sopenharmony_ci *		command).
768c2ecf20Sopenharmony_ci *	OP_SEARCH: Set if the manual says that the index of an entry can
778c2ecf20Sopenharmony_ci *		   be retrieved in the COMMAND portion of the buffer based
788c2ecf20Sopenharmony_ci *		   on its ENTRY portion, as a result of a SPI write command.
798c2ecf20Sopenharmony_ci *		   Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
808c2ecf20Sopenharmony_ci *		   this.
818c2ecf20Sopenharmony_ci * - .max_entry_count: The number of entries, counting from zero, that can be
828c2ecf20Sopenharmony_ci *		       reconfigured through the dynamic interface. If a static
838c2ecf20Sopenharmony_ci *		       table can be reconfigured at all dynamically, this
848c2ecf20Sopenharmony_ci *		       number always matches the maximum number of supported
858c2ecf20Sopenharmony_ci *		       static entries.
868c2ecf20Sopenharmony_ci * - .packed_size: The length in bytes of the compound ENTRY + COMMAND BUFFER.
878c2ecf20Sopenharmony_ci *		   Note that sometimes the compound buffer may contain holes in
888c2ecf20Sopenharmony_ci *		   it (see sja1105_vlan_lookup_cmd_packing). The @packed_buf is
898c2ecf20Sopenharmony_ci *		   contiguous however, so @packed_size includes any unused
908c2ecf20Sopenharmony_ci *		   bytes.
918c2ecf20Sopenharmony_ci * - .addr: The base SPI address at which the buffer must be written to the
928c2ecf20Sopenharmony_ci *	    switch's memory. When looking at the hardware manual, this must
938c2ecf20Sopenharmony_ci *	    always match the lowest documented address for the ENTRY, and not
948c2ecf20Sopenharmony_ci *	    that of the COMMAND, since the other 32-bit words will follow along
958c2ecf20Sopenharmony_ci *	    at the correct addresses.
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define SJA1105_SIZE_DYN_CMD					4
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD			\
1018c2ecf20Sopenharmony_ci	SJA1105_SIZE_DYN_CMD
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD			\
1048c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
1078c2ecf20Sopenharmony_ci	SJA1105_SIZE_DYN_CMD
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD			\
1108c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY)
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD			\
1138c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD			\
1168c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD			\
1198c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD			\
1228c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY)
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD			\
1258c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD			\
1288c2ecf20Sopenharmony_ci	SJA1105_SIZE_DYN_CMD
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
1318c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD			\
1348c2ecf20Sopenharmony_ci	SJA1105_SIZE_DYN_CMD
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD			\
1378c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD			\
1408c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci#define SJA1105_SIZE_RETAGGING_DYN_CMD				\
1438c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_RETAGGING_ENTRY)
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_CBS_DYN_CMD				\
1468c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_CBS_ENTRY)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_CBS_DYN_CMD				\
1498c2ecf20Sopenharmony_ci	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define SJA1105_MAX_DYN_CMD_SIZE				\
1528c2ecf20Sopenharmony_ci	SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistruct sja1105_dyn_cmd {
1558c2ecf20Sopenharmony_ci	bool search;
1568c2ecf20Sopenharmony_ci	u64 valid;
1578c2ecf20Sopenharmony_ci	u64 rdwrset;
1588c2ecf20Sopenharmony_ci	u64 errors;
1598c2ecf20Sopenharmony_ci	u64 valident;
1608c2ecf20Sopenharmony_ci	u64 index;
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cienum sja1105_hostcmd {
1648c2ecf20Sopenharmony_ci	SJA1105_HOSTCMD_SEARCH = 1,
1658c2ecf20Sopenharmony_ci	SJA1105_HOSTCMD_READ = 2,
1668c2ecf20Sopenharmony_ci	SJA1105_HOSTCMD_WRITE = 3,
1678c2ecf20Sopenharmony_ci	SJA1105_HOSTCMD_INVALIDATE = 4,
1688c2ecf20Sopenharmony_ci};
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/* Command and entry overlap */
1718c2ecf20Sopenharmony_cistatic void
1728c2ecf20Sopenharmony_cisja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
1738c2ecf20Sopenharmony_ci				enum packing_op op)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->valid,   31, 31, size, op);
1788c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->errors,  30, 30, size, op);
1798c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->rdwrset, 29, 29, size, op);
1808c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->index,    9,  0, size, op);
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/* Command and entry are separate */
1848c2ecf20Sopenharmony_cistatic void
1858c2ecf20Sopenharmony_cisja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
1868c2ecf20Sopenharmony_ci				  enum packing_op op)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
1898c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
1928c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
1938c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
1948c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->index,    9,  0, size, op);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
1988c2ecf20Sopenharmony_ci						enum packing_op op)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct sja1105_vl_lookup_entry *entry = entry_ptr;
2018c2ecf20Sopenharmony_ci	const int size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->egrmirr,  21, 17, size, op);
2048c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->ingrmirr, 16, 16, size, op);
2058c2ecf20Sopenharmony_ci	return size;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic void
2098c2ecf20Sopenharmony_cisja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
2108c2ecf20Sopenharmony_ci				  enum packing_op op)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
2138c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
2148c2ecf20Sopenharmony_ci	u64 hostcmd;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
2178c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
2188c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
2198c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
2228c2ecf20Sopenharmony_ci	 * using it to delete a management route was unsupported. UM10944
2238c2ecf20Sopenharmony_ci	 * said about it:
2248c2ecf20Sopenharmony_ci	 *
2258c2ecf20Sopenharmony_ci	 *   In case of a write access with the MGMTROUTE flag set,
2268c2ecf20Sopenharmony_ci	 *   the flag will be ignored. It will always be found cleared
2278c2ecf20Sopenharmony_ci	 *   for read accesses with the MGMTROUTE flag set.
2288c2ecf20Sopenharmony_ci	 *
2298c2ecf20Sopenharmony_ci	 * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there
2308c2ecf20Sopenharmony_ci	 * is now another flag called HOSTCMD which does more stuff (quoting
2318c2ecf20Sopenharmony_ci	 * from UM11040):
2328c2ecf20Sopenharmony_ci	 *
2338c2ecf20Sopenharmony_ci	 *   A write request is accepted only when HOSTCMD is set to write host
2348c2ecf20Sopenharmony_ci	 *   or invalid. A read request is accepted only when HOSTCMD is set to
2358c2ecf20Sopenharmony_ci	 *   search host or read host.
2368c2ecf20Sopenharmony_ci	 *
2378c2ecf20Sopenharmony_ci	 * So it is possible to translate a RDWRSET/VALIDENT combination into
2388c2ecf20Sopenharmony_ci	 * HOSTCMD so that we keep the dynamic command API in place, and
2398c2ecf20Sopenharmony_ci	 * at the same time achieve compatibility with the management route
2408c2ecf20Sopenharmony_ci	 * command structure.
2418c2ecf20Sopenharmony_ci	 */
2428c2ecf20Sopenharmony_ci	if (cmd->rdwrset == SPI_READ) {
2438c2ecf20Sopenharmony_ci		if (cmd->search)
2448c2ecf20Sopenharmony_ci			hostcmd = SJA1105_HOSTCMD_SEARCH;
2458c2ecf20Sopenharmony_ci		else
2468c2ecf20Sopenharmony_ci			hostcmd = SJA1105_HOSTCMD_READ;
2478c2ecf20Sopenharmony_ci	} else {
2488c2ecf20Sopenharmony_ci		/* SPI_WRITE */
2498c2ecf20Sopenharmony_ci		if (cmd->valident)
2508c2ecf20Sopenharmony_ci			hostcmd = SJA1105_HOSTCMD_WRITE;
2518c2ecf20Sopenharmony_ci		else
2528c2ecf20Sopenharmony_ci			hostcmd = SJA1105_HOSTCMD_INVALIDATE;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci	sja1105_packing(p, &hostcmd, 25, 23, size, op);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* Hack - The hardware takes the 'index' field within
2578c2ecf20Sopenharmony_ci	 * struct sja1105_l2_lookup_entry as the index on which this command
2588c2ecf20Sopenharmony_ci	 * will operate. However it will ignore everything else, so 'index'
2598c2ecf20Sopenharmony_ci	 * is logically part of command but physically part of entry.
2608c2ecf20Sopenharmony_ci	 * Populate the 'index' entry field from within the command callback,
2618c2ecf20Sopenharmony_ci	 * such that our API doesn't need to ask for a full-blown entry
2628c2ecf20Sopenharmony_ci	 * structure when e.g. a delete is requested.
2638c2ecf20Sopenharmony_ci	 */
2648c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->index, 15, 6,
2658c2ecf20Sopenharmony_ci			SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/* The switch is so retarded that it makes our command/entry abstraction
2698c2ecf20Sopenharmony_ci * crumble apart.
2708c2ecf20Sopenharmony_ci *
2718c2ecf20Sopenharmony_ci * On P/Q/R/S, the switch tries to say whether a FDB entry
2728c2ecf20Sopenharmony_ci * is statically programmed or dynamically learned via a flag called LOCKEDS.
2738c2ecf20Sopenharmony_ci * The hardware manual says about this fiels:
2748c2ecf20Sopenharmony_ci *
2758c2ecf20Sopenharmony_ci *   On write will specify the format of ENTRY.
2768c2ecf20Sopenharmony_ci *   On read the flag will be found cleared at times the VALID flag is found
2778c2ecf20Sopenharmony_ci *   set.  The flag will also be found cleared in response to a read having the
2788c2ecf20Sopenharmony_ci *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
2798c2ecf20Sopenharmony_ci *   cleared, the flag be set if the most recent access operated on an entry
2808c2ecf20Sopenharmony_ci *   that was either loaded by configuration or through dynamic reconfiguration
2818c2ecf20Sopenharmony_ci *   (as opposed to automatically learned entries).
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci * The trouble with this flag is that it's part of the *command* to access the
2848c2ecf20Sopenharmony_ci * dynamic interface, and not part of the *entry* retrieved from it.
2858c2ecf20Sopenharmony_ci * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
2868c2ecf20Sopenharmony_ci * an output from the switch into the command buffer, and for a
2878c2ecf20Sopenharmony_ci * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
2888c2ecf20Sopenharmony_ci * (hence we can write either static, or automatically learned entries, from
2898c2ecf20Sopenharmony_ci * the core).
2908c2ecf20Sopenharmony_ci * But the manual contradicts itself in the last phrase where it says that on
2918c2ecf20Sopenharmony_ci * read, LOCKEDS will be set to 1 for all FDB entries written through the
2928c2ecf20Sopenharmony_ci * dynamic interface (therefore, the value of LOCKEDS from the
2938c2ecf20Sopenharmony_ci * sja1105_dynamic_config_write is not really used for anything, it'll store a
2948c2ecf20Sopenharmony_ci * 1 anyway).
2958c2ecf20Sopenharmony_ci * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
2968c2ecf20Sopenharmony_ci * learned) into the switch, which kind of makes sense.
2978c2ecf20Sopenharmony_ci * As for reading through the dynamic interface, it doesn't make too much sense
2988c2ecf20Sopenharmony_ci * to put LOCKEDS into the command, since the switch will inevitably have to
2998c2ecf20Sopenharmony_ci * ignore it (otherwise a command would be like "read the FDB entry 123, but
3008c2ecf20Sopenharmony_ci * only if it's dynamically learned" <- well how am I supposed to know?) and
3018c2ecf20Sopenharmony_ci * just use it as an output buffer for its findings. But guess what... that's
3028c2ecf20Sopenharmony_ci * what the entry buffer is for!
3038c2ecf20Sopenharmony_ci * Unfortunately, what really breaks this abstraction is the fact that it
3048c2ecf20Sopenharmony_ci * wasn't designed having the fact in mind that the switch can output
3058c2ecf20Sopenharmony_ci * entry-related data as writeback through the command buffer.
3068c2ecf20Sopenharmony_ci * However, whether a FDB entry is statically or dynamically learned *is* part
3078c2ecf20Sopenharmony_ci * of the entry and not the command data, no matter what the switch thinks.
3088c2ecf20Sopenharmony_ci * In order to do that, we'll need to wrap around the
3098c2ecf20Sopenharmony_ci * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
3108c2ecf20Sopenharmony_ci * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
3118c2ecf20Sopenharmony_ci * command buffer.
3128c2ecf20Sopenharmony_ci */
3138c2ecf20Sopenharmony_cistatic size_t
3148c2ecf20Sopenharmony_cisja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
3158c2ecf20Sopenharmony_ci					enum packing_op op)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct sja1105_l2_lookup_entry *entry = entry_ptr;
3188c2ecf20Sopenharmony_ci	u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
3198c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic void
3278c2ecf20Sopenharmony_cisja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
3288c2ecf20Sopenharmony_ci				enum packing_op op)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
3318c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
3348c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
3358c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
3368c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
3378c2ecf20Sopenharmony_ci	/* Hack - see comments above. */
3388c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->index, 29, 20,
3398c2ecf20Sopenharmony_ci			SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
3438c2ecf20Sopenharmony_ci						    enum packing_op op)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct sja1105_l2_lookup_entry *entry = entry_ptr;
3468c2ecf20Sopenharmony_ci	u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
3478c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic void
3558c2ecf20Sopenharmony_cisja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
3568c2ecf20Sopenharmony_ci				 enum packing_op op)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
3598c2ecf20Sopenharmony_ci	u64 mgmtroute = 1;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	sja1105et_l2_lookup_cmd_packing(buf, cmd, op);
3628c2ecf20Sopenharmony_ci	if (op == PACK)
3638c2ecf20Sopenharmony_ci		sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
3678c2ecf20Sopenharmony_ci						 enum packing_op op)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct sja1105_mgmt_entry *entry = entry_ptr;
3708c2ecf20Sopenharmony_ci	const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* UM10944: To specify if a PTP egress timestamp shall be captured on
3738c2ecf20Sopenharmony_ci	 * each port upon transmission of the frame, the LSB of VLANID in the
3748c2ecf20Sopenharmony_ci	 * ENTRY field provided by the host must be set.
3758c2ecf20Sopenharmony_ci	 * Bit 1 of VLANID then specifies the register where the timestamp for
3768c2ecf20Sopenharmony_ci	 * this port is stored in.
3778c2ecf20Sopenharmony_ci	 */
3788c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->tsreg,     85, 85, size, op);
3798c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->takets,    84, 84, size, op);
3808c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->macaddr,   83, 36, size, op);
3818c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->destports, 35, 31, size, op);
3828c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->enfport,   30, 30, size, op);
3838c2ecf20Sopenharmony_ci	return size;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic void
3878c2ecf20Sopenharmony_cisja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
3888c2ecf20Sopenharmony_ci				   enum packing_op op)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
3918c2ecf20Sopenharmony_ci	u64 mgmtroute = 1;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
3948c2ecf20Sopenharmony_ci	if (op == PACK)
3958c2ecf20Sopenharmony_ci		sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
3998c2ecf20Sopenharmony_ci						   enum packing_op op)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
4028c2ecf20Sopenharmony_ci	struct sja1105_mgmt_entry *entry = entry_ptr;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
4058c2ecf20Sopenharmony_ci	 * is the same (driver uses it to confirm that frame was sent).
4068c2ecf20Sopenharmony_ci	 * So just keep the name from E/T.
4078c2ecf20Sopenharmony_ci	 */
4088c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->tsreg,     71, 71, size, op);
4098c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->takets,    70, 70, size, op);
4108c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->macaddr,   69, 22, size, op);
4118c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->destports, 21, 17, size, op);
4128c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->enfport,   16, 16, size, op);
4138c2ecf20Sopenharmony_ci	return size;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci/* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
4178c2ecf20Sopenharmony_ci * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
4188c2ecf20Sopenharmony_ci * between entry (0x2d, 0x2e) and command (0x30).
4198c2ecf20Sopenharmony_ci */
4208c2ecf20Sopenharmony_cistatic void
4218c2ecf20Sopenharmony_cisja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
4228c2ecf20Sopenharmony_ci				enum packing_op op)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4;
4258c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
4288c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
4298c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
4308c2ecf20Sopenharmony_ci	/* Hack - see comments above, applied for 'vlanid' field of
4318c2ecf20Sopenharmony_ci	 * struct sja1105_vlan_lookup_entry.
4328c2ecf20Sopenharmony_ci	 */
4338c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->index, 38, 27,
4348c2ecf20Sopenharmony_ci			SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic void
4388c2ecf20Sopenharmony_cisja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
4398c2ecf20Sopenharmony_ci				  enum packing_op op)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
4428c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
4458c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
4468c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
4478c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->index,    4,  0, size, op);
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void
4518c2ecf20Sopenharmony_cisja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
4528c2ecf20Sopenharmony_ci				 enum packing_op op)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
4558c2ecf20Sopenharmony_ci	/* Yup, user manual definitions are reversed */
4568c2ecf20Sopenharmony_ci	u8 *reg1 = buf + 4;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &cmd->valid, 31, 31, size, op);
4598c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &cmd->index, 26, 24, size, op);
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
4638c2ecf20Sopenharmony_ci						 enum packing_op op)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
4668c2ecf20Sopenharmony_ci	struct sja1105_mac_config_entry *entry = entry_ptr;
4678c2ecf20Sopenharmony_ci	/* Yup, user manual definitions are reversed */
4688c2ecf20Sopenharmony_ci	u8 *reg1 = buf + 4;
4698c2ecf20Sopenharmony_ci	u8 *reg2 = buf;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->speed,     30, 29, size, op);
4728c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->drpdtag,   23, 23, size, op);
4738c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->drpuntag,  22, 22, size, op);
4748c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->retag,     21, 21, size, op);
4758c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op);
4768c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->egress,    19, 19, size, op);
4778c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->ingress,   18, 18, size, op);
4788c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->ing_mirr,  17, 17, size, op);
4798c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->egr_mirr,  16, 16, size, op);
4808c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->vlanprio,  14, 12, size, op);
4818c2ecf20Sopenharmony_ci	sja1105_packing(reg1, &entry->vlanid,    11,  0, size, op);
4828c2ecf20Sopenharmony_ci	sja1105_packing(reg2, &entry->tp_delin,  31, 16, size, op);
4838c2ecf20Sopenharmony_ci	sja1105_packing(reg2, &entry->tp_delout, 15,  0, size, op);
4848c2ecf20Sopenharmony_ci	/* MAC configuration table entries which can't be reconfigured:
4858c2ecf20Sopenharmony_ci	 * top, base, enabled, ifg, maxage, drpnona664
4868c2ecf20Sopenharmony_ci	 */
4878c2ecf20Sopenharmony_ci	/* Bogus return value, not used anywhere */
4888c2ecf20Sopenharmony_ci	return 0;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic void
4928c2ecf20Sopenharmony_cisja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
4938c2ecf20Sopenharmony_ci				   enum packing_op op)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
4968c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
4998c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
5008c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
5018c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->index,    2,  0, size, op);
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic void
5058c2ecf20Sopenharmony_cisja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
5068c2ecf20Sopenharmony_ci				       enum packing_op op)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->valid, 31, 31,
5098c2ecf20Sopenharmony_ci			SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic size_t
5138c2ecf20Sopenharmony_cisja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
5148c2ecf20Sopenharmony_ci					 enum packing_op op)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->poly, 7, 0,
5198c2ecf20Sopenharmony_ci			SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
5208c2ecf20Sopenharmony_ci	/* Bogus return value, not used anywhere */
5218c2ecf20Sopenharmony_ci	return 0;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic void
5258c2ecf20Sopenharmony_cisja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
5268c2ecf20Sopenharmony_ci					 struct sja1105_dyn_cmd *cmd,
5278c2ecf20Sopenharmony_ci					 enum packing_op op)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY;
5308c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
5338c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic void
5378c2ecf20Sopenharmony_cisja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
5388c2ecf20Sopenharmony_ci				     enum packing_op op)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->valid,  31, 31, size, op);
5438c2ecf20Sopenharmony_ci	sja1105_packing(buf, &cmd->errors, 30, 30, size, op);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic size_t
5478c2ecf20Sopenharmony_cisja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
5488c2ecf20Sopenharmony_ci				       enum packing_op op)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	struct sja1105_general_params_entry *entry = entry_ptr;
5518c2ecf20Sopenharmony_ci	const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op);
5548c2ecf20Sopenharmony_ci	/* Bogus return value, not used anywhere */
5558c2ecf20Sopenharmony_ci	return 0;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic void
5598c2ecf20Sopenharmony_cisja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
5608c2ecf20Sopenharmony_ci				       enum packing_op op)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY;
5638c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
5668c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
5678c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op);
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic void
5718c2ecf20Sopenharmony_cisja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
5728c2ecf20Sopenharmony_ci				   enum packing_op op)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
5758c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
5788c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
5798c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic void
5838c2ecf20Sopenharmony_cisja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
5848c2ecf20Sopenharmony_ci			      enum packing_op op)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
5878c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
5908c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,   30, 30, size, op);
5918c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valident, 29, 29, size, op);
5928c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset,  28, 28, size, op);
5938c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->index,     5,  0, size, op);
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
5978c2ecf20Sopenharmony_ci				      enum packing_op op)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105ET_SIZE_CBS_ENTRY;
6008c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid, 31, 31, size, op);
6038c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->index, 19, 16, size, op);
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cistatic size_t sja1105et_cbs_entry_packing(void *buf, void *entry_ptr,
6078c2ecf20Sopenharmony_ci					  enum packing_op op)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	const size_t size = SJA1105ET_SIZE_CBS_ENTRY;
6108c2ecf20Sopenharmony_ci	struct sja1105_cbs_entry *entry = entry_ptr;
6118c2ecf20Sopenharmony_ci	u8 *cmd = buf + size;
6128c2ecf20Sopenharmony_ci	u32 *p = buf;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	sja1105_packing(cmd, &entry->port, 5, 3, SJA1105_SIZE_DYN_CMD, op);
6158c2ecf20Sopenharmony_ci	sja1105_packing(cmd, &entry->prio, 2, 0, SJA1105_SIZE_DYN_CMD, op);
6168c2ecf20Sopenharmony_ci	sja1105_packing(p + 3, &entry->credit_lo,  31, 0, size, op);
6178c2ecf20Sopenharmony_ci	sja1105_packing(p + 2, &entry->credit_hi,  31, 0, size, op);
6188c2ecf20Sopenharmony_ci	sja1105_packing(p + 1, &entry->send_slope, 31, 0, size, op);
6198c2ecf20Sopenharmony_ci	sja1105_packing(p + 0, &entry->idle_slope, 31, 0, size, op);
6208c2ecf20Sopenharmony_ci	return size;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
6248c2ecf20Sopenharmony_ci					enum packing_op op)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
6278c2ecf20Sopenharmony_ci	const int size = SJA1105_SIZE_DYN_CMD;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
6308c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
6318c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
6328c2ecf20Sopenharmony_ci	sja1105_packing(p, &cmd->index,    3,  0, size, op);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
6368c2ecf20Sopenharmony_ci					    enum packing_op op)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
6398c2ecf20Sopenharmony_ci	struct sja1105_cbs_entry *entry = entry_ptr;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->port,      159, 157, size, op);
6428c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->prio,      156, 154, size, op);
6438c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->credit_lo, 153, 122, size, op);
6448c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->credit_hi, 121,  90, size, op);
6458c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->send_slope, 89,  58, size, op);
6468c2ecf20Sopenharmony_ci	sja1105_packing(buf, &entry->idle_slope, 57,  26, size, op);
6478c2ecf20Sopenharmony_ci	return size;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci#define OP_READ		BIT(0)
6518c2ecf20Sopenharmony_ci#define OP_WRITE	BIT(1)
6528c2ecf20Sopenharmony_ci#define OP_DEL		BIT(2)
6538c2ecf20Sopenharmony_ci#define OP_SEARCH	BIT(3)
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci/* SJA1105E/T: First generation */
6568c2ecf20Sopenharmony_ciconst struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
6578c2ecf20Sopenharmony_ci	[BLK_IDX_VL_LOOKUP] = {
6588c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_vl_lookup_entry_packing,
6598c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_vl_lookup_cmd_packing,
6608c2ecf20Sopenharmony_ci		.access = OP_WRITE,
6618c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
6628c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
6638c2ecf20Sopenharmony_ci		.addr = 0x35,
6648c2ecf20Sopenharmony_ci	},
6658c2ecf20Sopenharmony_ci	[BLK_IDX_L2_LOOKUP] = {
6668c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
6678c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_l2_lookup_cmd_packing,
6688c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE | OP_DEL),
6698c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
6708c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
6718c2ecf20Sopenharmony_ci		.addr = 0x20,
6728c2ecf20Sopenharmony_ci	},
6738c2ecf20Sopenharmony_ci	[BLK_IDX_MGMT_ROUTE] = {
6748c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_mgmt_route_entry_packing,
6758c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_mgmt_route_cmd_packing,
6768c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE),
6778c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_NUM_PORTS,
6788c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
6798c2ecf20Sopenharmony_ci		.addr = 0x20,
6808c2ecf20Sopenharmony_ci	},
6818c2ecf20Sopenharmony_ci	[BLK_IDX_VLAN_LOOKUP] = {
6828c2ecf20Sopenharmony_ci		.entry_packing = sja1105_vlan_lookup_entry_packing,
6838c2ecf20Sopenharmony_ci		.cmd_packing = sja1105_vlan_lookup_cmd_packing,
6848c2ecf20Sopenharmony_ci		.access = (OP_WRITE | OP_DEL),
6858c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
6868c2ecf20Sopenharmony_ci		.packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
6878c2ecf20Sopenharmony_ci		.addr = 0x27,
6888c2ecf20Sopenharmony_ci	},
6898c2ecf20Sopenharmony_ci	[BLK_IDX_L2_FORWARDING] = {
6908c2ecf20Sopenharmony_ci		.entry_packing = sja1105_l2_forwarding_entry_packing,
6918c2ecf20Sopenharmony_ci		.cmd_packing = sja1105_l2_forwarding_cmd_packing,
6928c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
6938c2ecf20Sopenharmony_ci		.access = OP_WRITE,
6948c2ecf20Sopenharmony_ci		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
6958c2ecf20Sopenharmony_ci		.addr = 0x24,
6968c2ecf20Sopenharmony_ci	},
6978c2ecf20Sopenharmony_ci	[BLK_IDX_MAC_CONFIG] = {
6988c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_mac_config_entry_packing,
6998c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_mac_config_cmd_packing,
7008c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
7018c2ecf20Sopenharmony_ci		.access = OP_WRITE,
7028c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
7038c2ecf20Sopenharmony_ci		.addr = 0x36,
7048c2ecf20Sopenharmony_ci	},
7058c2ecf20Sopenharmony_ci	[BLK_IDX_L2_LOOKUP_PARAMS] = {
7068c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_l2_lookup_params_entry_packing,
7078c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
7088c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
7098c2ecf20Sopenharmony_ci		.access = OP_WRITE,
7108c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
7118c2ecf20Sopenharmony_ci		.addr = 0x38,
7128c2ecf20Sopenharmony_ci	},
7138c2ecf20Sopenharmony_ci	[BLK_IDX_GENERAL_PARAMS] = {
7148c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_general_params_entry_packing,
7158c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_general_params_cmd_packing,
7168c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
7178c2ecf20Sopenharmony_ci		.access = OP_WRITE,
7188c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
7198c2ecf20Sopenharmony_ci		.addr = 0x34,
7208c2ecf20Sopenharmony_ci	},
7218c2ecf20Sopenharmony_ci	[BLK_IDX_RETAGGING] = {
7228c2ecf20Sopenharmony_ci		.entry_packing = sja1105_retagging_entry_packing,
7238c2ecf20Sopenharmony_ci		.cmd_packing = sja1105_retagging_cmd_packing,
7248c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
7258c2ecf20Sopenharmony_ci		.access = (OP_WRITE | OP_DEL),
7268c2ecf20Sopenharmony_ci		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
7278c2ecf20Sopenharmony_ci		.addr = 0x31,
7288c2ecf20Sopenharmony_ci	},
7298c2ecf20Sopenharmony_ci	[BLK_IDX_CBS] = {
7308c2ecf20Sopenharmony_ci		.entry_packing = sja1105et_cbs_entry_packing,
7318c2ecf20Sopenharmony_ci		.cmd_packing = sja1105et_cbs_cmd_packing,
7328c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105ET_MAX_CBS_COUNT,
7338c2ecf20Sopenharmony_ci		.access = OP_WRITE,
7348c2ecf20Sopenharmony_ci		.packed_size = SJA1105ET_SIZE_CBS_DYN_CMD,
7358c2ecf20Sopenharmony_ci		.addr = 0x2c,
7368c2ecf20Sopenharmony_ci	},
7378c2ecf20Sopenharmony_ci};
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci/* SJA1105P/Q/R/S: Second generation */
7408c2ecf20Sopenharmony_ciconst struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
7418c2ecf20Sopenharmony_ci	[BLK_IDX_VL_LOOKUP] = {
7428c2ecf20Sopenharmony_ci		.entry_packing = sja1105_vl_lookup_entry_packing,
7438c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_vl_lookup_cmd_packing,
7448c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE),
7458c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
7468c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
7478c2ecf20Sopenharmony_ci		.addr = 0x47,
7488c2ecf20Sopenharmony_ci	},
7498c2ecf20Sopenharmony_ci	[BLK_IDX_L2_LOOKUP] = {
7508c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
7518c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
7528c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
7538c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
7548c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
7558c2ecf20Sopenharmony_ci		.addr = 0x24,
7568c2ecf20Sopenharmony_ci	},
7578c2ecf20Sopenharmony_ci	[BLK_IDX_MGMT_ROUTE] = {
7588c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_mgmt_route_entry_packing,
7598c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
7608c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
7618c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_NUM_PORTS,
7628c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
7638c2ecf20Sopenharmony_ci		.addr = 0x24,
7648c2ecf20Sopenharmony_ci	},
7658c2ecf20Sopenharmony_ci	[BLK_IDX_VLAN_LOOKUP] = {
7668c2ecf20Sopenharmony_ci		.entry_packing = sja1105_vlan_lookup_entry_packing,
7678c2ecf20Sopenharmony_ci		.cmd_packing = sja1105_vlan_lookup_cmd_packing,
7688c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE | OP_DEL),
7698c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
7708c2ecf20Sopenharmony_ci		.packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
7718c2ecf20Sopenharmony_ci		.addr = 0x2D,
7728c2ecf20Sopenharmony_ci	},
7738c2ecf20Sopenharmony_ci	[BLK_IDX_L2_FORWARDING] = {
7748c2ecf20Sopenharmony_ci		.entry_packing = sja1105_l2_forwarding_entry_packing,
7758c2ecf20Sopenharmony_ci		.cmd_packing = sja1105_l2_forwarding_cmd_packing,
7768c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
7778c2ecf20Sopenharmony_ci		.access = OP_WRITE,
7788c2ecf20Sopenharmony_ci		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
7798c2ecf20Sopenharmony_ci		.addr = 0x2A,
7808c2ecf20Sopenharmony_ci	},
7818c2ecf20Sopenharmony_ci	[BLK_IDX_MAC_CONFIG] = {
7828c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_mac_config_entry_packing,
7838c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_mac_config_cmd_packing,
7848c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
7858c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE),
7868c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
7878c2ecf20Sopenharmony_ci		.addr = 0x4B,
7888c2ecf20Sopenharmony_ci	},
7898c2ecf20Sopenharmony_ci	[BLK_IDX_L2_LOOKUP_PARAMS] = {
7908c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_l2_lookup_params_entry_packing,
7918c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing,
7928c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
7938c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE),
7948c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
7958c2ecf20Sopenharmony_ci		.addr = 0x54,
7968c2ecf20Sopenharmony_ci	},
7978c2ecf20Sopenharmony_ci	[BLK_IDX_AVB_PARAMS] = {
7988c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_avb_params_entry_packing,
7998c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
8008c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
8018c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE),
8028c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
8038c2ecf20Sopenharmony_ci		.addr = 0x8003,
8048c2ecf20Sopenharmony_ci	},
8058c2ecf20Sopenharmony_ci	[BLK_IDX_GENERAL_PARAMS] = {
8068c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_general_params_entry_packing,
8078c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_general_params_cmd_packing,
8088c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
8098c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE),
8108c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD,
8118c2ecf20Sopenharmony_ci		.addr = 0x3B,
8128c2ecf20Sopenharmony_ci	},
8138c2ecf20Sopenharmony_ci	[BLK_IDX_RETAGGING] = {
8148c2ecf20Sopenharmony_ci		.entry_packing = sja1105_retagging_entry_packing,
8158c2ecf20Sopenharmony_ci		.cmd_packing = sja1105_retagging_cmd_packing,
8168c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
8178c2ecf20Sopenharmony_ci		.access = (OP_READ | OP_WRITE | OP_DEL),
8188c2ecf20Sopenharmony_ci		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
8198c2ecf20Sopenharmony_ci		.addr = 0x38,
8208c2ecf20Sopenharmony_ci	},
8218c2ecf20Sopenharmony_ci	[BLK_IDX_CBS] = {
8228c2ecf20Sopenharmony_ci		.entry_packing = sja1105pqrs_cbs_entry_packing,
8238c2ecf20Sopenharmony_ci		.cmd_packing = sja1105pqrs_cbs_cmd_packing,
8248c2ecf20Sopenharmony_ci		.max_entry_count = SJA1105PQRS_MAX_CBS_COUNT,
8258c2ecf20Sopenharmony_ci		.access = OP_WRITE,
8268c2ecf20Sopenharmony_ci		.packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
8278c2ecf20Sopenharmony_ci		.addr = 0x32,
8288c2ecf20Sopenharmony_ci	},
8298c2ecf20Sopenharmony_ci};
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci/* Provides read access to the settings through the dynamic interface
8328c2ecf20Sopenharmony_ci * of the switch.
8338c2ecf20Sopenharmony_ci * @blk_idx	is used as key to select from the sja1105_dynamic_table_ops.
8348c2ecf20Sopenharmony_ci *		The selection is limited by the hardware in respect to which
8358c2ecf20Sopenharmony_ci *		configuration blocks can be read through the dynamic interface.
8368c2ecf20Sopenharmony_ci * @index	is used to retrieve a particular table entry. If negative,
8378c2ecf20Sopenharmony_ci *		(and if the @blk_idx supports the searching operation) a search
8388c2ecf20Sopenharmony_ci *		is performed by the @entry parameter.
8398c2ecf20Sopenharmony_ci * @entry	Type-casted to an unpacked structure that holds a table entry
8408c2ecf20Sopenharmony_ci *		of the type specified in @blk_idx.
8418c2ecf20Sopenharmony_ci *		Usually an output argument. If @index is negative, then this
8428c2ecf20Sopenharmony_ci *		argument is used as input/output: it should be pre-populated
8438c2ecf20Sopenharmony_ci *		with the element to search for. Entries which support the
8448c2ecf20Sopenharmony_ci *		search operation will have an "index" field (not the @index
8458c2ecf20Sopenharmony_ci *		argument to this function) and that is where the found index
8468c2ecf20Sopenharmony_ci *		will be returned (or left unmodified - thus negative - if not
8478c2ecf20Sopenharmony_ci *		found).
8488c2ecf20Sopenharmony_ci */
8498c2ecf20Sopenharmony_ciint sja1105_dynamic_config_read(struct sja1105_private *priv,
8508c2ecf20Sopenharmony_ci				enum sja1105_blk_idx blk_idx,
8518c2ecf20Sopenharmony_ci				int index, void *entry)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	const struct sja1105_dynamic_table_ops *ops;
8548c2ecf20Sopenharmony_ci	struct sja1105_dyn_cmd cmd = {0};
8558c2ecf20Sopenharmony_ci	/* SPI payload buffer */
8568c2ecf20Sopenharmony_ci	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
8578c2ecf20Sopenharmony_ci	int retries = 3;
8588c2ecf20Sopenharmony_ci	int rc;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	if (blk_idx >= BLK_IDX_MAX_DYN)
8618c2ecf20Sopenharmony_ci		return -ERANGE;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	ops = &priv->info->dyn_ops[blk_idx];
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	if (index >= 0 && index >= ops->max_entry_count)
8668c2ecf20Sopenharmony_ci		return -ERANGE;
8678c2ecf20Sopenharmony_ci	if (index < 0 && !(ops->access & OP_SEARCH))
8688c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8698c2ecf20Sopenharmony_ci	if (!(ops->access & OP_READ))
8708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8718c2ecf20Sopenharmony_ci	if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
8728c2ecf20Sopenharmony_ci		return -ERANGE;
8738c2ecf20Sopenharmony_ci	if (!ops->cmd_packing)
8748c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8758c2ecf20Sopenharmony_ci	if (!ops->entry_packing)
8768c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	cmd.valid = true; /* Trigger action on table entry */
8798c2ecf20Sopenharmony_ci	cmd.rdwrset = SPI_READ; /* Action is read */
8808c2ecf20Sopenharmony_ci	if (index < 0) {
8818c2ecf20Sopenharmony_ci		/* Avoid copying a signed negative number to an u64 */
8828c2ecf20Sopenharmony_ci		cmd.index = 0;
8838c2ecf20Sopenharmony_ci		cmd.search = true;
8848c2ecf20Sopenharmony_ci	} else {
8858c2ecf20Sopenharmony_ci		cmd.index = index;
8868c2ecf20Sopenharmony_ci		cmd.search = false;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci	cmd.valident = true;
8898c2ecf20Sopenharmony_ci	ops->cmd_packing(packed_buf, &cmd, PACK);
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	if (cmd.search)
8928c2ecf20Sopenharmony_ci		ops->entry_packing(packed_buf, entry, PACK);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/* Send SPI write operation: read config table entry */
8958c2ecf20Sopenharmony_ci	rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
8968c2ecf20Sopenharmony_ci			      ops->packed_size);
8978c2ecf20Sopenharmony_ci	if (rc < 0)
8988c2ecf20Sopenharmony_ci		return rc;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* Loop until we have confirmation that hardware has finished
9018c2ecf20Sopenharmony_ci	 * processing the command and has cleared the VALID field
9028c2ecf20Sopenharmony_ci	 */
9038c2ecf20Sopenharmony_ci	do {
9048c2ecf20Sopenharmony_ci		memset(packed_buf, 0, ops->packed_size);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci		/* Retrieve the read operation's result */
9078c2ecf20Sopenharmony_ci		rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf,
9088c2ecf20Sopenharmony_ci				      ops->packed_size);
9098c2ecf20Sopenharmony_ci		if (rc < 0)
9108c2ecf20Sopenharmony_ci			return rc;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci		cmd = (struct sja1105_dyn_cmd) {0};
9138c2ecf20Sopenharmony_ci		ops->cmd_packing(packed_buf, &cmd, UNPACK);
9148c2ecf20Sopenharmony_ci		/* UM10944: [valident] will always be found cleared
9158c2ecf20Sopenharmony_ci		 * during a read access with MGMTROUTE set.
9168c2ecf20Sopenharmony_ci		 * So don't error out in that case.
9178c2ecf20Sopenharmony_ci		 */
9188c2ecf20Sopenharmony_ci		if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
9198c2ecf20Sopenharmony_ci			return -ENOENT;
9208c2ecf20Sopenharmony_ci		cpu_relax();
9218c2ecf20Sopenharmony_ci	} while (cmd.valid && --retries);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (cmd.valid)
9248c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* Don't dereference possibly NULL pointer - maybe caller
9278c2ecf20Sopenharmony_ci	 * only wanted to see whether the entry existed or not.
9288c2ecf20Sopenharmony_ci	 */
9298c2ecf20Sopenharmony_ci	if (entry)
9308c2ecf20Sopenharmony_ci		ops->entry_packing(packed_buf, entry, UNPACK);
9318c2ecf20Sopenharmony_ci	return 0;
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ciint sja1105_dynamic_config_write(struct sja1105_private *priv,
9358c2ecf20Sopenharmony_ci				 enum sja1105_blk_idx blk_idx,
9368c2ecf20Sopenharmony_ci				 int index, void *entry, bool keep)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	const struct sja1105_dynamic_table_ops *ops;
9398c2ecf20Sopenharmony_ci	struct sja1105_dyn_cmd cmd = {0};
9408c2ecf20Sopenharmony_ci	/* SPI payload buffer */
9418c2ecf20Sopenharmony_ci	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
9428c2ecf20Sopenharmony_ci	int rc;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	if (blk_idx >= BLK_IDX_MAX_DYN)
9458c2ecf20Sopenharmony_ci		return -ERANGE;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	ops = &priv->info->dyn_ops[blk_idx];
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	if (index >= ops->max_entry_count)
9508c2ecf20Sopenharmony_ci		return -ERANGE;
9518c2ecf20Sopenharmony_ci	if (index < 0)
9528c2ecf20Sopenharmony_ci		return -ERANGE;
9538c2ecf20Sopenharmony_ci	if (!(ops->access & OP_WRITE))
9548c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9558c2ecf20Sopenharmony_ci	if (!keep && !(ops->access & OP_DEL))
9568c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9578c2ecf20Sopenharmony_ci	if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
9588c2ecf20Sopenharmony_ci		return -ERANGE;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	cmd.valident = keep; /* If false, deletes entry */
9618c2ecf20Sopenharmony_ci	cmd.valid = true; /* Trigger action on table entry */
9628c2ecf20Sopenharmony_ci	cmd.rdwrset = SPI_WRITE; /* Action is write */
9638c2ecf20Sopenharmony_ci	cmd.index = index;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (!ops->cmd_packing)
9668c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9678c2ecf20Sopenharmony_ci	ops->cmd_packing(packed_buf, &cmd, PACK);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	if (!ops->entry_packing)
9708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9718c2ecf20Sopenharmony_ci	/* Don't dereference potentially NULL pointer if just
9728c2ecf20Sopenharmony_ci	 * deleting a table entry is what was requested. For cases
9738c2ecf20Sopenharmony_ci	 * where 'index' field is physically part of entry structure,
9748c2ecf20Sopenharmony_ci	 * and needed here, we deal with that in the cmd_packing callback.
9758c2ecf20Sopenharmony_ci	 */
9768c2ecf20Sopenharmony_ci	if (keep)
9778c2ecf20Sopenharmony_ci		ops->entry_packing(packed_buf, entry, PACK);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	/* Send SPI write operation: read config table entry */
9808c2ecf20Sopenharmony_ci	rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
9818c2ecf20Sopenharmony_ci			      ops->packed_size);
9828c2ecf20Sopenharmony_ci	if (rc < 0)
9838c2ecf20Sopenharmony_ci		return rc;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	cmd = (struct sja1105_dyn_cmd) {0};
9868c2ecf20Sopenharmony_ci	ops->cmd_packing(packed_buf, &cmd, UNPACK);
9878c2ecf20Sopenharmony_ci	if (cmd.errors)
9888c2ecf20Sopenharmony_ci		return -EINVAL;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	return 0;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
9948c2ecf20Sopenharmony_ci{
9958c2ecf20Sopenharmony_ci	int i;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
9988c2ecf20Sopenharmony_ci		if ((crc ^ byte) & (1 << 7)) {
9998c2ecf20Sopenharmony_ci			crc <<= 1;
10008c2ecf20Sopenharmony_ci			crc ^= poly;
10018c2ecf20Sopenharmony_ci		} else {
10028c2ecf20Sopenharmony_ci			crc <<= 1;
10038c2ecf20Sopenharmony_ci		}
10048c2ecf20Sopenharmony_ci		byte <<= 1;
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci	return crc;
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci/* CRC8 algorithm with non-reversed input, non-reversed output,
10108c2ecf20Sopenharmony_ci * no input xor and no output xor. Code customized for receiving
10118c2ecf20Sopenharmony_ci * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
10128c2ecf20Sopenharmony_ci * is also received as argument in the Koopman notation that the switch
10138c2ecf20Sopenharmony_ci * hardware stores it in.
10148c2ecf20Sopenharmony_ci */
10158c2ecf20Sopenharmony_ciu8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	struct sja1105_l2_lookup_params_entry *l2_lookup_params =
10188c2ecf20Sopenharmony_ci		priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
10198c2ecf20Sopenharmony_ci	u64 poly_koopman = l2_lookup_params->poly;
10208c2ecf20Sopenharmony_ci	/* Convert polynomial from Koopman to 'normal' notation */
10218c2ecf20Sopenharmony_ci	u8 poly = (u8)(1 + (poly_koopman << 1));
10228c2ecf20Sopenharmony_ci	u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid;
10238c2ecf20Sopenharmony_ci	u64 input = (vlanid << 48) | ether_addr_to_u64(addr);
10248c2ecf20Sopenharmony_ci	u8 crc = 0; /* seed */
10258c2ecf20Sopenharmony_ci	int i;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	/* Mask the eight bytes starting from MSB one at a time */
10288c2ecf20Sopenharmony_ci	for (i = 56; i >= 0; i -= 8) {
10298c2ecf20Sopenharmony_ci		u8 byte = (input & (0xffull << i)) >> i;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci		crc = sja1105_crc8_add(crc, byte, poly);
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci	return crc;
10348c2ecf20Sopenharmony_ci}
1035