18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2017-2020 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/errno.h> 68c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 78c2ecf20Sopenharmony_ci#include <net/flow_offload.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "spectrum.h" 108c2ecf20Sopenharmony_ci#include "spectrum_span.h" 118c2ecf20Sopenharmony_ci#include "reg.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic struct mlxsw_sp_mall_entry * 148c2ecf20Sopenharmony_cimlxsw_sp_mall_entry_find(struct mlxsw_sp_flow_block *block, unsigned long cookie) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci list_for_each_entry(mall_entry, &block->mall.list, list) 198c2ecf20Sopenharmony_ci if (mall_entry->cookie == cookie) 208c2ecf20Sopenharmony_ci return mall_entry; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci return NULL; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int 268c2ecf20Sopenharmony_cimlxsw_sp_mall_port_mirror_add(struct mlxsw_sp_port *mlxsw_sp_port, 278c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 308c2ecf20Sopenharmony_ci struct mlxsw_sp_span_agent_parms agent_parms = {}; 318c2ecf20Sopenharmony_ci struct mlxsw_sp_span_trigger_parms parms; 328c2ecf20Sopenharmony_ci enum mlxsw_sp_span_trigger trigger; 338c2ecf20Sopenharmony_ci int err; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (!mall_entry->mirror.to_dev) { 368c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Could not find requested device\n"); 378c2ecf20Sopenharmony_ci return -EINVAL; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci agent_parms.to_dev = mall_entry->mirror.to_dev; 418c2ecf20Sopenharmony_ci err = mlxsw_sp_span_agent_get(mlxsw_sp, &mall_entry->mirror.span_id, 428c2ecf20Sopenharmony_ci &agent_parms); 438c2ecf20Sopenharmony_ci if (err) 448c2ecf20Sopenharmony_ci return err; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, 478c2ecf20Sopenharmony_ci mall_entry->ingress); 488c2ecf20Sopenharmony_ci if (err) 498c2ecf20Sopenharmony_ci goto err_analyzed_port_get; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS : 528c2ecf20Sopenharmony_ci MLXSW_SP_SPAN_TRIGGER_EGRESS; 538c2ecf20Sopenharmony_ci parms.span_id = mall_entry->mirror.span_id; 548c2ecf20Sopenharmony_ci err = mlxsw_sp_span_agent_bind(mlxsw_sp, trigger, mlxsw_sp_port, 558c2ecf20Sopenharmony_ci &parms); 568c2ecf20Sopenharmony_ci if (err) 578c2ecf20Sopenharmony_ci goto err_agent_bind; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cierr_agent_bind: 628c2ecf20Sopenharmony_ci mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress); 638c2ecf20Sopenharmony_cierr_analyzed_port_get: 648c2ecf20Sopenharmony_ci mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->mirror.span_id); 658c2ecf20Sopenharmony_ci return err; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void 698c2ecf20Sopenharmony_cimlxsw_sp_mall_port_mirror_del(struct mlxsw_sp_port *mlxsw_sp_port, 708c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 738c2ecf20Sopenharmony_ci struct mlxsw_sp_span_trigger_parms parms; 748c2ecf20Sopenharmony_ci enum mlxsw_sp_span_trigger trigger; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS : 778c2ecf20Sopenharmony_ci MLXSW_SP_SPAN_TRIGGER_EGRESS; 788c2ecf20Sopenharmony_ci parms.span_id = mall_entry->mirror.span_id; 798c2ecf20Sopenharmony_ci mlxsw_sp_span_agent_unbind(mlxsw_sp, trigger, mlxsw_sp_port, &parms); 808c2ecf20Sopenharmony_ci mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress); 818c2ecf20Sopenharmony_ci mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->mirror.span_id); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int mlxsw_sp_mall_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port, 858c2ecf20Sopenharmony_ci bool enable, u32 rate) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 888c2ecf20Sopenharmony_ci char mpsc_pl[MLXSW_REG_MPSC_LEN]; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci mlxsw_reg_mpsc_pack(mpsc_pl, mlxsw_sp_port->local_port, enable, rate); 918c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpsc), mpsc_pl); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int 958c2ecf20Sopenharmony_cimlxsw_sp_mall_port_sample_add(struct mlxsw_sp_port *mlxsw_sp_port, 968c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci int err; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (rtnl_dereference(mlxsw_sp_port->sample)) { 1018c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "sample already active\n"); 1028c2ecf20Sopenharmony_ci return -EEXIST; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci rcu_assign_pointer(mlxsw_sp_port->sample, &mall_entry->sample); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci err = mlxsw_sp_mall_port_sample_set(mlxsw_sp_port, true, 1078c2ecf20Sopenharmony_ci mall_entry->sample.rate); 1088c2ecf20Sopenharmony_ci if (err) 1098c2ecf20Sopenharmony_ci goto err_port_sample_set; 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cierr_port_sample_set: 1138c2ecf20Sopenharmony_ci RCU_INIT_POINTER(mlxsw_sp_port->sample, NULL); 1148c2ecf20Sopenharmony_ci return err; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void 1188c2ecf20Sopenharmony_cimlxsw_sp_mall_port_sample_del(struct mlxsw_sp_port *mlxsw_sp_port) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci if (!mlxsw_sp_port->sample) 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_sample_set(mlxsw_sp_port, false, 1); 1248c2ecf20Sopenharmony_ci RCU_INIT_POINTER(mlxsw_sp_port->sample, NULL); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int 1288c2ecf20Sopenharmony_cimlxsw_sp_mall_port_rule_add(struct mlxsw_sp_port *mlxsw_sp_port, 1298c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci switch (mall_entry->type) { 1328c2ecf20Sopenharmony_ci case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: 1338c2ecf20Sopenharmony_ci return mlxsw_sp_mall_port_mirror_add(mlxsw_sp_port, mall_entry); 1348c2ecf20Sopenharmony_ci case MLXSW_SP_MALL_ACTION_TYPE_SAMPLE: 1358c2ecf20Sopenharmony_ci return mlxsw_sp_mall_port_sample_add(mlxsw_sp_port, mall_entry); 1368c2ecf20Sopenharmony_ci default: 1378c2ecf20Sopenharmony_ci WARN_ON(1); 1388c2ecf20Sopenharmony_ci return -EINVAL; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void 1438c2ecf20Sopenharmony_cimlxsw_sp_mall_port_rule_del(struct mlxsw_sp_port *mlxsw_sp_port, 1448c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci switch (mall_entry->type) { 1478c2ecf20Sopenharmony_ci case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: 1488c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_mirror_del(mlxsw_sp_port, mall_entry); 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case MLXSW_SP_MALL_ACTION_TYPE_SAMPLE: 1518c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_sample_del(mlxsw_sp_port); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci default: 1548c2ecf20Sopenharmony_ci WARN_ON(1); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void mlxsw_sp_mall_prio_update(struct mlxsw_sp_flow_block *block) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (list_empty(&block->mall.list)) 1638c2ecf20Sopenharmony_ci return; 1648c2ecf20Sopenharmony_ci block->mall.min_prio = UINT_MAX; 1658c2ecf20Sopenharmony_ci block->mall.max_prio = 0; 1668c2ecf20Sopenharmony_ci list_for_each_entry(mall_entry, &block->mall.list, list) { 1678c2ecf20Sopenharmony_ci if (mall_entry->priority < block->mall.min_prio) 1688c2ecf20Sopenharmony_ci block->mall.min_prio = mall_entry->priority; 1698c2ecf20Sopenharmony_ci if (mall_entry->priority > block->mall.max_prio) 1708c2ecf20Sopenharmony_ci block->mall.max_prio = mall_entry->priority; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciint mlxsw_sp_mall_replace(struct mlxsw_sp *mlxsw_sp, 1758c2ecf20Sopenharmony_ci struct mlxsw_sp_flow_block *block, 1768c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload *f) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct mlxsw_sp_flow_block_binding *binding; 1798c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry; 1808c2ecf20Sopenharmony_ci __be16 protocol = f->common.protocol; 1818c2ecf20Sopenharmony_ci struct flow_action_entry *act; 1828c2ecf20Sopenharmony_ci unsigned int flower_min_prio; 1838c2ecf20Sopenharmony_ci unsigned int flower_max_prio; 1848c2ecf20Sopenharmony_ci bool flower_prio_valid; 1858c2ecf20Sopenharmony_ci int err; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (!flow_offload_has_one_action(&f->rule->action)) { 1888c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Only singular actions are supported"); 1898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (f->common.chain_index) { 1938c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Only chain 0 is supported"); 1948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (mlxsw_sp_flow_block_is_mixed_bound(block)) { 1988c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Only not mixed bound blocks are supported"); 1998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci err = mlxsw_sp_flower_prio_get(mlxsw_sp, block, f->common.chain_index, 2038c2ecf20Sopenharmony_ci &flower_min_prio, &flower_max_prio); 2048c2ecf20Sopenharmony_ci if (err) { 2058c2ecf20Sopenharmony_ci if (err != -ENOENT) { 2068c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Failed to get flower priorities"); 2078c2ecf20Sopenharmony_ci return err; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci flower_prio_valid = false; 2108c2ecf20Sopenharmony_ci /* No flower filters are installed in specified chain. */ 2118c2ecf20Sopenharmony_ci } else { 2128c2ecf20Sopenharmony_ci flower_prio_valid = true; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL); 2168c2ecf20Sopenharmony_ci if (!mall_entry) 2178c2ecf20Sopenharmony_ci return -ENOMEM; 2188c2ecf20Sopenharmony_ci mall_entry->cookie = f->cookie; 2198c2ecf20Sopenharmony_ci mall_entry->priority = f->common.prio; 2208c2ecf20Sopenharmony_ci mall_entry->ingress = mlxsw_sp_flow_block_is_ingress_bound(block); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci act = &f->rule->action.entries[0]; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) { 2258c2ecf20Sopenharmony_ci if (flower_prio_valid && mall_entry->ingress && 2268c2ecf20Sopenharmony_ci mall_entry->priority >= flower_min_prio) { 2278c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules"); 2288c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 2298c2ecf20Sopenharmony_ci goto errout; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci if (flower_prio_valid && !mall_entry->ingress && 2328c2ecf20Sopenharmony_ci mall_entry->priority <= flower_max_prio) { 2338c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing flower rules"); 2348c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 2358c2ecf20Sopenharmony_ci goto errout; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR; 2388c2ecf20Sopenharmony_ci mall_entry->mirror.to_dev = act->dev; 2398c2ecf20Sopenharmony_ci } else if (act->id == FLOW_ACTION_SAMPLE && 2408c2ecf20Sopenharmony_ci protocol == htons(ETH_P_ALL)) { 2418c2ecf20Sopenharmony_ci if (!mall_entry->ingress) { 2428c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Sample is not supported on egress"); 2438c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 2448c2ecf20Sopenharmony_ci goto errout; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci if (flower_prio_valid && 2478c2ecf20Sopenharmony_ci mall_entry->priority >= flower_min_prio) { 2488c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules"); 2498c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 2508c2ecf20Sopenharmony_ci goto errout; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci if (act->sample.rate > MLXSW_REG_MPSC_RATE_MAX) { 2538c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Sample rate not supported"); 2548c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 2558c2ecf20Sopenharmony_ci goto errout; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_SAMPLE; 2588c2ecf20Sopenharmony_ci mall_entry->sample.psample_group = act->sample.psample_group; 2598c2ecf20Sopenharmony_ci mall_entry->sample.truncate = act->sample.truncate; 2608c2ecf20Sopenharmony_ci mall_entry->sample.trunc_size = act->sample.trunc_size; 2618c2ecf20Sopenharmony_ci mall_entry->sample.rate = act->sample.rate; 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 2648c2ecf20Sopenharmony_ci goto errout; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci list_for_each_entry(binding, &block->binding_list, list) { 2688c2ecf20Sopenharmony_ci err = mlxsw_sp_mall_port_rule_add(binding->mlxsw_sp_port, 2698c2ecf20Sopenharmony_ci mall_entry); 2708c2ecf20Sopenharmony_ci if (err) 2718c2ecf20Sopenharmony_ci goto rollback; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci block->rule_count++; 2758c2ecf20Sopenharmony_ci if (mall_entry->ingress) 2768c2ecf20Sopenharmony_ci block->egress_blocker_rule_count++; 2778c2ecf20Sopenharmony_ci else 2788c2ecf20Sopenharmony_ci block->ingress_blocker_rule_count++; 2798c2ecf20Sopenharmony_ci list_add_tail(&mall_entry->list, &block->mall.list); 2808c2ecf20Sopenharmony_ci mlxsw_sp_mall_prio_update(block); 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cirollback: 2848c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(binding, &block->binding_list, 2858c2ecf20Sopenharmony_ci list) 2868c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_rule_del(binding->mlxsw_sp_port, mall_entry); 2878c2ecf20Sopenharmony_cierrout: 2888c2ecf20Sopenharmony_ci kfree(mall_entry); 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_civoid mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block *block, 2938c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload *f) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct mlxsw_sp_flow_block_binding *binding; 2968c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci mall_entry = mlxsw_sp_mall_entry_find(block, f->cookie); 2998c2ecf20Sopenharmony_ci if (!mall_entry) { 3008c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(f->common.extack, "Entry not found"); 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci list_del(&mall_entry->list); 3058c2ecf20Sopenharmony_ci if (mall_entry->ingress) 3068c2ecf20Sopenharmony_ci block->egress_blocker_rule_count--; 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci block->ingress_blocker_rule_count--; 3098c2ecf20Sopenharmony_ci block->rule_count--; 3108c2ecf20Sopenharmony_ci list_for_each_entry(binding, &block->binding_list, list) 3118c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_rule_del(binding->mlxsw_sp_port, mall_entry); 3128c2ecf20Sopenharmony_ci kfree_rcu(mall_entry, rcu); /* sample RX packets may be in-flight */ 3138c2ecf20Sopenharmony_ci mlxsw_sp_mall_prio_update(block); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciint mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, 3178c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry; 3208c2ecf20Sopenharmony_ci int err; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci list_for_each_entry(mall_entry, &block->mall.list, list) { 3238c2ecf20Sopenharmony_ci err = mlxsw_sp_mall_port_rule_add(mlxsw_sp_port, mall_entry); 3248c2ecf20Sopenharmony_ci if (err) 3258c2ecf20Sopenharmony_ci goto rollback; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cirollback: 3308c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(mall_entry, &block->mall.list, 3318c2ecf20Sopenharmony_ci list) 3328c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry); 3338c2ecf20Sopenharmony_ci return err; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_civoid mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block, 3378c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct mlxsw_sp_mall_entry *mall_entry; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci list_for_each_entry(mall_entry, &block->mall.list, list) 3428c2ecf20Sopenharmony_ci mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ciint mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block *block, u32 chain_index, 3468c2ecf20Sopenharmony_ci unsigned int *p_min_prio, unsigned int *p_max_prio) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci if (chain_index || list_empty(&block->mall.list)) 3498c2ecf20Sopenharmony_ci /* In case there are no matchall rules, the caller 3508c2ecf20Sopenharmony_ci * receives -ENOENT to indicate there is no need 3518c2ecf20Sopenharmony_ci * to check the priorities. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci return -ENOENT; 3548c2ecf20Sopenharmony_ci *p_min_prio = block->mall.min_prio; 3558c2ecf20Sopenharmony_ci *p_max_prio = block->mall.max_prio; 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 358