18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci#include "sja1105.h" 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* In the dynamic configuration interface, the switch exposes a register-like 78c2ecf20Sopenharmony_ci * view of some of the static configuration tables. 88c2ecf20Sopenharmony_ci * Many times the field organization of the dynamic tables is abbreviated (not 98c2ecf20Sopenharmony_ci * all fields are dynamically reconfigurable) and different from the static 108c2ecf20Sopenharmony_ci * ones, but the key reason for having it is that we can spare a switch reset 118c2ecf20Sopenharmony_ci * for settings that can be changed dynamically. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file creates a per-switch-family abstraction called 148c2ecf20Sopenharmony_ci * struct sja1105_dynamic_table_ops and two operations that work with it: 158c2ecf20Sopenharmony_ci * - sja1105_dynamic_config_write 168c2ecf20Sopenharmony_ci * - sja1105_dynamic_config_read 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Compared to the struct sja1105_table_ops from sja1105_static_config.c, 198c2ecf20Sopenharmony_ci * the dynamic accessors work with a compound buffer: 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * packed_buf 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * | 248c2ecf20Sopenharmony_ci * V 258c2ecf20Sopenharmony_ci * +-----------------------------------------+------------------+ 268c2ecf20Sopenharmony_ci * | ENTRY BUFFER | COMMAND BUFFER | 278c2ecf20Sopenharmony_ci * +-----------------------------------------+------------------+ 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * <----------------------- packed_size ------------------------> 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * The ENTRY BUFFER may or may not have the same layout, or size, as its static 328c2ecf20Sopenharmony_ci * configuration table entry counterpart. When it does, the same packing 338c2ecf20Sopenharmony_ci * function is reused (bar exceptional cases - see 348c2ecf20Sopenharmony_ci * sja1105pqrs_dyn_l2_lookup_entry_packing). 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * The reason for the COMMAND BUFFER being at the end is to be able to send 378c2ecf20Sopenharmony_ci * a dynamic write command through a single SPI burst. By the time the switch 388c2ecf20Sopenharmony_ci * reacts to the command, the ENTRY BUFFER is already populated with the data 398c2ecf20Sopenharmony_ci * sent by the core. 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * The COMMAND BUFFER is always SJA1105_SIZE_DYN_CMD bytes (one 32-bit word) in 428c2ecf20Sopenharmony_ci * size. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Sometimes the ENTRY BUFFER does not really exist (when the number of fields 458c2ecf20Sopenharmony_ci * that can be reconfigured is small), then the switch repurposes some of the 468c2ecf20Sopenharmony_ci * unused 32 bits of the COMMAND BUFFER to hold ENTRY data. 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * The key members of struct sja1105_dynamic_table_ops are: 498c2ecf20Sopenharmony_ci * - .entry_packing: A function that deals with packing an ENTRY structure 508c2ecf20Sopenharmony_ci * into an SPI buffer, or retrieving an ENTRY structure 518c2ecf20Sopenharmony_ci * from one. 528c2ecf20Sopenharmony_ci * The @packed_buf pointer it's given does always point to 538c2ecf20Sopenharmony_ci * the ENTRY portion of the buffer. 548c2ecf20Sopenharmony_ci * - .cmd_packing: A function that deals with packing/unpacking the COMMAND 558c2ecf20Sopenharmony_ci * structure to/from the SPI buffer. 568c2ecf20Sopenharmony_ci * It is given the same @packed_buf pointer as .entry_packing, 578c2ecf20Sopenharmony_ci * so most of the time, the @packed_buf points *behind* the 588c2ecf20Sopenharmony_ci * COMMAND offset inside the buffer. 598c2ecf20Sopenharmony_ci * To access the COMMAND portion of the buffer, the function 608c2ecf20Sopenharmony_ci * knows its correct offset. 618c2ecf20Sopenharmony_ci * Giving both functions the same pointer is handy because in 628c2ecf20Sopenharmony_ci * extreme cases (see sja1105pqrs_dyn_l2_lookup_entry_packing) 638c2ecf20Sopenharmony_ci * the .entry_packing is able to jump to the COMMAND portion, 648c2ecf20Sopenharmony_ci * or vice-versa (sja1105pqrs_l2_lookup_cmd_packing). 658c2ecf20Sopenharmony_ci * - .access: A bitmap of: 668c2ecf20Sopenharmony_ci * OP_READ: Set if the hardware manual marks the ENTRY portion of the 678c2ecf20Sopenharmony_ci * dynamic configuration table buffer as R (readable) after 688c2ecf20Sopenharmony_ci * an SPI read command (the switch will populate the buffer). 698c2ecf20Sopenharmony_ci * OP_WRITE: Set if the manual marks the ENTRY portion of the dynamic 708c2ecf20Sopenharmony_ci * table buffer as W (writable) after an SPI write command 718c2ecf20Sopenharmony_ci * (the switch will read the fields provided in the buffer). 728c2ecf20Sopenharmony_ci * OP_DEL: Set if the manual says the VALIDENT bit is supported in the 738c2ecf20Sopenharmony_ci * COMMAND portion of this dynamic config buffer (i.e. the 748c2ecf20Sopenharmony_ci * specified entry can be invalidated through a SPI write 758c2ecf20Sopenharmony_ci * command). 768c2ecf20Sopenharmony_ci * OP_SEARCH: Set if the manual says that the index of an entry can 778c2ecf20Sopenharmony_ci * be retrieved in the COMMAND portion of the buffer based 788c2ecf20Sopenharmony_ci * on its ENTRY portion, as a result of a SPI write command. 798c2ecf20Sopenharmony_ci * Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports 808c2ecf20Sopenharmony_ci * this. 818c2ecf20Sopenharmony_ci * - .max_entry_count: The number of entries, counting from zero, that can be 828c2ecf20Sopenharmony_ci * reconfigured through the dynamic interface. If a static 838c2ecf20Sopenharmony_ci * table can be reconfigured at all dynamically, this 848c2ecf20Sopenharmony_ci * number always matches the maximum number of supported 858c2ecf20Sopenharmony_ci * static entries. 868c2ecf20Sopenharmony_ci * - .packed_size: The length in bytes of the compound ENTRY + COMMAND BUFFER. 878c2ecf20Sopenharmony_ci * Note that sometimes the compound buffer may contain holes in 888c2ecf20Sopenharmony_ci * it (see sja1105_vlan_lookup_cmd_packing). The @packed_buf is 898c2ecf20Sopenharmony_ci * contiguous however, so @packed_size includes any unused 908c2ecf20Sopenharmony_ci * bytes. 918c2ecf20Sopenharmony_ci * - .addr: The base SPI address at which the buffer must be written to the 928c2ecf20Sopenharmony_ci * switch's memory. When looking at the hardware manual, this must 938c2ecf20Sopenharmony_ci * always match the lowest documented address for the ENTRY, and not 948c2ecf20Sopenharmony_ci * that of the COMMAND, since the other 32-bit words will follow along 958c2ecf20Sopenharmony_ci * at the correct addresses. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define SJA1105_SIZE_DYN_CMD 4 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD \ 1018c2ecf20Sopenharmony_ci SJA1105_SIZE_DYN_CMD 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD \ 1048c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY \ 1078c2ecf20Sopenharmony_ci SJA1105_SIZE_DYN_CMD 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD \ 1108c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_L2_LOOKUP_ENTRY) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD \ 1138c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD \ 1168c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD \ 1198c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD \ 1228c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD \ 1258c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD \ 1288c2ecf20Sopenharmony_ci SJA1105_SIZE_DYN_CMD 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD \ 1318c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD \ 1348c2ecf20Sopenharmony_ci SJA1105_SIZE_DYN_CMD 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD \ 1378c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY) 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD \ 1408c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define SJA1105_SIZE_RETAGGING_DYN_CMD \ 1438c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_RETAGGING_ENTRY) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define SJA1105ET_SIZE_CBS_DYN_CMD \ 1468c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105ET_SIZE_CBS_ENTRY) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define SJA1105PQRS_SIZE_CBS_DYN_CMD \ 1498c2ecf20Sopenharmony_ci (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY) 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define SJA1105_MAX_DYN_CMD_SIZE \ 1528c2ecf20Sopenharmony_ci SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistruct sja1105_dyn_cmd { 1558c2ecf20Sopenharmony_ci bool search; 1568c2ecf20Sopenharmony_ci u64 valid; 1578c2ecf20Sopenharmony_ci u64 rdwrset; 1588c2ecf20Sopenharmony_ci u64 errors; 1598c2ecf20Sopenharmony_ci u64 valident; 1608c2ecf20Sopenharmony_ci u64 index; 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cienum sja1105_hostcmd { 1648c2ecf20Sopenharmony_ci SJA1105_HOSTCMD_SEARCH = 1, 1658c2ecf20Sopenharmony_ci SJA1105_HOSTCMD_READ = 2, 1668c2ecf20Sopenharmony_ci SJA1105_HOSTCMD_WRITE = 3, 1678c2ecf20Sopenharmony_ci SJA1105_HOSTCMD_INVALIDATE = 4, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* Command and entry overlap */ 1718c2ecf20Sopenharmony_cistatic void 1728c2ecf20Sopenharmony_cisja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 1738c2ecf20Sopenharmony_ci enum packing_op op) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->valid, 31, 31, size, op); 1788c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->errors, 30, 30, size, op); 1798c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->rdwrset, 29, 29, size, op); 1808c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->index, 9, 0, size, op); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* Command and entry are separate */ 1848c2ecf20Sopenharmony_cistatic void 1858c2ecf20Sopenharmony_cisja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 1868c2ecf20Sopenharmony_ci enum packing_op op) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY; 1898c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 1928c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 30, 30, size, op); 1938c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); 1948c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->index, 9, 0, size, op); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr, 1988c2ecf20Sopenharmony_ci enum packing_op op) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct sja1105_vl_lookup_entry *entry = entry_ptr; 2018c2ecf20Sopenharmony_ci const int size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->egrmirr, 21, 17, size, op); 2048c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->ingrmirr, 16, 16, size, op); 2058c2ecf20Sopenharmony_ci return size; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void 2098c2ecf20Sopenharmony_cisja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 2108c2ecf20Sopenharmony_ci enum packing_op op) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY; 2138c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 2148c2ecf20Sopenharmony_ci u64 hostcmd; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 2178c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 2188c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 29, 29, size, op); 2198c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valident, 27, 27, size, op); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T, 2228c2ecf20Sopenharmony_ci * using it to delete a management route was unsupported. UM10944 2238c2ecf20Sopenharmony_ci * said about it: 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * In case of a write access with the MGMTROUTE flag set, 2268c2ecf20Sopenharmony_ci * the flag will be ignored. It will always be found cleared 2278c2ecf20Sopenharmony_ci * for read accesses with the MGMTROUTE flag set. 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there 2308c2ecf20Sopenharmony_ci * is now another flag called HOSTCMD which does more stuff (quoting 2318c2ecf20Sopenharmony_ci * from UM11040): 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * A write request is accepted only when HOSTCMD is set to write host 2348c2ecf20Sopenharmony_ci * or invalid. A read request is accepted only when HOSTCMD is set to 2358c2ecf20Sopenharmony_ci * search host or read host. 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * So it is possible to translate a RDWRSET/VALIDENT combination into 2388c2ecf20Sopenharmony_ci * HOSTCMD so that we keep the dynamic command API in place, and 2398c2ecf20Sopenharmony_ci * at the same time achieve compatibility with the management route 2408c2ecf20Sopenharmony_ci * command structure. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if (cmd->rdwrset == SPI_READ) { 2438c2ecf20Sopenharmony_ci if (cmd->search) 2448c2ecf20Sopenharmony_ci hostcmd = SJA1105_HOSTCMD_SEARCH; 2458c2ecf20Sopenharmony_ci else 2468c2ecf20Sopenharmony_ci hostcmd = SJA1105_HOSTCMD_READ; 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci /* SPI_WRITE */ 2498c2ecf20Sopenharmony_ci if (cmd->valident) 2508c2ecf20Sopenharmony_ci hostcmd = SJA1105_HOSTCMD_WRITE; 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci hostcmd = SJA1105_HOSTCMD_INVALIDATE; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci sja1105_packing(p, &hostcmd, 25, 23, size, op); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Hack - The hardware takes the 'index' field within 2578c2ecf20Sopenharmony_ci * struct sja1105_l2_lookup_entry as the index on which this command 2588c2ecf20Sopenharmony_ci * will operate. However it will ignore everything else, so 'index' 2598c2ecf20Sopenharmony_ci * is logically part of command but physically part of entry. 2608c2ecf20Sopenharmony_ci * Populate the 'index' entry field from within the command callback, 2618c2ecf20Sopenharmony_ci * such that our API doesn't need to ask for a full-blown entry 2628c2ecf20Sopenharmony_ci * structure when e.g. a delete is requested. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->index, 15, 6, 2658c2ecf20Sopenharmony_ci SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* The switch is so retarded that it makes our command/entry abstraction 2698c2ecf20Sopenharmony_ci * crumble apart. 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci * On P/Q/R/S, the switch tries to say whether a FDB entry 2728c2ecf20Sopenharmony_ci * is statically programmed or dynamically learned via a flag called LOCKEDS. 2738c2ecf20Sopenharmony_ci * The hardware manual says about this fiels: 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * On write will specify the format of ENTRY. 2768c2ecf20Sopenharmony_ci * On read the flag will be found cleared at times the VALID flag is found 2778c2ecf20Sopenharmony_ci * set. The flag will also be found cleared in response to a read having the 2788c2ecf20Sopenharmony_ci * MGMTROUTE flag set. In response to a read with the MGMTROUTE flag 2798c2ecf20Sopenharmony_ci * cleared, the flag be set if the most recent access operated on an entry 2808c2ecf20Sopenharmony_ci * that was either loaded by configuration or through dynamic reconfiguration 2818c2ecf20Sopenharmony_ci * (as opposed to automatically learned entries). 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * The trouble with this flag is that it's part of the *command* to access the 2848c2ecf20Sopenharmony_ci * dynamic interface, and not part of the *entry* retrieved from it. 2858c2ecf20Sopenharmony_ci * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be 2868c2ecf20Sopenharmony_ci * an output from the switch into the command buffer, and for a 2878c2ecf20Sopenharmony_ci * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input 2888c2ecf20Sopenharmony_ci * (hence we can write either static, or automatically learned entries, from 2898c2ecf20Sopenharmony_ci * the core). 2908c2ecf20Sopenharmony_ci * But the manual contradicts itself in the last phrase where it says that on 2918c2ecf20Sopenharmony_ci * read, LOCKEDS will be set to 1 for all FDB entries written through the 2928c2ecf20Sopenharmony_ci * dynamic interface (therefore, the value of LOCKEDS from the 2938c2ecf20Sopenharmony_ci * sja1105_dynamic_config_write is not really used for anything, it'll store a 2948c2ecf20Sopenharmony_ci * 1 anyway). 2958c2ecf20Sopenharmony_ci * This means you can't really write a FDB entry with LOCKEDS=0 (automatically 2968c2ecf20Sopenharmony_ci * learned) into the switch, which kind of makes sense. 2978c2ecf20Sopenharmony_ci * As for reading through the dynamic interface, it doesn't make too much sense 2988c2ecf20Sopenharmony_ci * to put LOCKEDS into the command, since the switch will inevitably have to 2998c2ecf20Sopenharmony_ci * ignore it (otherwise a command would be like "read the FDB entry 123, but 3008c2ecf20Sopenharmony_ci * only if it's dynamically learned" <- well how am I supposed to know?) and 3018c2ecf20Sopenharmony_ci * just use it as an output buffer for its findings. But guess what... that's 3028c2ecf20Sopenharmony_ci * what the entry buffer is for! 3038c2ecf20Sopenharmony_ci * Unfortunately, what really breaks this abstraction is the fact that it 3048c2ecf20Sopenharmony_ci * wasn't designed having the fact in mind that the switch can output 3058c2ecf20Sopenharmony_ci * entry-related data as writeback through the command buffer. 3068c2ecf20Sopenharmony_ci * However, whether a FDB entry is statically or dynamically learned *is* part 3078c2ecf20Sopenharmony_ci * of the entry and not the command data, no matter what the switch thinks. 3088c2ecf20Sopenharmony_ci * In order to do that, we'll need to wrap around the 3098c2ecf20Sopenharmony_ci * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take 3108c2ecf20Sopenharmony_ci * a peek outside of the caller-supplied @buf (the entry buffer), to reach the 3118c2ecf20Sopenharmony_ci * command buffer. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cistatic size_t 3148c2ecf20Sopenharmony_cisja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr, 3158c2ecf20Sopenharmony_ci enum packing_op op) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct sja1105_l2_lookup_entry *entry = entry_ptr; 3188c2ecf20Sopenharmony_ci u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY; 3198c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void 3278c2ecf20Sopenharmony_cisja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 3288c2ecf20Sopenharmony_ci enum packing_op op) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 3318c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 3348c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 3358c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 29, 29, size, op); 3368c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valident, 27, 27, size, op); 3378c2ecf20Sopenharmony_ci /* Hack - see comments above. */ 3388c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->index, 29, 20, 3398c2ecf20Sopenharmony_ci SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr, 3438c2ecf20Sopenharmony_ci enum packing_op op) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct sja1105_l2_lookup_entry *entry = entry_ptr; 3468c2ecf20Sopenharmony_ci u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 3478c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void 3558c2ecf20Sopenharmony_cisja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 3568c2ecf20Sopenharmony_ci enum packing_op op) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 3598c2ecf20Sopenharmony_ci u64 mgmtroute = 1; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci sja1105et_l2_lookup_cmd_packing(buf, cmd, op); 3628c2ecf20Sopenharmony_ci if (op == PACK) 3638c2ecf20Sopenharmony_ci sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr, 3678c2ecf20Sopenharmony_ci enum packing_op op) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct sja1105_mgmt_entry *entry = entry_ptr; 3708c2ecf20Sopenharmony_ci const size_t size = SJA1105ET_SIZE_L2_LOOKUP_ENTRY; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* UM10944: To specify if a PTP egress timestamp shall be captured on 3738c2ecf20Sopenharmony_ci * each port upon transmission of the frame, the LSB of VLANID in the 3748c2ecf20Sopenharmony_ci * ENTRY field provided by the host must be set. 3758c2ecf20Sopenharmony_ci * Bit 1 of VLANID then specifies the register where the timestamp for 3768c2ecf20Sopenharmony_ci * this port is stored in. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->tsreg, 85, 85, size, op); 3798c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->takets, 84, 84, size, op); 3808c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->macaddr, 83, 36, size, op); 3818c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->destports, 35, 31, size, op); 3828c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->enfport, 30, 30, size, op); 3838c2ecf20Sopenharmony_ci return size; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void 3878c2ecf20Sopenharmony_cisja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 3888c2ecf20Sopenharmony_ci enum packing_op op) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY; 3918c2ecf20Sopenharmony_ci u64 mgmtroute = 1; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op); 3948c2ecf20Sopenharmony_ci if (op == PACK) 3958c2ecf20Sopenharmony_ci sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr, 3998c2ecf20Sopenharmony_ci enum packing_op op) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY; 4028c2ecf20Sopenharmony_ci struct sja1105_mgmt_entry *entry = entry_ptr; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose 4058c2ecf20Sopenharmony_ci * is the same (driver uses it to confirm that frame was sent). 4068c2ecf20Sopenharmony_ci * So just keep the name from E/T. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->tsreg, 71, 71, size, op); 4098c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->takets, 70, 70, size, op); 4108c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->macaddr, 69, 22, size, op); 4118c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->destports, 21, 17, size, op); 4128c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->enfport, 16, 16, size, op); 4138c2ecf20Sopenharmony_ci return size; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29, 4178c2ecf20Sopenharmony_ci * and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap 4188c2ecf20Sopenharmony_ci * between entry (0x2d, 0x2e) and command (0x30). 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cistatic void 4218c2ecf20Sopenharmony_cisja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 4228c2ecf20Sopenharmony_ci enum packing_op op) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105_SIZE_VLAN_LOOKUP_ENTRY + 4; 4258c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 4288c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 4298c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valident, 27, 27, size, op); 4308c2ecf20Sopenharmony_ci /* Hack - see comments above, applied for 'vlanid' field of 4318c2ecf20Sopenharmony_ci * struct sja1105_vlan_lookup_entry. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->index, 38, 27, 4348c2ecf20Sopenharmony_ci SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic void 4388c2ecf20Sopenharmony_cisja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 4398c2ecf20Sopenharmony_ci enum packing_op op) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY; 4428c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 4458c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 30, 30, size, op); 4468c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); 4478c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->index, 4, 0, size, op); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void 4518c2ecf20Sopenharmony_cisja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 4528c2ecf20Sopenharmony_ci enum packing_op op) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 4558c2ecf20Sopenharmony_ci /* Yup, user manual definitions are reversed */ 4568c2ecf20Sopenharmony_ci u8 *reg1 = buf + 4; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci sja1105_packing(reg1, &cmd->valid, 31, 31, size, op); 4598c2ecf20Sopenharmony_ci sja1105_packing(reg1, &cmd->index, 26, 24, size, op); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr, 4638c2ecf20Sopenharmony_ci enum packing_op op) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY; 4668c2ecf20Sopenharmony_ci struct sja1105_mac_config_entry *entry = entry_ptr; 4678c2ecf20Sopenharmony_ci /* Yup, user manual definitions are reversed */ 4688c2ecf20Sopenharmony_ci u8 *reg1 = buf + 4; 4698c2ecf20Sopenharmony_ci u8 *reg2 = buf; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->speed, 30, 29, size, op); 4728c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->drpdtag, 23, 23, size, op); 4738c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->drpuntag, 22, 22, size, op); 4748c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->retag, 21, 21, size, op); 4758c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->dyn_learn, 20, 20, size, op); 4768c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->egress, 19, 19, size, op); 4778c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->ingress, 18, 18, size, op); 4788c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->ing_mirr, 17, 17, size, op); 4798c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->egr_mirr, 16, 16, size, op); 4808c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->vlanprio, 14, 12, size, op); 4818c2ecf20Sopenharmony_ci sja1105_packing(reg1, &entry->vlanid, 11, 0, size, op); 4828c2ecf20Sopenharmony_ci sja1105_packing(reg2, &entry->tp_delin, 31, 16, size, op); 4838c2ecf20Sopenharmony_ci sja1105_packing(reg2, &entry->tp_delout, 15, 0, size, op); 4848c2ecf20Sopenharmony_ci /* MAC configuration table entries which can't be reconfigured: 4858c2ecf20Sopenharmony_ci * top, base, enabled, ifg, maxage, drpnona664 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci /* Bogus return value, not used anywhere */ 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic void 4928c2ecf20Sopenharmony_cisja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 4938c2ecf20Sopenharmony_ci enum packing_op op) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci const int size = SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY; 4968c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 4998c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 30, 30, size, op); 5008c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); 5018c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->index, 2, 0, size, op); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void 5058c2ecf20Sopenharmony_cisja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 5068c2ecf20Sopenharmony_ci enum packing_op op) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->valid, 31, 31, 5098c2ecf20Sopenharmony_ci SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic size_t 5138c2ecf20Sopenharmony_cisja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr, 5148c2ecf20Sopenharmony_ci enum packing_op op) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct sja1105_l2_lookup_params_entry *entry = entry_ptr; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->poly, 7, 0, 5198c2ecf20Sopenharmony_ci SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, op); 5208c2ecf20Sopenharmony_ci /* Bogus return value, not used anywhere */ 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void 5258c2ecf20Sopenharmony_cisja1105pqrs_l2_lookup_params_cmd_packing(void *buf, 5268c2ecf20Sopenharmony_ci struct sja1105_dyn_cmd *cmd, 5278c2ecf20Sopenharmony_ci enum packing_op op) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY; 5308c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 5338c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void 5378c2ecf20Sopenharmony_cisja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 5388c2ecf20Sopenharmony_ci enum packing_op op) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->valid, 31, 31, size, op); 5438c2ecf20Sopenharmony_ci sja1105_packing(buf, &cmd->errors, 30, 30, size, op); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic size_t 5478c2ecf20Sopenharmony_cisja1105et_general_params_entry_packing(void *buf, void *entry_ptr, 5488c2ecf20Sopenharmony_ci enum packing_op op) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct sja1105_general_params_entry *entry = entry_ptr; 5518c2ecf20Sopenharmony_ci const int size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->mirr_port, 2, 0, size, op); 5548c2ecf20Sopenharmony_ci /* Bogus return value, not used anywhere */ 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic void 5598c2ecf20Sopenharmony_cisja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 5608c2ecf20Sopenharmony_ci enum packing_op op) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY; 5638c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 5668c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 30, 30, size, op); 5678c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void 5718c2ecf20Sopenharmony_cisja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 5728c2ecf20Sopenharmony_ci enum packing_op op) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY; 5758c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 5788c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 30, 30, size, op); 5798c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void 5838c2ecf20Sopenharmony_cisja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 5848c2ecf20Sopenharmony_ci enum packing_op op) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY; 5878c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 5908c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 30, 30, size, op); 5918c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valident, 29, 29, size, op); 5928c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op); 5938c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->index, 5, 0, size, op); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 5978c2ecf20Sopenharmony_ci enum packing_op op) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105ET_SIZE_CBS_ENTRY; 6008c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 6038c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->index, 19, 16, size, op); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic size_t sja1105et_cbs_entry_packing(void *buf, void *entry_ptr, 6078c2ecf20Sopenharmony_ci enum packing_op op) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci const size_t size = SJA1105ET_SIZE_CBS_ENTRY; 6108c2ecf20Sopenharmony_ci struct sja1105_cbs_entry *entry = entry_ptr; 6118c2ecf20Sopenharmony_ci u8 *cmd = buf + size; 6128c2ecf20Sopenharmony_ci u32 *p = buf; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci sja1105_packing(cmd, &entry->port, 5, 3, SJA1105_SIZE_DYN_CMD, op); 6158c2ecf20Sopenharmony_ci sja1105_packing(cmd, &entry->prio, 2, 0, SJA1105_SIZE_DYN_CMD, op); 6168c2ecf20Sopenharmony_ci sja1105_packing(p + 3, &entry->credit_lo, 31, 0, size, op); 6178c2ecf20Sopenharmony_ci sja1105_packing(p + 2, &entry->credit_hi, 31, 0, size, op); 6188c2ecf20Sopenharmony_ci sja1105_packing(p + 1, &entry->send_slope, 31, 0, size, op); 6198c2ecf20Sopenharmony_ci sja1105_packing(p + 0, &entry->idle_slope, 31, 0, size, op); 6208c2ecf20Sopenharmony_ci return size; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, 6248c2ecf20Sopenharmony_ci enum packing_op op) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY; 6278c2ecf20Sopenharmony_ci const int size = SJA1105_SIZE_DYN_CMD; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->valid, 31, 31, size, op); 6308c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op); 6318c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->errors, 29, 29, size, op); 6328c2ecf20Sopenharmony_ci sja1105_packing(p, &cmd->index, 3, 0, size, op); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr, 6368c2ecf20Sopenharmony_ci enum packing_op op) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY; 6398c2ecf20Sopenharmony_ci struct sja1105_cbs_entry *entry = entry_ptr; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->port, 159, 157, size, op); 6428c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->prio, 156, 154, size, op); 6438c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->credit_lo, 153, 122, size, op); 6448c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->credit_hi, 121, 90, size, op); 6458c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->send_slope, 89, 58, size, op); 6468c2ecf20Sopenharmony_ci sja1105_packing(buf, &entry->idle_slope, 57, 26, size, op); 6478c2ecf20Sopenharmony_ci return size; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci#define OP_READ BIT(0) 6518c2ecf20Sopenharmony_ci#define OP_WRITE BIT(1) 6528c2ecf20Sopenharmony_ci#define OP_DEL BIT(2) 6538c2ecf20Sopenharmony_ci#define OP_SEARCH BIT(3) 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci/* SJA1105E/T: First generation */ 6568c2ecf20Sopenharmony_ciconst struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { 6578c2ecf20Sopenharmony_ci [BLK_IDX_VL_LOOKUP] = { 6588c2ecf20Sopenharmony_ci .entry_packing = sja1105et_vl_lookup_entry_packing, 6598c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_vl_lookup_cmd_packing, 6608c2ecf20Sopenharmony_ci .access = OP_WRITE, 6618c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT, 6628c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD, 6638c2ecf20Sopenharmony_ci .addr = 0x35, 6648c2ecf20Sopenharmony_ci }, 6658c2ecf20Sopenharmony_ci [BLK_IDX_L2_LOOKUP] = { 6668c2ecf20Sopenharmony_ci .entry_packing = sja1105et_dyn_l2_lookup_entry_packing, 6678c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_l2_lookup_cmd_packing, 6688c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE | OP_DEL), 6698c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, 6708c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 6718c2ecf20Sopenharmony_ci .addr = 0x20, 6728c2ecf20Sopenharmony_ci }, 6738c2ecf20Sopenharmony_ci [BLK_IDX_MGMT_ROUTE] = { 6748c2ecf20Sopenharmony_ci .entry_packing = sja1105et_mgmt_route_entry_packing, 6758c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_mgmt_route_cmd_packing, 6768c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE), 6778c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_NUM_PORTS, 6788c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, 6798c2ecf20Sopenharmony_ci .addr = 0x20, 6808c2ecf20Sopenharmony_ci }, 6818c2ecf20Sopenharmony_ci [BLK_IDX_VLAN_LOOKUP] = { 6828c2ecf20Sopenharmony_ci .entry_packing = sja1105_vlan_lookup_entry_packing, 6838c2ecf20Sopenharmony_ci .cmd_packing = sja1105_vlan_lookup_cmd_packing, 6848c2ecf20Sopenharmony_ci .access = (OP_WRITE | OP_DEL), 6858c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT, 6868c2ecf20Sopenharmony_ci .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD, 6878c2ecf20Sopenharmony_ci .addr = 0x27, 6888c2ecf20Sopenharmony_ci }, 6898c2ecf20Sopenharmony_ci [BLK_IDX_L2_FORWARDING] = { 6908c2ecf20Sopenharmony_ci .entry_packing = sja1105_l2_forwarding_entry_packing, 6918c2ecf20Sopenharmony_ci .cmd_packing = sja1105_l2_forwarding_cmd_packing, 6928c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT, 6938c2ecf20Sopenharmony_ci .access = OP_WRITE, 6948c2ecf20Sopenharmony_ci .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD, 6958c2ecf20Sopenharmony_ci .addr = 0x24, 6968c2ecf20Sopenharmony_ci }, 6978c2ecf20Sopenharmony_ci [BLK_IDX_MAC_CONFIG] = { 6988c2ecf20Sopenharmony_ci .entry_packing = sja1105et_mac_config_entry_packing, 6998c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_mac_config_cmd_packing, 7008c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, 7018c2ecf20Sopenharmony_ci .access = OP_WRITE, 7028c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD, 7038c2ecf20Sopenharmony_ci .addr = 0x36, 7048c2ecf20Sopenharmony_ci }, 7058c2ecf20Sopenharmony_ci [BLK_IDX_L2_LOOKUP_PARAMS] = { 7068c2ecf20Sopenharmony_ci .entry_packing = sja1105et_l2_lookup_params_entry_packing, 7078c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_l2_lookup_params_cmd_packing, 7088c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT, 7098c2ecf20Sopenharmony_ci .access = OP_WRITE, 7108c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, 7118c2ecf20Sopenharmony_ci .addr = 0x38, 7128c2ecf20Sopenharmony_ci }, 7138c2ecf20Sopenharmony_ci [BLK_IDX_GENERAL_PARAMS] = { 7148c2ecf20Sopenharmony_ci .entry_packing = sja1105et_general_params_entry_packing, 7158c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_general_params_cmd_packing, 7168c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, 7178c2ecf20Sopenharmony_ci .access = OP_WRITE, 7188c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD, 7198c2ecf20Sopenharmony_ci .addr = 0x34, 7208c2ecf20Sopenharmony_ci }, 7218c2ecf20Sopenharmony_ci [BLK_IDX_RETAGGING] = { 7228c2ecf20Sopenharmony_ci .entry_packing = sja1105_retagging_entry_packing, 7238c2ecf20Sopenharmony_ci .cmd_packing = sja1105_retagging_cmd_packing, 7248c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, 7258c2ecf20Sopenharmony_ci .access = (OP_WRITE | OP_DEL), 7268c2ecf20Sopenharmony_ci .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD, 7278c2ecf20Sopenharmony_ci .addr = 0x31, 7288c2ecf20Sopenharmony_ci }, 7298c2ecf20Sopenharmony_ci [BLK_IDX_CBS] = { 7308c2ecf20Sopenharmony_ci .entry_packing = sja1105et_cbs_entry_packing, 7318c2ecf20Sopenharmony_ci .cmd_packing = sja1105et_cbs_cmd_packing, 7328c2ecf20Sopenharmony_ci .max_entry_count = SJA1105ET_MAX_CBS_COUNT, 7338c2ecf20Sopenharmony_ci .access = OP_WRITE, 7348c2ecf20Sopenharmony_ci .packed_size = SJA1105ET_SIZE_CBS_DYN_CMD, 7358c2ecf20Sopenharmony_ci .addr = 0x2c, 7368c2ecf20Sopenharmony_ci }, 7378c2ecf20Sopenharmony_ci}; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci/* SJA1105P/Q/R/S: Second generation */ 7408c2ecf20Sopenharmony_ciconst struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { 7418c2ecf20Sopenharmony_ci [BLK_IDX_VL_LOOKUP] = { 7428c2ecf20Sopenharmony_ci .entry_packing = sja1105_vl_lookup_entry_packing, 7438c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_vl_lookup_cmd_packing, 7448c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE), 7458c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT, 7468c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD, 7478c2ecf20Sopenharmony_ci .addr = 0x47, 7488c2ecf20Sopenharmony_ci }, 7498c2ecf20Sopenharmony_ci [BLK_IDX_L2_LOOKUP] = { 7508c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing, 7518c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing, 7528c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH), 7538c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, 7548c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD, 7558c2ecf20Sopenharmony_ci .addr = 0x24, 7568c2ecf20Sopenharmony_ci }, 7578c2ecf20Sopenharmony_ci [BLK_IDX_MGMT_ROUTE] = { 7588c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_mgmt_route_entry_packing, 7598c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing, 7608c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH), 7618c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_NUM_PORTS, 7628c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD, 7638c2ecf20Sopenharmony_ci .addr = 0x24, 7648c2ecf20Sopenharmony_ci }, 7658c2ecf20Sopenharmony_ci [BLK_IDX_VLAN_LOOKUP] = { 7668c2ecf20Sopenharmony_ci .entry_packing = sja1105_vlan_lookup_entry_packing, 7678c2ecf20Sopenharmony_ci .cmd_packing = sja1105_vlan_lookup_cmd_packing, 7688c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE | OP_DEL), 7698c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT, 7708c2ecf20Sopenharmony_ci .packed_size = SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD, 7718c2ecf20Sopenharmony_ci .addr = 0x2D, 7728c2ecf20Sopenharmony_ci }, 7738c2ecf20Sopenharmony_ci [BLK_IDX_L2_FORWARDING] = { 7748c2ecf20Sopenharmony_ci .entry_packing = sja1105_l2_forwarding_entry_packing, 7758c2ecf20Sopenharmony_ci .cmd_packing = sja1105_l2_forwarding_cmd_packing, 7768c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT, 7778c2ecf20Sopenharmony_ci .access = OP_WRITE, 7788c2ecf20Sopenharmony_ci .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD, 7798c2ecf20Sopenharmony_ci .addr = 0x2A, 7808c2ecf20Sopenharmony_ci }, 7818c2ecf20Sopenharmony_ci [BLK_IDX_MAC_CONFIG] = { 7828c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_mac_config_entry_packing, 7838c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_mac_config_cmd_packing, 7848c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, 7858c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE), 7868c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD, 7878c2ecf20Sopenharmony_ci .addr = 0x4B, 7888c2ecf20Sopenharmony_ci }, 7898c2ecf20Sopenharmony_ci [BLK_IDX_L2_LOOKUP_PARAMS] = { 7908c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_l2_lookup_params_entry_packing, 7918c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_l2_lookup_params_cmd_packing, 7928c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT, 7938c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE), 7948c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD, 7958c2ecf20Sopenharmony_ci .addr = 0x54, 7968c2ecf20Sopenharmony_ci }, 7978c2ecf20Sopenharmony_ci [BLK_IDX_AVB_PARAMS] = { 7988c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_avb_params_entry_packing, 7998c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_avb_params_cmd_packing, 8008c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT, 8018c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE), 8028c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD, 8038c2ecf20Sopenharmony_ci .addr = 0x8003, 8048c2ecf20Sopenharmony_ci }, 8058c2ecf20Sopenharmony_ci [BLK_IDX_GENERAL_PARAMS] = { 8068c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_general_params_entry_packing, 8078c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_general_params_cmd_packing, 8088c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, 8098c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE), 8108c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD, 8118c2ecf20Sopenharmony_ci .addr = 0x3B, 8128c2ecf20Sopenharmony_ci }, 8138c2ecf20Sopenharmony_ci [BLK_IDX_RETAGGING] = { 8148c2ecf20Sopenharmony_ci .entry_packing = sja1105_retagging_entry_packing, 8158c2ecf20Sopenharmony_ci .cmd_packing = sja1105_retagging_cmd_packing, 8168c2ecf20Sopenharmony_ci .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, 8178c2ecf20Sopenharmony_ci .access = (OP_READ | OP_WRITE | OP_DEL), 8188c2ecf20Sopenharmony_ci .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD, 8198c2ecf20Sopenharmony_ci .addr = 0x38, 8208c2ecf20Sopenharmony_ci }, 8218c2ecf20Sopenharmony_ci [BLK_IDX_CBS] = { 8228c2ecf20Sopenharmony_ci .entry_packing = sja1105pqrs_cbs_entry_packing, 8238c2ecf20Sopenharmony_ci .cmd_packing = sja1105pqrs_cbs_cmd_packing, 8248c2ecf20Sopenharmony_ci .max_entry_count = SJA1105PQRS_MAX_CBS_COUNT, 8258c2ecf20Sopenharmony_ci .access = OP_WRITE, 8268c2ecf20Sopenharmony_ci .packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD, 8278c2ecf20Sopenharmony_ci .addr = 0x32, 8288c2ecf20Sopenharmony_ci }, 8298c2ecf20Sopenharmony_ci}; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci/* Provides read access to the settings through the dynamic interface 8328c2ecf20Sopenharmony_ci * of the switch. 8338c2ecf20Sopenharmony_ci * @blk_idx is used as key to select from the sja1105_dynamic_table_ops. 8348c2ecf20Sopenharmony_ci * The selection is limited by the hardware in respect to which 8358c2ecf20Sopenharmony_ci * configuration blocks can be read through the dynamic interface. 8368c2ecf20Sopenharmony_ci * @index is used to retrieve a particular table entry. If negative, 8378c2ecf20Sopenharmony_ci * (and if the @blk_idx supports the searching operation) a search 8388c2ecf20Sopenharmony_ci * is performed by the @entry parameter. 8398c2ecf20Sopenharmony_ci * @entry Type-casted to an unpacked structure that holds a table entry 8408c2ecf20Sopenharmony_ci * of the type specified in @blk_idx. 8418c2ecf20Sopenharmony_ci * Usually an output argument. If @index is negative, then this 8428c2ecf20Sopenharmony_ci * argument is used as input/output: it should be pre-populated 8438c2ecf20Sopenharmony_ci * with the element to search for. Entries which support the 8448c2ecf20Sopenharmony_ci * search operation will have an "index" field (not the @index 8458c2ecf20Sopenharmony_ci * argument to this function) and that is where the found index 8468c2ecf20Sopenharmony_ci * will be returned (or left unmodified - thus negative - if not 8478c2ecf20Sopenharmony_ci * found). 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ciint sja1105_dynamic_config_read(struct sja1105_private *priv, 8508c2ecf20Sopenharmony_ci enum sja1105_blk_idx blk_idx, 8518c2ecf20Sopenharmony_ci int index, void *entry) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci const struct sja1105_dynamic_table_ops *ops; 8548c2ecf20Sopenharmony_ci struct sja1105_dyn_cmd cmd = {0}; 8558c2ecf20Sopenharmony_ci /* SPI payload buffer */ 8568c2ecf20Sopenharmony_ci u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0}; 8578c2ecf20Sopenharmony_ci int retries = 3; 8588c2ecf20Sopenharmony_ci int rc; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (blk_idx >= BLK_IDX_MAX_DYN) 8618c2ecf20Sopenharmony_ci return -ERANGE; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci ops = &priv->info->dyn_ops[blk_idx]; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (index >= 0 && index >= ops->max_entry_count) 8668c2ecf20Sopenharmony_ci return -ERANGE; 8678c2ecf20Sopenharmony_ci if (index < 0 && !(ops->access & OP_SEARCH)) 8688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8698c2ecf20Sopenharmony_ci if (!(ops->access & OP_READ)) 8708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8718c2ecf20Sopenharmony_ci if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE) 8728c2ecf20Sopenharmony_ci return -ERANGE; 8738c2ecf20Sopenharmony_ci if (!ops->cmd_packing) 8748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8758c2ecf20Sopenharmony_ci if (!ops->entry_packing) 8768c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci cmd.valid = true; /* Trigger action on table entry */ 8798c2ecf20Sopenharmony_ci cmd.rdwrset = SPI_READ; /* Action is read */ 8808c2ecf20Sopenharmony_ci if (index < 0) { 8818c2ecf20Sopenharmony_ci /* Avoid copying a signed negative number to an u64 */ 8828c2ecf20Sopenharmony_ci cmd.index = 0; 8838c2ecf20Sopenharmony_ci cmd.search = true; 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci cmd.index = index; 8868c2ecf20Sopenharmony_ci cmd.search = false; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci cmd.valident = true; 8898c2ecf20Sopenharmony_ci ops->cmd_packing(packed_buf, &cmd, PACK); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (cmd.search) 8928c2ecf20Sopenharmony_ci ops->entry_packing(packed_buf, entry, PACK); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Send SPI write operation: read config table entry */ 8958c2ecf20Sopenharmony_ci rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, 8968c2ecf20Sopenharmony_ci ops->packed_size); 8978c2ecf20Sopenharmony_ci if (rc < 0) 8988c2ecf20Sopenharmony_ci return rc; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Loop until we have confirmation that hardware has finished 9018c2ecf20Sopenharmony_ci * processing the command and has cleared the VALID field 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_ci do { 9048c2ecf20Sopenharmony_ci memset(packed_buf, 0, ops->packed_size); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* Retrieve the read operation's result */ 9078c2ecf20Sopenharmony_ci rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf, 9088c2ecf20Sopenharmony_ci ops->packed_size); 9098c2ecf20Sopenharmony_ci if (rc < 0) 9108c2ecf20Sopenharmony_ci return rc; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci cmd = (struct sja1105_dyn_cmd) {0}; 9138c2ecf20Sopenharmony_ci ops->cmd_packing(packed_buf, &cmd, UNPACK); 9148c2ecf20Sopenharmony_ci /* UM10944: [valident] will always be found cleared 9158c2ecf20Sopenharmony_ci * during a read access with MGMTROUTE set. 9168c2ecf20Sopenharmony_ci * So don't error out in that case. 9178c2ecf20Sopenharmony_ci */ 9188c2ecf20Sopenharmony_ci if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE) 9198c2ecf20Sopenharmony_ci return -ENOENT; 9208c2ecf20Sopenharmony_ci cpu_relax(); 9218c2ecf20Sopenharmony_ci } while (cmd.valid && --retries); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (cmd.valid) 9248c2ecf20Sopenharmony_ci return -ETIMEDOUT; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* Don't dereference possibly NULL pointer - maybe caller 9278c2ecf20Sopenharmony_ci * only wanted to see whether the entry existed or not. 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_ci if (entry) 9308c2ecf20Sopenharmony_ci ops->entry_packing(packed_buf, entry, UNPACK); 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ciint sja1105_dynamic_config_write(struct sja1105_private *priv, 9358c2ecf20Sopenharmony_ci enum sja1105_blk_idx blk_idx, 9368c2ecf20Sopenharmony_ci int index, void *entry, bool keep) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci const struct sja1105_dynamic_table_ops *ops; 9398c2ecf20Sopenharmony_ci struct sja1105_dyn_cmd cmd = {0}; 9408c2ecf20Sopenharmony_ci /* SPI payload buffer */ 9418c2ecf20Sopenharmony_ci u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {0}; 9428c2ecf20Sopenharmony_ci int rc; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (blk_idx >= BLK_IDX_MAX_DYN) 9458c2ecf20Sopenharmony_ci return -ERANGE; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ops = &priv->info->dyn_ops[blk_idx]; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (index >= ops->max_entry_count) 9508c2ecf20Sopenharmony_ci return -ERANGE; 9518c2ecf20Sopenharmony_ci if (index < 0) 9528c2ecf20Sopenharmony_ci return -ERANGE; 9538c2ecf20Sopenharmony_ci if (!(ops->access & OP_WRITE)) 9548c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9558c2ecf20Sopenharmony_ci if (!keep && !(ops->access & OP_DEL)) 9568c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9578c2ecf20Sopenharmony_ci if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE) 9588c2ecf20Sopenharmony_ci return -ERANGE; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci cmd.valident = keep; /* If false, deletes entry */ 9618c2ecf20Sopenharmony_ci cmd.valid = true; /* Trigger action on table entry */ 9628c2ecf20Sopenharmony_ci cmd.rdwrset = SPI_WRITE; /* Action is write */ 9638c2ecf20Sopenharmony_ci cmd.index = index; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (!ops->cmd_packing) 9668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9678c2ecf20Sopenharmony_ci ops->cmd_packing(packed_buf, &cmd, PACK); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (!ops->entry_packing) 9708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9718c2ecf20Sopenharmony_ci /* Don't dereference potentially NULL pointer if just 9728c2ecf20Sopenharmony_ci * deleting a table entry is what was requested. For cases 9738c2ecf20Sopenharmony_ci * where 'index' field is physically part of entry structure, 9748c2ecf20Sopenharmony_ci * and needed here, we deal with that in the cmd_packing callback. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_ci if (keep) 9778c2ecf20Sopenharmony_ci ops->entry_packing(packed_buf, entry, PACK); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* Send SPI write operation: read config table entry */ 9808c2ecf20Sopenharmony_ci rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, 9818c2ecf20Sopenharmony_ci ops->packed_size); 9828c2ecf20Sopenharmony_ci if (rc < 0) 9838c2ecf20Sopenharmony_ci return rc; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci cmd = (struct sja1105_dyn_cmd) {0}; 9868c2ecf20Sopenharmony_ci ops->cmd_packing(packed_buf, &cmd, UNPACK); 9878c2ecf20Sopenharmony_ci if (cmd.errors) 9888c2ecf20Sopenharmony_ci return -EINVAL; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci int i; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 9988c2ecf20Sopenharmony_ci if ((crc ^ byte) & (1 << 7)) { 9998c2ecf20Sopenharmony_ci crc <<= 1; 10008c2ecf20Sopenharmony_ci crc ^= poly; 10018c2ecf20Sopenharmony_ci } else { 10028c2ecf20Sopenharmony_ci crc <<= 1; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci byte <<= 1; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci return crc; 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci/* CRC8 algorithm with non-reversed input, non-reversed output, 10108c2ecf20Sopenharmony_ci * no input xor and no output xor. Code customized for receiving 10118c2ecf20Sopenharmony_ci * the SJA1105 E/T FDB keys (vlanid, macaddr) as input. CRC polynomial 10128c2ecf20Sopenharmony_ci * is also received as argument in the Koopman notation that the switch 10138c2ecf20Sopenharmony_ci * hardware stores it in. 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_ciu8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct sja1105_l2_lookup_params_entry *l2_lookup_params = 10188c2ecf20Sopenharmony_ci priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries; 10198c2ecf20Sopenharmony_ci u64 poly_koopman = l2_lookup_params->poly; 10208c2ecf20Sopenharmony_ci /* Convert polynomial from Koopman to 'normal' notation */ 10218c2ecf20Sopenharmony_ci u8 poly = (u8)(1 + (poly_koopman << 1)); 10228c2ecf20Sopenharmony_ci u64 vlanid = l2_lookup_params->shared_learn ? 0 : vid; 10238c2ecf20Sopenharmony_ci u64 input = (vlanid << 48) | ether_addr_to_u64(addr); 10248c2ecf20Sopenharmony_ci u8 crc = 0; /* seed */ 10258c2ecf20Sopenharmony_ci int i; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Mask the eight bytes starting from MSB one at a time */ 10288c2ecf20Sopenharmony_ci for (i = 56; i >= 0; i -= 8) { 10298c2ecf20Sopenharmony_ci u8 byte = (input & (0xffull << i)) >> i; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci crc = sja1105_crc8_add(crc, byte, poly); 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci return crc; 10348c2ecf20Sopenharmony_ci} 1035