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