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