]> Git Repo - linux.git/blob - drivers/net/dsa/sja1105/sja1105_dynamic_config.c
drm/nouveau/kms: Don't change EDID when it hasn't actually changed
[linux.git] / drivers / net / dsa / sja1105 / sja1105_dynamic_config.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018-2019, Vladimir Oltean <[email protected]>
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 const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
642         [BLK_IDX_VL_LOOKUP] = {
643                 .entry_packing = sja1105et_vl_lookup_entry_packing,
644                 .cmd_packing = sja1105_vl_lookup_cmd_packing,
645                 .access = OP_WRITE,
646                 .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
647                 .packed_size = SJA1105ET_SJA1105_SIZE_VL_LOOKUP_DYN_CMD,
648                 .addr = 0x35,
649         },
650         [BLK_IDX_L2_LOOKUP] = {
651                 .entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
652                 .cmd_packing = sja1105et_l2_lookup_cmd_packing,
653                 .access = (OP_READ | OP_WRITE | OP_DEL),
654                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
655                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
656                 .addr = 0x20,
657         },
658         [BLK_IDX_MGMT_ROUTE] = {
659                 .entry_packing = sja1105et_mgmt_route_entry_packing,
660                 .cmd_packing = sja1105et_mgmt_route_cmd_packing,
661                 .access = (OP_READ | OP_WRITE),
662                 .max_entry_count = SJA1105_NUM_PORTS,
663                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
664                 .addr = 0x20,
665         },
666         [BLK_IDX_VLAN_LOOKUP] = {
667                 .entry_packing = sja1105_vlan_lookup_entry_packing,
668                 .cmd_packing = sja1105_vlan_lookup_cmd_packing,
669                 .access = (OP_WRITE | OP_DEL),
670                 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
671                 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
672                 .addr = 0x27,
673         },
674         [BLK_IDX_L2_FORWARDING] = {
675                 .entry_packing = sja1105_l2_forwarding_entry_packing,
676                 .cmd_packing = sja1105_l2_forwarding_cmd_packing,
677                 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
678                 .access = OP_WRITE,
679                 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
680                 .addr = 0x24,
681         },
682         [BLK_IDX_MAC_CONFIG] = {
683                 .entry_packing = sja1105et_mac_config_entry_packing,
684                 .cmd_packing = sja1105et_mac_config_cmd_packing,
685                 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
686                 .access = OP_WRITE,
687                 .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
688                 .addr = 0x36,
689         },
690         [BLK_IDX_L2_LOOKUP_PARAMS] = {
691                 .entry_packing = sja1105et_l2_lookup_params_entry_packing,
692                 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
693                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
694                 .access = OP_WRITE,
695                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
696                 .addr = 0x38,
697         },
698         [BLK_IDX_GENERAL_PARAMS] = {
699                 .entry_packing = sja1105et_general_params_entry_packing,
700                 .cmd_packing = sja1105et_general_params_cmd_packing,
701                 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
702                 .access = OP_WRITE,
703                 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
704                 .addr = 0x34,
705         },
706         [BLK_IDX_RETAGGING] = {
707                 .entry_packing = sja1105_retagging_entry_packing,
708                 .cmd_packing = sja1105_retagging_cmd_packing,
709                 .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
710                 .access = (OP_WRITE | OP_DEL),
711                 .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
712                 .addr = 0x31,
713         },
714         [BLK_IDX_CBS] = {
715                 .entry_packing = sja1105et_cbs_entry_packing,
716                 .cmd_packing = sja1105et_cbs_cmd_packing,
717                 .max_entry_count = SJA1105ET_MAX_CBS_COUNT,
718                 .access = OP_WRITE,
719                 .packed_size = SJA1105ET_SIZE_CBS_DYN_CMD,
720                 .addr = 0x2c,
721         },
722 };
723
724 /* SJA1105P/Q/R/S: Second generation */
725 const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
726         [BLK_IDX_VL_LOOKUP] = {
727                 .entry_packing = sja1105_vl_lookup_entry_packing,
728                 .cmd_packing = sja1105_vl_lookup_cmd_packing,
729                 .access = (OP_READ | OP_WRITE),
730                 .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
731                 .packed_size = SJA1105PQRS_SJA1105_SIZE_VL_LOOKUP_DYN_CMD,
732                 .addr = 0x47,
733         },
734         [BLK_IDX_L2_LOOKUP] = {
735                 .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
736                 .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
737                 .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
738                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
739                 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
740                 .addr = 0x24,
741         },
742         [BLK_IDX_MGMT_ROUTE] = {
743                 .entry_packing = sja1105pqrs_mgmt_route_entry_packing,
744                 .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
745                 .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
746                 .max_entry_count = SJA1105_NUM_PORTS,
747                 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
748                 .addr = 0x24,
749         },
750         [BLK_IDX_VLAN_LOOKUP] = {
751                 .entry_packing = sja1105_vlan_lookup_entry_packing,
752                 .cmd_packing = sja1105_vlan_lookup_cmd_packing,
753                 .access = (OP_READ | OP_WRITE | OP_DEL),
754                 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
755                 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
756                 .addr = 0x2D,
757         },
758         [BLK_IDX_L2_FORWARDING] = {
759                 .entry_packing = sja1105_l2_forwarding_entry_packing,
760                 .cmd_packing = sja1105_l2_forwarding_cmd_packing,
761                 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
762                 .access = OP_WRITE,
763                 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
764                 .addr = 0x2A,
765         },
766         [BLK_IDX_MAC_CONFIG] = {
767                 .entry_packing = sja1105pqrs_mac_config_entry_packing,
768                 .cmd_packing = sja1105pqrs_mac_config_cmd_packing,
769                 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
770                 .access = (OP_READ | OP_WRITE),
771                 .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
772                 .addr = 0x4B,
773         },
774         [BLK_IDX_L2_LOOKUP_PARAMS] = {
775                 .entry_packing = sja1105pqrs_l2_lookup_params_entry_packing,
776                 .cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing,
777                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
778                 .access = (OP_READ | OP_WRITE),
779                 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
780                 .addr = 0x54,
781         },
782         [BLK_IDX_AVB_PARAMS] = {
783                 .entry_packing = sja1105pqrs_avb_params_entry_packing,
784                 .cmd_packing = sja1105pqrs_avb_params_cmd_packing,
785                 .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
786                 .access = (OP_READ | OP_WRITE),
787                 .packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
788                 .addr = 0x8003,
789         },
790         [BLK_IDX_GENERAL_PARAMS] = {
791                 .entry_packing = sja1105pqrs_general_params_entry_packing,
792                 .cmd_packing = sja1105pqrs_general_params_cmd_packing,
793                 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
794                 .access = (OP_READ | OP_WRITE),
795                 .packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD,
796                 .addr = 0x3B,
797         },
798         [BLK_IDX_RETAGGING] = {
799                 .entry_packing = sja1105_retagging_entry_packing,
800                 .cmd_packing = sja1105_retagging_cmd_packing,
801                 .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
802                 .access = (OP_READ | OP_WRITE | OP_DEL),
803                 .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
804                 .addr = 0x38,
805         },
806         [BLK_IDX_CBS] = {
807                 .entry_packing = sja1105pqrs_cbs_entry_packing,
808                 .cmd_packing = sja1105pqrs_cbs_cmd_packing,
809                 .max_entry_count = SJA1105PQRS_MAX_CBS_COUNT,
810                 .access = OP_WRITE,
811                 .packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
812                 .addr = 0x32,
813         },
814 };
815
816 /* Provides read access to the settings through the dynamic interface
817  * of the switch.
818  * @blk_idx     is used as key to select from the sja1105_dynamic_table_ops.
819  *              The selection is limited by the hardware in respect to which
820  *              configuration blocks can be read through the dynamic interface.
821  * @index       is used to retrieve a particular table entry. If negative,
822  *              (and if the @blk_idx supports the searching operation) a search
823  *              is performed by the @entry parameter.
824  * @entry       Type-casted to an unpacked structure that holds a table entry
825  *              of the type specified in @blk_idx.
826  *              Usually an output argument. If @index is negative, then this
827  *              argument is used as input/output: it should be pre-populated
828  *              with the element to search for. Entries which support the
829  *              search operation will have an "index" field (not the @index
830  *              argument to this function) and that is where the found index
831  *              will be returned (or left unmodified - thus negative - if not
832  *              found).
833  */
834 int sja1105_dynamic_config_read(struct sja1105_private *priv,
835                                 enum sja1105_blk_idx blk_idx,
836                                 int index, void *entry)
837 {
838         const struct sja1105_dynamic_table_ops *ops;
839         struct sja1105_dyn_cmd cmd = {0};
840         /* SPI payload buffer */
841         u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
842         int retries = 3;
843         int rc;
844
845         if (blk_idx >= BLK_IDX_MAX_DYN)
846                 return -ERANGE;
847
848         ops = &priv->info->dyn_ops[blk_idx];
849
850         if (index >= 0 && index >= ops->max_entry_count)
851                 return -ERANGE;
852         if (index < 0 && !(ops->access & OP_SEARCH))
853                 return -EOPNOTSUPP;
854         if (!(ops->access & OP_READ))
855                 return -EOPNOTSUPP;
856         if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
857                 return -ERANGE;
858         if (!ops->cmd_packing)
859                 return -EOPNOTSUPP;
860         if (!ops->entry_packing)
861                 return -EOPNOTSUPP;
862
863         cmd.valid = true; /* Trigger action on table entry */
864         cmd.rdwrset = SPI_READ; /* Action is read */
865         if (index < 0) {
866                 /* Avoid copying a signed negative number to an u64 */
867                 cmd.index = 0;
868                 cmd.search = true;
869         } else {
870                 cmd.index = index;
871                 cmd.search = false;
872         }
873         cmd.valident = true;
874         ops->cmd_packing(packed_buf, &cmd, PACK);
875
876         if (cmd.search)
877                 ops->entry_packing(packed_buf, entry, PACK);
878
879         /* Send SPI write operation: read config table entry */
880         rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
881                               ops->packed_size);
882         if (rc < 0)
883                 return rc;
884
885         /* Loop until we have confirmation that hardware has finished
886          * processing the command and has cleared the VALID field
887          */
888         do {
889                 memset(packed_buf, 0, ops->packed_size);
890
891                 /* Retrieve the read operation's result */
892                 rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf,
893                                       ops->packed_size);
894                 if (rc < 0)
895                         return rc;
896
897                 cmd = (struct sja1105_dyn_cmd) {0};
898                 ops->cmd_packing(packed_buf, &cmd, UNPACK);
899                 /* UM10944: [valident] will always be found cleared
900                  * during a read access with MGMTROUTE set.
901                  * So don't error out in that case.
902                  */
903                 if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
904                         return -ENOENT;
905                 cpu_relax();
906         } while (cmd.valid && --retries);
907
908         if (cmd.valid)
909                 return -ETIMEDOUT;
910
911         /* Don't dereference possibly NULL pointer - maybe caller
912          * only wanted to see whether the entry existed or not.
913          */
914         if (entry)
915                 ops->entry_packing(packed_buf, entry, UNPACK);
916         return 0;
917 }
918
919 int sja1105_dynamic_config_write(struct sja1105_private *priv,
920                                  enum sja1105_blk_idx blk_idx,
921                                  int index, void *entry, bool keep)
922 {
923         const struct sja1105_dynamic_table_ops *ops;
924         struct sja1105_dyn_cmd cmd = {0};
925         /* SPI payload buffer */
926         u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
927         int rc;
928
929         if (blk_idx >= BLK_IDX_MAX_DYN)
930                 return -ERANGE;
931
932         ops = &priv->info->dyn_ops[blk_idx];
933
934         if (index >= ops->max_entry_count)
935                 return -ERANGE;
936         if (index < 0)
937                 return -ERANGE;
938         if (!(ops->access & OP_WRITE))
939                 return -EOPNOTSUPP;
940         if (!keep && !(ops->access & OP_DEL))
941                 return -EOPNOTSUPP;
942         if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
943                 return -ERANGE;
944
945         cmd.valident = keep; /* If false, deletes entry */
946         cmd.valid = true; /* Trigger action on table entry */
947         cmd.rdwrset = SPI_WRITE; /* Action is write */
948         cmd.index = index;
949
950         if (!ops->cmd_packing)
951                 return -EOPNOTSUPP;
952         ops->cmd_packing(packed_buf, &cmd, PACK);
953
954         if (!ops->entry_packing)
955                 return -EOPNOTSUPP;
956         /* Don't dereference potentially NULL pointer if just
957          * deleting a table entry is what was requested. For cases
958          * where 'index' field is physically part of entry structure,
959          * and needed here, we deal with that in the cmd_packing callback.
960          */
961         if (keep)
962                 ops->entry_packing(packed_buf, entry, PACK);
963
964         /* Send SPI write operation: read config table entry */
965         rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
966                               ops->packed_size);
967         if (rc < 0)
968                 return rc;
969
970         cmd = (struct sja1105_dyn_cmd) {0};
971         ops->cmd_packing(packed_buf, &cmd, UNPACK);
972         if (cmd.errors)
973                 return -EINVAL;
974
975         return 0;
976 }
977
978 static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
979 {
980         int i;
981
982         for (i = 0; i < 8; i++) {
983                 if ((crc ^ byte) & (1 << 7)) {
984                         crc <<= 1;
985                         crc ^= poly;
986                 } else {
987                         crc <<= 1;
988                 }
989                 byte <<= 1;
990         }
991         return crc;
992 }
993
994 /* CRC8 algorithm with non-reversed input, non-reversed output,
995  * no input xor and no output xor. Code customized for receiving
996  * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
997  * is also received as argument in the Koopman notation that the switch
998  * hardware stores it in.
999  */
1000 u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
1001 {
1002         struct sja1105_l2_lookup_params_entry *l2_lookup_params =
1003                 priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
1004         u64 poly_koopman = l2_lookup_params->poly;
1005         /* Convert polynomial from Koopman to 'normal' notation */
1006         u8 poly = (u8)(1 + (poly_koopman << 1));
1007         u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid;
1008         u64 input = (vlanid << 48) | ether_addr_to_u64(addr);
1009         u8 crc = 0; /* seed */
1010         int i;
1011
1012         /* Mask the eight bytes starting from MSB one at a time */
1013         for (i = 56; i >= 0; i -= 8) {
1014                 u8 byte = (input & (0xffull << i)) >> i;
1015
1016                 crc = sja1105_crc8_add(crc, byte, poly);
1017         }
1018         return crc;
1019 }
This page took 0.091296 seconds and 4 git commands to generate.