1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> 3 */ 4 #include "sja1105.h" 5 6 #define SJA1105_SIZE_DYN_CMD 4 7 8 #define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY \ 9 SJA1105_SIZE_DYN_CMD 10 11 #define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD \ 12 (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY) 13 14 #define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD \ 15 (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY) 16 17 #define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD \ 18 (SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY) 19 20 #define SJA1105_SIZE_L2_FORWARDING_DYN_CMD \ 21 (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY) 22 23 #define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD \ 24 (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY) 25 26 #define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD \ 27 (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY) 28 29 #define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD \ 30 SJA1105_SIZE_DYN_CMD 31 32 #define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD \ 33 SJA1105_SIZE_DYN_CMD 34 35 #define SJA1105_MAX_DYN_CMD_SIZE \ 36 SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD 37 38 static void 39 sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 40 enum packing_op op) 41 { 42 u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY; 43 const int size = SJA1105_SIZE_DYN_CMD; 44 45 sja1105_packing(p, &cmd->valid, 31, 31, size, op); 46 sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 47 sja1105_packing(p, &cmd->errors, 29, 29, size, op); 48 sja1105_packing(p, &cmd->valident, 27, 27, size, op); 49 /* Hack - The hardware takes the 'index' field within 50 * struct sja1105_l2_lookup_entry as the index on which this command 51 * will operate. However it will ignore everything else, so 'index' 52 * is logically part of command but physically part of entry. 53 * Populate the 'index' entry field from within the command callback, 54 * such that our API doesn't need to ask for a full-blown entry 55 * structure when e.g. a delete is requested. 56 */ 57 sja1105_packing(buf, &cmd->index, 29, 20, 58 SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op); 59 /* TODO hostcmd */ 60 } 61 62 static void 63 sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 64 enum packing_op op) 65 { 66 u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 67 const int size = SJA1105_SIZE_DYN_CMD; 68 69 sja1105_packing(p, &cmd->valid, 31, 31, size, op); 70 sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 71 sja1105_packing(p, &cmd->errors, 29, 29, size, op); 72 sja1105_packing(p, &cmd->valident, 27, 27, size, op); 73 /* Hack - see comments above. */ 74 sja1105_packing(buf, &cmd->index, 29, 20, 75 SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op); 76 } 77 78 static void 79 sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 80 enum packing_op op) 81 { 82 u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 83 u64 mgmtroute = 1; 84 85 sja1105et_l2_lookup_cmd_packing(buf, cmd, op); 86 if (op == PACK) 87 sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD); 88 } 89 90 static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr, 91 enum packing_op op) 92 { 93 struct sja1105_mgmt_entry *entry = entry_ptr; 94 const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 95 96 /* UM10944: To specify if a PTP egress timestamp shall be captured on 97 * each port upon transmission of the frame, the LSB of VLANID in the 98 * ENTRY field provided by the host must be set. 99 * Bit 1 of VLANID then specifies the register where the timestamp for 100 * this port is stored in. 101 */ 102 sja1105_packing(buf, &entry->tsreg, 85, 85, size, op); 103 sja1105_packing(buf, &entry->takets, 84, 84, size, op); 104 sja1105_packing(buf, &entry->macaddr, 83, 36, size, op); 105 sja1105_packing(buf, &entry->destports, 35, 31, size, op); 106 sja1105_packing(buf, &entry->enfport, 30, 30, size, op); 107 return size; 108 } 109 110 /* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29, 111 * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap 112 * between entry (0x2d, 0x2e) and command (0x30). 113 */ 114 static void 115 sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 116 enum packing_op op) 117 { 118 u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4; 119 const int size = SJA1105_SIZE_DYN_CMD; 120 121 sja1105_packing(p, &cmd->valid, 31, 31, size, op); 122 sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 123 sja1105_packing(p, &cmd->valident, 27, 27, size, op); 124 /* Hack - see comments above, applied for 'vlanid' field of 125 * struct sja1105_vlan_lookup_entry. 126 */ 127 sja1105_packing(buf, &cmd->index, 38, 27, 128 SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op); 129 } 130 131 static void 132 sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 133 enum packing_op op) 134 { 135 u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY; 136 const int size = SJA1105_SIZE_DYN_CMD; 137 138 sja1105_packing(p, &cmd->valid, 31, 31, size, op); 139 sja1105_packing(p, &cmd->errors, 30, 30, size, op); 140 sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); 141 sja1105_packing(p, &cmd->index, 4, 0, size, op); 142 } 143 144 static void 145 sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 146 enum packing_op op) 147 { 148 const int size = SJA1105_SIZE_DYN_CMD; 149 /* Yup, user manual definitions are reversed */ 150 u8 *reg1 = buf + 4; 151 152 sja1105_packing(reg1, &cmd->valid, 31, 31, size, op); 153 sja1105_packing(reg1, &cmd->index, 26, 24, size, op); 154 } 155 156 static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr, 157 enum packing_op op) 158 { 159 const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY; 160 struct sja1105_mac_config_entry *entry = entry_ptr; 161 /* Yup, user manual definitions are reversed */ 162 u8 *reg1 = buf + 4; 163 u8 *reg2 = buf; 164 165 sja1105_packing(reg1, &entry->speed, 30, 29, size, op); 166 sja1105_packing(reg1, &entry->drpdtag, 23, 23, size, op); 167 sja1105_packing(reg1, &entry->drpuntag, 22, 22, size, op); 168 sja1105_packing(reg1, &entry->retag, 21, 21, size, op); 169 sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op); 170 sja1105_packing(reg1, &entry->egress, 19, 19, size, op); 171 sja1105_packing(reg1, &entry->ingress, 18, 18, size, op); 172 sja1105_packing(reg1, &entry->ing_mirr, 17, 17, size, op); 173 sja1105_packing(reg1, &entry->egr_mirr, 16, 16, size, op); 174 sja1105_packing(reg1, &entry->vlanprio, 14, 12, size, op); 175 sja1105_packing(reg1, &entry->vlanid, 11, 0, size, op); 176 sja1105_packing(reg2, &entry->tp_delin, 31, 16, size, op); 177 sja1105_packing(reg2, &entry->tp_delout, 15, 0, size, op); 178 /* MAC configuration table entries which can't be reconfigured: 179 * top, base, enabled, ifg, maxage, drpnona664 180 */ 181 /* Bogus return value, not used anywhere */ 182 return 0; 183 } 184 185 static void 186 sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 187 enum packing_op op) 188 { 189 const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY; 190 u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY; 191 192 sja1105_packing(p, &cmd->valid, 31, 31, size, op); 193 sja1105_packing(p, &cmd->errors, 30, 30, size, op); 194 sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); 195 sja1105_packing(p, &cmd->index, 2, 0, size, op); 196 } 197 198 static void 199 sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 200 enum packing_op op) 201 { 202 sja1105_packing(buf, &cmd->valid, 31, 31, 203 SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op); 204 } 205 206 static size_t 207 sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr, 208 enum packing_op op) 209 { 210 struct sja1105_l2_lookup_params_entry *entry = entry_ptr; 211 212 sja1105_packing(buf, &entry->poly, 7, 0, 213 SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op); 214 /* Bogus return value, not used anywhere */ 215 return 0; 216 } 217 218 static void 219 sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 220 enum packing_op op) 221 { 222 const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD; 223 224 sja1105_packing(buf, &cmd->valid, 31, 31, size, op); 225 sja1105_packing(buf, &cmd->errors, 30, 30, size, op); 226 } 227 228 static size_t 229 sja1105et_general_params_entry_packing(void *buf, void *entry_ptr, 230 enum packing_op op) 231 { 232 struct sja1105_general_params_entry *entry = entry_ptr; 233 const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD; 234 235 sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op); 236 /* Bogus return value, not used anywhere */ 237 return 0; 238 } 239 240 #define OP_READ BIT(0) 241 #define OP_WRITE BIT(1) 242 #define OP_DEL BIT(2) 243 244 /* SJA1105E/T: First generation */ 245 struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { 246 [BLK_IDX_L2_LOOKUP] = { 247 .entry_packing = sja1105et_l2_lookup_entry_packing, 248 .cmd_packing = sja1105et_l2_lookup_cmd_packing, 249 .access = (OP_READ | OP_WRITE | OP_DEL), 250 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, 251 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 252 .addr = 0x20, 253 }, 254 [BLK_IDX_MGMT_ROUTE] = { 255 .entry_packing = sja1105et_mgmt_route_entry_packing, 256 .cmd_packing = sja1105et_mgmt_route_cmd_packing, 257 .access = (OP_READ | OP_WRITE), 258 .max_entry_count = SJA1105_NUM_PORTS, 259 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 260 .addr = 0x20, 261 }, 262 [BLK_IDX_L2_POLICING] = {0}, 263 [BLK_IDX_VLAN_LOOKUP] = { 264 .entry_packing = sja1105_vlan_lookup_entry_packing, 265 .cmd_packing = sja1105_vlan_lookup_cmd_packing, 266 .access = (OP_WRITE | OP_DEL), 267 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT, 268 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD, 269 .addr = 0x27, 270 }, 271 [BLK_IDX_L2_FORWARDING] = { 272 .entry_packing = sja1105_l2_forwarding_entry_packing, 273 .cmd_packing = sja1105_l2_forwarding_cmd_packing, 274 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT, 275 .access = OP_WRITE, 276 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD, 277 .addr = 0x24, 278 }, 279 [BLK_IDX_MAC_CONFIG] = { 280 .entry_packing = sja1105et_mac_config_entry_packing, 281 .cmd_packing = sja1105et_mac_config_cmd_packing, 282 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, 283 .access = OP_WRITE, 284 .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD, 285 .addr = 0x36, 286 }, 287 [BLK_IDX_L2_LOOKUP_PARAMS] = { 288 .entry_packing = sja1105et_l2_lookup_params_entry_packing, 289 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing, 290 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT, 291 .access = OP_WRITE, 292 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, 293 .addr = 0x38, 294 }, 295 [BLK_IDX_L2_FORWARDING_PARAMS] = {0}, 296 [BLK_IDX_GENERAL_PARAMS] = { 297 .entry_packing = sja1105et_general_params_entry_packing, 298 .cmd_packing = sja1105et_general_params_cmd_packing, 299 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, 300 .access = OP_WRITE, 301 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD, 302 .addr = 0x34, 303 }, 304 [BLK_IDX_XMII_PARAMS] = {0}, 305 }; 306 307 /* SJA1105P/Q/R/S: Second generation: TODO */ 308 struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { 309 [BLK_IDX_L2_LOOKUP] = { 310 .entry_packing = sja1105pqrs_l2_lookup_entry_packing, 311 .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing, 312 .access = (OP_READ | OP_WRITE | OP_DEL), 313 .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, 314 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 315 .addr = 0x24, 316 }, 317 [BLK_IDX_L2_POLICING] = {0}, 318 [BLK_IDX_VLAN_LOOKUP] = { 319 .entry_packing = sja1105_vlan_lookup_entry_packing, 320 .cmd_packing = sja1105_vlan_lookup_cmd_packing, 321 .access = (OP_READ | OP_WRITE | OP_DEL), 322 .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT, 323 .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD, 324 .addr = 0x2D, 325 }, 326 [BLK_IDX_L2_FORWARDING] = { 327 .entry_packing = sja1105_l2_forwarding_entry_packing, 328 .cmd_packing = sja1105_l2_forwarding_cmd_packing, 329 .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT, 330 .access = OP_WRITE, 331 .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD, 332 .addr = 0x2A, 333 }, 334 [BLK_IDX_MAC_CONFIG] = { 335 .entry_packing = sja1105pqrs_mac_config_entry_packing, 336 .cmd_packing = sja1105pqrs_mac_config_cmd_packing, 337 .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, 338 .access = (OP_READ | OP_WRITE), 339 .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD, 340 .addr = 0x4B, 341 }, 342 [BLK_IDX_L2_LOOKUP_PARAMS] = { 343 .entry_packing = sja1105et_l2_lookup_params_entry_packing, 344 .cmd_packing = sja1105et_l2_lookup_params_cmd_packing, 345 .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT, 346 .access = (OP_READ | OP_WRITE), 347 .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, 348 .addr = 0x38, 349 }, 350 [BLK_IDX_L2_FORWARDING_PARAMS] = {0}, 351 [BLK_IDX_GENERAL_PARAMS] = { 352 .entry_packing = sja1105et_general_params_entry_packing, 353 .cmd_packing = sja1105et_general_params_cmd_packing, 354 .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, 355 .access = OP_WRITE, 356 .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD, 357 .addr = 0x34, 358 }, 359 [BLK_IDX_XMII_PARAMS] = {0}, 360 }; 361 362 int sja1105_dynamic_config_read(struct sja1105_private *priv, 363 enum sja1105_blk_idx blk_idx, 364 int index, void *entry) 365 { 366 const struct sja1105_dynamic_table_ops *ops; 367 struct sja1105_dyn_cmd cmd = {0}; 368 /* SPI payload buffer */ 369 u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0}; 370 int retries = 3; 371 int rc; 372 373 if (blk_idx >= BLK_IDX_MAX_DYN) 374 return -ERANGE; 375 376 ops = &priv->info->dyn_ops[blk_idx]; 377 378 if (index >= ops->max_entry_count) 379 return -ERANGE; 380 if (!(ops->access & OP_READ)) 381 return -EOPNOTSUPP; 382 if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE) 383 return -ERANGE; 384 if (!ops->cmd_packing) 385 return -EOPNOTSUPP; 386 if (!ops->entry_packing) 387 return -EOPNOTSUPP; 388 389 cmd.valid = true; /* Trigger action on table entry */ 390 cmd.rdwrset = SPI_READ; /* Action is read */ 391 cmd.index = index; 392 ops->cmd_packing(packed_buf, &cmd, PACK); 393 394 /* Send SPI write operation: read config table entry */ 395 rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr, 396 packed_buf, ops->packed_size); 397 if (rc < 0) 398 return rc; 399 400 /* Loop until we have confirmation that hardware has finished 401 * processing the command and has cleared the VALID field 402 */ 403 do { 404 memset(packed_buf, 0, ops->packed_size); 405 406 /* Retrieve the read operation's result */ 407 rc = sja1105_spi_send_packed_buf(priv, SPI_READ, ops->addr, 408 packed_buf, ops->packed_size); 409 if (rc < 0) 410 return rc; 411 412 cmd = (struct sja1105_dyn_cmd) {0}; 413 ops->cmd_packing(packed_buf, &cmd, UNPACK); 414 /* UM10944: [valident] will always be found cleared 415 * during a read access with MGMTROUTE set. 416 * So don't error out in that case. 417 */ 418 if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE) 419 return -EINVAL; 420 cpu_relax(); 421 } while (cmd.valid && --retries); 422 423 if (cmd.valid) 424 return -ETIMEDOUT; 425 426 /* Don't dereference possibly NULL pointer - maybe caller 427 * only wanted to see whether the entry existed or not. 428 */ 429 if (entry) 430 ops->entry_packing(packed_buf, entry, UNPACK); 431 return 0; 432 } 433 434 int sja1105_dynamic_config_write(struct sja1105_private *priv, 435 enum sja1105_blk_idx blk_idx, 436 int index, void *entry, bool keep) 437 { 438 const struct sja1105_dynamic_table_ops *ops; 439 struct sja1105_dyn_cmd cmd = {0}; 440 /* SPI payload buffer */ 441 u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0}; 442 int rc; 443 444 if (blk_idx >= BLK_IDX_MAX_DYN) 445 return -ERANGE; 446 447 ops = &priv->info->dyn_ops[blk_idx]; 448 449 if (index >= ops->max_entry_count) 450 return -ERANGE; 451 if (!(ops->access & OP_WRITE)) 452 return -EOPNOTSUPP; 453 if (!keep && !(ops->access & OP_DEL)) 454 return -EOPNOTSUPP; 455 if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE) 456 return -ERANGE; 457 458 cmd.valident = keep; /* If false, deletes entry */ 459 cmd.valid = true; /* Trigger action on table entry */ 460 cmd.rdwrset = SPI_WRITE; /* Action is write */ 461 cmd.index = index; 462 463 if (!ops->cmd_packing) 464 return -EOPNOTSUPP; 465 ops->cmd_packing(packed_buf, &cmd, PACK); 466 467 if (!ops->entry_packing) 468 return -EOPNOTSUPP; 469 /* Don't dereference potentially NULL pointer if just 470 * deleting a table entry is what was requested. For cases 471 * where 'index' field is physically part of entry structure, 472 * and needed here, we deal with that in the cmd_packing callback. 473 */ 474 if (keep) 475 ops->entry_packing(packed_buf, entry, PACK); 476 477 /* Send SPI write operation: read config table entry */ 478 rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr, 479 packed_buf, ops->packed_size); 480 if (rc < 0) 481 return rc; 482 483 cmd = (struct sja1105_dyn_cmd) {0}; 484 ops->cmd_packing(packed_buf, &cmd, UNPACK); 485 if (cmd.errors) 486 return -EINVAL; 487 488 return 0; 489 } 490 491 static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly) 492 { 493 int i; 494 495 for (i = 0; i < 8; i++) { 496 if ((crc ^ byte) & (1 << 7)) { 497 crc <<= 1; 498 crc ^= poly; 499 } else { 500 crc <<= 1; 501 } 502 byte <<= 1; 503 } 504 return crc; 505 } 506 507 /* CRC8 algorithm with non-reversed input, non-reversed output, 508 * no input xor and no output xor. Code customized for receiving 509 * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial 510 * is also received as argument in the Koopman notation that the switch 511 * hardware stores it in. 512 */ 513 u8 sja1105_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid) 514 { 515 struct sja1105_l2_lookup_params_entry *l2_lookup_params = 516 priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries; 517 u64 poly_koopman = l2_lookup_params->poly; 518 /* Convert polynomial from Koopman to 'normal' notation */ 519 u8 poly = (u8)(1 + (poly_koopman << 1)); 520 u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid; 521 u64 input = (vlanid << 48) | ether_addr_to_u64(addr); 522 u8 crc = 0; /* seed */ 523 int i; 524 525 /* Mask the eight bytes starting from MSB one at a time */ 526 for (i = 56; i >= 0; i -= 8) { 527 u8 byte = (input & (0xffull << i)) >> i; 528 529 crc = sja1105_crc8_add(crc, byte, poly); 530 } 531 return crc; 532 } 533