18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 28c2ecf20Sopenharmony_ci/* Microsemi Ocelot Switch driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2019 Microsemi Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 78c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <soc/mscc/ocelot_vcap.h> 108c2ecf20Sopenharmony_ci#include "ocelot_police.h" 118c2ecf20Sopenharmony_ci#include "ocelot_vcap.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define ENTRY_WIDTH 32 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cienum vcap_sel { 168c2ecf20Sopenharmony_ci VCAP_SEL_ENTRY = 0x1, 178c2ecf20Sopenharmony_ci VCAP_SEL_ACTION = 0x2, 188c2ecf20Sopenharmony_ci VCAP_SEL_COUNTER = 0x4, 198c2ecf20Sopenharmony_ci VCAP_SEL_ALL = 0x7, 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cienum vcap_cmd { 238c2ecf20Sopenharmony_ci VCAP_CMD_WRITE = 0, /* Copy from Cache to TCAM */ 248c2ecf20Sopenharmony_ci VCAP_CMD_READ = 1, /* Copy from TCAM to Cache */ 258c2ecf20Sopenharmony_ci VCAP_CMD_MOVE_UP = 2, /* Move <count> up */ 268c2ecf20Sopenharmony_ci VCAP_CMD_MOVE_DOWN = 3, /* Move <count> down */ 278c2ecf20Sopenharmony_ci VCAP_CMD_INITIALIZE = 4, /* Write all (from cache) */ 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define VCAP_ENTRY_WIDTH 12 /* Max entry width (32bit words) */ 318c2ecf20Sopenharmony_ci#define VCAP_COUNTER_WIDTH 4 /* Max counter width (32bit words) */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct vcap_data { 348c2ecf20Sopenharmony_ci u32 entry[VCAP_ENTRY_WIDTH]; /* ENTRY_DAT */ 358c2ecf20Sopenharmony_ci u32 mask[VCAP_ENTRY_WIDTH]; /* MASK_DAT */ 368c2ecf20Sopenharmony_ci u32 action[VCAP_ENTRY_WIDTH]; /* ACTION_DAT */ 378c2ecf20Sopenharmony_ci u32 counter[VCAP_COUNTER_WIDTH]; /* CNT_DAT */ 388c2ecf20Sopenharmony_ci u32 tg; /* TG_DAT */ 398c2ecf20Sopenharmony_ci u32 type; /* Action type */ 408c2ecf20Sopenharmony_ci u32 tg_sw; /* Current type-group */ 418c2ecf20Sopenharmony_ci u32 cnt; /* Current counter */ 428c2ecf20Sopenharmony_ci u32 key_offset; /* Current entry offset */ 438c2ecf20Sopenharmony_ci u32 action_offset; /* Current action offset */ 448c2ecf20Sopenharmony_ci u32 counter_offset; /* Current counter offset */ 458c2ecf20Sopenharmony_ci u32 tg_value; /* Current type-group value */ 468c2ecf20Sopenharmony_ci u32 tg_mask; /* Current type-group mask */ 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic u32 vcap_read_update_ctrl(struct ocelot *ocelot, 508c2ecf20Sopenharmony_ci const struct vcap_props *vcap) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return ocelot_target_read(ocelot, vcap->target, VCAP_CORE_UPDATE_CTRL); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void vcap_cmd(struct ocelot *ocelot, const struct vcap_props *vcap, 568c2ecf20Sopenharmony_ci u16 ix, int cmd, int sel) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci u32 value = (VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) | 598c2ecf20Sopenharmony_ci VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) | 608c2ecf20Sopenharmony_ci VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if ((sel & VCAP_SEL_ENTRY) && ix >= vcap->entry_count) 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!(sel & VCAP_SEL_ENTRY)) 668c2ecf20Sopenharmony_ci value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!(sel & VCAP_SEL_ACTION)) 698c2ecf20Sopenharmony_ci value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!(sel & VCAP_SEL_COUNTER)) 728c2ecf20Sopenharmony_ci value |= VCAP_CORE_UPDATE_CTRL_UPDATE_CNT_DIS; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci ocelot_target_write(ocelot, vcap->target, value, VCAP_CORE_UPDATE_CTRL); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci read_poll_timeout(vcap_read_update_ctrl, value, 778c2ecf20Sopenharmony_ci (value & VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0, 788c2ecf20Sopenharmony_ci 10, 100000, false, ocelot, vcap); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Convert from 0-based row to VCAP entry row and run command */ 828c2ecf20Sopenharmony_cistatic void vcap_row_cmd(struct ocelot *ocelot, const struct vcap_props *vcap, 838c2ecf20Sopenharmony_ci u32 row, int cmd, int sel) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci vcap_cmd(ocelot, vcap, vcap->entry_count - row - 1, cmd, sel); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void vcap_entry2cache(struct ocelot *ocelot, 898c2ecf20Sopenharmony_ci const struct vcap_props *vcap, 908c2ecf20Sopenharmony_ci struct vcap_data *data) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci u32 entry_words, i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci for (i = 0; i < entry_words; i++) { 978c2ecf20Sopenharmony_ci ocelot_target_write_rix(ocelot, vcap->target, data->entry[i], 988c2ecf20Sopenharmony_ci VCAP_CACHE_ENTRY_DAT, i); 998c2ecf20Sopenharmony_ci ocelot_target_write_rix(ocelot, vcap->target, ~data->mask[i], 1008c2ecf20Sopenharmony_ci VCAP_CACHE_MASK_DAT, i); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci ocelot_target_write(ocelot, vcap->target, data->tg, VCAP_CACHE_TG_DAT); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void vcap_cache2entry(struct ocelot *ocelot, 1068c2ecf20Sopenharmony_ci const struct vcap_props *vcap, 1078c2ecf20Sopenharmony_ci struct vcap_data *data) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci u32 entry_words, i; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci for (i = 0; i < entry_words; i++) { 1148c2ecf20Sopenharmony_ci data->entry[i] = ocelot_target_read_rix(ocelot, vcap->target, 1158c2ecf20Sopenharmony_ci VCAP_CACHE_ENTRY_DAT, i); 1168c2ecf20Sopenharmony_ci // Invert mask 1178c2ecf20Sopenharmony_ci data->mask[i] = ~ocelot_target_read_rix(ocelot, vcap->target, 1188c2ecf20Sopenharmony_ci VCAP_CACHE_MASK_DAT, i); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci data->tg = ocelot_target_read(ocelot, vcap->target, VCAP_CACHE_TG_DAT); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void vcap_action2cache(struct ocelot *ocelot, 1248c2ecf20Sopenharmony_ci const struct vcap_props *vcap, 1258c2ecf20Sopenharmony_ci struct vcap_data *data) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci u32 action_words, mask; 1288c2ecf20Sopenharmony_ci int i, width; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Encode action type */ 1318c2ecf20Sopenharmony_ci width = vcap->action_type_width; 1328c2ecf20Sopenharmony_ci if (width) { 1338c2ecf20Sopenharmony_ci mask = GENMASK(width, 0); 1348c2ecf20Sopenharmony_ci data->action[0] = ((data->action[0] & ~mask) | data->type); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (i = 0; i < action_words; i++) 1408c2ecf20Sopenharmony_ci ocelot_target_write_rix(ocelot, vcap->target, data->action[i], 1418c2ecf20Sopenharmony_ci VCAP_CACHE_ACTION_DAT, i); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < vcap->counter_words; i++) 1448c2ecf20Sopenharmony_ci ocelot_target_write_rix(ocelot, vcap->target, data->counter[i], 1458c2ecf20Sopenharmony_ci VCAP_CACHE_CNT_DAT, i); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void vcap_cache2action(struct ocelot *ocelot, 1498c2ecf20Sopenharmony_ci const struct vcap_props *vcap, 1508c2ecf20Sopenharmony_ci struct vcap_data *data) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci u32 action_words; 1538c2ecf20Sopenharmony_ci int i, width; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci for (i = 0; i < action_words; i++) 1588c2ecf20Sopenharmony_ci data->action[i] = ocelot_target_read_rix(ocelot, vcap->target, 1598c2ecf20Sopenharmony_ci VCAP_CACHE_ACTION_DAT, 1608c2ecf20Sopenharmony_ci i); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci for (i = 0; i < vcap->counter_words; i++) 1638c2ecf20Sopenharmony_ci data->counter[i] = ocelot_target_read_rix(ocelot, vcap->target, 1648c2ecf20Sopenharmony_ci VCAP_CACHE_CNT_DAT, 1658c2ecf20Sopenharmony_ci i); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Extract action type */ 1688c2ecf20Sopenharmony_ci width = vcap->action_type_width; 1698c2ecf20Sopenharmony_ci data->type = (width ? (data->action[0] & GENMASK(width, 0)) : 0); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* Calculate offsets for entry */ 1738c2ecf20Sopenharmony_cistatic void vcap_data_offset_get(const struct vcap_props *vcap, 1748c2ecf20Sopenharmony_ci struct vcap_data *data, int ix) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci int num_subwords_per_entry, num_subwords_per_action; 1778c2ecf20Sopenharmony_ci int i, col, offset, num_entries_per_row, base; 1788c2ecf20Sopenharmony_ci u32 width = vcap->tg_width; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci switch (data->tg_sw) { 1818c2ecf20Sopenharmony_ci case VCAP_TG_FULL: 1828c2ecf20Sopenharmony_ci num_entries_per_row = 1; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case VCAP_TG_HALF: 1858c2ecf20Sopenharmony_ci num_entries_per_row = 2; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case VCAP_TG_QUARTER: 1888c2ecf20Sopenharmony_ci num_entries_per_row = 4; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci return; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci col = (ix % num_entries_per_row); 1958c2ecf20Sopenharmony_ci num_subwords_per_entry = (vcap->sw_count / num_entries_per_row); 1968c2ecf20Sopenharmony_ci base = (vcap->sw_count - col * num_subwords_per_entry - 1978c2ecf20Sopenharmony_ci num_subwords_per_entry); 1988c2ecf20Sopenharmony_ci data->tg_value = 0; 1998c2ecf20Sopenharmony_ci data->tg_mask = 0; 2008c2ecf20Sopenharmony_ci for (i = 0; i < num_subwords_per_entry; i++) { 2018c2ecf20Sopenharmony_ci offset = ((base + i) * width); 2028c2ecf20Sopenharmony_ci data->tg_value |= (data->tg_sw << offset); 2038c2ecf20Sopenharmony_ci data->tg_mask |= GENMASK(offset + width - 1, offset); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Calculate key/action/counter offsets */ 2078c2ecf20Sopenharmony_ci col = (num_entries_per_row - col - 1); 2088c2ecf20Sopenharmony_ci data->key_offset = (base * vcap->entry_width) / vcap->sw_count; 2098c2ecf20Sopenharmony_ci data->counter_offset = (num_subwords_per_entry * col * 2108c2ecf20Sopenharmony_ci vcap->counter_width); 2118c2ecf20Sopenharmony_ci i = data->type; 2128c2ecf20Sopenharmony_ci width = vcap->action_table[i].width; 2138c2ecf20Sopenharmony_ci num_subwords_per_action = vcap->action_table[i].count; 2148c2ecf20Sopenharmony_ci data->action_offset = ((num_subwords_per_action * col * width) / 2158c2ecf20Sopenharmony_ci num_entries_per_row); 2168c2ecf20Sopenharmony_ci data->action_offset += vcap->action_type_width; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void vcap_data_set(u32 *data, u32 offset, u32 len, u32 value) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci u32 i, v, m; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci for (i = 0; i < len; i++, offset++) { 2248c2ecf20Sopenharmony_ci v = data[offset / ENTRY_WIDTH]; 2258c2ecf20Sopenharmony_ci m = (1 << (offset % ENTRY_WIDTH)); 2268c2ecf20Sopenharmony_ci if (value & (1 << i)) 2278c2ecf20Sopenharmony_ci v |= m; 2288c2ecf20Sopenharmony_ci else 2298c2ecf20Sopenharmony_ci v &= ~m; 2308c2ecf20Sopenharmony_ci data[offset / ENTRY_WIDTH] = v; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic u32 vcap_data_get(u32 *data, u32 offset, u32 len) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci u32 i, v, m, value = 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci for (i = 0; i < len; i++, offset++) { 2398c2ecf20Sopenharmony_ci v = data[offset / ENTRY_WIDTH]; 2408c2ecf20Sopenharmony_ci m = (1 << (offset % ENTRY_WIDTH)); 2418c2ecf20Sopenharmony_ci if (v & m) 2428c2ecf20Sopenharmony_ci value |= (1 << i); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci return value; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void vcap_key_field_set(struct vcap_data *data, u32 offset, u32 width, 2488c2ecf20Sopenharmony_ci u32 value, u32 mask) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci vcap_data_set(data->entry, offset + data->key_offset, width, value); 2518c2ecf20Sopenharmony_ci vcap_data_set(data->mask, offset + data->key_offset, width, mask); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void vcap_key_set(const struct vcap_props *vcap, struct vcap_data *data, 2558c2ecf20Sopenharmony_ci int field, u32 value, u32 mask) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci u32 offset = vcap->keys[field].offset; 2588c2ecf20Sopenharmony_ci u32 length = vcap->keys[field].length; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci vcap_key_field_set(data, offset, length, value, mask); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void vcap_key_bytes_set(const struct vcap_props *vcap, 2648c2ecf20Sopenharmony_ci struct vcap_data *data, int field, 2658c2ecf20Sopenharmony_ci u8 *val, u8 *msk) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci u32 offset = vcap->keys[field].offset; 2688c2ecf20Sopenharmony_ci u32 count = vcap->keys[field].length; 2698c2ecf20Sopenharmony_ci u32 i, j, n = 0, value = 0, mask = 0; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci WARN_ON(count % 8); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Data wider than 32 bits are split up in chunks of maximum 32 bits. 2748c2ecf20Sopenharmony_ci * The 32 LSB of the data are written to the 32 MSB of the TCAM. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci offset += count; 2778c2ecf20Sopenharmony_ci count /= 8; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 2808c2ecf20Sopenharmony_ci j = (count - i - 1); 2818c2ecf20Sopenharmony_ci value += (val[j] << n); 2828c2ecf20Sopenharmony_ci mask += (msk[j] << n); 2838c2ecf20Sopenharmony_ci n += 8; 2848c2ecf20Sopenharmony_ci if (n == ENTRY_WIDTH || (i + 1) == count) { 2858c2ecf20Sopenharmony_ci offset -= n; 2868c2ecf20Sopenharmony_ci vcap_key_field_set(data, offset, n, value, mask); 2878c2ecf20Sopenharmony_ci n = 0; 2888c2ecf20Sopenharmony_ci value = 0; 2898c2ecf20Sopenharmony_ci mask = 0; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void vcap_key_l4_port_set(const struct vcap_props *vcap, 2958c2ecf20Sopenharmony_ci struct vcap_data *data, int field, 2968c2ecf20Sopenharmony_ci struct ocelot_vcap_udp_tcp *port) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci u32 offset = vcap->keys[field].offset; 2998c2ecf20Sopenharmony_ci u32 length = vcap->keys[field].length; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci WARN_ON(length != 16); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci vcap_key_field_set(data, offset, length, port->value, port->mask); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void vcap_key_bit_set(const struct vcap_props *vcap, 3078c2ecf20Sopenharmony_ci struct vcap_data *data, int field, 3088c2ecf20Sopenharmony_ci enum ocelot_vcap_bit val) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci u32 value = (val == OCELOT_VCAP_BIT_1 ? 1 : 0); 3118c2ecf20Sopenharmony_ci u32 msk = (val == OCELOT_VCAP_BIT_ANY ? 0 : 1); 3128c2ecf20Sopenharmony_ci u32 offset = vcap->keys[field].offset; 3138c2ecf20Sopenharmony_ci u32 length = vcap->keys[field].length; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci WARN_ON(length != 1); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci vcap_key_field_set(data, offset, length, value, msk); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void vcap_action_set(const struct vcap_props *vcap, 3218c2ecf20Sopenharmony_ci struct vcap_data *data, int field, u32 value) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int offset = vcap->actions[field].offset; 3248c2ecf20Sopenharmony_ci int length = vcap->actions[field].length; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci vcap_data_set(data->action, offset + data->action_offset, length, 3278c2ecf20Sopenharmony_ci value); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic void is2_action_set(struct ocelot *ocelot, struct vcap_data *data, 3318c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2]; 3348c2ecf20Sopenharmony_ci struct ocelot_vcap_action *a = &filter->action; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode); 3378c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask); 3388c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena); 3398c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix); 3408c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num); 3418c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, a->cpu_copy_ena); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void is2_entry_set(struct ocelot *ocelot, int ix, 3458c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2]; 3488c2ecf20Sopenharmony_ci struct ocelot_vcap_key_vlan *tag = &filter->vlan; 3498c2ecf20Sopenharmony_ci u32 val, msk, type, type_mask = 0xf, i, count; 3508c2ecf20Sopenharmony_ci struct ocelot_vcap_u64 payload; 3518c2ecf20Sopenharmony_ci struct vcap_data data; 3528c2ecf20Sopenharmony_ci int row = (ix / 2); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 3558c2ecf20Sopenharmony_ci memset(&data, 0, sizeof(data)); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Read row */ 3588c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL); 3598c2ecf20Sopenharmony_ci vcap_cache2entry(ocelot, vcap, &data); 3608c2ecf20Sopenharmony_ci vcap_cache2action(ocelot, vcap, &data); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci data.tg_sw = VCAP_TG_HALF; 3638c2ecf20Sopenharmony_ci vcap_data_offset_get(vcap, &data, ix); 3648c2ecf20Sopenharmony_ci data.tg = (data.tg & ~data.tg_mask); 3658c2ecf20Sopenharmony_ci if (filter->prio != 0) 3668c2ecf20Sopenharmony_ci data.tg |= data.tg_value; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci data.type = IS2_ACTION_TYPE_NORMAL; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_PAG, filter->pag, 0xff); 3718c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_FIRST, 3728c2ecf20Sopenharmony_ci (filter->lookup == 0) ? OCELOT_VCAP_BIT_1 : 3738c2ecf20Sopenharmony_ci OCELOT_VCAP_BIT_0); 3748c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0, 3758c2ecf20Sopenharmony_ci ~filter->ingress_port_mask); 3768c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_HOST_MATCH, 3778c2ecf20Sopenharmony_ci OCELOT_VCAP_BIT_ANY); 3788c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_MC, filter->dmac_mc); 3798c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_BC, filter->dmac_bc); 3808c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged); 3818c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_VID, 3828c2ecf20Sopenharmony_ci tag->vid.value, tag->vid.mask); 3838c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_PCP, 3848c2ecf20Sopenharmony_ci tag->pcp.value[0], tag->pcp.mask[0]); 3858c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DEI, tag->dei); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci switch (filter->key_type) { 3888c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_ETYPE: { 3898c2ecf20Sopenharmony_ci struct ocelot_vcap_key_etype *etype = &filter->key.etype; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci type = IS2_TYPE_ETYPE; 3928c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC, 3938c2ecf20Sopenharmony_ci etype->dmac.value, etype->dmac.mask); 3948c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC, 3958c2ecf20Sopenharmony_ci etype->smac.value, etype->smac.mask); 3968c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE, 3978c2ecf20Sopenharmony_ci etype->etype.value, etype->etype.mask); 3988c2ecf20Sopenharmony_ci /* Clear unused bits */ 3998c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0, 4008c2ecf20Sopenharmony_ci 0, 0); 4018c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1, 4028c2ecf20Sopenharmony_ci 0, 0); 4038c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2, 4048c2ecf20Sopenharmony_ci 0, 0); 4058c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, 4068c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0, 4078c2ecf20Sopenharmony_ci etype->data.value, etype->data.mask); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_LLC: { 4118c2ecf20Sopenharmony_ci struct ocelot_vcap_key_llc *llc = &filter->key.llc; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci type = IS2_TYPE_LLC; 4148c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC, 4158c2ecf20Sopenharmony_ci llc->dmac.value, llc->dmac.mask); 4168c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC, 4178c2ecf20Sopenharmony_ci llc->smac.value, llc->smac.mask); 4188c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 4198c2ecf20Sopenharmony_ci payload.value[i] = llc->llc.value[i]; 4208c2ecf20Sopenharmony_ci payload.mask[i] = llc->llc.mask[i]; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC, 4238c2ecf20Sopenharmony_ci payload.value, payload.mask); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_SNAP: { 4278c2ecf20Sopenharmony_ci struct ocelot_vcap_key_snap *snap = &filter->key.snap; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci type = IS2_TYPE_SNAP; 4308c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC, 4318c2ecf20Sopenharmony_ci snap->dmac.value, snap->dmac.mask); 4328c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC, 4338c2ecf20Sopenharmony_ci snap->smac.value, snap->smac.mask); 4348c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP, 4358c2ecf20Sopenharmony_ci filter->key.snap.snap.value, 4368c2ecf20Sopenharmony_ci filter->key.snap.snap.mask); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_ARP: { 4408c2ecf20Sopenharmony_ci struct ocelot_vcap_key_arp *arp = &filter->key.arp; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci type = IS2_TYPE_ARP; 4438c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_SMAC, 4448c2ecf20Sopenharmony_ci arp->smac.value, arp->smac.mask); 4458c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 4468c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK, 4478c2ecf20Sopenharmony_ci arp->ethernet); 4488c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 4498c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK, 4508c2ecf20Sopenharmony_ci arp->ip); 4518c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 4528c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_LEN_OK, 4538c2ecf20Sopenharmony_ci arp->length); 4548c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 4558c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_TARGET_MATCH, 4568c2ecf20Sopenharmony_ci arp->dmac_match); 4578c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 4588c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_SENDER_MATCH, 4598c2ecf20Sopenharmony_ci arp->smac_match); 4608c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 4618c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN, 4628c2ecf20Sopenharmony_ci arp->unknown); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* OPCODE is inverse, bit 0 is reply flag, bit 1 is RARP flag */ 4658c2ecf20Sopenharmony_ci val = ((arp->req == OCELOT_VCAP_BIT_0 ? 1 : 0) | 4668c2ecf20Sopenharmony_ci (arp->arp == OCELOT_VCAP_BIT_0 ? 2 : 0)); 4678c2ecf20Sopenharmony_ci msk = ((arp->req == OCELOT_VCAP_BIT_ANY ? 0 : 1) | 4688c2ecf20Sopenharmony_ci (arp->arp == OCELOT_VCAP_BIT_ANY ? 0 : 2)); 4698c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_OPCODE, 4708c2ecf20Sopenharmony_ci val, msk); 4718c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, 4728c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP, 4738c2ecf20Sopenharmony_ci arp->dip.value.addr, arp->dip.mask.addr); 4748c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, 4758c2ecf20Sopenharmony_ci VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP, 4768c2ecf20Sopenharmony_ci arp->sip.value.addr, arp->sip.mask.addr); 4778c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP, 4788c2ecf20Sopenharmony_ci 0, 0); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_IPV4: 4828c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_IPV6: { 4838c2ecf20Sopenharmony_ci enum ocelot_vcap_bit sip_eq_dip, sport_eq_dport, seq_zero, tcp; 4848c2ecf20Sopenharmony_ci enum ocelot_vcap_bit ttl, fragment, options, tcp_ack, tcp_urg; 4858c2ecf20Sopenharmony_ci enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh; 4868c2ecf20Sopenharmony_ci struct ocelot_vcap_key_ipv4 *ipv4 = NULL; 4878c2ecf20Sopenharmony_ci struct ocelot_vcap_key_ipv6 *ipv6 = NULL; 4888c2ecf20Sopenharmony_ci struct ocelot_vcap_udp_tcp *sport, *dport; 4898c2ecf20Sopenharmony_ci struct ocelot_vcap_ipv4 sip, dip; 4908c2ecf20Sopenharmony_ci struct ocelot_vcap_u8 proto, ds; 4918c2ecf20Sopenharmony_ci struct ocelot_vcap_u48 *ip_data; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (filter->key_type == OCELOT_VCAP_KEY_IPV4) { 4948c2ecf20Sopenharmony_ci ipv4 = &filter->key.ipv4; 4958c2ecf20Sopenharmony_ci ttl = ipv4->ttl; 4968c2ecf20Sopenharmony_ci fragment = ipv4->fragment; 4978c2ecf20Sopenharmony_ci options = ipv4->options; 4988c2ecf20Sopenharmony_ci proto = ipv4->proto; 4998c2ecf20Sopenharmony_ci ds = ipv4->ds; 5008c2ecf20Sopenharmony_ci ip_data = &ipv4->data; 5018c2ecf20Sopenharmony_ci sip = ipv4->sip; 5028c2ecf20Sopenharmony_ci dip = ipv4->dip; 5038c2ecf20Sopenharmony_ci sport = &ipv4->sport; 5048c2ecf20Sopenharmony_ci dport = &ipv4->dport; 5058c2ecf20Sopenharmony_ci tcp_fin = ipv4->tcp_fin; 5068c2ecf20Sopenharmony_ci tcp_syn = ipv4->tcp_syn; 5078c2ecf20Sopenharmony_ci tcp_rst = ipv4->tcp_rst; 5088c2ecf20Sopenharmony_ci tcp_psh = ipv4->tcp_psh; 5098c2ecf20Sopenharmony_ci tcp_ack = ipv4->tcp_ack; 5108c2ecf20Sopenharmony_ci tcp_urg = ipv4->tcp_urg; 5118c2ecf20Sopenharmony_ci sip_eq_dip = ipv4->sip_eq_dip; 5128c2ecf20Sopenharmony_ci sport_eq_dport = ipv4->sport_eq_dport; 5138c2ecf20Sopenharmony_ci seq_zero = ipv4->seq_zero; 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci ipv6 = &filter->key.ipv6; 5168c2ecf20Sopenharmony_ci ttl = ipv6->ttl; 5178c2ecf20Sopenharmony_ci fragment = OCELOT_VCAP_BIT_ANY; 5188c2ecf20Sopenharmony_ci options = OCELOT_VCAP_BIT_ANY; 5198c2ecf20Sopenharmony_ci proto = ipv6->proto; 5208c2ecf20Sopenharmony_ci ds = ipv6->ds; 5218c2ecf20Sopenharmony_ci ip_data = &ipv6->data; 5228c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 5238c2ecf20Sopenharmony_ci val = ipv6->sip.value[i + 8]; 5248c2ecf20Sopenharmony_ci msk = ipv6->sip.mask[i + 8]; 5258c2ecf20Sopenharmony_ci if (i < 4) { 5268c2ecf20Sopenharmony_ci dip.value.addr[i] = val; 5278c2ecf20Sopenharmony_ci dip.mask.addr[i] = msk; 5288c2ecf20Sopenharmony_ci } else { 5298c2ecf20Sopenharmony_ci sip.value.addr[i - 4] = val; 5308c2ecf20Sopenharmony_ci sip.mask.addr[i - 4] = msk; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci sport = &ipv6->sport; 5348c2ecf20Sopenharmony_ci dport = &ipv6->dport; 5358c2ecf20Sopenharmony_ci tcp_fin = ipv6->tcp_fin; 5368c2ecf20Sopenharmony_ci tcp_syn = ipv6->tcp_syn; 5378c2ecf20Sopenharmony_ci tcp_rst = ipv6->tcp_rst; 5388c2ecf20Sopenharmony_ci tcp_psh = ipv6->tcp_psh; 5398c2ecf20Sopenharmony_ci tcp_ack = ipv6->tcp_ack; 5408c2ecf20Sopenharmony_ci tcp_urg = ipv6->tcp_urg; 5418c2ecf20Sopenharmony_ci sip_eq_dip = ipv6->sip_eq_dip; 5428c2ecf20Sopenharmony_ci sport_eq_dport = ipv6->sport_eq_dport; 5438c2ecf20Sopenharmony_ci seq_zero = ipv6->seq_zero; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4, 5478c2ecf20Sopenharmony_ci ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0); 5488c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_FRAGMENT, 5498c2ecf20Sopenharmony_ci fragment); 5508c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0); 5518c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_OPTIONS, 5528c2ecf20Sopenharmony_ci options); 5538c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0, 5548c2ecf20Sopenharmony_ci ttl); 5558c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_TOS, 5568c2ecf20Sopenharmony_ci ds.value, ds.mask); 5578c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_DIP, 5588c2ecf20Sopenharmony_ci dip.value.addr, dip.mask.addr); 5598c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_SIP, 5608c2ecf20Sopenharmony_ci sip.value.addr, sip.mask.addr); 5618c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DIP_EQ_SIP, 5628c2ecf20Sopenharmony_ci sip_eq_dip); 5638c2ecf20Sopenharmony_ci val = proto.value[0]; 5648c2ecf20Sopenharmony_ci msk = proto.mask[0]; 5658c2ecf20Sopenharmony_ci type = IS2_TYPE_IP_UDP_TCP; 5668c2ecf20Sopenharmony_ci if (msk == 0xff && (val == 6 || val == 17)) { 5678c2ecf20Sopenharmony_ci /* UDP/TCP protocol match */ 5688c2ecf20Sopenharmony_ci tcp = (val == 6 ? 5698c2ecf20Sopenharmony_ci OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0); 5708c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_TCP, tcp); 5718c2ecf20Sopenharmony_ci vcap_key_l4_port_set(vcap, &data, 5728c2ecf20Sopenharmony_ci VCAP_IS2_HK_L4_DPORT, dport); 5738c2ecf20Sopenharmony_ci vcap_key_l4_port_set(vcap, &data, 5748c2ecf20Sopenharmony_ci VCAP_IS2_HK_L4_SPORT, sport); 5758c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_RNG, 0, 0); 5768c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 5778c2ecf20Sopenharmony_ci VCAP_IS2_HK_L4_SPORT_EQ_DPORT, 5788c2ecf20Sopenharmony_ci sport_eq_dport); 5798c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, 5808c2ecf20Sopenharmony_ci VCAP_IS2_HK_L4_SEQUENCE_EQ0, 5818c2ecf20Sopenharmony_ci seq_zero); 5828c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_FIN, 5838c2ecf20Sopenharmony_ci tcp_fin); 5848c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_SYN, 5858c2ecf20Sopenharmony_ci tcp_syn); 5868c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_RST, 5878c2ecf20Sopenharmony_ci tcp_rst); 5888c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_PSH, 5898c2ecf20Sopenharmony_ci tcp_psh); 5908c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_ACK, 5918c2ecf20Sopenharmony_ci tcp_ack); 5928c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_URG, 5938c2ecf20Sopenharmony_ci tcp_urg); 5948c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_DOM, 5958c2ecf20Sopenharmony_ci 0, 0); 5968c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_VER, 5978c2ecf20Sopenharmony_ci 0, 0); 5988c2ecf20Sopenharmony_ci } else { 5998c2ecf20Sopenharmony_ci if (msk == 0) { 6008c2ecf20Sopenharmony_ci /* Any IP protocol match */ 6018c2ecf20Sopenharmony_ci type_mask = IS2_TYPE_MASK_IP_ANY; 6028c2ecf20Sopenharmony_ci } else { 6038c2ecf20Sopenharmony_ci /* Non-UDP/TCP protocol match */ 6048c2ecf20Sopenharmony_ci type = IS2_TYPE_IP_OTHER; 6058c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 6068c2ecf20Sopenharmony_ci payload.value[i] = ip_data->value[i]; 6078c2ecf20Sopenharmony_ci payload.mask[i] = ip_data->mask[i]; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, 6118c2ecf20Sopenharmony_ci VCAP_IS2_HK_IP4_L3_PROTO, 6128c2ecf20Sopenharmony_ci proto.value, proto.mask); 6138c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, 6148c2ecf20Sopenharmony_ci VCAP_IS2_HK_L3_PAYLOAD, 6158c2ecf20Sopenharmony_ci payload.value, payload.mask); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_ANY: 6208c2ecf20Sopenharmony_ci default: 6218c2ecf20Sopenharmony_ci type = 0; 6228c2ecf20Sopenharmony_ci type_mask = 0; 6238c2ecf20Sopenharmony_ci count = vcap->entry_width / 2; 6248c2ecf20Sopenharmony_ci /* Iterate over the non-common part of the key and 6258c2ecf20Sopenharmony_ci * clear entry data 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci for (i = vcap->keys[VCAP_IS2_HK_L2_DMAC].offset; 6288c2ecf20Sopenharmony_ci i < count; i += ENTRY_WIDTH) { 6298c2ecf20Sopenharmony_ci vcap_key_field_set(&data, i, min(32u, count - i), 0, 0); 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci break; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS2_TYPE, type, type_mask); 6358c2ecf20Sopenharmony_ci is2_action_set(ocelot, &data, filter); 6368c2ecf20Sopenharmony_ci vcap_data_set(data.counter, data.counter_offset, 6378c2ecf20Sopenharmony_ci vcap->counter_width, filter->stats.pkts); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* Write row */ 6408c2ecf20Sopenharmony_ci vcap_entry2cache(ocelot, vcap, &data); 6418c2ecf20Sopenharmony_ci vcap_action2cache(ocelot, vcap, &data); 6428c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL); 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic void is1_action_set(struct ocelot *ocelot, struct vcap_data *data, 6468c2ecf20Sopenharmony_ci const struct ocelot_vcap_filter *filter) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1]; 6498c2ecf20Sopenharmony_ci const struct ocelot_vcap_action *a = &filter->action; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_REPLACE_ENA, 6528c2ecf20Sopenharmony_ci a->vid_replace_ena); 6538c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_ADD_VAL, a->vid); 6548c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_VLAN_POP_CNT_ENA, 6558c2ecf20Sopenharmony_ci a->vlan_pop_cnt_ena); 6568c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_VLAN_POP_CNT, 6578c2ecf20Sopenharmony_ci a->vlan_pop_cnt); 6588c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_DEI_ENA, a->pcp_dei_ena); 6598c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_VAL, a->pcp); 6608c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_DEI_VAL, a->dei); 6618c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA, a->qos_ena); 6628c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_VAL, a->qos_val); 6638c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_OVERRIDE_MASK, 6648c2ecf20Sopenharmony_ci a->pag_override_mask); 6658c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_VAL, a->pag_val); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic void is1_entry_set(struct ocelot *ocelot, int ix, 6698c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1]; 6728c2ecf20Sopenharmony_ci struct ocelot_vcap_key_vlan *tag = &filter->vlan; 6738c2ecf20Sopenharmony_ci struct ocelot_vcap_u64 payload; 6748c2ecf20Sopenharmony_ci struct vcap_data data; 6758c2ecf20Sopenharmony_ci int row = ix / 2; 6768c2ecf20Sopenharmony_ci u32 type; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 6798c2ecf20Sopenharmony_ci memset(&data, 0, sizeof(data)); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* Read row */ 6828c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL); 6838c2ecf20Sopenharmony_ci vcap_cache2entry(ocelot, vcap, &data); 6848c2ecf20Sopenharmony_ci vcap_cache2action(ocelot, vcap, &data); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci data.tg_sw = VCAP_TG_HALF; 6878c2ecf20Sopenharmony_ci data.type = IS1_ACTION_TYPE_NORMAL; 6888c2ecf20Sopenharmony_ci vcap_data_offset_get(vcap, &data, ix); 6898c2ecf20Sopenharmony_ci data.tg = (data.tg & ~data.tg_mask); 6908c2ecf20Sopenharmony_ci if (filter->prio != 0) 6918c2ecf20Sopenharmony_ci data.tg |= data.tg_value; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS1_HK_LOOKUP, filter->lookup, 0x3); 6948c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS1_HK_IGR_PORT_MASK, 0, 6958c2ecf20Sopenharmony_ci ~filter->ingress_port_mask); 6968c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, filter->dmac_mc); 6978c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, filter->dmac_bc); 6988c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged); 6998c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS1_HK_VID, 7008c2ecf20Sopenharmony_ci tag->vid.value, tag->vid.mask); 7018c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP, 7028c2ecf20Sopenharmony_ci tag->pcp.value[0], tag->pcp.mask[0]); 7038c2ecf20Sopenharmony_ci type = IS1_TYPE_S1_NORMAL; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci switch (filter->key_type) { 7068c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_ETYPE: { 7078c2ecf20Sopenharmony_ci struct ocelot_vcap_key_etype *etype = &filter->key.etype; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L2_SMAC, 7108c2ecf20Sopenharmony_ci etype->smac.value, etype->smac.mask); 7118c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE, 7128c2ecf20Sopenharmony_ci etype->etype.value, etype->etype.mask); 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci case OCELOT_VCAP_KEY_IPV4: { 7168c2ecf20Sopenharmony_ci struct ocelot_vcap_key_ipv4 *ipv4 = &filter->key.ipv4; 7178c2ecf20Sopenharmony_ci struct ocelot_vcap_udp_tcp *sport = &ipv4->sport; 7188c2ecf20Sopenharmony_ci struct ocelot_vcap_udp_tcp *dport = &ipv4->dport; 7198c2ecf20Sopenharmony_ci enum ocelot_vcap_bit tcp_udp = OCELOT_VCAP_BIT_0; 7208c2ecf20Sopenharmony_ci struct ocelot_vcap_u8 proto = ipv4->proto; 7218c2ecf20Sopenharmony_ci struct ocelot_vcap_ipv4 sip = ipv4->sip; 7228c2ecf20Sopenharmony_ci u32 val, msk; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP, 7258c2ecf20Sopenharmony_ci OCELOT_VCAP_BIT_1); 7268c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4, 7278c2ecf20Sopenharmony_ci OCELOT_VCAP_BIT_1); 7288c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN, 7298c2ecf20Sopenharmony_ci OCELOT_VCAP_BIT_1); 7308c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP, 7318c2ecf20Sopenharmony_ci sip.value.addr, sip.mask.addr); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci val = proto.value[0]; 7348c2ecf20Sopenharmony_ci msk = proto.mask[0]; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && msk == 0xff) 7378c2ecf20Sopenharmony_ci tcp_udp = OCELOT_VCAP_BIT_1; 7388c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP_UDP, tcp_udp); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (tcp_udp) { 7418c2ecf20Sopenharmony_ci enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (val == NEXTHDR_TCP) 7448c2ecf20Sopenharmony_ci tcp = OCELOT_VCAP_BIT_1; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP, tcp); 7478c2ecf20Sopenharmony_ci vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_L4_SPORT, 7488c2ecf20Sopenharmony_ci sport); 7498c2ecf20Sopenharmony_ci /* Overloaded field */ 7508c2ecf20Sopenharmony_ci vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_ETYPE, 7518c2ecf20Sopenharmony_ci dport); 7528c2ecf20Sopenharmony_ci } else { 7538c2ecf20Sopenharmony_ci /* IPv4 "other" frame */ 7548c2ecf20Sopenharmony_ci struct ocelot_vcap_u16 etype = {0}; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* Overloaded field */ 7578c2ecf20Sopenharmony_ci etype.value[0] = proto.value[0]; 7588c2ecf20Sopenharmony_ci etype.mask[0] = proto.mask[0]; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE, 7618c2ecf20Sopenharmony_ci etype.value, etype.mask); 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci default: 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TYPE, 7688c2ecf20Sopenharmony_ci type ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci is1_action_set(ocelot, &data, filter); 7718c2ecf20Sopenharmony_ci vcap_data_set(data.counter, data.counter_offset, 7728c2ecf20Sopenharmony_ci vcap->counter_width, filter->stats.pkts); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Write row */ 7758c2ecf20Sopenharmony_ci vcap_entry2cache(ocelot, vcap, &data); 7768c2ecf20Sopenharmony_ci vcap_action2cache(ocelot, vcap, &data); 7778c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic void es0_action_set(struct ocelot *ocelot, struct vcap_data *data, 7818c2ecf20Sopenharmony_ci const struct ocelot_vcap_filter *filter) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; 7848c2ecf20Sopenharmony_ci const struct ocelot_vcap_action *a = &filter->action; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_PUSH_OUTER_TAG, 7878c2ecf20Sopenharmony_ci a->push_outer_tag); 7888c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_PUSH_INNER_TAG, 7898c2ecf20Sopenharmony_ci a->push_inner_tag); 7908c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_TPID_SEL, 7918c2ecf20Sopenharmony_ci a->tag_a_tpid_sel); 7928c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_VID_SEL, 7938c2ecf20Sopenharmony_ci a->tag_a_vid_sel); 7948c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_PCP_SEL, 7958c2ecf20Sopenharmony_ci a->tag_a_pcp_sel); 7968c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_VID_A_VAL, a->vid_a_val); 7978c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_PCP_A_VAL, a->pcp_a_val); 7988c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_B_TPID_SEL, 7998c2ecf20Sopenharmony_ci a->tag_b_tpid_sel); 8008c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_B_VID_SEL, 8018c2ecf20Sopenharmony_ci a->tag_b_vid_sel); 8028c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_B_PCP_SEL, 8038c2ecf20Sopenharmony_ci a->tag_b_pcp_sel); 8048c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_VID_B_VAL, a->vid_b_val); 8058c2ecf20Sopenharmony_ci vcap_action_set(vcap, data, VCAP_ES0_ACT_PCP_B_VAL, a->pcp_b_val); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic void es0_entry_set(struct ocelot *ocelot, int ix, 8098c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; 8128c2ecf20Sopenharmony_ci struct ocelot_vcap_key_vlan *tag = &filter->vlan; 8138c2ecf20Sopenharmony_ci struct ocelot_vcap_u64 payload; 8148c2ecf20Sopenharmony_ci struct vcap_data data; 8158c2ecf20Sopenharmony_ci int row = ix; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 8188c2ecf20Sopenharmony_ci memset(&data, 0, sizeof(data)); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* Read row */ 8218c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL); 8228c2ecf20Sopenharmony_ci vcap_cache2entry(ocelot, vcap, &data); 8238c2ecf20Sopenharmony_ci vcap_cache2action(ocelot, vcap, &data); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci data.tg_sw = VCAP_TG_FULL; 8268c2ecf20Sopenharmony_ci data.type = ES0_ACTION_TYPE_NORMAL; 8278c2ecf20Sopenharmony_ci vcap_data_offset_get(vcap, &data, ix); 8288c2ecf20Sopenharmony_ci data.tg = (data.tg & ~data.tg_mask); 8298c2ecf20Sopenharmony_ci if (filter->prio != 0) 8308c2ecf20Sopenharmony_ci data.tg |= data.tg_value; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_ES0_IGR_PORT, filter->ingress_port.value, 8338c2ecf20Sopenharmony_ci filter->ingress_port.mask); 8348c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_ES0_EGR_PORT, filter->egress_port.value, 8358c2ecf20Sopenharmony_ci filter->egress_port.mask); 8368c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_ES0_L2_MC, filter->dmac_mc); 8378c2ecf20Sopenharmony_ci vcap_key_bit_set(vcap, &data, VCAP_ES0_L2_BC, filter->dmac_bc); 8388c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_ES0_VID, 8398c2ecf20Sopenharmony_ci tag->vid.value, tag->vid.mask); 8408c2ecf20Sopenharmony_ci vcap_key_set(vcap, &data, VCAP_ES0_PCP, 8418c2ecf20Sopenharmony_ci tag->pcp.value[0], tag->pcp.mask[0]); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci es0_action_set(ocelot, &data, filter); 8448c2ecf20Sopenharmony_ci vcap_data_set(data.counter, data.counter_offset, 8458c2ecf20Sopenharmony_ci vcap->counter_width, filter->stats.pkts); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Write row */ 8488c2ecf20Sopenharmony_ci vcap_entry2cache(ocelot, vcap, &data); 8498c2ecf20Sopenharmony_ci vcap_action2cache(ocelot, vcap, &data); 8508c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL); 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic void vcap_entry_get(struct ocelot *ocelot, int ix, 8548c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci const struct vcap_props *vcap = &ocelot->vcap[filter->block_id]; 8578c2ecf20Sopenharmony_ci struct vcap_data data; 8588c2ecf20Sopenharmony_ci int row, count; 8598c2ecf20Sopenharmony_ci u32 cnt; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (filter->block_id == VCAP_ES0) 8628c2ecf20Sopenharmony_ci data.tg_sw = VCAP_TG_FULL; 8638c2ecf20Sopenharmony_ci else 8648c2ecf20Sopenharmony_ci data.tg_sw = VCAP_TG_HALF; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci count = (1 << (data.tg_sw - 1)); 8678c2ecf20Sopenharmony_ci row = (ix / count); 8688c2ecf20Sopenharmony_ci vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_COUNTER); 8698c2ecf20Sopenharmony_ci vcap_cache2action(ocelot, vcap, &data); 8708c2ecf20Sopenharmony_ci vcap_data_offset_get(vcap, &data, ix); 8718c2ecf20Sopenharmony_ci cnt = vcap_data_get(data.counter, data.counter_offset, 8728c2ecf20Sopenharmony_ci vcap->counter_width); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci filter->stats.pkts = cnt; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic void vcap_entry_set(struct ocelot *ocelot, int ix, 8788c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci if (filter->block_id == VCAP_IS1) 8818c2ecf20Sopenharmony_ci return is1_entry_set(ocelot, ix, filter); 8828c2ecf20Sopenharmony_ci if (filter->block_id == VCAP_IS2) 8838c2ecf20Sopenharmony_ci return is2_entry_set(ocelot, ix, filter); 8848c2ecf20Sopenharmony_ci if (filter->block_id == VCAP_ES0) 8858c2ecf20Sopenharmony_ci return es0_entry_set(ocelot, ix, filter); 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix, 8898c2ecf20Sopenharmony_ci struct ocelot_policer *pol) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct qos_policer_conf pp = { 0 }; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (!pol) 8948c2ecf20Sopenharmony_ci return -EINVAL; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci pp.mode = MSCC_QOS_RATE_MODE_DATA; 8978c2ecf20Sopenharmony_ci pp.pir = pol->rate; 8988c2ecf20Sopenharmony_ci pp.pbs = pol->burst; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return qos_policer_conf_set(ocelot, 0, pol_ix, &pp); 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic void ocelot_vcap_policer_del(struct ocelot *ocelot, 9048c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block, 9058c2ecf20Sopenharmony_ci u32 pol_ix) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter; 9088c2ecf20Sopenharmony_ci struct qos_policer_conf pp = {0}; 9098c2ecf20Sopenharmony_ci int index = -1; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (pol_ix < block->pol_lpr) 9128c2ecf20Sopenharmony_ci return; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci list_for_each_entry(filter, &block->rules, list) { 9158c2ecf20Sopenharmony_ci index++; 9168c2ecf20Sopenharmony_ci if (filter->block_id == VCAP_IS2 && 9178c2ecf20Sopenharmony_ci filter->action.police_ena && 9188c2ecf20Sopenharmony_ci filter->action.pol_ix < pol_ix) { 9198c2ecf20Sopenharmony_ci filter->action.pol_ix += 1; 9208c2ecf20Sopenharmony_ci ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, 9218c2ecf20Sopenharmony_ci &filter->action.pol); 9228c2ecf20Sopenharmony_ci is2_entry_set(ocelot, index, filter); 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci pp.mode = MSCC_QOS_RATE_MODE_DISABLED; 9278c2ecf20Sopenharmony_ci qos_policer_conf_set(ocelot, 0, pol_ix, &pp); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci block->pol_lpr++; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, 9338c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block, 9348c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 9378c2ecf20Sopenharmony_ci struct list_head *pos, *n; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (filter->block_id == VCAP_IS2 && filter->action.police_ena) { 9408c2ecf20Sopenharmony_ci block->pol_lpr--; 9418c2ecf20Sopenharmony_ci filter->action.pol_ix = block->pol_lpr; 9428c2ecf20Sopenharmony_ci ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, 9438c2ecf20Sopenharmony_ci &filter->action.pol); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci block->count++; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (list_empty(&block->rules)) { 9498c2ecf20Sopenharmony_ci list_add(&filter->list, &block->rules); 9508c2ecf20Sopenharmony_ci return; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci list_for_each_safe(pos, n, &block->rules) { 9548c2ecf20Sopenharmony_ci tmp = list_entry(pos, struct ocelot_vcap_filter, list); 9558c2ecf20Sopenharmony_ci if (filter->prio < tmp->prio) 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci list_add(&filter->list, pos->prev); 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic int ocelot_vcap_block_get_filter_index(struct ocelot_vcap_block *block, 9628c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 9658c2ecf20Sopenharmony_ci int index = 0; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &block->rules, list) { 9688c2ecf20Sopenharmony_ci if (filter->id == tmp->id) 9698c2ecf20Sopenharmony_ci return index; 9708c2ecf20Sopenharmony_ci index++; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return -ENOENT; 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic struct ocelot_vcap_filter* 9778c2ecf20Sopenharmony_ciocelot_vcap_block_find_filter_by_index(struct ocelot_vcap_block *block, 9788c2ecf20Sopenharmony_ci int index) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 9818c2ecf20Sopenharmony_ci int i = 0; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &block->rules, list) { 9848c2ecf20Sopenharmony_ci if (i == index) 9858c2ecf20Sopenharmony_ci return tmp; 9868c2ecf20Sopenharmony_ci ++i; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci return NULL; 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistruct ocelot_vcap_filter * 9938c2ecf20Sopenharmony_ciocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block, int id) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci list_for_each_entry(filter, &block->rules, list) 9988c2ecf20Sopenharmony_ci if (filter->id == id) 9998c2ecf20Sopenharmony_ci return filter; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return NULL; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/* If @on=false, then SNAP, ARP, IP and OAM frames will not match on keys based 10058c2ecf20Sopenharmony_ci * on destination and source MAC addresses, but only on higher-level protocol 10068c2ecf20Sopenharmony_ci * information. The only frame types to match on keys containing MAC addresses 10078c2ecf20Sopenharmony_ci * in this case are non-SNAP, non-ARP, non-IP and non-OAM frames. 10088c2ecf20Sopenharmony_ci * 10098c2ecf20Sopenharmony_ci * If @on=true, then the above frame types (SNAP, ARP, IP and OAM) will match 10108c2ecf20Sopenharmony_ci * on MAC_ETYPE keys such as destination and source MAC on this ingress port. 10118c2ecf20Sopenharmony_ci * However the setting has the side effect of making these frames not matching 10128c2ecf20Sopenharmony_ci * on any _other_ keys than MAC_ETYPE ones. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_cistatic void ocelot_match_all_as_mac_etype(struct ocelot *ocelot, int port, 10158c2ecf20Sopenharmony_ci int lookup, bool on) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci u32 val = 0; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (on) 10208c2ecf20Sopenharmony_ci val = ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(BIT(lookup)) | 10218c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(BIT(lookup)) | 10228c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(BIT(lookup)) | 10238c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(BIT(lookup)) | 10248c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(BIT(lookup)); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci ocelot_rmw_gix(ocelot, val, 10278c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(BIT(lookup)) | 10288c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(BIT(lookup)) | 10298c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(BIT(lookup)) | 10308c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(BIT(lookup)) | 10318c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(BIT(lookup)), 10328c2ecf20Sopenharmony_ci ANA_PORT_VCAP_S2_CFG, port); 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic bool 10368c2ecf20Sopenharmony_ciocelot_vcap_is_problematic_mac_etype(struct ocelot_vcap_filter *filter) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci u16 proto, mask; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (filter->key_type != OCELOT_VCAP_KEY_ETYPE) 10418c2ecf20Sopenharmony_ci return false; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci proto = ntohs(*(__be16 *)filter->key.etype.etype.value); 10448c2ecf20Sopenharmony_ci mask = ntohs(*(__be16 *)filter->key.etype.etype.mask); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* ETH_P_ALL match, so all protocols below are included */ 10478c2ecf20Sopenharmony_ci if (mask == 0) 10488c2ecf20Sopenharmony_ci return true; 10498c2ecf20Sopenharmony_ci if (proto == ETH_P_ARP) 10508c2ecf20Sopenharmony_ci return true; 10518c2ecf20Sopenharmony_ci if (proto == ETH_P_IP) 10528c2ecf20Sopenharmony_ci return true; 10538c2ecf20Sopenharmony_ci if (proto == ETH_P_IPV6) 10548c2ecf20Sopenharmony_ci return true; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci return false; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic bool 10608c2ecf20Sopenharmony_ciocelot_vcap_is_problematic_non_mac_etype(struct ocelot_vcap_filter *filter) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci if (filter->key_type == OCELOT_VCAP_KEY_SNAP) 10638c2ecf20Sopenharmony_ci return true; 10648c2ecf20Sopenharmony_ci if (filter->key_type == OCELOT_VCAP_KEY_ARP) 10658c2ecf20Sopenharmony_ci return true; 10668c2ecf20Sopenharmony_ci if (filter->key_type == OCELOT_VCAP_KEY_IPV4) 10678c2ecf20Sopenharmony_ci return true; 10688c2ecf20Sopenharmony_ci if (filter->key_type == OCELOT_VCAP_KEY_IPV6) 10698c2ecf20Sopenharmony_ci return true; 10708c2ecf20Sopenharmony_ci return false; 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic bool 10748c2ecf20Sopenharmony_ciocelot_exclusive_mac_etype_filter_rules(struct ocelot *ocelot, 10758c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block = &ocelot->block[filter->block_id]; 10788c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 10798c2ecf20Sopenharmony_ci unsigned long port; 10808c2ecf20Sopenharmony_ci int i; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* We only have the S2_IP_TCPUDP_DIS set of knobs for VCAP IS2 */ 10838c2ecf20Sopenharmony_ci if (filter->block_id != VCAP_IS2) 10848c2ecf20Sopenharmony_ci return true; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (ocelot_vcap_is_problematic_mac_etype(filter)) { 10878c2ecf20Sopenharmony_ci /* Search for any non-MAC_ETYPE rules on the port */ 10888c2ecf20Sopenharmony_ci for (i = 0; i < block->count; i++) { 10898c2ecf20Sopenharmony_ci tmp = ocelot_vcap_block_find_filter_by_index(block, i); 10908c2ecf20Sopenharmony_ci if (tmp->ingress_port_mask & filter->ingress_port_mask && 10918c2ecf20Sopenharmony_ci tmp->lookup == filter->lookup && 10928c2ecf20Sopenharmony_ci ocelot_vcap_is_problematic_non_mac_etype(tmp)) 10938c2ecf20Sopenharmony_ci return false; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci for_each_set_bit(port, &filter->ingress_port_mask, 10978c2ecf20Sopenharmony_ci ocelot->num_phys_ports) 10988c2ecf20Sopenharmony_ci ocelot_match_all_as_mac_etype(ocelot, port, 10998c2ecf20Sopenharmony_ci filter->lookup, true); 11008c2ecf20Sopenharmony_ci } else if (ocelot_vcap_is_problematic_non_mac_etype(filter)) { 11018c2ecf20Sopenharmony_ci /* Search for any MAC_ETYPE rules on the port */ 11028c2ecf20Sopenharmony_ci for (i = 0; i < block->count; i++) { 11038c2ecf20Sopenharmony_ci tmp = ocelot_vcap_block_find_filter_by_index(block, i); 11048c2ecf20Sopenharmony_ci if (tmp->ingress_port_mask & filter->ingress_port_mask && 11058c2ecf20Sopenharmony_ci tmp->lookup == filter->lookup && 11068c2ecf20Sopenharmony_ci ocelot_vcap_is_problematic_mac_etype(tmp)) 11078c2ecf20Sopenharmony_ci return false; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci for_each_set_bit(port, &filter->ingress_port_mask, 11118c2ecf20Sopenharmony_ci ocelot->num_phys_ports) 11128c2ecf20Sopenharmony_ci ocelot_match_all_as_mac_etype(ocelot, port, 11138c2ecf20Sopenharmony_ci filter->lookup, false); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci return true; 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ciint ocelot_vcap_filter_add(struct ocelot *ocelot, 11208c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter, 11218c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block = &ocelot->block[filter->block_id]; 11248c2ecf20Sopenharmony_ci int i, index; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (!ocelot_exclusive_mac_etype_filter_rules(ocelot, filter)) { 11278c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 11288c2ecf20Sopenharmony_ci "Cannot mix MAC_ETYPE with non-MAC_ETYPE rules, use the other IS2 lookup"); 11298c2ecf20Sopenharmony_ci return -EBUSY; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* Add filter to the linked list */ 11338c2ecf20Sopenharmony_ci ocelot_vcap_filter_add_to_block(ocelot, block, filter); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* Get the index of the inserted filter */ 11368c2ecf20Sopenharmony_ci index = ocelot_vcap_block_get_filter_index(block, filter); 11378c2ecf20Sopenharmony_ci if (index < 0) 11388c2ecf20Sopenharmony_ci return index; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci /* Move down the rules to make place for the new filter */ 11418c2ecf20Sopenharmony_ci for (i = block->count - 1; i > index; i--) { 11428c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci tmp = ocelot_vcap_block_find_filter_by_index(block, i); 11458c2ecf20Sopenharmony_ci /* Read back the filter's counters before moving it */ 11468c2ecf20Sopenharmony_ci vcap_entry_get(ocelot, i - 1, tmp); 11478c2ecf20Sopenharmony_ci vcap_entry_set(ocelot, i, tmp); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* Now insert the new filter */ 11518c2ecf20Sopenharmony_ci vcap_entry_set(ocelot, index, filter); 11528c2ecf20Sopenharmony_ci return 0; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic void ocelot_vcap_block_remove_filter(struct ocelot *ocelot, 11568c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block, 11578c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 11608c2ecf20Sopenharmony_ci struct list_head *pos, *q; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci list_for_each_safe(pos, q, &block->rules) { 11638c2ecf20Sopenharmony_ci tmp = list_entry(pos, struct ocelot_vcap_filter, list); 11648c2ecf20Sopenharmony_ci if (tmp->id == filter->id) { 11658c2ecf20Sopenharmony_ci if (tmp->block_id == VCAP_IS2 && 11668c2ecf20Sopenharmony_ci tmp->action.police_ena) 11678c2ecf20Sopenharmony_ci ocelot_vcap_policer_del(ocelot, block, 11688c2ecf20Sopenharmony_ci tmp->action.pol_ix); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci list_del(pos); 11718c2ecf20Sopenharmony_ci kfree(tmp); 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci block->count--; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ciint ocelot_vcap_filter_del(struct ocelot *ocelot, 11798c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block = &ocelot->block[filter->block_id]; 11828c2ecf20Sopenharmony_ci struct ocelot_vcap_filter del_filter; 11838c2ecf20Sopenharmony_ci int i, index; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* Need to inherit the block_id so that vcap_entry_set() 11868c2ecf20Sopenharmony_ci * does not get confused and knows where to install it. 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_ci memset(&del_filter, 0, sizeof(del_filter)); 11898c2ecf20Sopenharmony_ci del_filter.block_id = filter->block_id; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* Gets index of the filter */ 11928c2ecf20Sopenharmony_ci index = ocelot_vcap_block_get_filter_index(block, filter); 11938c2ecf20Sopenharmony_ci if (index < 0) 11948c2ecf20Sopenharmony_ci return index; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Delete filter */ 11978c2ecf20Sopenharmony_ci ocelot_vcap_block_remove_filter(ocelot, block, filter); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Move up all the blocks over the deleted filter */ 12008c2ecf20Sopenharmony_ci for (i = index; i < block->count; i++) { 12018c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *tmp; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci tmp = ocelot_vcap_block_find_filter_by_index(block, i); 12048c2ecf20Sopenharmony_ci /* Read back the filter's counters before moving it */ 12058c2ecf20Sopenharmony_ci vcap_entry_get(ocelot, i + 1, tmp); 12068c2ecf20Sopenharmony_ci vcap_entry_set(ocelot, i, tmp); 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* Now delete the last filter, because it is duplicated */ 12108c2ecf20Sopenharmony_ci vcap_entry_set(ocelot, block->count, &del_filter); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return 0; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ciint ocelot_vcap_filter_stats_update(struct ocelot *ocelot, 12168c2ecf20Sopenharmony_ci struct ocelot_vcap_filter *filter) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block = &ocelot->block[filter->block_id]; 12198c2ecf20Sopenharmony_ci struct ocelot_vcap_filter tmp; 12208c2ecf20Sopenharmony_ci int index; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci index = ocelot_vcap_block_get_filter_index(block, filter); 12238c2ecf20Sopenharmony_ci if (index < 0) 12248c2ecf20Sopenharmony_ci return index; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci vcap_entry_get(ocelot, index, filter); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* After we get the result we need to clear the counters */ 12298c2ecf20Sopenharmony_ci tmp = *filter; 12308c2ecf20Sopenharmony_ci tmp.stats.pkts = 0; 12318c2ecf20Sopenharmony_ci vcap_entry_set(ocelot, index, &tmp); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return 0; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic void ocelot_vcap_init_one(struct ocelot *ocelot, 12378c2ecf20Sopenharmony_ci const struct vcap_props *vcap) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci struct vcap_data data; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci memset(&data, 0, sizeof(data)); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci vcap_entry2cache(ocelot, vcap, &data); 12448c2ecf20Sopenharmony_ci ocelot_target_write(ocelot, vcap->target, vcap->entry_count, 12458c2ecf20Sopenharmony_ci VCAP_CORE_MV_CFG); 12468c2ecf20Sopenharmony_ci vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci vcap_action2cache(ocelot, vcap, &data); 12498c2ecf20Sopenharmony_ci ocelot_target_write(ocelot, vcap->target, vcap->action_count, 12508c2ecf20Sopenharmony_ci VCAP_CORE_MV_CFG); 12518c2ecf20Sopenharmony_ci vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE, 12528c2ecf20Sopenharmony_ci VCAP_SEL_ACTION | VCAP_SEL_COUNTER); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic void ocelot_vcap_detect_constants(struct ocelot *ocelot, 12568c2ecf20Sopenharmony_ci struct vcap_props *vcap) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci int counter_memory_width; 12598c2ecf20Sopenharmony_ci int num_default_actions; 12608c2ecf20Sopenharmony_ci int version; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci version = ocelot_target_read(ocelot, vcap->target, 12638c2ecf20Sopenharmony_ci VCAP_CONST_VCAP_VER); 12648c2ecf20Sopenharmony_ci /* Only version 0 VCAP supported for now */ 12658c2ecf20Sopenharmony_ci if (WARN_ON(version != 0)) 12668c2ecf20Sopenharmony_ci return; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Width in bits of type-group field */ 12698c2ecf20Sopenharmony_ci vcap->tg_width = ocelot_target_read(ocelot, vcap->target, 12708c2ecf20Sopenharmony_ci VCAP_CONST_ENTRY_TG_WIDTH); 12718c2ecf20Sopenharmony_ci /* Number of subwords per TCAM row */ 12728c2ecf20Sopenharmony_ci vcap->sw_count = ocelot_target_read(ocelot, vcap->target, 12738c2ecf20Sopenharmony_ci VCAP_CONST_ENTRY_SWCNT); 12748c2ecf20Sopenharmony_ci /* Number of rows in TCAM. There can be this many full keys, or double 12758c2ecf20Sopenharmony_ci * this number half keys, or 4 times this number quarter keys. 12768c2ecf20Sopenharmony_ci */ 12778c2ecf20Sopenharmony_ci vcap->entry_count = ocelot_target_read(ocelot, vcap->target, 12788c2ecf20Sopenharmony_ci VCAP_CONST_ENTRY_CNT); 12798c2ecf20Sopenharmony_ci /* Assuming there are 4 subwords per TCAM row, their layout in the 12808c2ecf20Sopenharmony_ci * actual TCAM (not in the cache) would be: 12818c2ecf20Sopenharmony_ci * 12828c2ecf20Sopenharmony_ci * | SW 3 | TG 3 | SW 2 | TG 2 | SW 1 | TG 1 | SW 0 | TG 0 | 12838c2ecf20Sopenharmony_ci * 12848c2ecf20Sopenharmony_ci * (where SW=subword and TG=Type-Group). 12858c2ecf20Sopenharmony_ci * 12868c2ecf20Sopenharmony_ci * What VCAP_CONST_ENTRY_CNT is giving us is the width of one full TCAM 12878c2ecf20Sopenharmony_ci * row. But when software accesses the TCAM through the cache 12888c2ecf20Sopenharmony_ci * registers, the Type-Group values are written through another set of 12898c2ecf20Sopenharmony_ci * registers VCAP_TG_DAT, and therefore, it appears as though the 4 12908c2ecf20Sopenharmony_ci * subwords are contiguous in the cache memory. 12918c2ecf20Sopenharmony_ci * Important mention: regardless of the number of key entries per row 12928c2ecf20Sopenharmony_ci * (and therefore of key size: 1 full key or 2 half keys or 4 quarter 12938c2ecf20Sopenharmony_ci * keys), software always has to configure 4 Type-Group values. For 12948c2ecf20Sopenharmony_ci * example, in the case of 1 full key, the driver needs to set all 4 12958c2ecf20Sopenharmony_ci * Type-Group to be full key. 12968c2ecf20Sopenharmony_ci * 12978c2ecf20Sopenharmony_ci * For this reason, we need to fix up the value that the hardware is 12988c2ecf20Sopenharmony_ci * giving us. We don't actually care about the width of the entry in 12998c2ecf20Sopenharmony_ci * the TCAM. What we care about is the width of the entry in the cache 13008c2ecf20Sopenharmony_ci * registers, which is how we get to interact with it. And since the 13018c2ecf20Sopenharmony_ci * VCAP_ENTRY_DAT cache registers access only the subwords and not the 13028c2ecf20Sopenharmony_ci * Type-Groups, this means we need to subtract the width of the 13038c2ecf20Sopenharmony_ci * Type-Groups when packing and unpacking key entry data in a TCAM row. 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_ci vcap->entry_width = ocelot_target_read(ocelot, vcap->target, 13068c2ecf20Sopenharmony_ci VCAP_CONST_ENTRY_WIDTH); 13078c2ecf20Sopenharmony_ci vcap->entry_width -= vcap->tg_width * vcap->sw_count; 13088c2ecf20Sopenharmony_ci num_default_actions = ocelot_target_read(ocelot, vcap->target, 13098c2ecf20Sopenharmony_ci VCAP_CONST_ACTION_DEF_CNT); 13108c2ecf20Sopenharmony_ci vcap->action_count = vcap->entry_count + num_default_actions; 13118c2ecf20Sopenharmony_ci vcap->action_width = ocelot_target_read(ocelot, vcap->target, 13128c2ecf20Sopenharmony_ci VCAP_CONST_ACTION_WIDTH); 13138c2ecf20Sopenharmony_ci /* The width of the counter memory, this is the complete width of all 13148c2ecf20Sopenharmony_ci * counter-fields associated with one full-word entry. There is one 13158c2ecf20Sopenharmony_ci * counter per entry sub-word (see CAP_CORE::ENTRY_SWCNT for number of 13168c2ecf20Sopenharmony_ci * subwords.) 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_ci vcap->counter_words = vcap->sw_count; 13198c2ecf20Sopenharmony_ci counter_memory_width = ocelot_target_read(ocelot, vcap->target, 13208c2ecf20Sopenharmony_ci VCAP_CONST_CNT_WIDTH); 13218c2ecf20Sopenharmony_ci vcap->counter_width = counter_memory_width / vcap->counter_words; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ciint ocelot_vcap_init(struct ocelot *ocelot) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci int i; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* Create a policer that will drop the frames for the cpu. 13298c2ecf20Sopenharmony_ci * This policer will be used as action in the acl rules to drop 13308c2ecf20Sopenharmony_ci * frames. 13318c2ecf20Sopenharmony_ci */ 13328c2ecf20Sopenharmony_ci ocelot_write_gix(ocelot, 0x299, ANA_POL_MODE_CFG, 13338c2ecf20Sopenharmony_ci OCELOT_POLICER_DISCARD); 13348c2ecf20Sopenharmony_ci ocelot_write_gix(ocelot, 0x1, ANA_POL_PIR_CFG, 13358c2ecf20Sopenharmony_ci OCELOT_POLICER_DISCARD); 13368c2ecf20Sopenharmony_ci ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_PIR_STATE, 13378c2ecf20Sopenharmony_ci OCELOT_POLICER_DISCARD); 13388c2ecf20Sopenharmony_ci ocelot_write_gix(ocelot, 0x0, ANA_POL_CIR_CFG, 13398c2ecf20Sopenharmony_ci OCELOT_POLICER_DISCARD); 13408c2ecf20Sopenharmony_ci ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE, 13418c2ecf20Sopenharmony_ci OCELOT_POLICER_DISCARD); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci for (i = 0; i < OCELOT_NUM_VCAP_BLOCKS; i++) { 13448c2ecf20Sopenharmony_ci struct ocelot_vcap_block *block = &ocelot->block[i]; 13458c2ecf20Sopenharmony_ci struct vcap_props *vcap = &ocelot->vcap[i]; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&block->rules); 13488c2ecf20Sopenharmony_ci block->pol_lpr = OCELOT_POLICER_DISCARD - 1; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci ocelot_vcap_detect_constants(ocelot, vcap); 13518c2ecf20Sopenharmony_ci ocelot_vcap_init_one(ocelot, vcap); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ocelot->dummy_rules); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci return 0; 13578c2ecf20Sopenharmony_ci} 1358