root/drivers/net/dsa/sja1105/sja1105_dynamic_config.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sja1105pqrs_l2_lookup_cmd_packing
  2. sja1105pqrs_dyn_l2_lookup_entry_packing
  3. sja1105et_l2_lookup_cmd_packing
  4. sja1105et_dyn_l2_lookup_entry_packing
  5. sja1105et_mgmt_route_cmd_packing
  6. sja1105et_mgmt_route_entry_packing
  7. sja1105pqrs_mgmt_route_cmd_packing
  8. sja1105pqrs_mgmt_route_entry_packing
  9. sja1105_vlan_lookup_cmd_packing
  10. sja1105_l2_forwarding_cmd_packing
  11. sja1105et_mac_config_cmd_packing
  12. sja1105et_mac_config_entry_packing
  13. sja1105pqrs_mac_config_cmd_packing
  14. sja1105et_l2_lookup_params_cmd_packing
  15. sja1105et_l2_lookup_params_entry_packing
  16. sja1105et_general_params_cmd_packing
  17. sja1105et_general_params_entry_packing
  18. sja1105_dynamic_config_read
  19. sja1105_dynamic_config_write
  20. sja1105_crc8_add
  21. sja1105et_fdb_hash

   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_MAC_CONFIG_DYN_ENTRY                     \
 101         SJA1105_SIZE_DYN_CMD
 102 
 103 #define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD                        \
 104         (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY)
 105 
 106 #define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD                      \
 107         (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
 108 
 109 #define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD                        \
 110         (SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
 111 
 112 #define SJA1105_SIZE_L2_FORWARDING_DYN_CMD                      \
 113         (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
 114 
 115 #define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD                       \
 116         (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY)
 117 
 118 #define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD                     \
 119         (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY)
 120 
 121 #define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD                 \
 122         SJA1105_SIZE_DYN_CMD
 123 
 124 #define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD                   \
 125         SJA1105_SIZE_DYN_CMD
 126 
 127 #define SJA1105_MAX_DYN_CMD_SIZE                                \
 128         SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD
 129 
 130 struct sja1105_dyn_cmd {
 131         bool search;
 132         u64 valid;
 133         u64 rdwrset;
 134         u64 errors;
 135         u64 valident;
 136         u64 index;
 137 };
 138 
 139 enum sja1105_hostcmd {
 140         SJA1105_HOSTCMD_SEARCH = 1,
 141         SJA1105_HOSTCMD_READ = 2,
 142         SJA1105_HOSTCMD_WRITE = 3,
 143         SJA1105_HOSTCMD_INVALIDATE = 4,
 144 };
 145 
 146 static void
 147 sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 148                                   enum packing_op op)
 149 {
 150         u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
 151         const int size = SJA1105_SIZE_DYN_CMD;
 152         u64 hostcmd;
 153 
 154         sja1105_packing(p, &cmd->valid,    31, 31, size, op);
 155         sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
 156         sja1105_packing(p, &cmd->errors,   29, 29, size, op);
 157         sja1105_packing(p, &cmd->valident, 27, 27, size, op);
 158 
 159         /* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
 160          * using it to delete a management route was unsupported. UM10944
 161          * said about it:
 162          *
 163          *   In case of a write access with the MGMTROUTE flag set,
 164          *   the flag will be ignored. It will always be found cleared
 165          *   for read accesses with the MGMTROUTE flag set.
 166          *
 167          * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there
 168          * is now another flag called HOSTCMD which does more stuff (quoting
 169          * from UM11040):
 170          *
 171          *   A write request is accepted only when HOSTCMD is set to write host
 172          *   or invalid. A read request is accepted only when HOSTCMD is set to
 173          *   search host or read host.
 174          *
 175          * So it is possible to translate a RDWRSET/VALIDENT combination into
 176          * HOSTCMD so that we keep the dynamic command API in place, and
 177          * at the same time achieve compatibility with the management route
 178          * command structure.
 179          */
 180         if (cmd->rdwrset == SPI_READ) {
 181                 if (cmd->search)
 182                         hostcmd = SJA1105_HOSTCMD_SEARCH;
 183                 else
 184                         hostcmd = SJA1105_HOSTCMD_READ;
 185         } else {
 186                 /* SPI_WRITE */
 187                 if (cmd->valident)
 188                         hostcmd = SJA1105_HOSTCMD_WRITE;
 189                 else
 190                         hostcmd = SJA1105_HOSTCMD_INVALIDATE;
 191         }
 192         sja1105_packing(p, &hostcmd, 25, 23, size, op);
 193 
 194         /* Hack - The hardware takes the 'index' field within
 195          * struct sja1105_l2_lookup_entry as the index on which this command
 196          * will operate. However it will ignore everything else, so 'index'
 197          * is logically part of command but physically part of entry.
 198          * Populate the 'index' entry field from within the command callback,
 199          * such that our API doesn't need to ask for a full-blown entry
 200          * structure when e.g. a delete is requested.
 201          */
 202         sja1105_packing(buf, &cmd->index, 15, 6,
 203                         SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
 204 }
 205 
 206 /* The switch is so retarded that it makes our command/entry abstraction
 207  * crumble apart.
 208  *
 209  * On P/Q/R/S, the switch tries to say whether a FDB entry
 210  * is statically programmed or dynamically learned via a flag called LOCKEDS.
 211  * The hardware manual says about this fiels:
 212  *
 213  *   On write will specify the format of ENTRY.
 214  *   On read the flag will be found cleared at times the VALID flag is found
 215  *   set.  The flag will also be found cleared in response to a read having the
 216  *   MGMTROUTE flag set.  In response to a read with the MGMTROUTE flag
 217  *   cleared, the flag be set if the most recent access operated on an entry
 218  *   that was either loaded by configuration or through dynamic reconfiguration
 219  *   (as opposed to automatically learned entries).
 220  *
 221  * The trouble with this flag is that it's part of the *command* to access the
 222  * dynamic interface, and not part of the *entry* retrieved from it.
 223  * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
 224  * an output from the switch into the command buffer, and for a
 225  * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
 226  * (hence we can write either static, or automatically learned entries, from
 227  * the core).
 228  * But the manual contradicts itself in the last phrase where it says that on
 229  * read, LOCKEDS will be set to 1 for all FDB entries written through the
 230  * dynamic interface (therefore, the value of LOCKEDS from the
 231  * sja1105_dynamic_config_write is not really used for anything, it'll store a
 232  * 1 anyway).
 233  * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
 234  * learned) into the switch, which kind of makes sense.
 235  * As for reading through the dynamic interface, it doesn't make too much sense
 236  * to put LOCKEDS into the command, since the switch will inevitably have to
 237  * ignore it (otherwise a command would be like "read the FDB entry 123, but
 238  * only if it's dynamically learned" <- well how am I supposed to know?) and
 239  * just use it as an output buffer for its findings. But guess what... that's
 240  * what the entry buffer is for!
 241  * Unfortunately, what really breaks this abstraction is the fact that it
 242  * wasn't designed having the fact in mind that the switch can output
 243  * entry-related data as writeback through the command buffer.
 244  * However, whether a FDB entry is statically or dynamically learned *is* part
 245  * of the entry and not the command data, no matter what the switch thinks.
 246  * In order to do that, we'll need to wrap around the
 247  * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
 248  * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
 249  * command buffer.
 250  */
 251 static size_t
 252 sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
 253                                         enum packing_op op)
 254 {
 255         struct sja1105_l2_lookup_entry *entry = entry_ptr;
 256         u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
 257         const int size = SJA1105_SIZE_DYN_CMD;
 258 
 259         sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
 260 
 261         return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
 262 }
 263 
 264 static void
 265 sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 266                                 enum packing_op op)
 267 {
 268         u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
 269         const int size = SJA1105_SIZE_DYN_CMD;
 270 
 271         sja1105_packing(p, &cmd->valid,    31, 31, size, op);
 272         sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
 273         sja1105_packing(p, &cmd->errors,   29, 29, size, op);
 274         sja1105_packing(p, &cmd->valident, 27, 27, size, op);
 275         /* Hack - see comments above. */
 276         sja1105_packing(buf, &cmd->index, 29, 20,
 277                         SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
 278 }
 279 
 280 static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
 281                                                     enum packing_op op)
 282 {
 283         struct sja1105_l2_lookup_entry *entry = entry_ptr;
 284         u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
 285         const int size = SJA1105_SIZE_DYN_CMD;
 286 
 287         sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
 288 
 289         return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
 290 }
 291 
 292 static void
 293 sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 294                                  enum packing_op op)
 295 {
 296         u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
 297         u64 mgmtroute = 1;
 298 
 299         sja1105et_l2_lookup_cmd_packing(buf, cmd, op);
 300         if (op == PACK)
 301                 sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
 302 }
 303 
 304 static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
 305                                                  enum packing_op op)
 306 {
 307         struct sja1105_mgmt_entry *entry = entry_ptr;
 308         const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
 309 
 310         /* UM10944: To specify if a PTP egress timestamp shall be captured on
 311          * each port upon transmission of the frame, the LSB of VLANID in the
 312          * ENTRY field provided by the host must be set.
 313          * Bit 1 of VLANID then specifies the register where the timestamp for
 314          * this port is stored in.
 315          */
 316         sja1105_packing(buf, &entry->tsreg,     85, 85, size, op);
 317         sja1105_packing(buf, &entry->takets,    84, 84, size, op);
 318         sja1105_packing(buf, &entry->macaddr,   83, 36, size, op);
 319         sja1105_packing(buf, &entry->destports, 35, 31, size, op);
 320         sja1105_packing(buf, &entry->enfport,   30, 30, size, op);
 321         return size;
 322 }
 323 
 324 static void
 325 sja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 326                                    enum packing_op op)
 327 {
 328         u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
 329         u64 mgmtroute = 1;
 330 
 331         sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
 332         if (op == PACK)
 333                 sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
 334 }
 335 
 336 static size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
 337                                                    enum packing_op op)
 338 {
 339         const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
 340         struct sja1105_mgmt_entry *entry = entry_ptr;
 341 
 342         /* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
 343          * is the same (driver uses it to confirm that frame was sent).
 344          * So just keep the name from E/T.
 345          */
 346         sja1105_packing(buf, &entry->tsreg,     71, 71, size, op);
 347         sja1105_packing(buf, &entry->takets,    70, 70, size, op);
 348         sja1105_packing(buf, &entry->macaddr,   69, 22, size, op);
 349         sja1105_packing(buf, &entry->destports, 21, 17, size, op);
 350         sja1105_packing(buf, &entry->enfport,   16, 16, size, op);
 351         return size;
 352 }
 353 
 354 /* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
 355  * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
 356  * between entry (0x2d, 0x2e) and command (0x30).
 357  */
 358 static void
 359 sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 360                                 enum packing_op op)
 361 {
 362         u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4;
 363         const int size = SJA1105_SIZE_DYN_CMD;
 364 
 365         sja1105_packing(p, &cmd->valid,    31, 31, size, op);
 366         sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
 367         sja1105_packing(p, &cmd->valident, 27, 27, size, op);
 368         /* Hack - see comments above, applied for 'vlanid' field of
 369          * struct sja1105_vlan_lookup_entry.
 370          */
 371         sja1105_packing(buf, &cmd->index, 38, 27,
 372                         SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
 373 }
 374 
 375 static void
 376 sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 377                                   enum packing_op op)
 378 {
 379         u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
 380         const int size = SJA1105_SIZE_DYN_CMD;
 381 
 382         sja1105_packing(p, &cmd->valid,   31, 31, size, op);
 383         sja1105_packing(p, &cmd->errors,  30, 30, size, op);
 384         sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
 385         sja1105_packing(p, &cmd->index,    4,  0, size, op);
 386 }
 387 
 388 static void
 389 sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 390                                  enum packing_op op)
 391 {
 392         const int size = SJA1105_SIZE_DYN_CMD;
 393         /* Yup, user manual definitions are reversed */
 394         u8 *reg1 = buf + 4;
 395 
 396         sja1105_packing(reg1, &cmd->valid, 31, 31, size, op);
 397         sja1105_packing(reg1, &cmd->index, 26, 24, size, op);
 398 }
 399 
 400 static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
 401                                                  enum packing_op op)
 402 {
 403         const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
 404         struct sja1105_mac_config_entry *entry = entry_ptr;
 405         /* Yup, user manual definitions are reversed */
 406         u8 *reg1 = buf + 4;
 407         u8 *reg2 = buf;
 408 
 409         sja1105_packing(reg1, &entry->speed,     30, 29, size, op);
 410         sja1105_packing(reg1, &entry->drpdtag,   23, 23, size, op);
 411         sja1105_packing(reg1, &entry->drpuntag,  22, 22, size, op);
 412         sja1105_packing(reg1, &entry->retag,     21, 21, size, op);
 413         sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op);
 414         sja1105_packing(reg1, &entry->egress,    19, 19, size, op);
 415         sja1105_packing(reg1, &entry->ingress,   18, 18, size, op);
 416         sja1105_packing(reg1, &entry->ing_mirr,  17, 17, size, op);
 417         sja1105_packing(reg1, &entry->egr_mirr,  16, 16, size, op);
 418         sja1105_packing(reg1, &entry->vlanprio,  14, 12, size, op);
 419         sja1105_packing(reg1, &entry->vlanid,    11,  0, size, op);
 420         sja1105_packing(reg2, &entry->tp_delin,  31, 16, size, op);
 421         sja1105_packing(reg2, &entry->tp_delout, 15,  0, size, op);
 422         /* MAC configuration table entries which can't be reconfigured:
 423          * top, base, enabled, ifg, maxage, drpnona664
 424          */
 425         /* Bogus return value, not used anywhere */
 426         return 0;
 427 }
 428 
 429 static void
 430 sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 431                                    enum packing_op op)
 432 {
 433         const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY;
 434         u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
 435 
 436         sja1105_packing(p, &cmd->valid,   31, 31, size, op);
 437         sja1105_packing(p, &cmd->errors,  30, 30, size, op);
 438         sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
 439         sja1105_packing(p, &cmd->index,    2,  0, size, op);
 440 }
 441 
 442 static void
 443 sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 444                                        enum packing_op op)
 445 {
 446         sja1105_packing(buf, &cmd->valid, 31, 31,
 447                         SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
 448 }
 449 
 450 static size_t
 451 sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
 452                                          enum packing_op op)
 453 {
 454         struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
 455 
 456         sja1105_packing(buf, &entry->poly, 7, 0,
 457                         SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op);
 458         /* Bogus return value, not used anywhere */
 459         return 0;
 460 }
 461 
 462 static void
 463 sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
 464                                      enum packing_op op)
 465 {
 466         const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
 467 
 468         sja1105_packing(buf, &cmd->valid,  31, 31, size, op);
 469         sja1105_packing(buf, &cmd->errors, 30, 30, size, op);
 470 }
 471 
 472 static size_t
 473 sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
 474                                        enum packing_op op)
 475 {
 476         struct sja1105_general_params_entry *entry = entry_ptr;
 477         const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD;
 478 
 479         sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op);
 480         /* Bogus return value, not used anywhere */
 481         return 0;
 482 }
 483 
 484 #define OP_READ         BIT(0)
 485 #define OP_WRITE        BIT(1)
 486 #define OP_DEL          BIT(2)
 487 #define OP_SEARCH       BIT(3)
 488 
 489 /* SJA1105E/T: First generation */
 490 struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
 491         [BLK_IDX_SCHEDULE] = {0},
 492         [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0},
 493         [BLK_IDX_L2_LOOKUP] = {
 494                 .entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
 495                 .cmd_packing = sja1105et_l2_lookup_cmd_packing,
 496                 .access = (OP_READ | OP_WRITE | OP_DEL),
 497                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
 498                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
 499                 .addr = 0x20,
 500         },
 501         [BLK_IDX_MGMT_ROUTE] = {
 502                 .entry_packing = sja1105et_mgmt_route_entry_packing,
 503                 .cmd_packing = sja1105et_mgmt_route_cmd_packing,
 504                 .access = (OP_READ | OP_WRITE),
 505                 .max_entry_count = SJA1105_NUM_PORTS,
 506                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
 507                 .addr = 0x20,
 508         },
 509         [BLK_IDX_L2_POLICING] = {0},
 510         [BLK_IDX_VLAN_LOOKUP] = {
 511                 .entry_packing = sja1105_vlan_lookup_entry_packing,
 512                 .cmd_packing = sja1105_vlan_lookup_cmd_packing,
 513                 .access = (OP_WRITE | OP_DEL),
 514                 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
 515                 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
 516                 .addr = 0x27,
 517         },
 518         [BLK_IDX_L2_FORWARDING] = {
 519                 .entry_packing = sja1105_l2_forwarding_entry_packing,
 520                 .cmd_packing = sja1105_l2_forwarding_cmd_packing,
 521                 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
 522                 .access = OP_WRITE,
 523                 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
 524                 .addr = 0x24,
 525         },
 526         [BLK_IDX_MAC_CONFIG] = {
 527                 .entry_packing = sja1105et_mac_config_entry_packing,
 528                 .cmd_packing = sja1105et_mac_config_cmd_packing,
 529                 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
 530                 .access = OP_WRITE,
 531                 .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD,
 532                 .addr = 0x36,
 533         },
 534         [BLK_IDX_SCHEDULE_PARAMS] = {0},
 535         [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0},
 536         [BLK_IDX_L2_LOOKUP_PARAMS] = {
 537                 .entry_packing = sja1105et_l2_lookup_params_entry_packing,
 538                 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
 539                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
 540                 .access = OP_WRITE,
 541                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
 542                 .addr = 0x38,
 543         },
 544         [BLK_IDX_L2_FORWARDING_PARAMS] = {0},
 545         [BLK_IDX_AVB_PARAMS] = {0},
 546         [BLK_IDX_GENERAL_PARAMS] = {
 547                 .entry_packing = sja1105et_general_params_entry_packing,
 548                 .cmd_packing = sja1105et_general_params_cmd_packing,
 549                 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
 550                 .access = OP_WRITE,
 551                 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
 552                 .addr = 0x34,
 553         },
 554         [BLK_IDX_XMII_PARAMS] = {0},
 555 };
 556 
 557 /* SJA1105P/Q/R/S: Second generation */
 558 struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
 559         [BLK_IDX_SCHEDULE] = {0},
 560         [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0},
 561         [BLK_IDX_L2_LOOKUP] = {
 562                 .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
 563                 .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
 564                 .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
 565                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
 566                 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
 567                 .addr = 0x24,
 568         },
 569         [BLK_IDX_MGMT_ROUTE] = {
 570                 .entry_packing = sja1105pqrs_mgmt_route_entry_packing,
 571                 .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
 572                 .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
 573                 .max_entry_count = SJA1105_NUM_PORTS,
 574                 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
 575                 .addr = 0x24,
 576         },
 577         [BLK_IDX_L2_POLICING] = {0},
 578         [BLK_IDX_VLAN_LOOKUP] = {
 579                 .entry_packing = sja1105_vlan_lookup_entry_packing,
 580                 .cmd_packing = sja1105_vlan_lookup_cmd_packing,
 581                 .access = (OP_READ | OP_WRITE | OP_DEL),
 582                 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
 583                 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD,
 584                 .addr = 0x2D,
 585         },
 586         [BLK_IDX_L2_FORWARDING] = {
 587                 .entry_packing = sja1105_l2_forwarding_entry_packing,
 588                 .cmd_packing = sja1105_l2_forwarding_cmd_packing,
 589                 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
 590                 .access = OP_WRITE,
 591                 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
 592                 .addr = 0x2A,
 593         },
 594         [BLK_IDX_MAC_CONFIG] = {
 595                 .entry_packing = sja1105pqrs_mac_config_entry_packing,
 596                 .cmd_packing = sja1105pqrs_mac_config_cmd_packing,
 597                 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
 598                 .access = (OP_READ | OP_WRITE),
 599                 .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
 600                 .addr = 0x4B,
 601         },
 602         [BLK_IDX_SCHEDULE_PARAMS] = {0},
 603         [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0},
 604         [BLK_IDX_L2_LOOKUP_PARAMS] = {
 605                 .entry_packing = sja1105et_l2_lookup_params_entry_packing,
 606                 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
 607                 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
 608                 .access = (OP_READ | OP_WRITE),
 609                 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
 610                 .addr = 0x38,
 611         },
 612         [BLK_IDX_L2_FORWARDING_PARAMS] = {0},
 613         [BLK_IDX_AVB_PARAMS] = {0},
 614         [BLK_IDX_GENERAL_PARAMS] = {
 615                 .entry_packing = sja1105et_general_params_entry_packing,
 616                 .cmd_packing = sja1105et_general_params_cmd_packing,
 617                 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
 618                 .access = OP_WRITE,
 619                 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD,
 620                 .addr = 0x34,
 621         },
 622         [BLK_IDX_XMII_PARAMS] = {0},
 623 };
 624 
 625 /* Provides read access to the settings through the dynamic interface
 626  * of the switch.
 627  * @blk_idx     is used as key to select from the sja1105_dynamic_table_ops.
 628  *              The selection is limited by the hardware in respect to which
 629  *              configuration blocks can be read through the dynamic interface.
 630  * @index       is used to retrieve a particular table entry. If negative,
 631  *              (and if the @blk_idx supports the searching operation) a search
 632  *              is performed by the @entry parameter.
 633  * @entry       Type-casted to an unpacked structure that holds a table entry
 634  *              of the type specified in @blk_idx.
 635  *              Usually an output argument. If @index is negative, then this
 636  *              argument is used as input/output: it should be pre-populated
 637  *              with the element to search for. Entries which support the
 638  *              search operation will have an "index" field (not the @index
 639  *              argument to this function) and that is where the found index
 640  *              will be returned (or left unmodified - thus negative - if not
 641  *              found).
 642  */
 643 int sja1105_dynamic_config_read(struct sja1105_private *priv,
 644                                 enum sja1105_blk_idx blk_idx,
 645                                 int index, void *entry)
 646 {
 647         const struct sja1105_dynamic_table_ops *ops;
 648         struct sja1105_dyn_cmd cmd = {0};
 649         /* SPI payload buffer */
 650         u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
 651         int retries = 3;
 652         int rc;
 653 
 654         if (blk_idx >= BLK_IDX_MAX_DYN)
 655                 return -ERANGE;
 656 
 657         ops = &priv->info->dyn_ops[blk_idx];
 658 
 659         if (index >= 0 && index >= ops->max_entry_count)
 660                 return -ERANGE;
 661         if (index < 0 && !(ops->access & OP_SEARCH))
 662                 return -EOPNOTSUPP;
 663         if (!(ops->access & OP_READ))
 664                 return -EOPNOTSUPP;
 665         if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
 666                 return -ERANGE;
 667         if (!ops->cmd_packing)
 668                 return -EOPNOTSUPP;
 669         if (!ops->entry_packing)
 670                 return -EOPNOTSUPP;
 671 
 672         cmd.valid = true; /* Trigger action on table entry */
 673         cmd.rdwrset = SPI_READ; /* Action is read */
 674         if (index < 0) {
 675                 /* Avoid copying a signed negative number to an u64 */
 676                 cmd.index = 0;
 677                 cmd.search = true;
 678         } else {
 679                 cmd.index = index;
 680                 cmd.search = false;
 681         }
 682         cmd.valident = true;
 683         ops->cmd_packing(packed_buf, &cmd, PACK);
 684 
 685         if (cmd.search)
 686                 ops->entry_packing(packed_buf, entry, PACK);
 687 
 688         /* Send SPI write operation: read config table entry */
 689         rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr,
 690                                          packed_buf, ops->packed_size);
 691         if (rc < 0)
 692                 return rc;
 693 
 694         /* Loop until we have confirmation that hardware has finished
 695          * processing the command and has cleared the VALID field
 696          */
 697         do {
 698                 memset(packed_buf, 0, ops->packed_size);
 699 
 700                 /* Retrieve the read operation's result */
 701                 rc = sja1105_spi_send_packed_buf(priv, SPI_READ, ops->addr,
 702                                                  packed_buf, ops->packed_size);
 703                 if (rc < 0)
 704                         return rc;
 705 
 706                 cmd = (struct sja1105_dyn_cmd) {0};
 707                 ops->cmd_packing(packed_buf, &cmd, UNPACK);
 708                 /* UM10944: [valident] will always be found cleared
 709                  * during a read access with MGMTROUTE set.
 710                  * So don't error out in that case.
 711                  */
 712                 if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
 713                         return -ENOENT;
 714                 cpu_relax();
 715         } while (cmd.valid && --retries);
 716 
 717         if (cmd.valid)
 718                 return -ETIMEDOUT;
 719 
 720         /* Don't dereference possibly NULL pointer - maybe caller
 721          * only wanted to see whether the entry existed or not.
 722          */
 723         if (entry)
 724                 ops->entry_packing(packed_buf, entry, UNPACK);
 725         return 0;
 726 }
 727 
 728 int sja1105_dynamic_config_write(struct sja1105_private *priv,
 729                                  enum sja1105_blk_idx blk_idx,
 730                                  int index, void *entry, bool keep)
 731 {
 732         const struct sja1105_dynamic_table_ops *ops;
 733         struct sja1105_dyn_cmd cmd = {0};
 734         /* SPI payload buffer */
 735         u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0};
 736         int rc;
 737 
 738         if (blk_idx >= BLK_IDX_MAX_DYN)
 739                 return -ERANGE;
 740 
 741         ops = &priv->info->dyn_ops[blk_idx];
 742 
 743         if (index >= ops->max_entry_count)
 744                 return -ERANGE;
 745         if (index < 0)
 746                 return -ERANGE;
 747         if (!(ops->access & OP_WRITE))
 748                 return -EOPNOTSUPP;
 749         if (!keep && !(ops->access & OP_DEL))
 750                 return -EOPNOTSUPP;
 751         if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
 752                 return -ERANGE;
 753 
 754         cmd.valident = keep; /* If false, deletes entry */
 755         cmd.valid = true; /* Trigger action on table entry */
 756         cmd.rdwrset = SPI_WRITE; /* Action is write */
 757         cmd.index = index;
 758 
 759         if (!ops->cmd_packing)
 760                 return -EOPNOTSUPP;
 761         ops->cmd_packing(packed_buf, &cmd, PACK);
 762 
 763         if (!ops->entry_packing)
 764                 return -EOPNOTSUPP;
 765         /* Don't dereference potentially NULL pointer if just
 766          * deleting a table entry is what was requested. For cases
 767          * where 'index' field is physically part of entry structure,
 768          * and needed here, we deal with that in the cmd_packing callback.
 769          */
 770         if (keep)
 771                 ops->entry_packing(packed_buf, entry, PACK);
 772 
 773         /* Send SPI write operation: read config table entry */
 774         rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr,
 775                                          packed_buf, ops->packed_size);
 776         if (rc < 0)
 777                 return rc;
 778 
 779         cmd = (struct sja1105_dyn_cmd) {0};
 780         ops->cmd_packing(packed_buf, &cmd, UNPACK);
 781         if (cmd.errors)
 782                 return -EINVAL;
 783 
 784         return 0;
 785 }
 786 
 787 static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
 788 {
 789         int i;
 790 
 791         for (i = 0; i < 8; i++) {
 792                 if ((crc ^ byte) & (1 << 7)) {
 793                         crc <<= 1;
 794                         crc ^= poly;
 795                 } else {
 796                         crc <<= 1;
 797                 }
 798                 byte <<= 1;
 799         }
 800         return crc;
 801 }
 802 
 803 /* CRC8 algorithm with non-reversed input, non-reversed output,
 804  * no input xor and no output xor. Code customized for receiving
 805  * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial
 806  * is also received as argument in the Koopman notation that the switch
 807  * hardware stores it in.
 808  */
 809 u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
 810 {
 811         struct sja1105_l2_lookup_params_entry *l2_lookup_params =
 812                 priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
 813         u64 poly_koopman = l2_lookup_params->poly;
 814         /* Convert polynomial from Koopman to 'normal' notation */
 815         u8 poly = (u8)(1 + (poly_koopman << 1));
 816         u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid;
 817         u64 input = (vlanid << 48) | ether_addr_to_u64(addr);
 818         u8 crc = 0; /* seed */
 819         int i;
 820 
 821         /* Mask the eight bytes starting from MSB one at a time */
 822         for (i = 56; i >= 0; i -= 8) {
 823                 u8 byte = (input & (0xffull << i)) >> i;
 824 
 825                 crc = sja1105_crc8_add(crc, byte, poly);
 826         }
 827         return crc;
 828 }

/* [<][>][^][v][top][bottom][index][help] */