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_SJA1105_SIZE_VL_LOOKUP_DYN_CMD \ 101 SJA1105_SIZE_DYN_CMD 102 103 #define SJA1105PQRS_SJA1105_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 154 struct sja1105_dyn_cmd { 155 bool search; 156 u64 valid; 157 u64 rdwrset; 158 u64 errors; 159 u64 valident; 160 u64 index; 161 }; 162 163 enum sja1105_hostcmd { 164 SJA1105_HOSTCMD_SEARCH = 1, 165 SJA1105_HOSTCMD_READ = 2, 166 SJA1105_HOSTCMD_WRITE = 3, 167 SJA1105_HOSTCMD_INVALIDATE = 4, 168 }; 169 170 static void 171 sja1105_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 182 static 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_SJA1105_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 193 static void 194 sja1105pqrs_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 */ 298 static size_t 299 sja1105pqrs_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 311 static void 312 sja1105et_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 327 static 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 339 static void 340 sja1105et_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 351 static 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 371 static void 372 sja1105pqrs_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 383 static 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 */ 405 static void 406 sja1105_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 422 static void 423 sja1105_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 435 static void 436 sja1105et_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 447 static 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 476 static void 477 sja1105pqrs_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 489 static void 490 sja1105et_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 497 static size_t 498 sja1105et_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 509 static void 510 sja1105pqrs_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 521 static void 522 sja1105et_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 531 static size_t 532 sja1105et_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 543 static void 544 sja1105pqrs_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 555 static void 556 sja1105pqrs_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 567 static void 568 sja1105_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 581 static 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 591 static 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 608 static 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 620 static 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 */ 641 struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { 642 [BLK_IDX_SCHEDULE] = {0}, 643 [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, 644 [BLK_IDX_VL_LOOKUP] = { 645 .entry_packing = sja1105et_vl_lookup_entry_packing, 646 .cmd_packing = sja1105_vl_lookup_cmd_packing, 647 .access = OP_WRITE, 648 .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT, 649 .packed_size = SJA1105ET_SJA1105_SIZE_VL_LOOKUP_DYN_CMD, 650 .addr = 0x35, 651 }, 652 [BLK_IDX_VL_POLICING] = {0}, 653 [BLK_IDX_VL_FORWARDING] = {0}, 654 [BLK_IDX_L2_LOOKUP] = { 655 .entry_packing = sja1105et_dyn_l2_lookup_entry_packing, 656 .cmd_packing = sja1105et_l2_lookup_cmd_packing, 657 .access = (OP_READ | OP_WRITE | OP_DEL), 658 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, 659 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 660 .addr = 0x20, 661 }, 662 [BLK_IDX_MGMT_ROUTE] = { 663 .entry_packing = sja1105et_mgmt_route_entry_packing, 664 .cmd_packing = sja1105et_mgmt_route_cmd_packing, 665 .access = (OP_READ | OP_WRITE), 666 .max_entry_count = SJA1105_NUM_PORTS, 667 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 668 .addr = 0x20, 669 }, 670 [BLK_IDX_L2_POLICING] = {0}, 671 [BLK_IDX_VLAN_LOOKUP] = { 672 .entry_packing = sja1105_vlan_lookup_entry_packing, 673 .cmd_packing = sja1105_vlan_lookup_cmd_packing, 674 .access = (OP_WRITE | OP_DEL), 675 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT, 676 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD, 677 .addr = 0x27, 678 }, 679 [BLK_IDX_L2_FORWARDING] = { 680 .entry_packing = sja1105_l2_forwarding_entry_packing, 681 .cmd_packing = sja1105_l2_forwarding_cmd_packing, 682 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT, 683 .access = OP_WRITE, 684 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD, 685 .addr = 0x24, 686 }, 687 [BLK_IDX_MAC_CONFIG] = { 688 .entry_packing = sja1105et_mac_config_entry_packing, 689 .cmd_packing = sja1105et_mac_config_cmd_packing, 690 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, 691 .access = OP_WRITE, 692 .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD, 693 .addr = 0x36, 694 }, 695 [BLK_IDX_SCHEDULE_PARAMS] = {0}, 696 [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, 697 [BLK_IDX_VL_FORWARDING_PARAMS] = {0}, 698 [BLK_IDX_L2_LOOKUP_PARAMS] = { 699 .entry_packing = sja1105et_l2_lookup_params_entry_packing, 700 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing, 701 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT, 702 .access = OP_WRITE, 703 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, 704 .addr = 0x38, 705 }, 706 [BLK_IDX_L2_FORWARDING_PARAMS] = {0}, 707 [BLK_IDX_AVB_PARAMS] = {0}, 708 [BLK_IDX_GENERAL_PARAMS] = { 709 .entry_packing = sja1105et_general_params_entry_packing, 710 .cmd_packing = sja1105et_general_params_cmd_packing, 711 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, 712 .access = OP_WRITE, 713 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD, 714 .addr = 0x34, 715 }, 716 [BLK_IDX_RETAGGING] = { 717 .entry_packing = sja1105_retagging_entry_packing, 718 .cmd_packing = sja1105_retagging_cmd_packing, 719 .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, 720 .access = (OP_WRITE | OP_DEL), 721 .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD, 722 .addr = 0x31, 723 }, 724 [BLK_IDX_CBS] = { 725 .entry_packing = sja1105et_cbs_entry_packing, 726 .cmd_packing = sja1105et_cbs_cmd_packing, 727 .max_entry_count = SJA1105ET_MAX_CBS_COUNT, 728 .access = OP_WRITE, 729 .packed_size = SJA1105ET_SIZE_CBS_DYN_CMD, 730 .addr = 0x2c, 731 }, 732 [BLK_IDX_XMII_PARAMS] = {0}, 733 }; 734 735 /* SJA1105P/Q/R/S: Second generation */ 736 struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { 737 [BLK_IDX_SCHEDULE] = {0}, 738 [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, 739 [BLK_IDX_VL_LOOKUP] = { 740 .entry_packing = sja1105_vl_lookup_entry_packing, 741 .cmd_packing = sja1105_vl_lookup_cmd_packing, 742 .access = (OP_READ | OP_WRITE), 743 .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT, 744 .packed_size = SJA1105PQRS_SJA1105_SIZE_VL_LOOKUP_DYN_CMD, 745 .addr = 0x47, 746 }, 747 [BLK_IDX_VL_POLICING] = {0}, 748 [BLK_IDX_VL_FORWARDING] = {0}, 749 [BLK_IDX_L2_LOOKUP] = { 750 .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing, 751 .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing, 752 .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH), 753 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, 754 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD, 755 .addr = 0x24, 756 }, 757 [BLK_IDX_MGMT_ROUTE] = { 758 .entry_packing = sja1105pqrs_mgmt_route_entry_packing, 759 .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing, 760 .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH), 761 .max_entry_count = SJA1105_NUM_PORTS, 762 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD, 763 .addr = 0x24, 764 }, 765 [BLK_IDX_L2_POLICING] = {0}, 766 [BLK_IDX_VLAN_LOOKUP] = { 767 .entry_packing = sja1105_vlan_lookup_entry_packing, 768 .cmd_packing = sja1105_vlan_lookup_cmd_packing, 769 .access = (OP_READ | OP_WRITE | OP_DEL), 770 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT, 771 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD, 772 .addr = 0x2D, 773 }, 774 [BLK_IDX_L2_FORWARDING] = { 775 .entry_packing = sja1105_l2_forwarding_entry_packing, 776 .cmd_packing = sja1105_l2_forwarding_cmd_packing, 777 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT, 778 .access = OP_WRITE, 779 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD, 780 .addr = 0x2A, 781 }, 782 [BLK_IDX_MAC_CONFIG] = { 783 .entry_packing = sja1105pqrs_mac_config_entry_packing, 784 .cmd_packing = sja1105pqrs_mac_config_cmd_packing, 785 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, 786 .access = (OP_READ | OP_WRITE), 787 .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD, 788 .addr = 0x4B, 789 }, 790 [BLK_IDX_SCHEDULE_PARAMS] = {0}, 791 [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, 792 [BLK_IDX_VL_FORWARDING_PARAMS] = {0}, 793 [BLK_IDX_L2_LOOKUP_PARAMS] = { 794 .entry_packing = sja1105pqrs_l2_lookup_params_entry_packing, 795 .cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing, 796 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT, 797 .access = (OP_READ | OP_WRITE), 798 .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, 799 .addr = 0x54, 800 }, 801 [BLK_IDX_L2_FORWARDING_PARAMS] = {0}, 802 [BLK_IDX_AVB_PARAMS] = { 803 .entry_packing = sja1105pqrs_avb_params_entry_packing, 804 .cmd_packing = sja1105pqrs_avb_params_cmd_packing, 805 .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT, 806 .access = (OP_READ | OP_WRITE), 807 .packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD, 808 .addr = 0x8003, 809 }, 810 [BLK_IDX_GENERAL_PARAMS] = { 811 .entry_packing = sja1105pqrs_general_params_entry_packing, 812 .cmd_packing = sja1105pqrs_general_params_cmd_packing, 813 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, 814 .access = (OP_READ | OP_WRITE), 815 .packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD, 816 .addr = 0x3B, 817 }, 818 [BLK_IDX_RETAGGING] = { 819 .entry_packing = sja1105_retagging_entry_packing, 820 .cmd_packing = sja1105_retagging_cmd_packing, 821 .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, 822 .access = (OP_READ | OP_WRITE | OP_DEL), 823 .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD, 824 .addr = 0x38, 825 }, 826 [BLK_IDX_CBS] = { 827 .entry_packing = sja1105pqrs_cbs_entry_packing, 828 .cmd_packing = sja1105pqrs_cbs_cmd_packing, 829 .max_entry_count = SJA1105PQRS_MAX_CBS_COUNT, 830 .access = OP_WRITE, 831 .packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD, 832 .addr = 0x32, 833 }, 834 [BLK_IDX_XMII_PARAMS] = {0}, 835 }; 836 837 /* Provides read access to the settings through the dynamic interface 838 * of the switch. 839 * @blk_idx is used as key to select from the sja1105_dynamic_table_ops. 840 * The selection is limited by the hardware in respect to which 841 * configuration blocks can be read through the dynamic interface. 842 * @index is used to retrieve a particular table entry. If negative, 843 * (and if the @blk_idx supports the searching operation) a search 844 * is performed by the @entry parameter. 845 * @entry Type-casted to an unpacked structure that holds a table entry 846 * of the type specified in @blk_idx. 847 * Usually an output argument. If @index is negative, then this 848 * argument is used as input/output: it should be pre-populated 849 * with the element to search for. Entries which support the 850 * search operation will have an "index" field (not the @index 851 * argument to this function) and that is where the found index 852 * will be returned (or left unmodified - thus negative - if not 853 * found). 854 */ 855 int sja1105_dynamic_config_read(struct sja1105_private *priv, 856 enum sja1105_blk_idx blk_idx, 857 int index, void *entry) 858 { 859 const struct sja1105_dynamic_table_ops *ops; 860 struct sja1105_dyn_cmd cmd = {0}; 861 /* SPI payload buffer */ 862 u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0}; 863 int retries = 3; 864 int rc; 865 866 if (blk_idx >= BLK_IDX_MAX_DYN) 867 return -ERANGE; 868 869 ops = &priv->info->dyn_ops[blk_idx]; 870 871 if (index >= 0 && index >= ops->max_entry_count) 872 return -ERANGE; 873 if (index < 0 && !(ops->access & OP_SEARCH)) 874 return -EOPNOTSUPP; 875 if (!(ops->access & OP_READ)) 876 return -EOPNOTSUPP; 877 if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE) 878 return -ERANGE; 879 if (!ops->cmd_packing) 880 return -EOPNOTSUPP; 881 if (!ops->entry_packing) 882 return -EOPNOTSUPP; 883 884 cmd.valid = true; /* Trigger action on table entry */ 885 cmd.rdwrset = SPI_READ; /* Action is read */ 886 if (index < 0) { 887 /* Avoid copying a signed negative number to an u64 */ 888 cmd.index = 0; 889 cmd.search = true; 890 } else { 891 cmd.index = index; 892 cmd.search = false; 893 } 894 cmd.valident = true; 895 ops->cmd_packing(packed_buf, &cmd, PACK); 896 897 if (cmd.search) 898 ops->entry_packing(packed_buf, entry, PACK); 899 900 /* Send SPI write operation: read config table entry */ 901 rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, 902 ops->packed_size); 903 if (rc < 0) 904 return rc; 905 906 /* Loop until we have confirmation that hardware has finished 907 * processing the command and has cleared the VALID field 908 */ 909 do { 910 memset(packed_buf, 0, ops->packed_size); 911 912 /* Retrieve the read operation's result */ 913 rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf, 914 ops->packed_size); 915 if (rc < 0) 916 return rc; 917 918 cmd = (struct sja1105_dyn_cmd) {0}; 919 ops->cmd_packing(packed_buf, &cmd, UNPACK); 920 /* UM10944: [valident] will always be found cleared 921 * during a read access with MGMTROUTE set. 922 * So don't error out in that case. 923 */ 924 if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE) 925 return -ENOENT; 926 cpu_relax(); 927 } while (cmd.valid && --retries); 928 929 if (cmd.valid) 930 return -ETIMEDOUT; 931 932 /* Don't dereference possibly NULL pointer - maybe caller 933 * only wanted to see whether the entry existed or not. 934 */ 935 if (entry) 936 ops->entry_packing(packed_buf, entry, UNPACK); 937 return 0; 938 } 939 940 int sja1105_dynamic_config_write(struct sja1105_private *priv, 941 enum sja1105_blk_idx blk_idx, 942 int index, void *entry, bool keep) 943 { 944 const struct sja1105_dynamic_table_ops *ops; 945 struct sja1105_dyn_cmd cmd = {0}; 946 /* SPI payload buffer */ 947 u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0}; 948 int rc; 949 950 if (blk_idx >= BLK_IDX_MAX_DYN) 951 return -ERANGE; 952 953 ops = &priv->info->dyn_ops[blk_idx]; 954 955 if (index >= ops->max_entry_count) 956 return -ERANGE; 957 if (index < 0) 958 return -ERANGE; 959 if (!(ops->access & OP_WRITE)) 960 return -EOPNOTSUPP; 961 if (!keep && !(ops->access & OP_DEL)) 962 return -EOPNOTSUPP; 963 if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE) 964 return -ERANGE; 965 966 cmd.valident = keep; /* If false, deletes entry */ 967 cmd.valid = true; /* Trigger action on table entry */ 968 cmd.rdwrset = SPI_WRITE; /* Action is write */ 969 cmd.index = index; 970 971 if (!ops->cmd_packing) 972 return -EOPNOTSUPP; 973 ops->cmd_packing(packed_buf, &cmd, PACK); 974 975 if (!ops->entry_packing) 976 return -EOPNOTSUPP; 977 /* Don't dereference potentially NULL pointer if just 978 * deleting a table entry is what was requested. For cases 979 * where 'index' field is physically part of entry structure, 980 * and needed here, we deal with that in the cmd_packing callback. 981 */ 982 if (keep) 983 ops->entry_packing(packed_buf, entry, PACK); 984 985 /* Send SPI write operation: read config table entry */ 986 rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, 987 ops->packed_size); 988 if (rc < 0) 989 return rc; 990 991 cmd = (struct sja1105_dyn_cmd) {0}; 992 ops->cmd_packing(packed_buf, &cmd, UNPACK); 993 if (cmd.errors) 994 return -EINVAL; 995 996 return 0; 997 } 998 999 static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly) 1000 { 1001 int i; 1002 1003 for (i = 0; i < 8; i++) { 1004 if ((crc ^ byte) & (1 << 7)) { 1005 crc <<= 1; 1006 crc ^= poly; 1007 } else { 1008 crc <<= 1; 1009 } 1010 byte <<= 1; 1011 } 1012 return crc; 1013 } 1014 1015 /* CRC8 algorithm with non-reversed input, non-reversed output, 1016 * no input xor and no output xor. Code customized for receiving 1017 * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial 1018 * is also received as argument in the Koopman notation that the switch 1019 * hardware stores it in. 1020 */ 1021 u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid) 1022 { 1023 struct sja1105_l2_lookup_params_entry *l2_lookup_params = 1024 priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries; 1025 u64 poly_koopman = l2_lookup_params->poly; 1026 /* Convert polynomial from Koopman to 'normal' notation */ 1027 u8 poly = (u8)(1 + (poly_koopman << 1)); 1028 u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid; 1029 u64 input = (vlanid << 48) | ether_addr_to_u64(addr); 1030 u8 crc = 0; /* seed */ 1031 int i; 1032 1033 /* Mask the eight bytes starting from MSB one at a time */ 1034 for (i = 56; i >= 0; i -= 8) { 1035 u8 byte = (input & (0xffull << i)) >> i; 1036 1037 crc = sja1105_crc8_add(crc, byte, poly); 1038 } 1039 return crc; 1040 } 1041