Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
0003  */
0004 #include "sja1105.h"
0005 
0006 /* In the dynamic configuration interface, the switch exposes a register-like
0007  * view of some of the static configuration tables.
0008  * Many times the field organization of the dynamic tables is abbreviated (not
0009  * all fields are dynamically reconfigurable) and different from the static
0010  * ones, but the key reason for having it is that we can spare a switch reset
0011  * for settings that can be changed dynamically.
0012  *
0013  * This file creates a per-switch-family abstraction called
0014  * struct sja1105_dynamic_table_ops and two operations that work with it:
0015  * - sja1105_dynamic_config_write
0016  * - sja1105_dynamic_config_read
0017  *
0018  * Compared to the struct sja1105_table_ops from sja1105_static_config.c,
0019  * the dynamic accessors work with a compound buffer:
0020  *
0021  * packed_buf
0022  *
0023  * |
0024  * V
0025  * +-----------------------------------------+------------------+
0026  * |              ENTRY BUFFER               |  COMMAND BUFFER  |
0027  * +-----------------------------------------+------------------+
0028  *
0029  * <----------------------- packed_size ------------------------>
0030  *
0031  * The ENTRY BUFFER may or may not have the same layout, or size, as its static
0032  * configuration table entry counterpart. When it does, the same packing
0033  * function is reused (bar exceptional cases - see
0034  * sja1105pqrs_dyn_l2_lookup_entry_packing).
0035  *
0036  * The reason for the COMMAND BUFFER being at the end is to be able to send
0037  * a dynamic write command through a single SPI burst. By the time the switch
0038  * reacts to the command, the ENTRY BUFFER is already populated with the data
0039  * sent by the core.
0040  *
0041  * The COMMAND BUFFER is always SJA1105_SIZE_DYN_CMD bytes (one 32-bit word) in
0042  * size.
0043  *
0044  * Sometimes the ENTRY BUFFER does not really exist (when the number of fields
0045  * that can be reconfigured is small), then the switch repurposes some of the
0046  * unused 32 bits of the COMMAND BUFFER to hold ENTRY data.
0047  *
0048  * The key members of struct sja1105_dynamic_table_ops are:
0049  * - .entry_packing: A function that deals with packing an ENTRY structure
0050  *           into an SPI buffer, or retrieving an ENTRY structure
0051  *           from one.
0052  *           The @packed_buf pointer it's given does always point to
0053  *           the ENTRY portion of the buffer.
0054  * - .cmd_packing: A function that deals with packing/unpacking the COMMAND
0055  *         structure to/from the SPI buffer.
0056  *         It is given the same @packed_buf pointer as .entry_packing,
0057  *         so most of the time, the @packed_buf points *behind* the
0058  *         COMMAND offset inside the buffer.
0059  *         To access the COMMAND portion of the buffer, the function
0060  *         knows its correct offset.
0061  *         Giving both functions the same pointer is handy because in
0062  *         extreme cases (see sja1105pqrs_dyn_l2_lookup_entry_packing)
0063  *         the .entry_packing is able to jump to the COMMAND portion,
0064  *         or vice-versa (sja1105pqrs_l2_lookup_cmd_packing).
0065  * - .access: A bitmap of:
0066  *  OP_READ: Set if the hardware manual marks the ENTRY portion of the
0067  *       dynamic configuration table buffer as R (readable) after
0068  *       an SPI read command (the switch will populate the buffer).
0069  *  OP_WRITE: Set if the manual marks the ENTRY portion of the dynamic
0070  *        table buffer as W (writable) after an SPI write command
0071  *        (the switch will read the fields provided in the buffer).
0072  *  OP_DEL: Set if the manual says the VALIDENT bit is supported in the
0073  *      COMMAND portion of this dynamic config buffer (i.e. the
0074  *      specified entry can be invalidated through a SPI write
0075  *      command).
0076  *  OP_SEARCH: Set if the manual says that the index of an entry can
0077  *         be retrieved in the COMMAND portion of the buffer based
0078  *         on its ENTRY portion, as a result of a SPI write command.
0079  *         Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
0080  *         this.
0081  *  OP_VALID_ANYWAY: Reading some tables through the dynamic config
0082  *           interface is possible even if the VALIDENT bit is not
0083  *           set in the writeback. So don't error out in that case.
0084  * - .max_entry_count: The number of entries, counting from zero, that can be
0085  *             reconfigured through the dynamic interface. If a static
0086  *             table can be reconfigured at all dynamically, this
0087  *             number always matches the maximum number of supported
0088  *             static entries.
0089  * - .packed_size: The length in bytes of the compound ENTRY + COMMAND BUFFER.
0090  *         Note that sometimes the compound buffer may contain holes in
0091  *         it (see sja1105_vlan_lookup_cmd_packing). The @packed_buf is
0092  *         contiguous however, so @packed_size includes any unused
0093  *         bytes.
0094  * - .addr: The base SPI address at which the buffer must be written to the
0095  *      switch's memory. When looking at the hardware manual, this must
0096  *      always match the lowest documented address for the ENTRY, and not
0097  *      that of the COMMAND, since the other 32-bit words will follow along
0098  *      at the correct addresses.
0099  */
0100 
0101 #define SJA1105_SIZE_DYN_CMD                    4
0102 
0103 #define SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD            \
0104     SJA1105_SIZE_DYN_CMD
0105 
0106 #define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD          \
0107     (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)
0108 
0109 #define SJA1110_SIZE_VL_POLICING_DYN_CMD            \
0110     (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_POLICING_ENTRY)
0111 
0112 #define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY         \
0113     SJA1105_SIZE_DYN_CMD
0114 
0115 #define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD            \
0116     (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY)
0117 
0118 #define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD          \
0119     (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
0120 
0121 #define SJA1110_SIZE_L2_LOOKUP_DYN_CMD              \
0122     (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_ENTRY)
0123 
0124 #define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD            \
0125     (SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
0126 
0127 #define SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD            \
0128     (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_VLAN_LOOKUP_ENTRY)
0129 
0130 #define SJA1105_SIZE_L2_FORWARDING_DYN_CMD          \
0131     (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
0132 
0133 #define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD           \
0134     (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY)
0135 
0136 #define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD         \
0137     (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY)
0138 
0139 #define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD         \
0140     SJA1105_SIZE_DYN_CMD
0141 
0142 #define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD       \
0143     (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)
0144 
0145 #define SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD       \
0146     (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY)
0147 
0148 #define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD           \
0149     SJA1105_SIZE_DYN_CMD
0150 
0151 #define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD         \
0152     (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)
0153 
0154 #define SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD         \
0155     (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_GENERAL_PARAMS_ENTRY)
0156 
0157 #define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD         \
0158     (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)
0159 
0160 #define SJA1105_SIZE_RETAGGING_DYN_CMD              \
0161     (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_RETAGGING_ENTRY)
0162 
0163 #define SJA1105ET_SIZE_CBS_DYN_CMD              \
0164     (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_CBS_ENTRY)
0165 
0166 #define SJA1105PQRS_SIZE_CBS_DYN_CMD                \
0167     (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)
0168 
0169 #define SJA1110_SIZE_XMII_PARAMS_DYN_CMD            \
0170     SJA1110_SIZE_XMII_PARAMS_ENTRY
0171 
0172 #define SJA1110_SIZE_L2_POLICING_DYN_CMD            \
0173     (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_POLICING_ENTRY)
0174 
0175 #define SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD       \
0176     SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY
0177 
0178 #define SJA1105_MAX_DYN_CMD_SIZE                \
0179     SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD
0180 
0181 struct sja1105_dyn_cmd {
0182     bool search;
0183     u64 valid;
0184     u64 rdwrset;
0185     u64 errors;
0186     u64 valident;
0187     u64 index;
0188 };
0189 
0190 enum sja1105_hostcmd {
0191     SJA1105_HOSTCMD_SEARCH = 1,
0192     SJA1105_HOSTCMD_READ = 2,
0193     SJA1105_HOSTCMD_WRITE = 3,
0194     SJA1105_HOSTCMD_INVALIDATE = 4,
0195 };
0196 
0197 /* Command and entry overlap */
0198 static void
0199 sja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0200                 enum packing_op op)
0201 {
0202     const int size = SJA1105_SIZE_DYN_CMD;
0203 
0204     sja1105_packing(buf, &cmd->valid,   31, 31, size, op);
0205     sja1105_packing(buf, &cmd->errors,  30, 30, size, op);
0206     sja1105_packing(buf, &cmd->rdwrset, 29, 29, size, op);
0207     sja1105_packing(buf, &cmd->index,    9,  0, size, op);
0208 }
0209 
0210 /* Command and entry are separate */
0211 static void
0212 sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0213                   enum packing_op op)
0214 {
0215     u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
0216     const int size = SJA1105_SIZE_DYN_CMD;
0217 
0218     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0219     sja1105_packing(p, &cmd->errors,  30, 30, size, op);
0220     sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
0221     sja1105_packing(p, &cmd->index,    9,  0, size, op);
0222 }
0223 
0224 static void
0225 sja1110_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0226                   enum packing_op op)
0227 {
0228     u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
0229     const int size = SJA1105_SIZE_DYN_CMD;
0230 
0231     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0232     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0233     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0234     sja1105_packing(p, &cmd->index,   11,  0, size, op);
0235 }
0236 
0237 static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
0238                         enum packing_op op)
0239 {
0240     struct sja1105_vl_lookup_entry *entry = entry_ptr;
0241     const int size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD;
0242 
0243     sja1105_packing(buf, &entry->egrmirr,  21, 17, size, op);
0244     sja1105_packing(buf, &entry->ingrmirr, 16, 16, size, op);
0245     return size;
0246 }
0247 
0248 static void
0249 sja1110_vl_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0250                 enum packing_op op)
0251 {
0252     u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
0253     const int size = SJA1105_SIZE_DYN_CMD;
0254 
0255     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0256     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0257     sja1105_packing(p, &cmd->index,   11,  0, size, op);
0258 }
0259 
0260 static void
0261 sja1105pqrs_common_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0262                      enum packing_op op, int entry_size)
0263 {
0264     const int size = SJA1105_SIZE_DYN_CMD;
0265     u8 *p = buf + entry_size;
0266     u64 hostcmd;
0267 
0268     sja1105_packing(p, &cmd->valid,    31, 31, size, op);
0269     sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
0270     sja1105_packing(p, &cmd->errors,   29, 29, size, op);
0271     sja1105_packing(p, &cmd->valident, 27, 27, size, op);
0272 
0273     /* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
0274      * using it to delete a management route was unsupported. UM10944
0275      * said about it:
0276      *
0277      *   In case of a write access with the MGMTROUTE flag set,
0278      *   the flag will be ignored. It will always be found cleared
0279      *   for read accesses with the MGMTROUTE flag set.
0280      *
0281      * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there
0282      * is now another flag called HOSTCMD which does more stuff (quoting
0283      * from UM11040):
0284      *
0285      *   A write request is accepted only when HOSTCMD is set to write host
0286      *   or invalid. A read request is accepted only when HOSTCMD is set to
0287      *   search host or read host.
0288      *
0289      * So it is possible to translate a RDWRSET/VALIDENT combination into
0290      * HOSTCMD so that we keep the dynamic command API in place, and
0291      * at the same time achieve compatibility with the management route
0292      * command structure.
0293      */
0294     if (cmd->rdwrset == SPI_READ) {
0295         if (cmd->search)
0296             hostcmd = SJA1105_HOSTCMD_SEARCH;
0297         else
0298             hostcmd = SJA1105_HOSTCMD_READ;
0299     } else {
0300         /* SPI_WRITE */
0301         if (cmd->valident)
0302             hostcmd = SJA1105_HOSTCMD_WRITE;
0303         else
0304             hostcmd = SJA1105_HOSTCMD_INVALIDATE;
0305     }
0306     sja1105_packing(p, &hostcmd, 25, 23, size, op);
0307 }
0308 
0309 static void
0310 sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0311                   enum packing_op op)
0312 {
0313     int entry_size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
0314 
0315     sja1105pqrs_common_l2_lookup_cmd_packing(buf, cmd, op, entry_size);
0316 
0317     /* Hack - The hardware takes the 'index' field within
0318      * struct sja1105_l2_lookup_entry as the index on which this command
0319      * will operate. However it will ignore everything else, so 'index'
0320      * is logically part of command but physically part of entry.
0321      * Populate the 'index' entry field from within the command callback,
0322      * such that our API doesn't need to ask for a full-blown entry
0323      * structure when e.g. a delete is requested.
0324      */
0325     sja1105_packing(buf, &cmd->index, 15, 6, entry_size, op);
0326 }
0327 
0328 static void
0329 sja1110_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0330                   enum packing_op op)
0331 {
0332     int entry_size = SJA1110_SIZE_L2_LOOKUP_ENTRY;
0333 
0334     sja1105pqrs_common_l2_lookup_cmd_packing(buf, cmd, op, entry_size);
0335 
0336     sja1105_packing(buf, &cmd->index, 10, 1, entry_size, op);
0337 }
0338 
0339 /* The switch is so retarded that it makes our command/entry abstraction
0340  * crumble apart.
0341  *
0342  * On P/Q/R/S, the switch tries to say whether a FDB entry
0343  * is statically programmed or dynamically learned via a flag called LOCKEDS.
0344  * The hardware manual says about this fiels:
0345  *
0346  *   On write will specify the format of ENTRY.
0347  *   On read the flag will be found cleared at times the VALID flag is found
0348  *   set.  The flag will also be found cleared in response to a read having the
0349  *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
0350  *   cleared, the flag be set if the most recent access operated on an entry
0351  *   that was either loaded by configuration or through dynamic reconfiguration
0352  *   (as opposed to automatically learned entries).
0353  *
0354  * The trouble with this flag is that it's part of the *command* to access the
0355  * dynamic interface, and not part of the *entry* retrieved from it.
0356  * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
0357  * an output from the switch into the command buffer, and for a
0358  * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
0359  * (hence we can write either static, or automatically learned entries, from
0360  * the core).
0361  * But the manual contradicts itself in the last phrase where it says that on
0362  * read, LOCKEDS will be set to 1 for all FDB entries written through the
0363  * dynamic interface (therefore, the value of LOCKEDS from the
0364  * sja1105_dynamic_config_write is not really used for anything, it'll store a
0365  * 1 anyway).
0366  * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
0367  * learned) into the switch, which kind of makes sense.
0368  * As for reading through the dynamic interface, it doesn't make too much sense
0369  * to put LOCKEDS into the command, since the switch will inevitably have to
0370  * ignore it (otherwise a command would be like "read the FDB entry 123, but
0371  * only if it's dynamically learned" <- well how am I supposed to know?) and
0372  * just use it as an output buffer for its findings. But guess what... that's
0373  * what the entry buffer is for!
0374  * Unfortunately, what really breaks this abstraction is the fact that it
0375  * wasn't designed having the fact in mind that the switch can output
0376  * entry-related data as writeback through the command buffer.
0377  * However, whether a FDB entry is statically or dynamically learned *is* part
0378  * of the entry and not the command data, no matter what the switch thinks.
0379  * In order to do that, we'll need to wrap around the
0380  * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
0381  * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
0382  * command buffer.
0383  */
0384 static size_t
0385 sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
0386                     enum packing_op op)
0387 {
0388     struct sja1105_l2_lookup_entry *entry = entry_ptr;
0389     u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
0390     const int size = SJA1105_SIZE_DYN_CMD;
0391 
0392     sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
0393 
0394     return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
0395 }
0396 
0397 static size_t sja1110_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
0398                           enum packing_op op)
0399 {
0400     struct sja1105_l2_lookup_entry *entry = entry_ptr;
0401     u8 *cmd = buf + SJA1110_SIZE_L2_LOOKUP_ENTRY;
0402     const int size = SJA1105_SIZE_DYN_CMD;
0403 
0404     sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
0405 
0406     return sja1110_l2_lookup_entry_packing(buf, entry_ptr, op);
0407 }
0408 
0409 static void
0410 sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0411                 enum packing_op op)
0412 {
0413     u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
0414     const int size = SJA1105_SIZE_DYN_CMD;
0415 
0416     sja1105_packing(p, &cmd->valid,    31, 31, size, op);
0417     sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
0418     sja1105_packing(p, &cmd->errors,   29, 29, size, op);
0419     sja1105_packing(p, &cmd->valident, 27, 27, size, op);
0420     /* Hack - see comments above. */
0421     sja1105_packing(buf, &cmd->index, 29, 20,
0422             SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
0423 }
0424 
0425 static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
0426                             enum packing_op op)
0427 {
0428     struct sja1105_l2_lookup_entry *entry = entry_ptr;
0429     u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
0430     const int size = SJA1105_SIZE_DYN_CMD;
0431 
0432     sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
0433 
0434     return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
0435 }
0436 
0437 static void
0438 sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0439                  enum packing_op op)
0440 {
0441     u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
0442     u64 mgmtroute = 1;
0443 
0444     sja1105et_l2_lookup_cmd_packing(buf, cmd, op);
0445     if (op == PACK)
0446         sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
0447 }
0448 
0449 static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
0450                          enum packing_op op)
0451 {
0452     struct sja1105_mgmt_entry *entry = entry_ptr;
0453     const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
0454 
0455     /* UM10944: To specify if a PTP egress timestamp shall be captured on
0456      * each port upon transmission of the frame, the LSB of VLANID in the
0457      * ENTRY field provided by the host must be set.
0458      * Bit 1 of VLANID then specifies the register where the timestamp for
0459      * this port is stored in.
0460      */
0461     sja1105_packing(buf, &entry->tsreg,     85, 85, size, op);
0462     sja1105_packing(buf, &entry->takets,    84, 84, size, op);
0463     sja1105_packing(buf, &entry->macaddr,   83, 36, size, op);
0464     sja1105_packing(buf, &entry->destports, 35, 31, size, op);
0465     sja1105_packing(buf, &entry->enfport,   30, 30, size, op);
0466     return size;
0467 }
0468 
0469 static void
0470 sja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0471                    enum packing_op op)
0472 {
0473     u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
0474     u64 mgmtroute = 1;
0475 
0476     sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
0477     if (op == PACK)
0478         sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
0479 }
0480 
0481 static size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
0482                            enum packing_op op)
0483 {
0484     const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
0485     struct sja1105_mgmt_entry *entry = entry_ptr;
0486 
0487     /* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
0488      * is the same (driver uses it to confirm that frame was sent).
0489      * So just keep the name from E/T.
0490      */
0491     sja1105_packing(buf, &entry->tsreg,     71, 71, size, op);
0492     sja1105_packing(buf, &entry->takets,    70, 70, size, op);
0493     sja1105_packing(buf, &entry->macaddr,   69, 22, size, op);
0494     sja1105_packing(buf, &entry->destports, 21, 17, size, op);
0495     sja1105_packing(buf, &entry->enfport,   16, 16, size, op);
0496     return size;
0497 }
0498 
0499 /* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
0500  * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
0501  * between entry (0x2d, 0x2e) and command (0x30).
0502  */
0503 static void
0504 sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0505                 enum packing_op op)
0506 {
0507     u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4;
0508     const int size = SJA1105_SIZE_DYN_CMD;
0509 
0510     sja1105_packing(p, &cmd->valid,    31, 31, size, op);
0511     sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
0512     sja1105_packing(p, &cmd->valident, 27, 27, size, op);
0513     /* Hack - see comments above, applied for 'vlanid' field of
0514      * struct sja1105_vlan_lookup_entry.
0515      */
0516     sja1105_packing(buf, &cmd->index, 38, 27,
0517             SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
0518 }
0519 
0520 /* In SJA1110 there is no gap between the command and the data, yay... */
0521 static void
0522 sja1110_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0523                 enum packing_op op)
0524 {
0525     u8 *p = buf + SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
0526     const int size = SJA1105_SIZE_DYN_CMD;
0527     u64 type_entry = 0;
0528 
0529     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0530     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0531     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0532     /* Hack: treat 'vlanid' field of struct sja1105_vlan_lookup_entry as
0533      * cmd->index.
0534      */
0535     sja1105_packing(buf, &cmd->index, 38, 27,
0536             SJA1110_SIZE_VLAN_LOOKUP_ENTRY, op);
0537 
0538     /* But the VALIDENT bit has disappeared, now we are supposed to
0539      * invalidate an entry through the TYPE_ENTRY field of the entry..
0540      * This is a hack to transform the non-zero quality of the TYPE_ENTRY
0541      * field into a VALIDENT bit.
0542      */
0543     if (op == PACK && !cmd->valident) {
0544         sja1105_packing(buf, &type_entry, 40, 39,
0545                 SJA1110_SIZE_VLAN_LOOKUP_ENTRY, PACK);
0546     } else if (op == UNPACK) {
0547         sja1105_packing(buf, &type_entry, 40, 39,
0548                 SJA1110_SIZE_VLAN_LOOKUP_ENTRY, UNPACK);
0549         cmd->valident = !!type_entry;
0550     }
0551 }
0552 
0553 static void
0554 sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0555                   enum packing_op op)
0556 {
0557     u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
0558     const int size = SJA1105_SIZE_DYN_CMD;
0559 
0560     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0561     sja1105_packing(p, &cmd->errors,  30, 30, size, op);
0562     sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
0563     sja1105_packing(p, &cmd->index,    4,  0, size, op);
0564 }
0565 
0566 static void
0567 sja1110_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0568                   enum packing_op op)
0569 {
0570     u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
0571     const int size = SJA1105_SIZE_DYN_CMD;
0572 
0573     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0574     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0575     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0576     sja1105_packing(p, &cmd->index,    4,  0, size, op);
0577 }
0578 
0579 static void
0580 sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0581                  enum packing_op op)
0582 {
0583     const int size = SJA1105_SIZE_DYN_CMD;
0584     /* Yup, user manual definitions are reversed */
0585     u8 *reg1 = buf + 4;
0586 
0587     sja1105_packing(reg1, &cmd->valid, 31, 31, size, op);
0588     sja1105_packing(reg1, &cmd->index, 26, 24, size, op);
0589 }
0590 
0591 static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
0592                          enum packing_op op)
0593 {
0594     const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
0595     struct sja1105_mac_config_entry *entry = entry_ptr;
0596     /* Yup, user manual definitions are reversed */
0597     u8 *reg1 = buf + 4;
0598     u8 *reg2 = buf;
0599 
0600     sja1105_packing(reg1, &entry->speed,     30, 29, size, op);
0601     sja1105_packing(reg1, &entry->drpdtag,   23, 23, size, op);
0602     sja1105_packing(reg1, &entry->drpuntag,  22, 22, size, op);
0603     sja1105_packing(reg1, &entry->retag,     21, 21, size, op);
0604     sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op);
0605     sja1105_packing(reg1, &entry->egress,    19, 19, size, op);
0606     sja1105_packing(reg1, &entry->ingress,   18, 18, size, op);
0607     sja1105_packing(reg1, &entry->ing_mirr,  17, 17, size, op);
0608     sja1105_packing(reg1, &entry->egr_mirr,  16, 16, size, op);
0609     sja1105_packing(reg1, &entry->vlanprio,  14, 12, size, op);
0610     sja1105_packing(reg1, &entry->vlanid,    11,  0, size, op);
0611     sja1105_packing(reg2, &entry->tp_delin,  31, 16, size, op);
0612     sja1105_packing(reg2, &entry->tp_delout, 15,  0, size, op);
0613     /* MAC configuration table entries which can't be reconfigured:
0614      * top, base, enabled, ifg, maxage, drpnona664
0615      */
0616     /* Bogus return value, not used anywhere */
0617     return 0;
0618 }
0619 
0620 static void
0621 sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0622                    enum packing_op op)
0623 {
0624     const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
0625     u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
0626 
0627     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0628     sja1105_packing(p, &cmd->errors,  30, 30, size, op);
0629     sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
0630     sja1105_packing(p, &cmd->index,    2,  0, size, op);
0631 }
0632 
0633 static void
0634 sja1110_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0635                    enum packing_op op)
0636 {
0637     u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
0638     const int size = SJA1105_SIZE_DYN_CMD;
0639 
0640     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0641     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0642     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0643     sja1105_packing(p, &cmd->index,    3,  0, size, op);
0644 }
0645 
0646 static void
0647 sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0648                        enum packing_op op)
0649 {
0650     sja1105_packing(buf, &cmd->valid, 31, 31,
0651             SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
0652 }
0653 
0654 static size_t
0655 sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
0656                      enum packing_op op)
0657 {
0658     struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
0659 
0660     sja1105_packing(buf, &entry->poly, 7, 0,
0661             SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
0662     /* Bogus return value, not used anywhere */
0663     return 0;
0664 }
0665 
0666 static void
0667 sja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
0668                      struct sja1105_dyn_cmd *cmd,
0669                      enum packing_op op)
0670 {
0671     u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY;
0672     const int size = SJA1105_SIZE_DYN_CMD;
0673 
0674     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0675     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0676 }
0677 
0678 static void
0679 sja1110_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0680                      enum packing_op op)
0681 {
0682     u8 *p = buf + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY;
0683     const int size = SJA1105_SIZE_DYN_CMD;
0684 
0685     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0686     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0687     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0688 }
0689 
0690 static void
0691 sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0692                      enum packing_op op)
0693 {
0694     const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
0695 
0696     sja1105_packing(buf, &cmd->valid,  31, 31, size, op);
0697     sja1105_packing(buf, &cmd->errors, 30, 30, size, op);
0698 }
0699 
0700 static size_t
0701 sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
0702                        enum packing_op op)
0703 {
0704     struct sja1105_general_params_entry *entry = entry_ptr;
0705     const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
0706 
0707     sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op);
0708     /* Bogus return value, not used anywhere */
0709     return 0;
0710 }
0711 
0712 static void
0713 sja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0714                        enum packing_op op)
0715 {
0716     u8 *p = buf + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY;
0717     const int size = SJA1105_SIZE_DYN_CMD;
0718 
0719     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0720     sja1105_packing(p, &cmd->errors,  30, 30, size, op);
0721     sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op);
0722 }
0723 
0724 static void
0725 sja1110_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0726                    enum packing_op op)
0727 {
0728     u8 *p = buf + SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
0729     const int size = SJA1105_SIZE_DYN_CMD;
0730 
0731     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0732     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0733     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0734 }
0735 
0736 static void
0737 sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0738                    enum packing_op op)
0739 {
0740     u8 *p = buf + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
0741     const int size = SJA1105_SIZE_DYN_CMD;
0742 
0743     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0744     sja1105_packing(p, &cmd->errors,  30, 30, size, op);
0745     sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
0746 }
0747 
0748 static void
0749 sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0750                   enum packing_op op)
0751 {
0752     u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
0753     const int size = SJA1105_SIZE_DYN_CMD;
0754 
0755     sja1105_packing(p, &cmd->valid,    31, 31, size, op);
0756     sja1105_packing(p, &cmd->errors,   30, 30, size, op);
0757     sja1105_packing(p, &cmd->valident, 29, 29, size, op);
0758     sja1105_packing(p, &cmd->rdwrset,  28, 28, size, op);
0759     sja1105_packing(p, &cmd->index,     5,  0, size, op);
0760 }
0761 
0762 static void
0763 sja1110_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0764                   enum packing_op op)
0765 {
0766     u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
0767     const int size = SJA1105_SIZE_DYN_CMD;
0768 
0769     sja1105_packing(p, &cmd->valid,    31, 31, size, op);
0770     sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
0771     sja1105_packing(p, &cmd->errors,   29, 29, size, op);
0772     sja1105_packing(p, &cmd->valident, 28, 28, size, op);
0773     sja1105_packing(p, &cmd->index,     4,  0, size, op);
0774 }
0775 
0776 static void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0777                       enum packing_op op)
0778 {
0779     u8 *p = buf + SJA1105ET_SIZE_CBS_ENTRY;
0780     const int size = SJA1105_SIZE_DYN_CMD;
0781 
0782     sja1105_packing(p, &cmd->valid, 31, 31, size, op);
0783     sja1105_packing(p, &cmd->index, 19, 16, size, op);
0784 }
0785 
0786 static size_t sja1105et_cbs_entry_packing(void *buf, void *entry_ptr,
0787                       enum packing_op op)
0788 {
0789     const size_t size = SJA1105ET_SIZE_CBS_ENTRY;
0790     struct sja1105_cbs_entry *entry = entry_ptr;
0791     u8 *cmd = buf + size;
0792     u32 *p = buf;
0793 
0794     sja1105_packing(cmd, &entry->port, 5, 3, SJA1105_SIZE_DYN_CMD, op);
0795     sja1105_packing(cmd, &entry->prio, 2, 0, SJA1105_SIZE_DYN_CMD, op);
0796     sja1105_packing(p + 3, &entry->credit_lo,  31, 0, size, op);
0797     sja1105_packing(p + 2, &entry->credit_hi,  31, 0, size, op);
0798     sja1105_packing(p + 1, &entry->send_slope, 31, 0, size, op);
0799     sja1105_packing(p + 0, &entry->idle_slope, 31, 0, size, op);
0800     return size;
0801 }
0802 
0803 static void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0804                     enum packing_op op)
0805 {
0806     u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
0807     const int size = SJA1105_SIZE_DYN_CMD;
0808 
0809     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0810     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0811     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0812     sja1105_packing(p, &cmd->index,    3,  0, size, op);
0813 }
0814 
0815 static void sja1110_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0816                     enum packing_op op)
0817 {
0818     u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
0819     const int size = SJA1105_SIZE_DYN_CMD;
0820 
0821     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0822     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0823     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0824     sja1105_packing(p, &cmd->index,    7,  0, size, op);
0825 }
0826 
0827 static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
0828                         enum packing_op op)
0829 {
0830     const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
0831     struct sja1105_cbs_entry *entry = entry_ptr;
0832 
0833     sja1105_packing(buf, &entry->port,      159, 157, size, op);
0834     sja1105_packing(buf, &entry->prio,      156, 154, size, op);
0835     sja1105_packing(buf, &entry->credit_lo, 153, 122, size, op);
0836     sja1105_packing(buf, &entry->credit_hi, 121,  90, size, op);
0837     sja1105_packing(buf, &entry->send_slope, 89,  58, size, op);
0838     sja1105_packing(buf, &entry->idle_slope, 57,  26, size, op);
0839     return size;
0840 }
0841 
0842 static size_t sja1110_cbs_entry_packing(void *buf, void *entry_ptr,
0843                     enum packing_op op)
0844 {
0845     const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
0846     struct sja1105_cbs_entry *entry = entry_ptr;
0847     u64 entry_type = SJA1110_CBS_SHAPER;
0848 
0849     sja1105_packing(buf, &entry_type,       159, 159, size, op);
0850     sja1105_packing(buf, &entry->credit_lo, 151, 120, size, op);
0851     sja1105_packing(buf, &entry->credit_hi, 119,  88, size, op);
0852     sja1105_packing(buf, &entry->send_slope, 87,  56, size, op);
0853     sja1105_packing(buf, &entry->idle_slope, 55,  24, size, op);
0854     return size;
0855 }
0856 
0857 static void sja1110_dummy_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0858                       enum packing_op op)
0859 {
0860 }
0861 
0862 static void
0863 sja1110_l2_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
0864                 enum packing_op op)
0865 {
0866     u8 *p = buf + SJA1105_SIZE_L2_POLICING_ENTRY;
0867     const int size = SJA1105_SIZE_DYN_CMD;
0868 
0869     sja1105_packing(p, &cmd->valid,   31, 31, size, op);
0870     sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
0871     sja1105_packing(p, &cmd->errors,  29, 29, size, op);
0872     sja1105_packing(p, &cmd->index,    6,  0, size, op);
0873 }
0874 
0875 #define OP_READ     BIT(0)
0876 #define OP_WRITE    BIT(1)
0877 #define OP_DEL      BIT(2)
0878 #define OP_SEARCH   BIT(3)
0879 #define OP_VALID_ANYWAY BIT(4)
0880 
0881 /* SJA1105E/T: First generation */
0882 const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
0883     [BLK_IDX_VL_LOOKUP] = {
0884         .entry_packing = sja1105et_vl_lookup_entry_packing,
0885         .cmd_packing = sja1105et_vl_lookup_cmd_packing,
0886         .access = OP_WRITE,
0887         .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
0888         .packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
0889         .addr = 0x35,
0890     },
0891     [BLK_IDX_L2_LOOKUP] = {
0892         .entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
0893         .cmd_packing = sja1105et_l2_lookup_cmd_packing,
0894         .access = (OP_READ | OP_WRITE | OP_DEL),
0895         .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
0896         .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
0897         .addr = 0x20,
0898     },
0899     [BLK_IDX_MGMT_ROUTE] = {
0900         .entry_packing = sja1105et_mgmt_route_entry_packing,
0901         .cmd_packing = sja1105et_mgmt_route_cmd_packing,
0902         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
0903         .max_entry_count = SJA1105_NUM_PORTS,
0904         .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
0905         .addr = 0x20,
0906     },
0907     [BLK_IDX_VLAN_LOOKUP] = {
0908         .entry_packing = sja1105_vlan_lookup_entry_packing,
0909         .cmd_packing = sja1105_vlan_lookup_cmd_packing,
0910         .access = (OP_WRITE | OP_DEL),
0911         .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
0912         .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
0913         .addr = 0x27,
0914     },
0915     [BLK_IDX_L2_FORWARDING] = {
0916         .entry_packing = sja1105_l2_forwarding_entry_packing,
0917         .cmd_packing = sja1105_l2_forwarding_cmd_packing,
0918         .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
0919         .access = OP_WRITE,
0920         .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
0921         .addr = 0x24,
0922     },
0923     [BLK_IDX_MAC_CONFIG] = {
0924         .entry_packing = sja1105et_mac_config_entry_packing,
0925         .cmd_packing = sja1105et_mac_config_cmd_packing,
0926         .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
0927         .access = OP_WRITE,
0928         .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
0929         .addr = 0x36,
0930     },
0931     [BLK_IDX_L2_LOOKUP_PARAMS] = {
0932         .entry_packing = sja1105et_l2_lookup_params_entry_packing,
0933         .cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
0934         .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
0935         .access = OP_WRITE,
0936         .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
0937         .addr = 0x38,
0938     },
0939     [BLK_IDX_GENERAL_PARAMS] = {
0940         .entry_packing = sja1105et_general_params_entry_packing,
0941         .cmd_packing = sja1105et_general_params_cmd_packing,
0942         .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
0943         .access = OP_WRITE,
0944         .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
0945         .addr = 0x34,
0946     },
0947     [BLK_IDX_RETAGGING] = {
0948         .entry_packing = sja1105_retagging_entry_packing,
0949         .cmd_packing = sja1105_retagging_cmd_packing,
0950         .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
0951         .access = (OP_WRITE | OP_DEL),
0952         .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
0953         .addr = 0x31,
0954     },
0955     [BLK_IDX_CBS] = {
0956         .entry_packing = sja1105et_cbs_entry_packing,
0957         .cmd_packing = sja1105et_cbs_cmd_packing,
0958         .max_entry_count = SJA1105ET_MAX_CBS_COUNT,
0959         .access = OP_WRITE,
0960         .packed_size = SJA1105ET_SIZE_CBS_DYN_CMD,
0961         .addr = 0x2c,
0962     },
0963 };
0964 
0965 /* SJA1105P/Q/R/S: Second generation */
0966 const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
0967     [BLK_IDX_VL_LOOKUP] = {
0968         .entry_packing = sja1105_vl_lookup_entry_packing,
0969         .cmd_packing = sja1105pqrs_vl_lookup_cmd_packing,
0970         .access = (OP_READ | OP_WRITE),
0971         .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
0972         .packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
0973         .addr = 0x47,
0974     },
0975     [BLK_IDX_L2_LOOKUP] = {
0976         .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
0977         .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
0978         .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
0979         .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
0980         .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
0981         .addr = 0x24,
0982     },
0983     [BLK_IDX_MGMT_ROUTE] = {
0984         .entry_packing = sja1105pqrs_mgmt_route_entry_packing,
0985         .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
0986         .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH | OP_VALID_ANYWAY),
0987         .max_entry_count = SJA1105_NUM_PORTS,
0988         .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
0989         .addr = 0x24,
0990     },
0991     [BLK_IDX_VLAN_LOOKUP] = {
0992         .entry_packing = sja1105_vlan_lookup_entry_packing,
0993         .cmd_packing = sja1105_vlan_lookup_cmd_packing,
0994         .access = (OP_READ | OP_WRITE | OP_DEL),
0995         .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
0996         .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
0997         .addr = 0x2D,
0998     },
0999     [BLK_IDX_L2_FORWARDING] = {
1000         .entry_packing = sja1105_l2_forwarding_entry_packing,
1001         .cmd_packing = sja1105_l2_forwarding_cmd_packing,
1002         .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
1003         .access = OP_WRITE,
1004         .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
1005         .addr = 0x2A,
1006     },
1007     [BLK_IDX_MAC_CONFIG] = {
1008         .entry_packing = sja1105pqrs_mac_config_entry_packing,
1009         .cmd_packing = sja1105pqrs_mac_config_cmd_packing,
1010         .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
1011         .access = (OP_READ | OP_WRITE),
1012         .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
1013         .addr = 0x4B,
1014     },
1015     [BLK_IDX_L2_LOOKUP_PARAMS] = {
1016         .entry_packing = sja1105pqrs_l2_lookup_params_entry_packing,
1017         .cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing,
1018         .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
1019         .access = (OP_READ | OP_WRITE),
1020         .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
1021         .addr = 0x54,
1022     },
1023     [BLK_IDX_AVB_PARAMS] = {
1024         .entry_packing = sja1105pqrs_avb_params_entry_packing,
1025         .cmd_packing = sja1105pqrs_avb_params_cmd_packing,
1026         .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
1027         .access = (OP_READ | OP_WRITE),
1028         .packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
1029         .addr = 0x8003,
1030     },
1031     [BLK_IDX_GENERAL_PARAMS] = {
1032         .entry_packing = sja1105pqrs_general_params_entry_packing,
1033         .cmd_packing = sja1105pqrs_general_params_cmd_packing,
1034         .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
1035         .access = (OP_READ | OP_WRITE),
1036         .packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD,
1037         .addr = 0x3B,
1038     },
1039     [BLK_IDX_RETAGGING] = {
1040         .entry_packing = sja1105_retagging_entry_packing,
1041         .cmd_packing = sja1105_retagging_cmd_packing,
1042         .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
1043         .access = (OP_READ | OP_WRITE | OP_DEL),
1044         .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
1045         .addr = 0x38,
1046     },
1047     [BLK_IDX_CBS] = {
1048         .entry_packing = sja1105pqrs_cbs_entry_packing,
1049         .cmd_packing = sja1105pqrs_cbs_cmd_packing,
1050         .max_entry_count = SJA1105PQRS_MAX_CBS_COUNT,
1051         .access = OP_WRITE,
1052         .packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
1053         .addr = 0x32,
1054     },
1055 };
1056 
1057 /* SJA1110: Third generation */
1058 const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = {
1059     [BLK_IDX_VL_LOOKUP] = {
1060         .entry_packing = sja1110_vl_lookup_entry_packing,
1061         .cmd_packing = sja1110_vl_lookup_cmd_packing,
1062         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1063         .max_entry_count = SJA1110_MAX_VL_LOOKUP_COUNT,
1064         .packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
1065         .addr = SJA1110_SPI_ADDR(0x124),
1066     },
1067     [BLK_IDX_VL_POLICING] = {
1068         .entry_packing = sja1110_vl_policing_entry_packing,
1069         .cmd_packing = sja1110_vl_policing_cmd_packing,
1070         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1071         .max_entry_count = SJA1110_MAX_VL_POLICING_COUNT,
1072         .packed_size = SJA1110_SIZE_VL_POLICING_DYN_CMD,
1073         .addr = SJA1110_SPI_ADDR(0x310),
1074     },
1075     [BLK_IDX_L2_LOOKUP] = {
1076         .entry_packing = sja1110_dyn_l2_lookup_entry_packing,
1077         .cmd_packing = sja1110_l2_lookup_cmd_packing,
1078         .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
1079         .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
1080         .packed_size = SJA1110_SIZE_L2_LOOKUP_DYN_CMD,
1081         .addr = SJA1110_SPI_ADDR(0x8c),
1082     },
1083     [BLK_IDX_VLAN_LOOKUP] = {
1084         .entry_packing = sja1110_vlan_lookup_entry_packing,
1085         .cmd_packing = sja1110_vlan_lookup_cmd_packing,
1086         .access = (OP_READ | OP_WRITE | OP_DEL),
1087         .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
1088         .packed_size = SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD,
1089         .addr = SJA1110_SPI_ADDR(0xb4),
1090     },
1091     [BLK_IDX_L2_FORWARDING] = {
1092         .entry_packing = sja1110_l2_forwarding_entry_packing,
1093         .cmd_packing = sja1110_l2_forwarding_cmd_packing,
1094         .max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
1095         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1096         .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
1097         .addr = SJA1110_SPI_ADDR(0xa8),
1098     },
1099     [BLK_IDX_MAC_CONFIG] = {
1100         .entry_packing = sja1110_mac_config_entry_packing,
1101         .cmd_packing = sja1110_mac_config_cmd_packing,
1102         .max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
1103         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1104         .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
1105         .addr = SJA1110_SPI_ADDR(0x134),
1106     },
1107     [BLK_IDX_L2_LOOKUP_PARAMS] = {
1108         .entry_packing = sja1110_l2_lookup_params_entry_packing,
1109         .cmd_packing = sja1110_l2_lookup_params_cmd_packing,
1110         .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
1111         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1112         .packed_size = SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
1113         .addr = SJA1110_SPI_ADDR(0x158),
1114     },
1115     [BLK_IDX_AVB_PARAMS] = {
1116         .entry_packing = sja1105pqrs_avb_params_entry_packing,
1117         .cmd_packing = sja1105pqrs_avb_params_cmd_packing,
1118         .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
1119         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1120         .packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
1121         .addr = SJA1110_SPI_ADDR(0x2000C),
1122     },
1123     [BLK_IDX_GENERAL_PARAMS] = {
1124         .entry_packing = sja1110_general_params_entry_packing,
1125         .cmd_packing = sja1110_general_params_cmd_packing,
1126         .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
1127         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1128         .packed_size = SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD,
1129         .addr = SJA1110_SPI_ADDR(0xe8),
1130     },
1131     [BLK_IDX_RETAGGING] = {
1132         .entry_packing = sja1110_retagging_entry_packing,
1133         .cmd_packing = sja1110_retagging_cmd_packing,
1134         .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
1135         .access = (OP_READ | OP_WRITE | OP_DEL),
1136         .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
1137         .addr = SJA1110_SPI_ADDR(0xdc),
1138     },
1139     [BLK_IDX_CBS] = {
1140         .entry_packing = sja1110_cbs_entry_packing,
1141         .cmd_packing = sja1110_cbs_cmd_packing,
1142         .max_entry_count = SJA1110_MAX_CBS_COUNT,
1143         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1144         .packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
1145         .addr = SJA1110_SPI_ADDR(0xc4),
1146     },
1147     [BLK_IDX_XMII_PARAMS] = {
1148         .entry_packing = sja1110_xmii_params_entry_packing,
1149         .cmd_packing = sja1110_dummy_cmd_packing,
1150         .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
1151         .access = (OP_READ | OP_VALID_ANYWAY),
1152         .packed_size = SJA1110_SIZE_XMII_PARAMS_DYN_CMD,
1153         .addr = SJA1110_SPI_ADDR(0x3c),
1154     },
1155     [BLK_IDX_L2_POLICING] = {
1156         .entry_packing = sja1110_l2_policing_entry_packing,
1157         .cmd_packing = sja1110_l2_policing_cmd_packing,
1158         .max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
1159         .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
1160         .packed_size = SJA1110_SIZE_L2_POLICING_DYN_CMD,
1161         .addr = SJA1110_SPI_ADDR(0x2fc),
1162     },
1163     [BLK_IDX_L2_FORWARDING_PARAMS] = {
1164         .entry_packing = sja1110_l2_forwarding_params_entry_packing,
1165         .cmd_packing = sja1110_dummy_cmd_packing,
1166         .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
1167         .access = (OP_READ | OP_VALID_ANYWAY),
1168         .packed_size = SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD,
1169         .addr = SJA1110_SPI_ADDR(0x20000),
1170     },
1171 };
1172 
1173 #define SJA1105_DYNAMIC_CONFIG_SLEEP_US     10
1174 #define SJA1105_DYNAMIC_CONFIG_TIMEOUT_US   100000
1175 
1176 static int
1177 sja1105_dynamic_config_poll_valid(struct sja1105_private *priv,
1178                   struct sja1105_dyn_cmd *cmd,
1179                   const struct sja1105_dynamic_table_ops *ops)
1180 {
1181     u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {};
1182     int rc;
1183 
1184     /* We don't _need_ to read the full entry, just the command area which
1185      * is a fixed SJA1105_SIZE_DYN_CMD. But our cmd_packing() API expects a
1186      * buffer that contains the full entry too. Additionally, our API
1187      * doesn't really know how many bytes into the buffer does the command
1188      * area really begin. So just read back the whole entry.
1189      */
1190     rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf,
1191                   ops->packed_size);
1192     if (rc)
1193         return rc;
1194 
1195     /* Unpack the command structure, and return it to the caller in case it
1196      * needs to perform further checks on it (VALIDENT).
1197      */
1198     memset(cmd, 0, sizeof(*cmd));
1199     ops->cmd_packing(packed_buf, cmd, UNPACK);
1200 
1201     /* Hardware hasn't cleared VALID => still working on it */
1202     return cmd->valid ? -EAGAIN : 0;
1203 }
1204 
1205 /* Poll the dynamic config entry's control area until the hardware has
1206  * cleared the VALID bit, which means we have confirmation that it has
1207  * finished processing the command.
1208  */
1209 static int
1210 sja1105_dynamic_config_wait_complete(struct sja1105_private *priv,
1211                      struct sja1105_dyn_cmd *cmd,
1212                      const struct sja1105_dynamic_table_ops *ops)
1213 {
1214     int rc;
1215 
1216     return read_poll_timeout(sja1105_dynamic_config_poll_valid,
1217                  rc, rc != -EAGAIN,
1218                  SJA1105_DYNAMIC_CONFIG_SLEEP_US,
1219                  SJA1105_DYNAMIC_CONFIG_TIMEOUT_US,
1220                  false, priv, cmd, ops);
1221 }
1222 
1223 /* Provides read access to the settings through the dynamic interface
1224  * of the switch.
1225  * @blk_idx is used as key to select from the sja1105_dynamic_table_ops.
1226  *      The selection is limited by the hardware in respect to which
1227  *      configuration blocks can be read through the dynamic interface.
1228  * @index   is used to retrieve a particular table entry. If negative,
1229  *      (and if the @blk_idx supports the searching operation) a search
1230  *      is performed by the @entry parameter.
1231  * @entry   Type-casted to an unpacked structure that holds a table entry
1232  *      of the type specified in @blk_idx.
1233  *      Usually an output argument. If @index is negative, then this
1234  *      argument is used as input/output: it should be pre-populated
1235  *      with the element to search for. Entries which support the
1236  *      search operation will have an "index" field (not the @index
1237  *      argument to this function) and that is where the found index
1238  *      will be returned (or left unmodified - thus negative - if not
1239  *      found).
1240  */
1241 int sja1105_dynamic_config_read(struct sja1105_private *priv,
1242                 enum sja1105_blk_idx blk_idx,
1243                 int index, void *entry)
1244 {
1245     const struct sja1105_dynamic_table_ops *ops;
1246     struct sja1105_dyn_cmd cmd = {0};
1247     /* SPI payload buffer */
1248     u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
1249     int rc;
1250 
1251     if (blk_idx >= BLK_IDX_MAX_DYN)
1252         return -ERANGE;
1253 
1254     ops = &priv->info->dyn_ops[blk_idx];
1255 
1256     if (index >= 0 && index >= ops->max_entry_count)
1257         return -ERANGE;
1258     if (index < 0 && !(ops->access & OP_SEARCH))
1259         return -EOPNOTSUPP;
1260     if (!(ops->access & OP_READ))
1261         return -EOPNOTSUPP;
1262     if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
1263         return -ERANGE;
1264     if (!ops->cmd_packing)
1265         return -EOPNOTSUPP;
1266     if (!ops->entry_packing)
1267         return -EOPNOTSUPP;
1268 
1269     cmd.valid = true; /* Trigger action on table entry */
1270     cmd.rdwrset = SPI_READ; /* Action is read */
1271     if (index < 0) {
1272         /* Avoid copying a signed negative number to an u64 */
1273         cmd.index = 0;
1274         cmd.search = true;
1275     } else {
1276         cmd.index = index;
1277         cmd.search = false;
1278     }
1279     cmd.valident = true;
1280     ops->cmd_packing(packed_buf, &cmd, PACK);
1281 
1282     if (cmd.search)
1283         ops->entry_packing(packed_buf, entry, PACK);
1284 
1285     /* Send SPI write operation: read config table entry */
1286     mutex_lock(&priv->dynamic_config_lock);
1287     rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
1288                   ops->packed_size);
1289     if (rc < 0) {
1290         mutex_unlock(&priv->dynamic_config_lock);
1291         return rc;
1292     }
1293 
1294     rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops);
1295     mutex_unlock(&priv->dynamic_config_lock);
1296     if (rc < 0)
1297         return rc;
1298 
1299     if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
1300         return -ENOENT;
1301 
1302     /* Don't dereference possibly NULL pointer - maybe caller
1303      * only wanted to see whether the entry existed or not.
1304      */
1305     if (entry)
1306         ops->entry_packing(packed_buf, entry, UNPACK);
1307     return 0;
1308 }
1309 
1310 int sja1105_dynamic_config_write(struct sja1105_private *priv,
1311                  enum sja1105_blk_idx blk_idx,
1312                  int index, void *entry, bool keep)
1313 {
1314     const struct sja1105_dynamic_table_ops *ops;
1315     struct sja1105_dyn_cmd cmd = {0};
1316     /* SPI payload buffer */
1317     u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
1318     int rc;
1319 
1320     if (blk_idx >= BLK_IDX_MAX_DYN)
1321         return -ERANGE;
1322 
1323     ops = &priv->info->dyn_ops[blk_idx];
1324 
1325     if (index >= ops->max_entry_count)
1326         return -ERANGE;
1327     if (index < 0)
1328         return -ERANGE;
1329     if (!(ops->access & OP_WRITE))
1330         return -EOPNOTSUPP;
1331     if (!keep && !(ops->access & OP_DEL))
1332         return -EOPNOTSUPP;
1333     if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
1334         return -ERANGE;
1335 
1336     cmd.valident = keep; /* If false, deletes entry */
1337     cmd.valid = true; /* Trigger action on table entry */
1338     cmd.rdwrset = SPI_WRITE; /* Action is write */
1339     cmd.index = index;
1340 
1341     if (!ops->cmd_packing)
1342         return -EOPNOTSUPP;
1343     ops->cmd_packing(packed_buf, &cmd, PACK);
1344 
1345     if (!ops->entry_packing)
1346         return -EOPNOTSUPP;
1347     /* Don't dereference potentially NULL pointer if just
1348      * deleting a table entry is what was requested. For cases
1349      * where 'index' field is physically part of entry structure,
1350      * and needed here, we deal with that in the cmd_packing callback.
1351      */
1352     if (keep)
1353         ops->entry_packing(packed_buf, entry, PACK);
1354 
1355     /* Send SPI write operation: read config table entry */
1356     mutex_lock(&priv->dynamic_config_lock);
1357     rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
1358                   ops->packed_size);
1359     if (rc < 0) {
1360         mutex_unlock(&priv->dynamic_config_lock);
1361         return rc;
1362     }
1363 
1364     rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops);
1365     mutex_unlock(&priv->dynamic_config_lock);
1366     if (rc < 0)
1367         return rc;
1368 
1369     cmd = (struct sja1105_dyn_cmd) {0};
1370     ops->cmd_packing(packed_buf, &cmd, UNPACK);
1371     if (cmd.errors)
1372         return -EINVAL;
1373 
1374     return 0;
1375 }
1376 
1377 static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
1378 {
1379     int i;
1380 
1381     for (i = 0; i < 8; i++) {
1382         if ((crc ^ byte) & (1 << 7)) {
1383             crc <<= 1;
1384             crc ^= poly;
1385         } else {
1386             crc <<= 1;
1387         }
1388         byte <<= 1;
1389     }
1390     return crc;
1391 }
1392 
1393 /* CRC8 algorithm with non-reversed input, non-reversed output,
1394  * no input xor and no output xor. Code customized for receiving
1395  * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
1396  * is also received as argument in the Koopman notation that the switch
1397  * hardware stores it in.
1398  */
1399 u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
1400 {
1401     struct sja1105_l2_lookup_params_entry *l2_lookup_params =
1402         priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
1403     u64 input, poly_koopman = l2_lookup_params->poly;
1404     /* Convert polynomial from Koopman to 'normal' notation */
1405     u8 poly = (u8)(1 + (poly_koopman << 1));
1406     u8 crc = 0; /* seed */
1407     int i;
1408 
1409     input = ((u64)vid << 48) | ether_addr_to_u64(addr);
1410 
1411     /* Mask the eight bytes starting from MSB one at a time */
1412     for (i = 56; i >= 0; i -= 8) {
1413         u8 byte = (input & (0xffull << i)) >> i;
1414 
1415         crc = sja1105_crc8_add(crc, byte, poly);
1416     }
1417     return crc;
1418 }