]> git.ipfire.org Git - thirdparty/linux.git/blame - drivers/net/dsa/sja1105/sja1105_dynamic_config.c
net: dsa: sja1105: Make room for P/Q/R/S FDB operations
[thirdparty/linux.git] / drivers / net / dsa / sja1105 / sja1105_dynamic_config.c
CommitLineData
8aa9ebcc
VO
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
3 */
4#include "sja1105.h"
5
6#define SJA1105_SIZE_DYN_CMD 4
7
8#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY \
9 SJA1105_SIZE_DYN_CMD
10
11#define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD \
12 (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY)
13
14#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD \
15 (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
16
17#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD \
18 (SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
19
20#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD \
21 (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
22
23#define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD \
24 (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY)
25
26#define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD \
27 (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY)
28
29#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD \
30 SJA1105_SIZE_DYN_CMD
31
32#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD \
33 SJA1105_SIZE_DYN_CMD
34
35#define SJA1105_MAX_DYN_CMD_SIZE \
36 SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD
37
31b31120 38struct sja1105_dyn_cmd {
90c96cca 39 bool search;
31b31120
VO
40 u64 valid;
41 u64 rdwrset;
42 u64 errors;
43 u64 valident;
44 u64 index;
45};
46
8aa9ebcc
VO
47static void
48sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
49 enum packing_op op)
50{
51 u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
52 const int size = SJA1105_SIZE_DYN_CMD;
53
54 sja1105_packing(p, &cmd->valid, 31, 31, size, op);
55 sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
56 sja1105_packing(p, &cmd->errors, 29, 29, size, op);
57 sja1105_packing(p, &cmd->valident, 27, 27, size, op);
58 /* Hack - The hardware takes the 'index' field within
59 * struct sja1105_l2_lookup_entry as the index on which this command
60 * will operate. However it will ignore everything else, so 'index'
61 * is logically part of command but physically part of entry.
62 * Populate the 'index' entry field from within the command callback,
63 * such that our API doesn't need to ask for a full-blown entry
64 * structure when e.g. a delete is requested.
65 */
afad12a0 66 sja1105_packing(buf, &cmd->index, 15, 6,
8aa9ebcc
VO
67 SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
68 /* TODO hostcmd */
69}
70
71static void
72sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
73 enum packing_op op)
74{
75 u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
76 const int size = SJA1105_SIZE_DYN_CMD;
77
78 sja1105_packing(p, &cmd->valid, 31, 31, size, op);
79 sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
80 sja1105_packing(p, &cmd->errors, 29, 29, size, op);
81 sja1105_packing(p, &cmd->valident, 27, 27, size, op);
82 /* Hack - see comments above. */
83 sja1105_packing(buf, &cmd->index, 29, 20,
84 SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
85}
86
87static void
88sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
89 enum packing_op op)
90{
91 u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
92 u64 mgmtroute = 1;
93
94 sja1105et_l2_lookup_cmd_packing(buf, cmd, op);
95 if (op == PACK)
96 sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
97}
98
99static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
100 enum packing_op op)
101{
102 struct sja1105_mgmt_entry *entry = entry_ptr;
103 const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
104
105 /* UM10944: To specify if a PTP egress timestamp shall be captured on
106 * each port upon transmission of the frame, the LSB of VLANID in the
107 * ENTRY field provided by the host must be set.
108 * Bit 1 of VLANID then specifies the register where the timestamp for
109 * this port is stored in.
110 */
111 sja1105_packing(buf, &entry->tsreg, 85, 85, size, op);
112 sja1105_packing(buf, &entry->takets, 84, 84, size, op);
113 sja1105_packing(buf, &entry->macaddr, 83, 36, size, op);
114 sja1105_packing(buf, &entry->destports, 35, 31, size, op);
115 sja1105_packing(buf, &entry->enfport, 30, 30, size, op);
116 return size;
117}
118
119/* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
120 * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
121 * between entry (0x2d, 0x2e) and command (0x30).
122 */
123static void
124sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
125 enum packing_op op)
126{
127 u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4;
128 const int size = SJA1105_SIZE_DYN_CMD;
129
130 sja1105_packing(p, &cmd->valid, 31, 31, size, op);
131 sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
132 sja1105_packing(p, &cmd->valident, 27, 27, size, op);
133 /* Hack - see comments above, applied for 'vlanid' field of
134 * struct sja1105_vlan_lookup_entry.
135 */
136 sja1105_packing(buf, &cmd->index, 38, 27,
137 SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
138}
139
140static void
141sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
142 enum packing_op op)
143{
144 u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
145 const int size = SJA1105_SIZE_DYN_CMD;
146
147 sja1105_packing(p, &cmd->valid, 31, 31, size, op);
148 sja1105_packing(p, &cmd->errors, 30, 30, size, op);
149 sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
150 sja1105_packing(p, &cmd->index, 4, 0, size, op);
151}
152
153static void
154sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
155 enum packing_op op)
156{
157 const int size = SJA1105_SIZE_DYN_CMD;
158 /* Yup, user manual definitions are reversed */
159 u8 *reg1 = buf + 4;
160
161 sja1105_packing(reg1, &cmd->valid, 31, 31, size, op);
162 sja1105_packing(reg1, &cmd->index, 26, 24, size, op);
163}
164
165static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
166 enum packing_op op)
167{
168 const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
169 struct sja1105_mac_config_entry *entry = entry_ptr;
170 /* Yup, user manual definitions are reversed */
171 u8 *reg1 = buf + 4;
172 u8 *reg2 = buf;
173
174 sja1105_packing(reg1, &entry->speed, 30, 29, size, op);
175 sja1105_packing(reg1, &entry->drpdtag, 23, 23, size, op);
176 sja1105_packing(reg1, &entry->drpuntag, 22, 22, size, op);
177 sja1105_packing(reg1, &entry->retag, 21, 21, size, op);
178 sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op);
179 sja1105_packing(reg1, &entry->egress, 19, 19, size, op);
180 sja1105_packing(reg1, &entry->ingress, 18, 18, size, op);
181 sja1105_packing(reg1, &entry->ing_mirr, 17, 17, size, op);
182 sja1105_packing(reg1, &entry->egr_mirr, 16, 16, size, op);
183 sja1105_packing(reg1, &entry->vlanprio, 14, 12, size, op);
184 sja1105_packing(reg1, &entry->vlanid, 11, 0, size, op);
185 sja1105_packing(reg2, &entry->tp_delin, 31, 16, size, op);
186 sja1105_packing(reg2, &entry->tp_delout, 15, 0, size, op);
187 /* MAC configuration table entries which can't be reconfigured:
188 * top, base, enabled, ifg, maxage, drpnona664
189 */
190 /* Bogus return value, not used anywhere */
191 return 0;
192}
193
194static void
195sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
196 enum packing_op op)
197{
198 const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
199 u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
200
201 sja1105_packing(p, &cmd->valid, 31, 31, size, op);
202 sja1105_packing(p, &cmd->errors, 30, 30, size, op);
203 sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
204 sja1105_packing(p, &cmd->index, 2, 0, size, op);
205}
206
207static void
208sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
209 enum packing_op op)
210{
211 sja1105_packing(buf, &cmd->valid, 31, 31,
212 SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
213}
214
215static size_t
216sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
217 enum packing_op op)
218{
219 struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
220
221 sja1105_packing(buf, &entry->poly, 7, 0,
222 SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
223 /* Bogus return value, not used anywhere */
224 return 0;
225}
226
227static void
228sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
229 enum packing_op op)
230{
231 const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
232
233 sja1105_packing(buf, &cmd->valid, 31, 31, size, op);
234 sja1105_packing(buf, &cmd->errors, 30, 30, size, op);
235}
236
237static size_t
238sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
239 enum packing_op op)
240{
241 struct sja1105_general_params_entry *entry = entry_ptr;
242 const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
243
244 sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op);
245 /* Bogus return value, not used anywhere */
246 return 0;
247}
248
249#define OP_READ BIT(0)
250#define OP_WRITE BIT(1)
251#define OP_DEL BIT(2)
90c96cca 252#define OP_SEARCH BIT(3)
8aa9ebcc
VO
253
254/* SJA1105E/T: First generation */
255struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
256 [BLK_IDX_L2_LOOKUP] = {
257 .entry_packing = sja1105et_l2_lookup_entry_packing,
258 .cmd_packing = sja1105et_l2_lookup_cmd_packing,
259 .access = (OP_READ | OP_WRITE | OP_DEL),
260 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
261 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
262 .addr = 0x20,
263 },
264 [BLK_IDX_MGMT_ROUTE] = {
265 .entry_packing = sja1105et_mgmt_route_entry_packing,
266 .cmd_packing = sja1105et_mgmt_route_cmd_packing,
267 .access = (OP_READ | OP_WRITE),
268 .max_entry_count = SJA1105_NUM_PORTS,
269 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
270 .addr = 0x20,
271 },
272 [BLK_IDX_L2_POLICING] = {0},
273 [BLK_IDX_VLAN_LOOKUP] = {
274 .entry_packing = sja1105_vlan_lookup_entry_packing,
275 .cmd_packing = sja1105_vlan_lookup_cmd_packing,
276 .access = (OP_WRITE | OP_DEL),
277 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
278 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
279 .addr = 0x27,
280 },
281 [BLK_IDX_L2_FORWARDING] = {
282 .entry_packing = sja1105_l2_forwarding_entry_packing,
283 .cmd_packing = sja1105_l2_forwarding_cmd_packing,
284 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
285 .access = OP_WRITE,
286 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
287 .addr = 0x24,
288 },
289 [BLK_IDX_MAC_CONFIG] = {
290 .entry_packing = sja1105et_mac_config_entry_packing,
291 .cmd_packing = sja1105et_mac_config_cmd_packing,
292 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
293 .access = OP_WRITE,
294 .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
295 .addr = 0x36,
296 },
297 [BLK_IDX_L2_LOOKUP_PARAMS] = {
298 .entry_packing = sja1105et_l2_lookup_params_entry_packing,
299 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
300 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
301 .access = OP_WRITE,
302 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
303 .addr = 0x38,
304 },
305 [BLK_IDX_L2_FORWARDING_PARAMS] = {0},
306 [BLK_IDX_GENERAL_PARAMS] = {
307 .entry_packing = sja1105et_general_params_entry_packing,
308 .cmd_packing = sja1105et_general_params_cmd_packing,
309 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
310 .access = OP_WRITE,
311 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
312 .addr = 0x34,
313 },
314 [BLK_IDX_XMII_PARAMS] = {0},
315};
316
317/* SJA1105P/Q/R/S: Second generation: TODO */
318struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
319 [BLK_IDX_L2_LOOKUP] = {
320 .entry_packing = sja1105pqrs_l2_lookup_entry_packing,
321 .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
322 .access = (OP_READ | OP_WRITE | OP_DEL),
323 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
324 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
325 .addr = 0x24,
326 },
327 [BLK_IDX_L2_POLICING] = {0},
328 [BLK_IDX_VLAN_LOOKUP] = {
329 .entry_packing = sja1105_vlan_lookup_entry_packing,
330 .cmd_packing = sja1105_vlan_lookup_cmd_packing,
331 .access = (OP_READ | OP_WRITE | OP_DEL),
332 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
333 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
334 .addr = 0x2D,
335 },
336 [BLK_IDX_L2_FORWARDING] = {
337 .entry_packing = sja1105_l2_forwarding_entry_packing,
338 .cmd_packing = sja1105_l2_forwarding_cmd_packing,
339 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
340 .access = OP_WRITE,
341 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
342 .addr = 0x2A,
343 },
344 [BLK_IDX_MAC_CONFIG] = {
345 .entry_packing = sja1105pqrs_mac_config_entry_packing,
346 .cmd_packing = sja1105pqrs_mac_config_cmd_packing,
347 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
348 .access = (OP_READ | OP_WRITE),
349 .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
350 .addr = 0x4B,
351 },
352 [BLK_IDX_L2_LOOKUP_PARAMS] = {
353 .entry_packing = sja1105et_l2_lookup_params_entry_packing,
354 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
355 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
356 .access = (OP_READ | OP_WRITE),
357 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
358 .addr = 0x38,
359 },
360 [BLK_IDX_L2_FORWARDING_PARAMS] = {0},
361 [BLK_IDX_GENERAL_PARAMS] = {
362 .entry_packing = sja1105et_general_params_entry_packing,
363 .cmd_packing = sja1105et_general_params_cmd_packing,
364 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
365 .access = OP_WRITE,
366 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
367 .addr = 0x34,
368 },
369 [BLK_IDX_XMII_PARAMS] = {0},
370};
371
90c96cca
VO
372/* Provides read access to the settings through the dynamic interface
373 * of the switch.
374 * @blk_idx is used as key to select from the sja1105_dynamic_table_ops.
375 * The selection is limited by the hardware in respect to which
376 * configuration blocks can be read through the dynamic interface.
377 * @index is used to retrieve a particular table entry. If negative,
378 * (and if the @blk_idx supports the searching operation) a search
379 * is performed by the @entry parameter.
380 * @entry Type-casted to an unpacked structure that holds a table entry
381 * of the type specified in @blk_idx.
382 * Usually an output argument. If @index is negative, then this
383 * argument is used as input/output: it should be pre-populated
384 * with the element to search for. Entries which support the
385 * search operation will have an "index" field (not the @index
386 * argument to this function) and that is where the found index
387 * will be returned (or left unmodified - thus negative - if not
388 * found).
389 */
8aa9ebcc
VO
390int sja1105_dynamic_config_read(struct sja1105_private *priv,
391 enum sja1105_blk_idx blk_idx,
392 int index, void *entry)
393{
394 const struct sja1105_dynamic_table_ops *ops;
395 struct sja1105_dyn_cmd cmd = {0};
396 /* SPI payload buffer */
397 u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
398 int retries = 3;
399 int rc;
400
401 if (blk_idx >= BLK_IDX_MAX_DYN)
402 return -ERANGE;
403
404 ops = &priv->info->dyn_ops[blk_idx];
405
406 if (index >= ops->max_entry_count)
407 return -ERANGE;
90c96cca
VO
408 if (index < 0 && !(ops->access & OP_SEARCH))
409 return -EOPNOTSUPP;
8aa9ebcc
VO
410 if (!(ops->access & OP_READ))
411 return -EOPNOTSUPP;
412 if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
413 return -ERANGE;
414 if (!ops->cmd_packing)
415 return -EOPNOTSUPP;
416 if (!ops->entry_packing)
417 return -EOPNOTSUPP;
418
419 cmd.valid = true; /* Trigger action on table entry */
420 cmd.rdwrset = SPI_READ; /* Action is read */
90c96cca
VO
421 if (index < 0) {
422 /* Avoid copying a signed negative number to an u64 */
423 cmd.index = 0;
424 cmd.search = true;
425 } else {
426 cmd.index = index;
427 cmd.search = false;
428 }
8aa9ebcc
VO
429 ops->cmd_packing(packed_buf, &cmd, PACK);
430
90c96cca
VO
431 if (cmd.search)
432 ops->entry_packing(packed_buf, entry, PACK);
433
8aa9ebcc
VO
434 /* Send SPI write operation: read config table entry */
435 rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr,
436 packed_buf, ops->packed_size);
437 if (rc < 0)
438 return rc;
439
440 /* Loop until we have confirmation that hardware has finished
441 * processing the command and has cleared the VALID field
442 */
443 do {
444 memset(packed_buf, 0, ops->packed_size);
445
446 /* Retrieve the read operation's result */
447 rc = sja1105_spi_send_packed_buf(priv, SPI_READ, ops->addr,
448 packed_buf, ops->packed_size);
449 if (rc < 0)
450 return rc;
451
452 cmd = (struct sja1105_dyn_cmd) {0};
453 ops->cmd_packing(packed_buf, &cmd, UNPACK);
454 /* UM10944: [valident] will always be found cleared
455 * during a read access with MGMTROUTE set.
456 * So don't error out in that case.
457 */
458 if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
459 return -EINVAL;
460 cpu_relax();
461 } while (cmd.valid && --retries);
462
463 if (cmd.valid)
464 return -ETIMEDOUT;
465
466 /* Don't dereference possibly NULL pointer - maybe caller
467 * only wanted to see whether the entry existed or not.
468 */
469 if (entry)
470 ops->entry_packing(packed_buf, entry, UNPACK);
471 return 0;
472}
473
474int sja1105_dynamic_config_write(struct sja1105_private *priv,
475 enum sja1105_blk_idx blk_idx,
476 int index, void *entry, bool keep)
477{
478 const struct sja1105_dynamic_table_ops *ops;
479 struct sja1105_dyn_cmd cmd = {0};
480 /* SPI payload buffer */
481 u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
482 int rc;
483
484 if (blk_idx >= BLK_IDX_MAX_DYN)
485 return -ERANGE;
486
487 ops = &priv->info->dyn_ops[blk_idx];
488
489 if (index >= ops->max_entry_count)
490 return -ERANGE;
90c96cca
VO
491 if (index < 0)
492 return -ERANGE;
8aa9ebcc
VO
493 if (!(ops->access & OP_WRITE))
494 return -EOPNOTSUPP;
495 if (!keep && !(ops->access & OP_DEL))
496 return -EOPNOTSUPP;
497 if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
498 return -ERANGE;
499
500 cmd.valident = keep; /* If false, deletes entry */
501 cmd.valid = true; /* Trigger action on table entry */
502 cmd.rdwrset = SPI_WRITE; /* Action is write */
503 cmd.index = index;
504
505 if (!ops->cmd_packing)
506 return -EOPNOTSUPP;
507 ops->cmd_packing(packed_buf, &cmd, PACK);
508
509 if (!ops->entry_packing)
510 return -EOPNOTSUPP;
511 /* Don't dereference potentially NULL pointer if just
512 * deleting a table entry is what was requested. For cases
513 * where 'index' field is physically part of entry structure,
514 * and needed here, we deal with that in the cmd_packing callback.
515 */
516 if (keep)
517 ops->entry_packing(packed_buf, entry, PACK);
518
519 /* Send SPI write operation: read config table entry */
520 rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr,
521 packed_buf, ops->packed_size);
522 if (rc < 0)
523 return rc;
524
525 cmd = (struct sja1105_dyn_cmd) {0};
526 ops->cmd_packing(packed_buf, &cmd, UNPACK);
527 if (cmd.errors)
528 return -EINVAL;
529
530 return 0;
531}
291d1e72
VO
532
533static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
534{
535 int i;
536
537 for (i = 0; i < 8; i++) {
538 if ((crc ^ byte) & (1 << 7)) {
539 crc <<= 1;
540 crc ^= poly;
541 } else {
542 crc <<= 1;
543 }
544 byte <<= 1;
545 }
546 return crc;
547}
548
549/* CRC8 algorithm with non-reversed input, non-reversed output,
550 * no input xor and no output xor. Code customized for receiving
551 * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
552 * is also received as argument in the Koopman notation that the switch
553 * hardware stores it in.
554 */
9dfa6911 555u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
291d1e72
VO
556{
557 struct sja1105_l2_lookup_params_entry *l2_lookup_params =
558 priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
559 u64 poly_koopman = l2_lookup_params->poly;
560 /* Convert polynomial from Koopman to 'normal' notation */
561 u8 poly = (u8)(1 + (poly_koopman << 1));
562 u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid;
563 u64 input = (vlanid << 48) | ether_addr_to_u64(addr);
564 u8 crc = 0; /* seed */
565 int i;
566
567 /* Mask the eight bytes starting from MSB one at a time */
568 for (i = 56; i >= 0; i -= 8) {
569 u8 byte = (input & (0xffull << i)) >> i;
570
571 crc = sja1105_crc8_add(crc, byte, poly);
572 }
573 return crc;
574}