cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sja1105_dynamic_config.c (50178B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
      3 */
      4#include "sja1105.h"
      5
      6/* In the dynamic configuration interface, the switch exposes a register-like
      7 * view of some of the static configuration tables.
      8 * Many times the field organization of the dynamic tables is abbreviated (not
      9 * all fields are dynamically reconfigurable) and different from the static
     10 * ones, but the key reason for having it is that we can spare a switch reset
     11 * for settings that can be changed dynamically.
     12 *
     13 * This file creates a per-switch-family abstraction called
     14 * struct sja1105_dynamic_table_ops and two operations that work with it:
     15 * - sja1105_dynamic_config_write
     16 * - sja1105_dynamic_config_read
     17 *
     18 * Compared to the struct sja1105_table_ops from sja1105_static_config.c,
     19 * the dynamic accessors work with a compound buffer:
     20 *
     21 * packed_buf
     22 *
     23 * |
     24 * V
     25 * +-----------------------------------------+------------------+
     26 * |              ENTRY BUFFER               |  COMMAND BUFFER  |
     27 * +-----------------------------------------+------------------+
     28 *
     29 * <----------------------- packed_size ------------------------>
     30 *
     31 * The ENTRY BUFFER may or may not have the same layout, or size, as its static
     32 * configuration table entry counterpart. When it does, the same packing
     33 * function is reused (bar exceptional cases - see
     34 * sja1105pqrs_dyn_l2_lookup_entry_packing).
     35 *
     36 * The reason for the COMMAND BUFFER being at the end is to be able to send
     37 * a dynamic write command through a single SPI burst. By the time the switch
     38 * reacts to the command, the ENTRY BUFFER is already populated with the data
     39 * sent by the core.
     40 *
     41 * The COMMAND BUFFER is always SJA1105_SIZE_DYN_CMD bytes (one 32-bit word) in
     42 * size.
     43 *
     44 * Sometimes the ENTRY BUFFER does not really exist (when the number of fields
     45 * that can be reconfigured is small), then the switch repurposes some of the
     46 * unused 32 bits of the COMMAND BUFFER to hold ENTRY data.
     47 *
     48 * The key members of struct sja1105_dynamic_table_ops are:
     49 * - .entry_packing: A function that deals with packing an ENTRY structure
     50 *		     into an SPI buffer, or retrieving an ENTRY structure
     51 *		     from one.
     52 *		     The @packed_buf pointer it's given does always point to
     53 *		     the ENTRY portion of the buffer.
     54 * - .cmd_packing: A function that deals with packing/unpacking the COMMAND
     55 *		   structure to/from the SPI buffer.
     56 *		   It is given the same @packed_buf pointer as .entry_packing,
     57 *		   so most of the time, the @packed_buf points *behind* the
     58 *		   COMMAND offset inside the buffer.
     59 *		   To access the COMMAND portion of the buffer, the function
     60 *		   knows its correct offset.
     61 *		   Giving both functions the same pointer is handy because in
     62 *		   extreme cases (see sja1105pqrs_dyn_l2_lookup_entry_packing)
     63 *		   the .entry_packing is able to jump to the COMMAND portion,
     64 *		   or vice-versa (sja1105pqrs_l2_lookup_cmd_packing).
     65 * - .access: A bitmap of:
     66 *	OP_READ: Set if the hardware manual marks the ENTRY portion of the
     67 *		 dynamic configuration table buffer as R (readable) after
     68 *		 an SPI read command (the switch will populate the buffer).
     69 *	OP_WRITE: Set if the manual marks the ENTRY portion of the dynamic
     70 *		  table buffer as W (writable) after an SPI write command
     71 *		  (the switch will read the fields provided in the buffer).
     72 *	OP_DEL: Set if the manual says the VALIDENT bit is supported in the
     73 *		COMMAND portion of this dynamic config buffer (i.e. the
     74 *		specified entry can be invalidated through a SPI write
     75 *		command).
     76 *	OP_SEARCH: Set if the manual says that the index of an entry can
     77 *		   be retrieved in the COMMAND portion of the buffer based
     78 *		   on its ENTRY portion, as a result of a SPI write command.
     79 *		   Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
     80 *		   this.
     81 *	OP_VALID_ANYWAY: Reading some tables through the dynamic config
     82 *			 interface is possible even if the VALIDENT bit is not
     83 *			 set in the writeback. So don't error out in that case.
     84 * - .max_entry_count: The number of entries, counting from zero, that can be
     85 *		       reconfigured through the dynamic interface. If a static
     86 *		       table can be reconfigured at all dynamically, this
     87 *		       number always matches the maximum number of supported
     88 *		       static entries.
     89 * - .packed_size: The length in bytes of the compound ENTRY + COMMAND BUFFER.
     90 *		   Note that sometimes the compound buffer may contain holes in
     91 *		   it (see sja1105_vlan_lookup_cmd_packing). The @packed_buf is
     92 *		   contiguous however, so @packed_size includes any unused
     93 *		   bytes.
     94 * - .addr: The base SPI address at which the buffer must be written to the
     95 *	    switch's memory. When looking at the hardware manual, this must
     96 *	    always match the lowest documented address for the ENTRY, and not
     97 *	    that of the COMMAND, since the other 32-bit words will follow along
     98 *	    at the correct addresses.
     99 */
    100
    101#define SJA1105_SIZE_DYN_CMD					4
    102
    103#define SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD			\
    104	SJA1105_SIZE_DYN_CMD
    105
    106#define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD			\
    107	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)
    108
    109#define SJA1110_SIZE_VL_POLICING_DYN_CMD			\
    110	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_POLICING_ENTRY)
    111
    112#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
    113	SJA1105_SIZE_DYN_CMD
    114
    115#define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD			\
    116	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY)
    117
    118#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD			\
    119	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
    120
    121#define SJA1110_SIZE_L2_LOOKUP_DYN_CMD				\
    122	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_ENTRY)
    123
    124#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD			\
    125	(SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
    126
    127#define SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD			\
    128	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_VLAN_LOOKUP_ENTRY)
    129
    130#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD			\
    131	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
    132
    133#define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD			\
    134	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY)
    135
    136#define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD			\
    137	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY)
    138
    139#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD			\
    140	SJA1105_SIZE_DYN_CMD
    141
    142#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
    143	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)
    144
    145#define SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
    146	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY)
    147
    148#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD			\
    149	SJA1105_SIZE_DYN_CMD
    150
    151#define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD			\
    152	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)
    153
    154#define SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD			\
    155	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_GENERAL_PARAMS_ENTRY)
    156
    157#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD			\
    158	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)
    159
    160#define SJA1105_SIZE_RETAGGING_DYN_CMD				\
    161	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_RETAGGING_ENTRY)
    162
    163#define SJA1105ET_SIZE_CBS_DYN_CMD				\
    164	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_CBS_ENTRY)
    165
    166#define SJA1105PQRS_SIZE_CBS_DYN_CMD				\
    167	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)
    168
    169#define SJA1110_SIZE_XMII_PARAMS_DYN_CMD			\
    170	SJA1110_SIZE_XMII_PARAMS_ENTRY
    171
    172#define SJA1110_SIZE_L2_POLICING_DYN_CMD			\
    173	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_POLICING_ENTRY)
    174
    175#define SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD		\
    176	SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY
    177
    178#define SJA1105_MAX_DYN_CMD_SIZE				\
    179	SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD
    180
    181struct sja1105_dyn_cmd {
    182	bool search;
    183	u64 valid;
    184	u64 rdwrset;
    185	u64 errors;
    186	u64 valident;
    187	u64 index;
    188};
    189
    190enum sja1105_hostcmd {
    191	SJA1105_HOSTCMD_SEARCH = 1,
    192	SJA1105_HOSTCMD_READ = 2,
    193	SJA1105_HOSTCMD_WRITE = 3,
    194	SJA1105_HOSTCMD_INVALIDATE = 4,
    195};
    196
    197/* Command and entry overlap */
    198static void
    199sja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    200				enum packing_op op)
    201{
    202	const int size = SJA1105_SIZE_DYN_CMD;
    203
    204	sja1105_packing(buf, &cmd->valid,   31, 31, size, op);
    205	sja1105_packing(buf, &cmd->errors,  30, 30, size, op);
    206	sja1105_packing(buf, &cmd->rdwrset, 29, 29, size, op);
    207	sja1105_packing(buf, &cmd->index,    9,  0, size, op);
    208}
    209
    210/* Command and entry are separate */
    211static void
    212sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    213				  enum packing_op op)
    214{
    215	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
    216	const int size = SJA1105_SIZE_DYN_CMD;
    217
    218	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    219	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
    220	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
    221	sja1105_packing(p, &cmd->index,    9,  0, size, op);
    222}
    223
    224static void
    225sja1110_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    226			      enum packing_op op)
    227{
    228	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
    229	const int size = SJA1105_SIZE_DYN_CMD;
    230
    231	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    232	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    233	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    234	sja1105_packing(p, &cmd->index,   11,  0, size, op);
    235}
    236
    237static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
    238						enum packing_op op)
    239{
    240	struct sja1105_vl_lookup_entry *entry = entry_ptr;
    241	const int size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD;
    242
    243	sja1105_packing(buf, &entry->egrmirr,  21, 17, size, op);
    244	sja1105_packing(buf, &entry->ingrmirr, 16, 16, size, op);
    245	return size;
    246}
    247
    248static void
    249sja1110_vl_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    250				enum packing_op op)
    251{
    252	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
    253	const int size = SJA1105_SIZE_DYN_CMD;
    254
    255	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    256	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    257	sja1105_packing(p, &cmd->index,   11,  0, size, op);
    258}
    259
    260static void
    261sja1105pqrs_common_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    262					 enum packing_op op, int entry_size)
    263{
    264	const int size = SJA1105_SIZE_DYN_CMD;
    265	u8 *p = buf + entry_size;
    266	u64 hostcmd;
    267
    268	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
    269	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
    270	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
    271	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
    272
    273	/* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
    274	 * using it to delete a management route was unsupported. UM10944
    275	 * said about it:
    276	 *
    277	 *   In case of a write access with the MGMTROUTE flag set,
    278	 *   the flag will be ignored. It will always be found cleared
    279	 *   for read accesses with the MGMTROUTE flag set.
    280	 *
    281	 * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there
    282	 * is now another flag called HOSTCMD which does more stuff (quoting
    283	 * from UM11040):
    284	 *
    285	 *   A write request is accepted only when HOSTCMD is set to write host
    286	 *   or invalid. A read request is accepted only when HOSTCMD is set to
    287	 *   search host or read host.
    288	 *
    289	 * So it is possible to translate a RDWRSET/VALIDENT combination into
    290	 * HOSTCMD so that we keep the dynamic command API in place, and
    291	 * at the same time achieve compatibility with the management route
    292	 * command structure.
    293	 */
    294	if (cmd->rdwrset == SPI_READ) {
    295		if (cmd->search)
    296			hostcmd = SJA1105_HOSTCMD_SEARCH;
    297		else
    298			hostcmd = SJA1105_HOSTCMD_READ;
    299	} else {
    300		/* SPI_WRITE */
    301		if (cmd->valident)
    302			hostcmd = SJA1105_HOSTCMD_WRITE;
    303		else
    304			hostcmd = SJA1105_HOSTCMD_INVALIDATE;
    305	}
    306	sja1105_packing(p, &hostcmd, 25, 23, size, op);
    307}
    308
    309static void
    310sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    311				  enum packing_op op)
    312{
    313	int entry_size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
    314
    315	sja1105pqrs_common_l2_lookup_cmd_packing(buf, cmd, op, entry_size);
    316
    317	/* Hack - The hardware takes the 'index' field within
    318	 * struct sja1105_l2_lookup_entry as the index on which this command
    319	 * will operate. However it will ignore everything else, so 'index'
    320	 * is logically part of command but physically part of entry.
    321	 * Populate the 'index' entry field from within the command callback,
    322	 * such that our API doesn't need to ask for a full-blown entry
    323	 * structure when e.g. a delete is requested.
    324	 */
    325	sja1105_packing(buf, &cmd->index, 15, 6, entry_size, op);
    326}
    327
    328static void
    329sja1110_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    330			      enum packing_op op)
    331{
    332	int entry_size = SJA1110_SIZE_L2_LOOKUP_ENTRY;
    333
    334	sja1105pqrs_common_l2_lookup_cmd_packing(buf, cmd, op, entry_size);
    335
    336	sja1105_packing(buf, &cmd->index, 10, 1, entry_size, op);
    337}
    338
    339/* The switch is so retarded that it makes our command/entry abstraction
    340 * crumble apart.
    341 *
    342 * On P/Q/R/S, the switch tries to say whether a FDB entry
    343 * is statically programmed or dynamically learned via a flag called LOCKEDS.
    344 * The hardware manual says about this fiels:
    345 *
    346 *   On write will specify the format of ENTRY.
    347 *   On read the flag will be found cleared at times the VALID flag is found
    348 *   set.  The flag will also be found cleared in response to a read having the
    349 *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
    350 *   cleared, the flag be set if the most recent access operated on an entry
    351 *   that was either loaded by configuration or through dynamic reconfiguration
    352 *   (as opposed to automatically learned entries).
    353 *
    354 * The trouble with this flag is that it's part of the *command* to access the
    355 * dynamic interface, and not part of the *entry* retrieved from it.
    356 * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
    357 * an output from the switch into the command buffer, and for a
    358 * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
    359 * (hence we can write either static, or automatically learned entries, from
    360 * the core).
    361 * But the manual contradicts itself in the last phrase where it says that on
    362 * read, LOCKEDS will be set to 1 for all FDB entries written through the
    363 * dynamic interface (therefore, the value of LOCKEDS from the
    364 * sja1105_dynamic_config_write is not really used for anything, it'll store a
    365 * 1 anyway).
    366 * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
    367 * learned) into the switch, which kind of makes sense.
    368 * As for reading through the dynamic interface, it doesn't make too much sense
    369 * to put LOCKEDS into the command, since the switch will inevitably have to
    370 * ignore it (otherwise a command would be like "read the FDB entry 123, but
    371 * only if it's dynamically learned" <- well how am I supposed to know?) and
    372 * just use it as an output buffer for its findings. But guess what... that's
    373 * what the entry buffer is for!
    374 * Unfortunately, what really breaks this abstraction is the fact that it
    375 * wasn't designed having the fact in mind that the switch can output
    376 * entry-related data as writeback through the command buffer.
    377 * However, whether a FDB entry is statically or dynamically learned *is* part
    378 * of the entry and not the command data, no matter what the switch thinks.
    379 * In order to do that, we'll need to wrap around the
    380 * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
    381 * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
    382 * command buffer.
    383 */
    384static size_t
    385sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
    386					enum packing_op op)
    387{
    388	struct sja1105_l2_lookup_entry *entry = entry_ptr;
    389	u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
    390	const int size = SJA1105_SIZE_DYN_CMD;
    391
    392	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
    393
    394	return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
    395}
    396
    397static size_t sja1110_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
    398						  enum packing_op op)
    399{
    400	struct sja1105_l2_lookup_entry *entry = entry_ptr;
    401	u8 *cmd = buf + SJA1110_SIZE_L2_LOOKUP_ENTRY;
    402	const int size = SJA1105_SIZE_DYN_CMD;
    403
    404	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
    405
    406	return sja1110_l2_lookup_entry_packing(buf, entry_ptr, op);
    407}
    408
    409static void
    410sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    411				enum packing_op op)
    412{
    413	u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
    414	const int size = SJA1105_SIZE_DYN_CMD;
    415
    416	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
    417	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
    418	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
    419	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
    420	/* Hack - see comments above. */
    421	sja1105_packing(buf, &cmd->index, 29, 20,
    422			SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
    423}
    424
    425static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
    426						    enum packing_op op)
    427{
    428	struct sja1105_l2_lookup_entry *entry = entry_ptr;
    429	u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
    430	const int size = SJA1105_SIZE_DYN_CMD;
    431
    432	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
    433
    434	return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
    435}
    436
    437static void
    438sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    439				 enum packing_op op)
    440{
    441	u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
    442	u64 mgmtroute = 1;
    443
    444	sja1105et_l2_lookup_cmd_packing(buf, cmd, op);
    445	if (op == PACK)
    446		sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
    447}
    448
    449static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
    450						 enum packing_op op)
    451{
    452	struct sja1105_mgmt_entry *entry = entry_ptr;
    453	const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
    454
    455	/* UM10944: To specify if a PTP egress timestamp shall be captured on
    456	 * each port upon transmission of the frame, the LSB of VLANID in the
    457	 * ENTRY field provided by the host must be set.
    458	 * Bit 1 of VLANID then specifies the register where the timestamp for
    459	 * this port is stored in.
    460	 */
    461	sja1105_packing(buf, &entry->tsreg,     85, 85, size, op);
    462	sja1105_packing(buf, &entry->takets,    84, 84, size, op);
    463	sja1105_packing(buf, &entry->macaddr,   83, 36, size, op);
    464	sja1105_packing(buf, &entry->destports, 35, 31, size, op);
    465	sja1105_packing(buf, &entry->enfport,   30, 30, size, op);
    466	return size;
    467}
    468
    469static void
    470sja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    471				   enum packing_op op)
    472{
    473	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
    474	u64 mgmtroute = 1;
    475
    476	sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
    477	if (op == PACK)
    478		sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
    479}
    480
    481static size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
    482						   enum packing_op op)
    483{
    484	const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
    485	struct sja1105_mgmt_entry *entry = entry_ptr;
    486
    487	/* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
    488	 * is the same (driver uses it to confirm that frame was sent).
    489	 * So just keep the name from E/T.
    490	 */
    491	sja1105_packing(buf, &entry->tsreg,     71, 71, size, op);
    492	sja1105_packing(buf, &entry->takets,    70, 70, size, op);
    493	sja1105_packing(buf, &entry->macaddr,   69, 22, size, op);
    494	sja1105_packing(buf, &entry->destports, 21, 17, size, op);
    495	sja1105_packing(buf, &entry->enfport,   16, 16, size, op);
    496	return size;
    497}
    498
    499/* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
    500 * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
    501 * between entry (0x2d, 0x2e) and command (0x30).
    502 */
    503static void
    504sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    505				enum packing_op op)
    506{
    507	u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4;
    508	const int size = SJA1105_SIZE_DYN_CMD;
    509
    510	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
    511	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
    512	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
    513	/* Hack - see comments above, applied for 'vlanid' field of
    514	 * struct sja1105_vlan_lookup_entry.
    515	 */
    516	sja1105_packing(buf, &cmd->index, 38, 27,
    517			SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
    518}
    519
    520/* In SJA1110 there is no gap between the command and the data, yay... */
    521static void
    522sja1110_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    523				enum packing_op op)
    524{
    525	u8 *p = buf + SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
    526	const int size = SJA1105_SIZE_DYN_CMD;
    527	u64 type_entry = 0;
    528
    529	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    530	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    531	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    532	/* Hack: treat 'vlanid' field of struct sja1105_vlan_lookup_entry as
    533	 * cmd->index.
    534	 */
    535	sja1105_packing(buf, &cmd->index, 38, 27,
    536			SJA1110_SIZE_VLAN_LOOKUP_ENTRY, op);
    537
    538	/* But the VALIDENT bit has disappeared, now we are supposed to
    539	 * invalidate an entry through the TYPE_ENTRY field of the entry..
    540	 * This is a hack to transform the non-zero quality of the TYPE_ENTRY
    541	 * field into a VALIDENT bit.
    542	 */
    543	if (op == PACK && !cmd->valident) {
    544		sja1105_packing(buf, &type_entry, 40, 39,
    545				SJA1110_SIZE_VLAN_LOOKUP_ENTRY, PACK);
    546	} else if (op == UNPACK) {
    547		sja1105_packing(buf, &type_entry, 40, 39,
    548				SJA1110_SIZE_VLAN_LOOKUP_ENTRY, UNPACK);
    549		cmd->valident = !!type_entry;
    550	}
    551}
    552
    553static void
    554sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    555				  enum packing_op op)
    556{
    557	u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
    558	const int size = SJA1105_SIZE_DYN_CMD;
    559
    560	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    561	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
    562	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
    563	sja1105_packing(p, &cmd->index,    4,  0, size, op);
    564}
    565
    566static void
    567sja1110_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    568				  enum packing_op op)
    569{
    570	u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
    571	const int size = SJA1105_SIZE_DYN_CMD;
    572
    573	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    574	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    575	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    576	sja1105_packing(p, &cmd->index,    4,  0, size, op);
    577}
    578
    579static void
    580sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    581				 enum packing_op op)
    582{
    583	const int size = SJA1105_SIZE_DYN_CMD;
    584	/* Yup, user manual definitions are reversed */
    585	u8 *reg1 = buf + 4;
    586
    587	sja1105_packing(reg1, &cmd->valid, 31, 31, size, op);
    588	sja1105_packing(reg1, &cmd->index, 26, 24, size, op);
    589}
    590
    591static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
    592						 enum packing_op op)
    593{
    594	const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
    595	struct sja1105_mac_config_entry *entry = entry_ptr;
    596	/* Yup, user manual definitions are reversed */
    597	u8 *reg1 = buf + 4;
    598	u8 *reg2 = buf;
    599
    600	sja1105_packing(reg1, &entry->speed,     30, 29, size, op);
    601	sja1105_packing(reg1, &entry->drpdtag,   23, 23, size, op);
    602	sja1105_packing(reg1, &entry->drpuntag,  22, 22, size, op);
    603	sja1105_packing(reg1, &entry->retag,     21, 21, size, op);
    604	sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op);
    605	sja1105_packing(reg1, &entry->egress,    19, 19, size, op);
    606	sja1105_packing(reg1, &entry->ingress,   18, 18, size, op);
    607	sja1105_packing(reg1, &entry->ing_mirr,  17, 17, size, op);
    608	sja1105_packing(reg1, &entry->egr_mirr,  16, 16, size, op);
    609	sja1105_packing(reg1, &entry->vlanprio,  14, 12, size, op);
    610	sja1105_packing(reg1, &entry->vlanid,    11,  0, size, op);
    611	sja1105_packing(reg2, &entry->tp_delin,  31, 16, size, op);
    612	sja1105_packing(reg2, &entry->tp_delout, 15,  0, size, op);
    613	/* MAC configuration table entries which can't be reconfigured:
    614	 * top, base, enabled, ifg, maxage, drpnona664
    615	 */
    616	/* Bogus return value, not used anywhere */
    617	return 0;
    618}
    619
    620static void
    621sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    622				   enum packing_op op)
    623{
    624	const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
    625	u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
    626
    627	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    628	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
    629	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
    630	sja1105_packing(p, &cmd->index,    2,  0, size, op);
    631}
    632
    633static void
    634sja1110_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    635			       enum packing_op op)
    636{
    637	u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
    638	const int size = SJA1105_SIZE_DYN_CMD;
    639
    640	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    641	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    642	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    643	sja1105_packing(p, &cmd->index,    3,  0, size, op);
    644}
    645
    646static void
    647sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    648				       enum packing_op op)
    649{
    650	sja1105_packing(buf, &cmd->valid, 31, 31,
    651			SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
    652}
    653
    654static size_t
    655sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
    656					 enum packing_op op)
    657{
    658	struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
    659
    660	sja1105_packing(buf, &entry->poly, 7, 0,
    661			SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
    662	/* Bogus return value, not used anywhere */
    663	return 0;
    664}
    665
    666static void
    667sja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
    668					 struct sja1105_dyn_cmd *cmd,
    669					 enum packing_op op)
    670{
    671	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY;
    672	const int size = SJA1105_SIZE_DYN_CMD;
    673
    674	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    675	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    676}
    677
    678static void
    679sja1110_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    680				     enum packing_op op)
    681{
    682	u8 *p = buf + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY;
    683	const int size = SJA1105_SIZE_DYN_CMD;
    684
    685	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    686	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    687	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    688}
    689
    690static void
    691sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    692				     enum packing_op op)
    693{
    694	const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
    695
    696	sja1105_packing(buf, &cmd->valid,  31, 31, size, op);
    697	sja1105_packing(buf, &cmd->errors, 30, 30, size, op);
    698}
    699
    700static size_t
    701sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
    702				       enum packing_op op)
    703{
    704	struct sja1105_general_params_entry *entry = entry_ptr;
    705	const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
    706
    707	sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op);
    708	/* Bogus return value, not used anywhere */
    709	return 0;
    710}
    711
    712static void
    713sja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    714				       enum packing_op op)
    715{
    716	u8 *p = buf + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY;
    717	const int size = SJA1105_SIZE_DYN_CMD;
    718
    719	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    720	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
    721	sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op);
    722}
    723
    724static void
    725sja1110_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    726				   enum packing_op op)
    727{
    728	u8 *p = buf + SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
    729	const int size = SJA1105_SIZE_DYN_CMD;
    730
    731	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    732	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    733	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    734}
    735
    736static void
    737sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    738				   enum packing_op op)
    739{
    740	u8 *p = buf + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
    741	const int size = SJA1105_SIZE_DYN_CMD;
    742
    743	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    744	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
    745	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
    746}
    747
    748static void
    749sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    750			      enum packing_op op)
    751{
    752	u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
    753	const int size = SJA1105_SIZE_DYN_CMD;
    754
    755	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
    756	sja1105_packing(p, &cmd->errors,   30, 30, size, op);
    757	sja1105_packing(p, &cmd->valident, 29, 29, size, op);
    758	sja1105_packing(p, &cmd->rdwrset,  28, 28, size, op);
    759	sja1105_packing(p, &cmd->index,     5,  0, size, op);
    760}
    761
    762static void
    763sja1110_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    764			      enum packing_op op)
    765{
    766	u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
    767	const int size = SJA1105_SIZE_DYN_CMD;
    768
    769	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
    770	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
    771	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
    772	sja1105_packing(p, &cmd->valident, 28, 28, size, op);
    773	sja1105_packing(p, &cmd->index,     4,  0, size, op);
    774}
    775
    776static void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    777				      enum packing_op op)
    778{
    779	u8 *p = buf + SJA1105ET_SIZE_CBS_ENTRY;
    780	const int size = SJA1105_SIZE_DYN_CMD;
    781
    782	sja1105_packing(p, &cmd->valid, 31, 31, size, op);
    783	sja1105_packing(p, &cmd->index, 19, 16, size, op);
    784}
    785
    786static size_t sja1105et_cbs_entry_packing(void *buf, void *entry_ptr,
    787					  enum packing_op op)
    788{
    789	const size_t size = SJA1105ET_SIZE_CBS_ENTRY;
    790	struct sja1105_cbs_entry *entry = entry_ptr;
    791	u8 *cmd = buf + size;
    792	u32 *p = buf;
    793
    794	sja1105_packing(cmd, &entry->port, 5, 3, SJA1105_SIZE_DYN_CMD, op);
    795	sja1105_packing(cmd, &entry->prio, 2, 0, SJA1105_SIZE_DYN_CMD, op);
    796	sja1105_packing(p + 3, &entry->credit_lo,  31, 0, size, op);
    797	sja1105_packing(p + 2, &entry->credit_hi,  31, 0, size, op);
    798	sja1105_packing(p + 1, &entry->send_slope, 31, 0, size, op);
    799	sja1105_packing(p + 0, &entry->idle_slope, 31, 0, size, op);
    800	return size;
    801}
    802
    803static void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    804					enum packing_op op)
    805{
    806	u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
    807	const int size = SJA1105_SIZE_DYN_CMD;
    808
    809	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    810	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    811	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    812	sja1105_packing(p, &cmd->index,    3,  0, size, op);
    813}
    814
    815static void sja1110_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    816				    enum packing_op op)
    817{
    818	u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
    819	const int size = SJA1105_SIZE_DYN_CMD;
    820
    821	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    822	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    823	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    824	sja1105_packing(p, &cmd->index,    7,  0, size, op);
    825}
    826
    827static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
    828					    enum packing_op op)
    829{
    830	const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
    831	struct sja1105_cbs_entry *entry = entry_ptr;
    832
    833	sja1105_packing(buf, &entry->port,      159, 157, size, op);
    834	sja1105_packing(buf, &entry->prio,      156, 154, size, op);
    835	sja1105_packing(buf, &entry->credit_lo, 153, 122, size, op);
    836	sja1105_packing(buf, &entry->credit_hi, 121,  90, size, op);
    837	sja1105_packing(buf, &entry->send_slope, 89,  58, size, op);
    838	sja1105_packing(buf, &entry->idle_slope, 57,  26, size, op);
    839	return size;
    840}
    841
    842static size_t sja1110_cbs_entry_packing(void *buf, void *entry_ptr,
    843					enum packing_op op)
    844{
    845	const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
    846	struct sja1105_cbs_entry *entry = entry_ptr;
    847	u64 entry_type = SJA1110_CBS_SHAPER;
    848
    849	sja1105_packing(buf, &entry_type,       159, 159, size, op);
    850	sja1105_packing(buf, &entry->credit_lo, 151, 120, size, op);
    851	sja1105_packing(buf, &entry->credit_hi, 119,  88, size, op);
    852	sja1105_packing(buf, &entry->send_slope, 87,  56, size, op);
    853	sja1105_packing(buf, &entry->idle_slope, 55,  24, size, op);
    854	return size;
    855}
    856
    857static void sja1110_dummy_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    858				      enum packing_op op)
    859{
    860}
    861
    862static void
    863sja1110_l2_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
    864				enum packing_op op)
    865{
    866	u8 *p = buf + SJA1105_SIZE_L2_POLICING_ENTRY;
    867	const int size = SJA1105_SIZE_DYN_CMD;
    868
    869	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
    870	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
    871	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
    872	sja1105_packing(p, &cmd->index,    6,  0, size, op);
    873}
    874
    875#define OP_READ		BIT(0)
    876#define OP_WRITE	BIT(1)
    877#define OP_DEL		BIT(2)
    878#define OP_SEARCH	BIT(3)
    879#define OP_VALID_ANYWAY	BIT(4)
    880
    881/* SJA1105E/T: First generation */
    882const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
    883	[BLK_IDX_VL_LOOKUP] = {
    884		.entry_packing = sja1105et_vl_lookup_entry_packing,
    885		.cmd_packing = sja1105et_vl_lookup_cmd_packing,
    886		.access = OP_WRITE,
    887		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
    888		.packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
    889		.addr = 0x35,
    890	},
    891	[BLK_IDX_L2_LOOKUP] = {
    892		.entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
    893		.cmd_packing = sja1105et_l2_lookup_cmd_packing,
    894		.access = (OP_READ | OP_WRITE | OP_DEL),
    895		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
    896		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
    897		.addr = 0x20,
    898	},
    899	[BLK_IDX_MGMT_ROUTE] = {
    900		.entry_packing = sja1105et_mgmt_route_entry_packing,
    901		.cmd_packing = sja1105et_mgmt_route_cmd_packing,
    902		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
    903		.max_entry_count = SJA1105_NUM_PORTS,
    904		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
    905		.addr = 0x20,
    906	},
    907	[BLK_IDX_VLAN_LOOKUP] = {
    908		.entry_packing = sja1105_vlan_lookup_entry_packing,
    909		.cmd_packing = sja1105_vlan_lookup_cmd_packing,
    910		.access = (OP_WRITE | OP_DEL),
    911		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
    912		.packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
    913		.addr = 0x27,
    914	},
    915	[BLK_IDX_L2_FORWARDING] = {
    916		.entry_packing = sja1105_l2_forwarding_entry_packing,
    917		.cmd_packing = sja1105_l2_forwarding_cmd_packing,
    918		.max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
    919		.access = OP_WRITE,
    920		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
    921		.addr = 0x24,
    922	},
    923	[BLK_IDX_MAC_CONFIG] = {
    924		.entry_packing = sja1105et_mac_config_entry_packing,
    925		.cmd_packing = sja1105et_mac_config_cmd_packing,
    926		.max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
    927		.access = OP_WRITE,
    928		.packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
    929		.addr = 0x36,
    930	},
    931	[BLK_IDX_L2_LOOKUP_PARAMS] = {
    932		.entry_packing = sja1105et_l2_lookup_params_entry_packing,
    933		.cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
    934		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
    935		.access = OP_WRITE,
    936		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
    937		.addr = 0x38,
    938	},
    939	[BLK_IDX_GENERAL_PARAMS] = {
    940		.entry_packing = sja1105et_general_params_entry_packing,
    941		.cmd_packing = sja1105et_general_params_cmd_packing,
    942		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
    943		.access = OP_WRITE,
    944		.packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
    945		.addr = 0x34,
    946	},
    947	[BLK_IDX_RETAGGING] = {
    948		.entry_packing = sja1105_retagging_entry_packing,
    949		.cmd_packing = sja1105_retagging_cmd_packing,
    950		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
    951		.access = (OP_WRITE | OP_DEL),
    952		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
    953		.addr = 0x31,
    954	},
    955	[BLK_IDX_CBS] = {
    956		.entry_packing = sja1105et_cbs_entry_packing,
    957		.cmd_packing = sja1105et_cbs_cmd_packing,
    958		.max_entry_count = SJA1105ET_MAX_CBS_COUNT,
    959		.access = OP_WRITE,
    960		.packed_size = SJA1105ET_SIZE_CBS_DYN_CMD,
    961		.addr = 0x2c,
    962	},
    963};
    964
    965/* SJA1105P/Q/R/S: Second generation */
    966const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
    967	[BLK_IDX_VL_LOOKUP] = {
    968		.entry_packing = sja1105_vl_lookup_entry_packing,
    969		.cmd_packing = sja1105pqrs_vl_lookup_cmd_packing,
    970		.access = (OP_READ | OP_WRITE),
    971		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
    972		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
    973		.addr = 0x47,
    974	},
    975	[BLK_IDX_L2_LOOKUP] = {
    976		.entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
    977		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
    978		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
    979		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
    980		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
    981		.addr = 0x24,
    982	},
    983	[BLK_IDX_MGMT_ROUTE] = {
    984		.entry_packing = sja1105pqrs_mgmt_route_entry_packing,
    985		.cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
    986		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH | OP_VALID_ANYWAY),
    987		.max_entry_count = SJA1105_NUM_PORTS,
    988		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
    989		.addr = 0x24,
    990	},
    991	[BLK_IDX_VLAN_LOOKUP] = {
    992		.entry_packing = sja1105_vlan_lookup_entry_packing,
    993		.cmd_packing = sja1105_vlan_lookup_cmd_packing,
    994		.access = (OP_READ | OP_WRITE | OP_DEL),
    995		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
    996		.packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
    997		.addr = 0x2D,
    998	},
    999	[BLK_IDX_L2_FORWARDING] = {
   1000		.entry_packing = sja1105_l2_forwarding_entry_packing,
   1001		.cmd_packing = sja1105_l2_forwarding_cmd_packing,
   1002		.max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
   1003		.access = OP_WRITE,
   1004		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
   1005		.addr = 0x2A,
   1006	},
   1007	[BLK_IDX_MAC_CONFIG] = {
   1008		.entry_packing = sja1105pqrs_mac_config_entry_packing,
   1009		.cmd_packing = sja1105pqrs_mac_config_cmd_packing,
   1010		.max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
   1011		.access = (OP_READ | OP_WRITE),
   1012		.packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
   1013		.addr = 0x4B,
   1014	},
   1015	[BLK_IDX_L2_LOOKUP_PARAMS] = {
   1016		.entry_packing = sja1105pqrs_l2_lookup_params_entry_packing,
   1017		.cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing,
   1018		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
   1019		.access = (OP_READ | OP_WRITE),
   1020		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
   1021		.addr = 0x54,
   1022	},
   1023	[BLK_IDX_AVB_PARAMS] = {
   1024		.entry_packing = sja1105pqrs_avb_params_entry_packing,
   1025		.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
   1026		.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
   1027		.access = (OP_READ | OP_WRITE),
   1028		.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
   1029		.addr = 0x8003,
   1030	},
   1031	[BLK_IDX_GENERAL_PARAMS] = {
   1032		.entry_packing = sja1105pqrs_general_params_entry_packing,
   1033		.cmd_packing = sja1105pqrs_general_params_cmd_packing,
   1034		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
   1035		.access = (OP_READ | OP_WRITE),
   1036		.packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD,
   1037		.addr = 0x3B,
   1038	},
   1039	[BLK_IDX_RETAGGING] = {
   1040		.entry_packing = sja1105_retagging_entry_packing,
   1041		.cmd_packing = sja1105_retagging_cmd_packing,
   1042		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
   1043		.access = (OP_READ | OP_WRITE | OP_DEL),
   1044		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
   1045		.addr = 0x38,
   1046	},
   1047	[BLK_IDX_CBS] = {
   1048		.entry_packing = sja1105pqrs_cbs_entry_packing,
   1049		.cmd_packing = sja1105pqrs_cbs_cmd_packing,
   1050		.max_entry_count = SJA1105PQRS_MAX_CBS_COUNT,
   1051		.access = OP_WRITE,
   1052		.packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
   1053		.addr = 0x32,
   1054	},
   1055};
   1056
   1057/* SJA1110: Third generation */
   1058const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = {
   1059	[BLK_IDX_VL_LOOKUP] = {
   1060		.entry_packing = sja1110_vl_lookup_entry_packing,
   1061		.cmd_packing = sja1110_vl_lookup_cmd_packing,
   1062		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1063		.max_entry_count = SJA1110_MAX_VL_LOOKUP_COUNT,
   1064		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
   1065		.addr = SJA1110_SPI_ADDR(0x124),
   1066	},
   1067	[BLK_IDX_VL_POLICING] = {
   1068		.entry_packing = sja1110_vl_policing_entry_packing,
   1069		.cmd_packing = sja1110_vl_policing_cmd_packing,
   1070		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1071		.max_entry_count = SJA1110_MAX_VL_POLICING_COUNT,
   1072		.packed_size = SJA1110_SIZE_VL_POLICING_DYN_CMD,
   1073		.addr = SJA1110_SPI_ADDR(0x310),
   1074	},
   1075	[BLK_IDX_L2_LOOKUP] = {
   1076		.entry_packing = sja1110_dyn_l2_lookup_entry_packing,
   1077		.cmd_packing = sja1110_l2_lookup_cmd_packing,
   1078		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
   1079		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
   1080		.packed_size = SJA1110_SIZE_L2_LOOKUP_DYN_CMD,
   1081		.addr = SJA1110_SPI_ADDR(0x8c),
   1082	},
   1083	[BLK_IDX_VLAN_LOOKUP] = {
   1084		.entry_packing = sja1110_vlan_lookup_entry_packing,
   1085		.cmd_packing = sja1110_vlan_lookup_cmd_packing,
   1086		.access = (OP_READ | OP_WRITE | OP_DEL),
   1087		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
   1088		.packed_size = SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD,
   1089		.addr = SJA1110_SPI_ADDR(0xb4),
   1090	},
   1091	[BLK_IDX_L2_FORWARDING] = {
   1092		.entry_packing = sja1110_l2_forwarding_entry_packing,
   1093		.cmd_packing = sja1110_l2_forwarding_cmd_packing,
   1094		.max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
   1095		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1096		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
   1097		.addr = SJA1110_SPI_ADDR(0xa8),
   1098	},
   1099	[BLK_IDX_MAC_CONFIG] = {
   1100		.entry_packing = sja1110_mac_config_entry_packing,
   1101		.cmd_packing = sja1110_mac_config_cmd_packing,
   1102		.max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
   1103		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1104		.packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
   1105		.addr = SJA1110_SPI_ADDR(0x134),
   1106	},
   1107	[BLK_IDX_L2_LOOKUP_PARAMS] = {
   1108		.entry_packing = sja1110_l2_lookup_params_entry_packing,
   1109		.cmd_packing = sja1110_l2_lookup_params_cmd_packing,
   1110		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
   1111		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1112		.packed_size = SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
   1113		.addr = SJA1110_SPI_ADDR(0x158),
   1114	},
   1115	[BLK_IDX_AVB_PARAMS] = {
   1116		.entry_packing = sja1105pqrs_avb_params_entry_packing,
   1117		.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
   1118		.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
   1119		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1120		.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
   1121		.addr = SJA1110_SPI_ADDR(0x2000C),
   1122	},
   1123	[BLK_IDX_GENERAL_PARAMS] = {
   1124		.entry_packing = sja1110_general_params_entry_packing,
   1125		.cmd_packing = sja1110_general_params_cmd_packing,
   1126		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
   1127		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1128		.packed_size = SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD,
   1129		.addr = SJA1110_SPI_ADDR(0xe8),
   1130	},
   1131	[BLK_IDX_RETAGGING] = {
   1132		.entry_packing = sja1110_retagging_entry_packing,
   1133		.cmd_packing = sja1110_retagging_cmd_packing,
   1134		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
   1135		.access = (OP_READ | OP_WRITE | OP_DEL),
   1136		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
   1137		.addr = SJA1110_SPI_ADDR(0xdc),
   1138	},
   1139	[BLK_IDX_CBS] = {
   1140		.entry_packing = sja1110_cbs_entry_packing,
   1141		.cmd_packing = sja1110_cbs_cmd_packing,
   1142		.max_entry_count = SJA1110_MAX_CBS_COUNT,
   1143		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1144		.packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
   1145		.addr = SJA1110_SPI_ADDR(0xc4),
   1146	},
   1147	[BLK_IDX_XMII_PARAMS] = {
   1148		.entry_packing = sja1110_xmii_params_entry_packing,
   1149		.cmd_packing = sja1110_dummy_cmd_packing,
   1150		.max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
   1151		.access = (OP_READ | OP_VALID_ANYWAY),
   1152		.packed_size = SJA1110_SIZE_XMII_PARAMS_DYN_CMD,
   1153		.addr = SJA1110_SPI_ADDR(0x3c),
   1154	},
   1155	[BLK_IDX_L2_POLICING] = {
   1156		.entry_packing = sja1110_l2_policing_entry_packing,
   1157		.cmd_packing = sja1110_l2_policing_cmd_packing,
   1158		.max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
   1159		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
   1160		.packed_size = SJA1110_SIZE_L2_POLICING_DYN_CMD,
   1161		.addr = SJA1110_SPI_ADDR(0x2fc),
   1162	},
   1163	[BLK_IDX_L2_FORWARDING_PARAMS] = {
   1164		.entry_packing = sja1110_l2_forwarding_params_entry_packing,
   1165		.cmd_packing = sja1110_dummy_cmd_packing,
   1166		.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
   1167		.access = (OP_READ | OP_VALID_ANYWAY),
   1168		.packed_size = SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD,
   1169		.addr = SJA1110_SPI_ADDR(0x20000),
   1170	},
   1171};
   1172
   1173#define SJA1105_DYNAMIC_CONFIG_SLEEP_US		10
   1174#define SJA1105_DYNAMIC_CONFIG_TIMEOUT_US	100000
   1175
   1176static int
   1177sja1105_dynamic_config_poll_valid(struct sja1105_private *priv,
   1178				  struct sja1105_dyn_cmd *cmd,
   1179				  const struct sja1105_dynamic_table_ops *ops)
   1180{
   1181	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {};
   1182	int rc;
   1183
   1184	/* We don't _need_ to read the full entry, just the command area which
   1185	 * is a fixed SJA1105_SIZE_DYN_CMD. But our cmd_packing() API expects a
   1186	 * buffer that contains the full entry too. Additionally, our API
   1187	 * doesn't really know how many bytes into the buffer does the command
   1188	 * area really begin. So just read back the whole entry.
   1189	 */
   1190	rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf,
   1191			      ops->packed_size);
   1192	if (rc)
   1193		return rc;
   1194
   1195	/* Unpack the command structure, and return it to the caller in case it
   1196	 * needs to perform further checks on it (VALIDENT).
   1197	 */
   1198	memset(cmd, 0, sizeof(*cmd));
   1199	ops->cmd_packing(packed_buf, cmd, UNPACK);
   1200
   1201	/* Hardware hasn't cleared VALID => still working on it */
   1202	return cmd->valid ? -EAGAIN : 0;
   1203}
   1204
   1205/* Poll the dynamic config entry's control area until the hardware has
   1206 * cleared the VALID bit, which means we have confirmation that it has
   1207 * finished processing the command.
   1208 */
   1209static int
   1210sja1105_dynamic_config_wait_complete(struct sja1105_private *priv,
   1211				     struct sja1105_dyn_cmd *cmd,
   1212				     const struct sja1105_dynamic_table_ops *ops)
   1213{
   1214	int rc;
   1215
   1216	return read_poll_timeout(sja1105_dynamic_config_poll_valid,
   1217				 rc, rc != -EAGAIN,
   1218				 SJA1105_DYNAMIC_CONFIG_SLEEP_US,
   1219				 SJA1105_DYNAMIC_CONFIG_TIMEOUT_US,
   1220				 false, priv, cmd, ops);
   1221}
   1222
   1223/* Provides read access to the settings through the dynamic interface
   1224 * of the switch.
   1225 * @blk_idx	is used as key to select from the sja1105_dynamic_table_ops.
   1226 *		The selection is limited by the hardware in respect to which
   1227 *		configuration blocks can be read through the dynamic interface.
   1228 * @index	is used to retrieve a particular table entry. If negative,
   1229 *		(and if the @blk_idx supports the searching operation) a search
   1230 *		is performed by the @entry parameter.
   1231 * @entry	Type-casted to an unpacked structure that holds a table entry
   1232 *		of the type specified in @blk_idx.
   1233 *		Usually an output argument. If @index is negative, then this
   1234 *		argument is used as input/output: it should be pre-populated
   1235 *		with the element to search for. Entries which support the
   1236 *		search operation will have an "index" field (not the @index
   1237 *		argument to this function) and that is where the found index
   1238 *		will be returned (or left unmodified - thus negative - if not
   1239 *		found).
   1240 */
   1241int sja1105_dynamic_config_read(struct sja1105_private *priv,
   1242				enum sja1105_blk_idx blk_idx,
   1243				int index, void *entry)
   1244{
   1245	const struct sja1105_dynamic_table_ops *ops;
   1246	struct sja1105_dyn_cmd cmd = {0};
   1247	/* SPI payload buffer */
   1248	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
   1249	int rc;
   1250
   1251	if (blk_idx >= BLK_IDX_MAX_DYN)
   1252		return -ERANGE;
   1253
   1254	ops = &priv->info->dyn_ops[blk_idx];
   1255
   1256	if (index >= 0 && index >= ops->max_entry_count)
   1257		return -ERANGE;
   1258	if (index < 0 && !(ops->access & OP_SEARCH))
   1259		return -EOPNOTSUPP;
   1260	if (!(ops->access & OP_READ))
   1261		return -EOPNOTSUPP;
   1262	if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
   1263		return -ERANGE;
   1264	if (!ops->cmd_packing)
   1265		return -EOPNOTSUPP;
   1266	if (!ops->entry_packing)
   1267		return -EOPNOTSUPP;
   1268
   1269	cmd.valid = true; /* Trigger action on table entry */
   1270	cmd.rdwrset = SPI_READ; /* Action is read */
   1271	if (index < 0) {
   1272		/* Avoid copying a signed negative number to an u64 */
   1273		cmd.index = 0;
   1274		cmd.search = true;
   1275	} else {
   1276		cmd.index = index;
   1277		cmd.search = false;
   1278	}
   1279	cmd.valident = true;
   1280	ops->cmd_packing(packed_buf, &cmd, PACK);
   1281
   1282	if (cmd.search)
   1283		ops->entry_packing(packed_buf, entry, PACK);
   1284
   1285	/* Send SPI write operation: read config table entry */
   1286	mutex_lock(&priv->dynamic_config_lock);
   1287	rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
   1288			      ops->packed_size);
   1289	if (rc < 0) {
   1290		mutex_unlock(&priv->dynamic_config_lock);
   1291		return rc;
   1292	}
   1293
   1294	rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops);
   1295	mutex_unlock(&priv->dynamic_config_lock);
   1296	if (rc < 0)
   1297		return rc;
   1298
   1299	if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
   1300		return -ENOENT;
   1301
   1302	/* Don't dereference possibly NULL pointer - maybe caller
   1303	 * only wanted to see whether the entry existed or not.
   1304	 */
   1305	if (entry)
   1306		ops->entry_packing(packed_buf, entry, UNPACK);
   1307	return 0;
   1308}
   1309
   1310int sja1105_dynamic_config_write(struct sja1105_private *priv,
   1311				 enum sja1105_blk_idx blk_idx,
   1312				 int index, void *entry, bool keep)
   1313{
   1314	const struct sja1105_dynamic_table_ops *ops;
   1315	struct sja1105_dyn_cmd cmd = {0};
   1316	/* SPI payload buffer */
   1317	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
   1318	int rc;
   1319
   1320	if (blk_idx >= BLK_IDX_MAX_DYN)
   1321		return -ERANGE;
   1322
   1323	ops = &priv->info->dyn_ops[blk_idx];
   1324
   1325	if (index >= ops->max_entry_count)
   1326		return -ERANGE;
   1327	if (index < 0)
   1328		return -ERANGE;
   1329	if (!(ops->access & OP_WRITE))
   1330		return -EOPNOTSUPP;
   1331	if (!keep && !(ops->access & OP_DEL))
   1332		return -EOPNOTSUPP;
   1333	if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
   1334		return -ERANGE;
   1335
   1336	cmd.valident = keep; /* If false, deletes entry */
   1337	cmd.valid = true; /* Trigger action on table entry */
   1338	cmd.rdwrset = SPI_WRITE; /* Action is write */
   1339	cmd.index = index;
   1340
   1341	if (!ops->cmd_packing)
   1342		return -EOPNOTSUPP;
   1343	ops->cmd_packing(packed_buf, &cmd, PACK);
   1344
   1345	if (!ops->entry_packing)
   1346		return -EOPNOTSUPP;
   1347	/* Don't dereference potentially NULL pointer if just
   1348	 * deleting a table entry is what was requested. For cases
   1349	 * where 'index' field is physically part of entry structure,
   1350	 * and needed here, we deal with that in the cmd_packing callback.
   1351	 */
   1352	if (keep)
   1353		ops->entry_packing(packed_buf, entry, PACK);
   1354
   1355	/* Send SPI write operation: read config table entry */
   1356	mutex_lock(&priv->dynamic_config_lock);
   1357	rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
   1358			      ops->packed_size);
   1359	if (rc < 0) {
   1360		mutex_unlock(&priv->dynamic_config_lock);
   1361		return rc;
   1362	}
   1363
   1364	rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops);
   1365	mutex_unlock(&priv->dynamic_config_lock);
   1366	if (rc < 0)
   1367		return rc;
   1368
   1369	cmd = (struct sja1105_dyn_cmd) {0};
   1370	ops->cmd_packing(packed_buf, &cmd, UNPACK);
   1371	if (cmd.errors)
   1372		return -EINVAL;
   1373
   1374	return 0;
   1375}
   1376
   1377static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
   1378{
   1379	int i;
   1380
   1381	for (i = 0; i < 8; i++) {
   1382		if ((crc ^ byte) & (1 << 7)) {
   1383			crc <<= 1;
   1384			crc ^= poly;
   1385		} else {
   1386			crc <<= 1;
   1387		}
   1388		byte <<= 1;
   1389	}
   1390	return crc;
   1391}
   1392
   1393/* CRC8 algorithm with non-reversed input, non-reversed output,
   1394 * no input xor and no output xor. Code customized for receiving
   1395 * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
   1396 * is also received as argument in the Koopman notation that the switch
   1397 * hardware stores it in.
   1398 */
   1399u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
   1400{
   1401	struct sja1105_l2_lookup_params_entry *l2_lookup_params =
   1402		priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
   1403	u64 input, poly_koopman = l2_lookup_params->poly;
   1404	/* Convert polynomial from Koopman to 'normal' notation */
   1405	u8 poly = (u8)(1 + (poly_koopman << 1));
   1406	u8 crc = 0; /* seed */
   1407	int i;
   1408
   1409	input = ((u64)vid << 48) | ether_addr_to_u64(addr);
   1410
   1411	/* Mask the eight bytes starting from MSB one at a time */
   1412	for (i = 56; i >= 0; i -= 8) {
   1413		u8 byte = (input & (0xffull << i)) >> i;
   1414
   1415		crc = sja1105_crc8_add(crc, byte, poly);
   1416	}
   1417	return crc;
   1418}