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 SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
110 	SJA1105_SIZE_DYN_CMD
111 
112 #define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD			\
113 	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY)
114 
115 #define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD			\
116 	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
117 
118 #define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD			\
119 	(SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
120 
121 #define SJA1105_SIZE_L2_FORWARDING_DYN_CMD			\
122 	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
123 
124 #define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD			\
125 	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY)
126 
127 #define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD			\
128 	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY)
129 
130 #define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD			\
131 	SJA1105_SIZE_DYN_CMD
132 
133 #define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
134 	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)
135 
136 #define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD			\
137 	SJA1105_SIZE_DYN_CMD
138 
139 #define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD			\
140 	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)
141 
142 #define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD			\
143 	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)
144 
145 #define SJA1105_SIZE_RETAGGING_DYN_CMD				\
146 	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_RETAGGING_ENTRY)
147 
148 #define SJA1105ET_SIZE_CBS_DYN_CMD				\
149 	(SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_CBS_ENTRY)
150 
151 #define SJA1105PQRS_SIZE_CBS_DYN_CMD				\
152 	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)
153 
154 #define SJA1105_MAX_DYN_CMD_SIZE				\
155 	SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD
156 
157 struct sja1105_dyn_cmd {
158 	bool search;
159 	u64 valid;
160 	u64 rdwrset;
161 	u64 errors;
162 	u64 valident;
163 	u64 index;
164 };
165 
166 enum sja1105_hostcmd {
167 	SJA1105_HOSTCMD_SEARCH = 1,
168 	SJA1105_HOSTCMD_READ = 2,
169 	SJA1105_HOSTCMD_WRITE = 3,
170 	SJA1105_HOSTCMD_INVALIDATE = 4,
171 };
172 
173 /* Command and entry overlap */
174 static void
175 sja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
176 				enum packing_op op)
177 {
178 	const int size = SJA1105_SIZE_DYN_CMD;
179 
180 	sja1105_packing(buf, &cmd->valid,   31, 31, size, op);
181 	sja1105_packing(buf, &cmd->errors,  30, 30, size, op);
182 	sja1105_packing(buf, &cmd->rdwrset, 29, 29, size, op);
183 	sja1105_packing(buf, &cmd->index,    9,  0, size, op);
184 }
185 
186 /* Command and entry are separate */
187 static void
188 sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
189 				  enum packing_op op)
190 {
191 	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
192 	const int size = SJA1105_SIZE_DYN_CMD;
193 
194 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
195 	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
196 	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
197 	sja1105_packing(p, &cmd->index,    9,  0, size, op);
198 }
199 
200 static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
201 						enum packing_op op)
202 {
203 	struct sja1105_vl_lookup_entry *entry = entry_ptr;
204 	const int size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD;
205 
206 	sja1105_packing(buf, &entry->egrmirr,  21, 17, size, op);
207 	sja1105_packing(buf, &entry->ingrmirr, 16, 16, size, op);
208 	return size;
209 }
210 
211 static void
212 sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
213 				  enum packing_op op)
214 {
215 	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
216 	const int size = SJA1105_SIZE_DYN_CMD;
217 	u64 hostcmd;
218 
219 	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
220 	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
221 	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
222 	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
223 
224 	/* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
225 	 * using it to delete a management route was unsupported. UM10944
226 	 * said about it:
227 	 *
228 	 *   In case of a write access with the MGMTROUTE flag set,
229 	 *   the flag will be ignored. It will always be found cleared
230 	 *   for read accesses with the MGMTROUTE flag set.
231 	 *
232 	 * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there
233 	 * is now another flag called HOSTCMD which does more stuff (quoting
234 	 * from UM11040):
235 	 *
236 	 *   A write request is accepted only when HOSTCMD is set to write host
237 	 *   or invalid. A read request is accepted only when HOSTCMD is set to
238 	 *   search host or read host.
239 	 *
240 	 * So it is possible to translate a RDWRSET/VALIDENT combination into
241 	 * HOSTCMD so that we keep the dynamic command API in place, and
242 	 * at the same time achieve compatibility with the management route
243 	 * command structure.
244 	 */
245 	if (cmd->rdwrset == SPI_READ) {
246 		if (cmd->search)
247 			hostcmd = SJA1105_HOSTCMD_SEARCH;
248 		else
249 			hostcmd = SJA1105_HOSTCMD_READ;
250 	} else {
251 		/* SPI_WRITE */
252 		if (cmd->valident)
253 			hostcmd = SJA1105_HOSTCMD_WRITE;
254 		else
255 			hostcmd = SJA1105_HOSTCMD_INVALIDATE;
256 	}
257 	sja1105_packing(p, &hostcmd, 25, 23, size, op);
258 
259 	/* Hack - The hardware takes the 'index' field within
260 	 * struct sja1105_l2_lookup_entry as the index on which this command
261 	 * will operate. However it will ignore everything else, so 'index'
262 	 * is logically part of command but physically part of entry.
263 	 * Populate the 'index' entry field from within the command callback,
264 	 * such that our API doesn't need to ask for a full-blown entry
265 	 * structure when e.g. a delete is requested.
266 	 */
267 	sja1105_packing(buf, &cmd->index, 15, 6,
268 			SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
269 }
270 
271 /* The switch is so retarded that it makes our command/entry abstraction
272  * crumble apart.
273  *
274  * On P/Q/R/S, the switch tries to say whether a FDB entry
275  * is statically programmed or dynamically learned via a flag called LOCKEDS.
276  * The hardware manual says about this fiels:
277  *
278  *   On write will specify the format of ENTRY.
279  *   On read the flag will be found cleared at times the VALID flag is found
280  *   set.  The flag will also be found cleared in response to a read having the
281  *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
282  *   cleared, the flag be set if the most recent access operated on an entry
283  *   that was either loaded by configuration or through dynamic reconfiguration
284  *   (as opposed to automatically learned entries).
285  *
286  * The trouble with this flag is that it's part of the *command* to access the
287  * dynamic interface, and not part of the *entry* retrieved from it.
288  * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
289  * an output from the switch into the command buffer, and for a
290  * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
291  * (hence we can write either static, or automatically learned entries, from
292  * the core).
293  * But the manual contradicts itself in the last phrase where it says that on
294  * read, LOCKEDS will be set to 1 for all FDB entries written through the
295  * dynamic interface (therefore, the value of LOCKEDS from the
296  * sja1105_dynamic_config_write is not really used for anything, it'll store a
297  * 1 anyway).
298  * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
299  * learned) into the switch, which kind of makes sense.
300  * As for reading through the dynamic interface, it doesn't make too much sense
301  * to put LOCKEDS into the command, since the switch will inevitably have to
302  * ignore it (otherwise a command would be like "read the FDB entry 123, but
303  * only if it's dynamically learned" <- well how am I supposed to know?) and
304  * just use it as an output buffer for its findings. But guess what... that's
305  * what the entry buffer is for!
306  * Unfortunately, what really breaks this abstraction is the fact that it
307  * wasn't designed having the fact in mind that the switch can output
308  * entry-related data as writeback through the command buffer.
309  * However, whether a FDB entry is statically or dynamically learned *is* part
310  * of the entry and not the command data, no matter what the switch thinks.
311  * In order to do that, we'll need to wrap around the
312  * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
313  * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
314  * command buffer.
315  */
316 static size_t
317 sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
318 					enum packing_op op)
319 {
320 	struct sja1105_l2_lookup_entry *entry = entry_ptr;
321 	u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
322 	const int size = SJA1105_SIZE_DYN_CMD;
323 
324 	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
325 
326 	return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
327 }
328 
329 static void
330 sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
331 				enum packing_op op)
332 {
333 	u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
334 	const int size = SJA1105_SIZE_DYN_CMD;
335 
336 	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
337 	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
338 	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
339 	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
340 	/* Hack - see comments above. */
341 	sja1105_packing(buf, &cmd->index, 29, 20,
342 			SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
343 }
344 
345 static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
346 						    enum packing_op op)
347 {
348 	struct sja1105_l2_lookup_entry *entry = entry_ptr;
349 	u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
350 	const int size = SJA1105_SIZE_DYN_CMD;
351 
352 	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
353 
354 	return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
355 }
356 
357 static void
358 sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
359 				 enum packing_op op)
360 {
361 	u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
362 	u64 mgmtroute = 1;
363 
364 	sja1105et_l2_lookup_cmd_packing(buf, cmd, op);
365 	if (op == PACK)
366 		sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
367 }
368 
369 static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
370 						 enum packing_op op)
371 {
372 	struct sja1105_mgmt_entry *entry = entry_ptr;
373 	const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
374 
375 	/* UM10944: To specify if a PTP egress timestamp shall be captured on
376 	 * each port upon transmission of the frame, the LSB of VLANID in the
377 	 * ENTRY field provided by the host must be set.
378 	 * Bit 1 of VLANID then specifies the register where the timestamp for
379 	 * this port is stored in.
380 	 */
381 	sja1105_packing(buf, &entry->tsreg,     85, 85, size, op);
382 	sja1105_packing(buf, &entry->takets,    84, 84, size, op);
383 	sja1105_packing(buf, &entry->macaddr,   83, 36, size, op);
384 	sja1105_packing(buf, &entry->destports, 35, 31, size, op);
385 	sja1105_packing(buf, &entry->enfport,   30, 30, size, op);
386 	return size;
387 }
388 
389 static void
390 sja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
391 				   enum packing_op op)
392 {
393 	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
394 	u64 mgmtroute = 1;
395 
396 	sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
397 	if (op == PACK)
398 		sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
399 }
400 
401 static size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
402 						   enum packing_op op)
403 {
404 	const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
405 	struct sja1105_mgmt_entry *entry = entry_ptr;
406 
407 	/* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
408 	 * is the same (driver uses it to confirm that frame was sent).
409 	 * So just keep the name from E/T.
410 	 */
411 	sja1105_packing(buf, &entry->tsreg,     71, 71, size, op);
412 	sja1105_packing(buf, &entry->takets,    70, 70, size, op);
413 	sja1105_packing(buf, &entry->macaddr,   69, 22, size, op);
414 	sja1105_packing(buf, &entry->destports, 21, 17, size, op);
415 	sja1105_packing(buf, &entry->enfport,   16, 16, size, op);
416 	return size;
417 }
418 
419 /* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
420  * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
421  * between entry (0x2d, 0x2e) and command (0x30).
422  */
423 static void
424 sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
425 				enum packing_op op)
426 {
427 	u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4;
428 	const int size = SJA1105_SIZE_DYN_CMD;
429 
430 	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
431 	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
432 	sja1105_packing(p, &cmd->valident, 27, 27, size, op);
433 	/* Hack - see comments above, applied for 'vlanid' field of
434 	 * struct sja1105_vlan_lookup_entry.
435 	 */
436 	sja1105_packing(buf, &cmd->index, 38, 27,
437 			SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
438 }
439 
440 static void
441 sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
442 				  enum packing_op op)
443 {
444 	u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
445 	const int size = SJA1105_SIZE_DYN_CMD;
446 
447 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
448 	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
449 	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
450 	sja1105_packing(p, &cmd->index,    4,  0, size, op);
451 }
452 
453 static void
454 sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
455 				 enum packing_op op)
456 {
457 	const int size = SJA1105_SIZE_DYN_CMD;
458 	/* Yup, user manual definitions are reversed */
459 	u8 *reg1 = buf + 4;
460 
461 	sja1105_packing(reg1, &cmd->valid, 31, 31, size, op);
462 	sja1105_packing(reg1, &cmd->index, 26, 24, size, op);
463 }
464 
465 static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
466 						 enum packing_op op)
467 {
468 	const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
469 	struct sja1105_mac_config_entry *entry = entry_ptr;
470 	/* Yup, user manual definitions are reversed */
471 	u8 *reg1 = buf + 4;
472 	u8 *reg2 = buf;
473 
474 	sja1105_packing(reg1, &entry->speed,     30, 29, size, op);
475 	sja1105_packing(reg1, &entry->drpdtag,   23, 23, size, op);
476 	sja1105_packing(reg1, &entry->drpuntag,  22, 22, size, op);
477 	sja1105_packing(reg1, &entry->retag,     21, 21, size, op);
478 	sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op);
479 	sja1105_packing(reg1, &entry->egress,    19, 19, size, op);
480 	sja1105_packing(reg1, &entry->ingress,   18, 18, size, op);
481 	sja1105_packing(reg1, &entry->ing_mirr,  17, 17, size, op);
482 	sja1105_packing(reg1, &entry->egr_mirr,  16, 16, size, op);
483 	sja1105_packing(reg1, &entry->vlanprio,  14, 12, size, op);
484 	sja1105_packing(reg1, &entry->vlanid,    11,  0, size, op);
485 	sja1105_packing(reg2, &entry->tp_delin,  31, 16, size, op);
486 	sja1105_packing(reg2, &entry->tp_delout, 15,  0, size, op);
487 	/* MAC configuration table entries which can't be reconfigured:
488 	 * top, base, enabled, ifg, maxage, drpnona664
489 	 */
490 	/* Bogus return value, not used anywhere */
491 	return 0;
492 }
493 
494 static void
495 sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
496 				   enum packing_op op)
497 {
498 	const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
499 	u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
500 
501 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
502 	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
503 	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
504 	sja1105_packing(p, &cmd->index,    2,  0, size, op);
505 }
506 
507 static void
508 sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
509 				       enum packing_op op)
510 {
511 	sja1105_packing(buf, &cmd->valid, 31, 31,
512 			SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
513 }
514 
515 static size_t
516 sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
517 					 enum packing_op op)
518 {
519 	struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
520 
521 	sja1105_packing(buf, &entry->poly, 7, 0,
522 			SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
523 	/* Bogus return value, not used anywhere */
524 	return 0;
525 }
526 
527 static void
528 sja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
529 					 struct sja1105_dyn_cmd *cmd,
530 					 enum packing_op op)
531 {
532 	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY;
533 	const int size = SJA1105_SIZE_DYN_CMD;
534 
535 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
536 	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
537 }
538 
539 static void
540 sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
541 				     enum packing_op op)
542 {
543 	const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
544 
545 	sja1105_packing(buf, &cmd->valid,  31, 31, size, op);
546 	sja1105_packing(buf, &cmd->errors, 30, 30, size, op);
547 }
548 
549 static size_t
550 sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
551 				       enum packing_op op)
552 {
553 	struct sja1105_general_params_entry *entry = entry_ptr;
554 	const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
555 
556 	sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op);
557 	/* Bogus return value, not used anywhere */
558 	return 0;
559 }
560 
561 static void
562 sja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
563 				       enum packing_op op)
564 {
565 	u8 *p = buf + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY;
566 	const int size = SJA1105_SIZE_DYN_CMD;
567 
568 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
569 	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
570 	sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op);
571 }
572 
573 static void
574 sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
575 				   enum packing_op op)
576 {
577 	u8 *p = buf + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
578 	const int size = SJA1105_SIZE_DYN_CMD;
579 
580 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
581 	sja1105_packing(p, &cmd->errors,  30, 30, size, op);
582 	sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
583 }
584 
585 static void
586 sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
587 			      enum packing_op op)
588 {
589 	u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
590 	const int size = SJA1105_SIZE_DYN_CMD;
591 
592 	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
593 	sja1105_packing(p, &cmd->errors,   30, 30, size, op);
594 	sja1105_packing(p, &cmd->valident, 29, 29, size, op);
595 	sja1105_packing(p, &cmd->rdwrset,  28, 28, size, op);
596 	sja1105_packing(p, &cmd->index,     5,  0, size, op);
597 }
598 
599 static void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
600 				      enum packing_op op)
601 {
602 	u8 *p = buf + SJA1105ET_SIZE_CBS_ENTRY;
603 	const int size = SJA1105_SIZE_DYN_CMD;
604 
605 	sja1105_packing(p, &cmd->valid, 31, 31, size, op);
606 	sja1105_packing(p, &cmd->index, 19, 16, size, op);
607 }
608 
609 static size_t sja1105et_cbs_entry_packing(void *buf, void *entry_ptr,
610 					  enum packing_op op)
611 {
612 	const size_t size = SJA1105ET_SIZE_CBS_ENTRY;
613 	struct sja1105_cbs_entry *entry = entry_ptr;
614 	u8 *cmd = buf + size;
615 	u32 *p = buf;
616 
617 	sja1105_packing(cmd, &entry->port, 5, 3, SJA1105_SIZE_DYN_CMD, op);
618 	sja1105_packing(cmd, &entry->prio, 2, 0, SJA1105_SIZE_DYN_CMD, op);
619 	sja1105_packing(p + 3, &entry->credit_lo,  31, 0, size, op);
620 	sja1105_packing(p + 2, &entry->credit_hi,  31, 0, size, op);
621 	sja1105_packing(p + 1, &entry->send_slope, 31, 0, size, op);
622 	sja1105_packing(p + 0, &entry->idle_slope, 31, 0, size, op);
623 	return size;
624 }
625 
626 static void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
627 					enum packing_op op)
628 {
629 	u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
630 	const int size = SJA1105_SIZE_DYN_CMD;
631 
632 	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
633 	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
634 	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
635 	sja1105_packing(p, &cmd->index,    3,  0, size, op);
636 }
637 
638 static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
639 					    enum packing_op op)
640 {
641 	const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
642 	struct sja1105_cbs_entry *entry = entry_ptr;
643 
644 	sja1105_packing(buf, &entry->port,      159, 157, size, op);
645 	sja1105_packing(buf, &entry->prio,      156, 154, size, op);
646 	sja1105_packing(buf, &entry->credit_lo, 153, 122, size, op);
647 	sja1105_packing(buf, &entry->credit_hi, 121,  90, size, op);
648 	sja1105_packing(buf, &entry->send_slope, 89,  58, size, op);
649 	sja1105_packing(buf, &entry->idle_slope, 57,  26, size, op);
650 	return size;
651 }
652 
653 #define OP_READ		BIT(0)
654 #define OP_WRITE	BIT(1)
655 #define OP_DEL		BIT(2)
656 #define OP_SEARCH	BIT(3)
657 #define OP_VALID_ANYWAY	BIT(4)
658 
659 /* SJA1105E/T: First generation */
660 const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
661 	[BLK_IDX_VL_LOOKUP] = {
662 		.entry_packing = sja1105et_vl_lookup_entry_packing,
663 		.cmd_packing = sja1105et_vl_lookup_cmd_packing,
664 		.access = OP_WRITE,
665 		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
666 		.packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
667 		.addr = 0x35,
668 	},
669 	[BLK_IDX_L2_LOOKUP] = {
670 		.entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
671 		.cmd_packing = sja1105et_l2_lookup_cmd_packing,
672 		.access = (OP_READ | OP_WRITE | OP_DEL),
673 		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
674 		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
675 		.addr = 0x20,
676 	},
677 	[BLK_IDX_MGMT_ROUTE] = {
678 		.entry_packing = sja1105et_mgmt_route_entry_packing,
679 		.cmd_packing = sja1105et_mgmt_route_cmd_packing,
680 		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
681 		.max_entry_count = SJA1105_NUM_PORTS,
682 		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
683 		.addr = 0x20,
684 	},
685 	[BLK_IDX_VLAN_LOOKUP] = {
686 		.entry_packing = sja1105_vlan_lookup_entry_packing,
687 		.cmd_packing = sja1105_vlan_lookup_cmd_packing,
688 		.access = (OP_WRITE | OP_DEL),
689 		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
690 		.packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
691 		.addr = 0x27,
692 	},
693 	[BLK_IDX_L2_FORWARDING] = {
694 		.entry_packing = sja1105_l2_forwarding_entry_packing,
695 		.cmd_packing = sja1105_l2_forwarding_cmd_packing,
696 		.max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
697 		.access = OP_WRITE,
698 		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
699 		.addr = 0x24,
700 	},
701 	[BLK_IDX_MAC_CONFIG] = {
702 		.entry_packing = sja1105et_mac_config_entry_packing,
703 		.cmd_packing = sja1105et_mac_config_cmd_packing,
704 		.max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
705 		.access = OP_WRITE,
706 		.packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
707 		.addr = 0x36,
708 	},
709 	[BLK_IDX_L2_LOOKUP_PARAMS] = {
710 		.entry_packing = sja1105et_l2_lookup_params_entry_packing,
711 		.cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
712 		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
713 		.access = OP_WRITE,
714 		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
715 		.addr = 0x38,
716 	},
717 	[BLK_IDX_GENERAL_PARAMS] = {
718 		.entry_packing = sja1105et_general_params_entry_packing,
719 		.cmd_packing = sja1105et_general_params_cmd_packing,
720 		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
721 		.access = OP_WRITE,
722 		.packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
723 		.addr = 0x34,
724 	},
725 	[BLK_IDX_RETAGGING] = {
726 		.entry_packing = sja1105_retagging_entry_packing,
727 		.cmd_packing = sja1105_retagging_cmd_packing,
728 		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
729 		.access = (OP_WRITE | OP_DEL),
730 		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
731 		.addr = 0x31,
732 	},
733 	[BLK_IDX_CBS] = {
734 		.entry_packing = sja1105et_cbs_entry_packing,
735 		.cmd_packing = sja1105et_cbs_cmd_packing,
736 		.max_entry_count = SJA1105ET_MAX_CBS_COUNT,
737 		.access = OP_WRITE,
738 		.packed_size = SJA1105ET_SIZE_CBS_DYN_CMD,
739 		.addr = 0x2c,
740 	},
741 };
742 
743 /* SJA1105P/Q/R/S: Second generation */
744 const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
745 	[BLK_IDX_VL_LOOKUP] = {
746 		.entry_packing = sja1105_vl_lookup_entry_packing,
747 		.cmd_packing = sja1105pqrs_vl_lookup_cmd_packing,
748 		.access = (OP_READ | OP_WRITE),
749 		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
750 		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
751 		.addr = 0x47,
752 	},
753 	[BLK_IDX_L2_LOOKUP] = {
754 		.entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
755 		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
756 		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
757 		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
758 		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
759 		.addr = 0x24,
760 	},
761 	[BLK_IDX_MGMT_ROUTE] = {
762 		.entry_packing = sja1105pqrs_mgmt_route_entry_packing,
763 		.cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
764 		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH | OP_VALID_ANYWAY),
765 		.max_entry_count = SJA1105_NUM_PORTS,
766 		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
767 		.addr = 0x24,
768 	},
769 	[BLK_IDX_VLAN_LOOKUP] = {
770 		.entry_packing = sja1105_vlan_lookup_entry_packing,
771 		.cmd_packing = sja1105_vlan_lookup_cmd_packing,
772 		.access = (OP_READ | OP_WRITE | OP_DEL),
773 		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
774 		.packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
775 		.addr = 0x2D,
776 	},
777 	[BLK_IDX_L2_FORWARDING] = {
778 		.entry_packing = sja1105_l2_forwarding_entry_packing,
779 		.cmd_packing = sja1105_l2_forwarding_cmd_packing,
780 		.max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
781 		.access = OP_WRITE,
782 		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
783 		.addr = 0x2A,
784 	},
785 	[BLK_IDX_MAC_CONFIG] = {
786 		.entry_packing = sja1105pqrs_mac_config_entry_packing,
787 		.cmd_packing = sja1105pqrs_mac_config_cmd_packing,
788 		.max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
789 		.access = (OP_READ | OP_WRITE),
790 		.packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
791 		.addr = 0x4B,
792 	},
793 	[BLK_IDX_L2_LOOKUP_PARAMS] = {
794 		.entry_packing = sja1105pqrs_l2_lookup_params_entry_packing,
795 		.cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing,
796 		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
797 		.access = (OP_READ | OP_WRITE),
798 		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
799 		.addr = 0x54,
800 	},
801 	[BLK_IDX_AVB_PARAMS] = {
802 		.entry_packing = sja1105pqrs_avb_params_entry_packing,
803 		.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
804 		.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
805 		.access = (OP_READ | OP_WRITE),
806 		.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
807 		.addr = 0x8003,
808 	},
809 	[BLK_IDX_GENERAL_PARAMS] = {
810 		.entry_packing = sja1105pqrs_general_params_entry_packing,
811 		.cmd_packing = sja1105pqrs_general_params_cmd_packing,
812 		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
813 		.access = (OP_READ | OP_WRITE),
814 		.packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD,
815 		.addr = 0x3B,
816 	},
817 	[BLK_IDX_RETAGGING] = {
818 		.entry_packing = sja1105_retagging_entry_packing,
819 		.cmd_packing = sja1105_retagging_cmd_packing,
820 		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
821 		.access = (OP_READ | OP_WRITE | OP_DEL),
822 		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
823 		.addr = 0x38,
824 	},
825 	[BLK_IDX_CBS] = {
826 		.entry_packing = sja1105pqrs_cbs_entry_packing,
827 		.cmd_packing = sja1105pqrs_cbs_cmd_packing,
828 		.max_entry_count = SJA1105PQRS_MAX_CBS_COUNT,
829 		.access = OP_WRITE,
830 		.packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
831 		.addr = 0x32,
832 	},
833 };
834 
835 /* Provides read access to the settings through the dynamic interface
836  * of the switch.
837  * @blk_idx	is used as key to select from the sja1105_dynamic_table_ops.
838  *		The selection is limited by the hardware in respect to which
839  *		configuration blocks can be read through the dynamic interface.
840  * @index	is used to retrieve a particular table entry. If negative,
841  *		(and if the @blk_idx supports the searching operation) a search
842  *		is performed by the @entry parameter.
843  * @entry	Type-casted to an unpacked structure that holds a table entry
844  *		of the type specified in @blk_idx.
845  *		Usually an output argument. If @index is negative, then this
846  *		argument is used as input/output: it should be pre-populated
847  *		with the element to search for. Entries which support the
848  *		search operation will have an "index" field (not the @index
849  *		argument to this function) and that is where the found index
850  *		will be returned (or left unmodified - thus negative - if not
851  *		found).
852  */
853 int sja1105_dynamic_config_read(struct sja1105_private *priv,
854 				enum sja1105_blk_idx blk_idx,
855 				int index, void *entry)
856 {
857 	const struct sja1105_dynamic_table_ops *ops;
858 	struct sja1105_dyn_cmd cmd = {0};
859 	/* SPI payload buffer */
860 	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
861 	int retries = 3;
862 	int rc;
863 
864 	if (blk_idx >= BLK_IDX_MAX_DYN)
865 		return -ERANGE;
866 
867 	ops = &priv->info->dyn_ops[blk_idx];
868 
869 	if (index >= 0 && index >= ops->max_entry_count)
870 		return -ERANGE;
871 	if (index < 0 && !(ops->access & OP_SEARCH))
872 		return -EOPNOTSUPP;
873 	if (!(ops->access & OP_READ))
874 		return -EOPNOTSUPP;
875 	if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
876 		return -ERANGE;
877 	if (!ops->cmd_packing)
878 		return -EOPNOTSUPP;
879 	if (!ops->entry_packing)
880 		return -EOPNOTSUPP;
881 
882 	cmd.valid = true; /* Trigger action on table entry */
883 	cmd.rdwrset = SPI_READ; /* Action is read */
884 	if (index < 0) {
885 		/* Avoid copying a signed negative number to an u64 */
886 		cmd.index = 0;
887 		cmd.search = true;
888 	} else {
889 		cmd.index = index;
890 		cmd.search = false;
891 	}
892 	cmd.valident = true;
893 	ops->cmd_packing(packed_buf, &cmd, PACK);
894 
895 	if (cmd.search)
896 		ops->entry_packing(packed_buf, entry, PACK);
897 
898 	/* Send SPI write operation: read config table entry */
899 	rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
900 			      ops->packed_size);
901 	if (rc < 0)
902 		return rc;
903 
904 	/* Loop until we have confirmation that hardware has finished
905 	 * processing the command and has cleared the VALID field
906 	 */
907 	do {
908 		memset(packed_buf, 0, ops->packed_size);
909 
910 		/* Retrieve the read operation's result */
911 		rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf,
912 				      ops->packed_size);
913 		if (rc < 0)
914 			return rc;
915 
916 		cmd = (struct sja1105_dyn_cmd) {0};
917 		ops->cmd_packing(packed_buf, &cmd, UNPACK);
918 
919 		if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
920 			return -ENOENT;
921 		cpu_relax();
922 	} while (cmd.valid && --retries);
923 
924 	if (cmd.valid)
925 		return -ETIMEDOUT;
926 
927 	/* Don't dereference possibly NULL pointer - maybe caller
928 	 * only wanted to see whether the entry existed or not.
929 	 */
930 	if (entry)
931 		ops->entry_packing(packed_buf, entry, UNPACK);
932 	return 0;
933 }
934 
935 int sja1105_dynamic_config_write(struct sja1105_private *priv,
936 				 enum sja1105_blk_idx blk_idx,
937 				 int index, void *entry, bool keep)
938 {
939 	const struct sja1105_dynamic_table_ops *ops;
940 	struct sja1105_dyn_cmd cmd = {0};
941 	/* SPI payload buffer */
942 	u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
943 	int rc;
944 
945 	if (blk_idx >= BLK_IDX_MAX_DYN)
946 		return -ERANGE;
947 
948 	ops = &priv->info->dyn_ops[blk_idx];
949 
950 	if (index >= ops->max_entry_count)
951 		return -ERANGE;
952 	if (index < 0)
953 		return -ERANGE;
954 	if (!(ops->access & OP_WRITE))
955 		return -EOPNOTSUPP;
956 	if (!keep && !(ops->access & OP_DEL))
957 		return -EOPNOTSUPP;
958 	if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
959 		return -ERANGE;
960 
961 	cmd.valident = keep; /* If false, deletes entry */
962 	cmd.valid = true; /* Trigger action on table entry */
963 	cmd.rdwrset = SPI_WRITE; /* Action is write */
964 	cmd.index = index;
965 
966 	if (!ops->cmd_packing)
967 		return -EOPNOTSUPP;
968 	ops->cmd_packing(packed_buf, &cmd, PACK);
969 
970 	if (!ops->entry_packing)
971 		return -EOPNOTSUPP;
972 	/* Don't dereference potentially NULL pointer if just
973 	 * deleting a table entry is what was requested. For cases
974 	 * where 'index' field is physically part of entry structure,
975 	 * and needed here, we deal with that in the cmd_packing callback.
976 	 */
977 	if (keep)
978 		ops->entry_packing(packed_buf, entry, PACK);
979 
980 	/* Send SPI write operation: read config table entry */
981 	rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
982 			      ops->packed_size);
983 	if (rc < 0)
984 		return rc;
985 
986 	cmd = (struct sja1105_dyn_cmd) {0};
987 	ops->cmd_packing(packed_buf, &cmd, UNPACK);
988 	if (cmd.errors)
989 		return -EINVAL;
990 
991 	return 0;
992 }
993 
994 static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
995 {
996 	int i;
997 
998 	for (i = 0; i < 8; i++) {
999 		if ((crc ^ byte) & (1 << 7)) {
1000 			crc <<= 1;
1001 			crc ^= poly;
1002 		} else {
1003 			crc <<= 1;
1004 		}
1005 		byte <<= 1;
1006 	}
1007 	return crc;
1008 }
1009 
1010 /* CRC8 algorithm with non-reversed input, non-reversed output,
1011  * no input xor and no output xor. Code customized for receiving
1012  * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
1013  * is also received as argument in the Koopman notation that the switch
1014  * hardware stores it in.
1015  */
1016 u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
1017 {
1018 	struct sja1105_l2_lookup_params_entry *l2_lookup_params =
1019 		priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
1020 	u64 poly_koopman = l2_lookup_params->poly;
1021 	/* Convert polynomial from Koopman to 'normal' notation */
1022 	u8 poly = (u8)(1 + (poly_koopman << 1));
1023 	u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid;
1024 	u64 input = (vlanid << 48) | ether_addr_to_u64(addr);
1025 	u8 crc = 0; /* seed */
1026 	int i;
1027 
1028 	/* Mask the eight bytes starting from MSB one at a time */
1029 	for (i = 56; i >= 0; i -= 8) {
1030 		u8 byte = (input & (0xffull << i)) >> i;
1031 
1032 		crc = sja1105_crc8_add(crc, byte, poly);
1033 	}
1034 	return crc;
1035 }
1036