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