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