brintos

brintos / linux-shallow public Read only

0
0
Text · 23.6 KiB · 701a873 Raw
892 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * DPAA2 Ethernet Switch flower support4 *5 * Copyright 2021 NXP6 *7 */8 9#include "dpaa2-switch.h"10 11static int dpaa2_switch_flower_parse_key(struct flow_cls_offload *cls,12					 struct dpsw_acl_key *acl_key)13{14	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);15	struct flow_dissector *dissector = rule->match.dissector;16	struct netlink_ext_ack *extack = cls->common.extack;17	struct dpsw_acl_fields *acl_h, *acl_m;18 19	if (dissector->used_keys &20	    ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |21	      BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |22	      BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |23	      BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |24	      BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |25	      BIT_ULL(FLOW_DISSECTOR_KEY_IP) |26	      BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |27	      BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS))) {28		NL_SET_ERR_MSG_MOD(extack,29				   "Unsupported keys used");30		return -EOPNOTSUPP;31	}32 33	acl_h = &acl_key->match;34	acl_m = &acl_key->mask;35 36	if (flow_rule_match_has_control_flags(rule, extack))37		return -EOPNOTSUPP;38 39	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {40		struct flow_match_basic match;41 42		flow_rule_match_basic(rule, &match);43		acl_h->l3_protocol = match.key->ip_proto;44		acl_h->l2_ether_type = be16_to_cpu(match.key->n_proto);45		acl_m->l3_protocol = match.mask->ip_proto;46		acl_m->l2_ether_type = be16_to_cpu(match.mask->n_proto);47	}48 49	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {50		struct flow_match_eth_addrs match;51 52		flow_rule_match_eth_addrs(rule, &match);53		ether_addr_copy(acl_h->l2_dest_mac, &match.key->dst[0]);54		ether_addr_copy(acl_h->l2_source_mac, &match.key->src[0]);55		ether_addr_copy(acl_m->l2_dest_mac, &match.mask->dst[0]);56		ether_addr_copy(acl_m->l2_source_mac, &match.mask->src[0]);57	}58 59	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {60		struct flow_match_vlan match;61 62		flow_rule_match_vlan(rule, &match);63		acl_h->l2_vlan_id = match.key->vlan_id;64		acl_h->l2_tpid = be16_to_cpu(match.key->vlan_tpid);65		acl_h->l2_pcp_dei = match.key->vlan_priority << 1 |66				    match.key->vlan_dei;67 68		acl_m->l2_vlan_id = match.mask->vlan_id;69		acl_m->l2_tpid = be16_to_cpu(match.mask->vlan_tpid);70		acl_m->l2_pcp_dei = match.mask->vlan_priority << 1 |71				    match.mask->vlan_dei;72	}73 74	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {75		struct flow_match_ipv4_addrs match;76 77		flow_rule_match_ipv4_addrs(rule, &match);78		acl_h->l3_source_ip = be32_to_cpu(match.key->src);79		acl_h->l3_dest_ip = be32_to_cpu(match.key->dst);80		acl_m->l3_source_ip = be32_to_cpu(match.mask->src);81		acl_m->l3_dest_ip = be32_to_cpu(match.mask->dst);82	}83 84	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {85		struct flow_match_ports match;86 87		flow_rule_match_ports(rule, &match);88		acl_h->l4_source_port = be16_to_cpu(match.key->src);89		acl_h->l4_dest_port = be16_to_cpu(match.key->dst);90		acl_m->l4_source_port = be16_to_cpu(match.mask->src);91		acl_m->l4_dest_port = be16_to_cpu(match.mask->dst);92	}93 94	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {95		struct flow_match_ip match;96 97		flow_rule_match_ip(rule, &match);98		if (match.mask->ttl != 0) {99			NL_SET_ERR_MSG_MOD(extack,100					   "Matching on TTL not supported");101			return -EOPNOTSUPP;102		}103 104		if ((match.mask->tos & 0x3) != 0) {105			NL_SET_ERR_MSG_MOD(extack,106					   "Matching on ECN not supported, only DSCP");107			return -EOPNOTSUPP;108		}109 110		acl_h->l3_dscp = match.key->tos >> 2;111		acl_m->l3_dscp = match.mask->tos >> 2;112	}113 114	return 0;115}116 117int dpaa2_switch_acl_entry_add(struct dpaa2_switch_filter_block *filter_block,118			       struct dpaa2_switch_acl_entry *entry)119{120	struct dpsw_acl_entry_cfg *acl_entry_cfg = &entry->cfg;121	struct ethsw_core *ethsw = filter_block->ethsw;122	struct dpsw_acl_key *acl_key = &entry->key;123	struct device *dev = ethsw->dev;124	u8 *cmd_buff;125	int err;126 127	cmd_buff = kzalloc(DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE, GFP_KERNEL);128	if (!cmd_buff)129		return -ENOMEM;130 131	dpsw_acl_prepare_entry_cfg(acl_key, cmd_buff);132 133	acl_entry_cfg->key_iova = dma_map_single(dev, cmd_buff,134						 DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE,135						 DMA_TO_DEVICE);136	if (unlikely(dma_mapping_error(dev, acl_entry_cfg->key_iova))) {137		dev_err(dev, "DMA mapping failed\n");138		kfree(cmd_buff);139		return -EFAULT;140	}141 142	err = dpsw_acl_add_entry(ethsw->mc_io, 0, ethsw->dpsw_handle,143				 filter_block->acl_id, acl_entry_cfg);144 145	dma_unmap_single(dev, acl_entry_cfg->key_iova,146			 DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE,147			 DMA_TO_DEVICE);148	if (err) {149		dev_err(dev, "dpsw_acl_add_entry() failed %d\n", err);150		kfree(cmd_buff);151		return err;152	}153 154	kfree(cmd_buff);155 156	return 0;157}158 159static int160dpaa2_switch_acl_entry_remove(struct dpaa2_switch_filter_block *block,161			      struct dpaa2_switch_acl_entry *entry)162{163	struct dpsw_acl_entry_cfg *acl_entry_cfg = &entry->cfg;164	struct dpsw_acl_key *acl_key = &entry->key;165	struct ethsw_core *ethsw = block->ethsw;166	struct device *dev = ethsw->dev;167	u8 *cmd_buff;168	int err;169 170	cmd_buff = kzalloc(DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE, GFP_KERNEL);171	if (!cmd_buff)172		return -ENOMEM;173 174	dpsw_acl_prepare_entry_cfg(acl_key, cmd_buff);175 176	acl_entry_cfg->key_iova = dma_map_single(dev, cmd_buff,177						 DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE,178						 DMA_TO_DEVICE);179	if (unlikely(dma_mapping_error(dev, acl_entry_cfg->key_iova))) {180		dev_err(dev, "DMA mapping failed\n");181		kfree(cmd_buff);182		return -EFAULT;183	}184 185	err = dpsw_acl_remove_entry(ethsw->mc_io, 0, ethsw->dpsw_handle,186				    block->acl_id, acl_entry_cfg);187 188	dma_unmap_single(dev, acl_entry_cfg->key_iova,189			 DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE, DMA_TO_DEVICE);190	if (err) {191		dev_err(dev, "dpsw_acl_remove_entry() failed %d\n", err);192		kfree(cmd_buff);193		return err;194	}195 196	kfree(cmd_buff);197 198	return 0;199}200 201static int202dpaa2_switch_acl_entry_add_to_list(struct dpaa2_switch_filter_block *block,203				   struct dpaa2_switch_acl_entry *entry)204{205	struct dpaa2_switch_acl_entry *tmp;206	struct list_head *pos, *n;207	int index = 0;208 209	if (list_empty(&block->acl_entries)) {210		list_add(&entry->list, &block->acl_entries);211		return index;212	}213 214	list_for_each_safe(pos, n, &block->acl_entries) {215		tmp = list_entry(pos, struct dpaa2_switch_acl_entry, list);216		if (entry->prio < tmp->prio)217			break;218		index++;219	}220	list_add(&entry->list, pos->prev);221	return index;222}223 224static struct dpaa2_switch_acl_entry*225dpaa2_switch_acl_entry_get_by_index(struct dpaa2_switch_filter_block *block,226				    int index)227{228	struct dpaa2_switch_acl_entry *tmp;229	int i = 0;230 231	list_for_each_entry(tmp, &block->acl_entries, list) {232		if (i == index)233			return tmp;234		++i;235	}236 237	return NULL;238}239 240static int241dpaa2_switch_acl_entry_set_precedence(struct dpaa2_switch_filter_block *block,242				      struct dpaa2_switch_acl_entry *entry,243				      int precedence)244{245	int err;246 247	err = dpaa2_switch_acl_entry_remove(block, entry);248	if (err)249		return err;250 251	entry->cfg.precedence = precedence;252	return dpaa2_switch_acl_entry_add(block, entry);253}254 255static int256dpaa2_switch_acl_tbl_add_entry(struct dpaa2_switch_filter_block *block,257			       struct dpaa2_switch_acl_entry *entry)258{259	struct dpaa2_switch_acl_entry *tmp;260	int index, i, precedence, err;261 262	/* Add the new ACL entry to the linked list and get its index */263	index = dpaa2_switch_acl_entry_add_to_list(block, entry);264 265	/* Move up in priority the ACL entries to make space266	 * for the new filter.267	 */268	precedence = DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES - block->num_acl_rules - 1;269	for (i = 0; i < index; i++) {270		tmp = dpaa2_switch_acl_entry_get_by_index(block, i);271 272		err = dpaa2_switch_acl_entry_set_precedence(block, tmp,273							    precedence);274		if (err)275			return err;276 277		precedence++;278	}279 280	/* Add the new entry to hardware */281	entry->cfg.precedence = precedence;282	err = dpaa2_switch_acl_entry_add(block, entry);283	block->num_acl_rules++;284 285	return err;286}287 288static struct dpaa2_switch_acl_entry *289dpaa2_switch_acl_tbl_find_entry_by_cookie(struct dpaa2_switch_filter_block *block,290					  unsigned long cookie)291{292	struct dpaa2_switch_acl_entry *tmp, *n;293 294	list_for_each_entry_safe(tmp, n, &block->acl_entries, list) {295		if (tmp->cookie == cookie)296			return tmp;297	}298	return NULL;299}300 301static int302dpaa2_switch_acl_entry_get_index(struct dpaa2_switch_filter_block *block,303				 struct dpaa2_switch_acl_entry *entry)304{305	struct dpaa2_switch_acl_entry *tmp, *n;306	int index = 0;307 308	list_for_each_entry_safe(tmp, n, &block->acl_entries, list) {309		if (tmp->cookie == entry->cookie)310			return index;311		index++;312	}313	return -ENOENT;314}315 316static struct dpaa2_switch_mirror_entry *317dpaa2_switch_mirror_find_entry_by_cookie(struct dpaa2_switch_filter_block *block,318					 unsigned long cookie)319{320	struct dpaa2_switch_mirror_entry *tmp, *n;321 322	list_for_each_entry_safe(tmp, n, &block->mirror_entries, list) {323		if (tmp->cookie == cookie)324			return tmp;325	}326	return NULL;327}328 329static int330dpaa2_switch_acl_tbl_remove_entry(struct dpaa2_switch_filter_block *block,331				  struct dpaa2_switch_acl_entry *entry)332{333	struct dpaa2_switch_acl_entry *tmp;334	int index, i, precedence, err;335 336	index = dpaa2_switch_acl_entry_get_index(block, entry);337 338	/* Remove from hardware the ACL entry */339	err = dpaa2_switch_acl_entry_remove(block, entry);340	if (err)341		return err;342 343	block->num_acl_rules--;344 345	/* Remove it from the list also */346	list_del(&entry->list);347 348	/* Move down in priority the entries over the deleted one */349	precedence = entry->cfg.precedence;350	for (i = index - 1; i >= 0; i--) {351		tmp = dpaa2_switch_acl_entry_get_by_index(block, i);352		err = dpaa2_switch_acl_entry_set_precedence(block, tmp,353							    precedence);354		if (err)355			return err;356 357		precedence--;358	}359 360	kfree(entry);361 362	return 0;363}364 365static int dpaa2_switch_tc_parse_action_acl(struct ethsw_core *ethsw,366					    struct flow_action_entry *cls_act,367					    struct dpsw_acl_result *dpsw_act,368					    struct netlink_ext_ack *extack)369{370	int err = 0;371 372	switch (cls_act->id) {373	case FLOW_ACTION_TRAP:374		dpsw_act->action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;375		break;376	case FLOW_ACTION_REDIRECT:377		if (!dpaa2_switch_port_dev_check(cls_act->dev)) {378			NL_SET_ERR_MSG_MOD(extack,379					   "Destination not a DPAA2 switch port");380			return -EOPNOTSUPP;381		}382 383		dpsw_act->if_id = dpaa2_switch_get_index(ethsw, cls_act->dev);384		dpsw_act->action = DPSW_ACL_ACTION_REDIRECT;385		break;386	case FLOW_ACTION_DROP:387		dpsw_act->action = DPSW_ACL_ACTION_DROP;388		break;389	default:390		NL_SET_ERR_MSG_MOD(extack,391				   "Action not supported");392		err = -EOPNOTSUPP;393		goto out;394	}395 396out:397	return err;398}399 400static int401dpaa2_switch_block_add_mirror(struct dpaa2_switch_filter_block *block,402			      struct dpaa2_switch_mirror_entry *entry,403			      u16 to, struct netlink_ext_ack *extack)404{405	unsigned long block_ports = block->ports;406	struct ethsw_core *ethsw = block->ethsw;407	struct ethsw_port_priv *port_priv;408	unsigned long ports_added = 0;409	u16 vlan = entry->cfg.vlan_id;410	bool mirror_port_enabled;411	int err, port;412 413	/* Setup the mirroring port */414	mirror_port_enabled = (ethsw->mirror_port != ethsw->sw_attr.num_ifs);415	if (!mirror_port_enabled) {416		err = dpsw_set_reflection_if(ethsw->mc_io, 0,417					     ethsw->dpsw_handle, to);418		if (err)419			return err;420		ethsw->mirror_port = to;421	}422 423	/* Setup the same egress mirroring configuration on all the switch424	 * ports that share the same filter block.425	 */426	for_each_set_bit(port, &block_ports, ethsw->sw_attr.num_ifs) {427		port_priv = ethsw->ports[port];428 429		/* We cannot add a per VLAN mirroring rule if the VLAN in430		 * question is not installed on the switch port.431		 */432		if (entry->cfg.filter == DPSW_REFLECTION_FILTER_INGRESS_VLAN &&433		    !(port_priv->vlans[vlan] & ETHSW_VLAN_MEMBER)) {434			NL_SET_ERR_MSG(extack,435				       "VLAN must be installed on the switch port");436			err = -EINVAL;437			goto err_remove_filters;438		}439 440		err = dpsw_if_add_reflection(ethsw->mc_io, 0,441					     ethsw->dpsw_handle,442					     port, &entry->cfg);443		if (err)444			goto err_remove_filters;445 446		ports_added |= BIT(port);447	}448 449	list_add(&entry->list, &block->mirror_entries);450 451	return 0;452 453err_remove_filters:454	for_each_set_bit(port, &ports_added, ethsw->sw_attr.num_ifs) {455		dpsw_if_remove_reflection(ethsw->mc_io, 0, ethsw->dpsw_handle,456					  port, &entry->cfg);457	}458 459	if (!mirror_port_enabled)460		ethsw->mirror_port = ethsw->sw_attr.num_ifs;461 462	return err;463}464 465static int466dpaa2_switch_block_remove_mirror(struct dpaa2_switch_filter_block *block,467				 struct dpaa2_switch_mirror_entry *entry)468{469	struct dpsw_reflection_cfg *cfg = &entry->cfg;470	unsigned long block_ports = block->ports;471	struct ethsw_core *ethsw = block->ethsw;472	int port;473 474	/* Remove this mirroring configuration from all the ports belonging to475	 * the filter block.476	 */477	for_each_set_bit(port, &block_ports, ethsw->sw_attr.num_ifs)478		dpsw_if_remove_reflection(ethsw->mc_io, 0, ethsw->dpsw_handle,479					  port, cfg);480 481	/* Also remove it from the list of mirror filters */482	list_del(&entry->list);483	kfree(entry);484 485	/* If this was the last mirror filter, then unset the mirror port */486	if (list_empty(&block->mirror_entries))487		ethsw->mirror_port =  ethsw->sw_attr.num_ifs;488 489	return 0;490}491 492static int493dpaa2_switch_cls_flower_replace_acl(struct dpaa2_switch_filter_block *block,494				    struct flow_cls_offload *cls)495{496	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);497	struct netlink_ext_ack *extack = cls->common.extack;498	struct dpaa2_switch_acl_entry *acl_entry;499	struct ethsw_core *ethsw = block->ethsw;500	struct flow_action_entry *act;501	int err;502 503	if (dpaa2_switch_acl_tbl_is_full(block)) {504		NL_SET_ERR_MSG(extack, "Maximum filter capacity reached");505		return -ENOMEM;506	}507 508	acl_entry = kzalloc(sizeof(*acl_entry), GFP_KERNEL);509	if (!acl_entry)510		return -ENOMEM;511 512	err = dpaa2_switch_flower_parse_key(cls, &acl_entry->key);513	if (err)514		goto free_acl_entry;515 516	act = &rule->action.entries[0];517	err = dpaa2_switch_tc_parse_action_acl(ethsw, act,518					       &acl_entry->cfg.result, extack);519	if (err)520		goto free_acl_entry;521 522	acl_entry->prio = cls->common.prio;523	acl_entry->cookie = cls->cookie;524 525	err = dpaa2_switch_acl_tbl_add_entry(block, acl_entry);526	if (err)527		goto free_acl_entry;528 529	return 0;530 531free_acl_entry:532	kfree(acl_entry);533 534	return err;535}536 537static int dpaa2_switch_flower_parse_mirror_key(struct flow_cls_offload *cls,538						u16 *vlan)539{540	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);541	struct flow_dissector *dissector = rule->match.dissector;542	struct netlink_ext_ack *extack = cls->common.extack;543	int ret = -EOPNOTSUPP;544 545	if (dissector->used_keys &546	    ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |547	      BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |548	      BIT_ULL(FLOW_DISSECTOR_KEY_VLAN))) {549		NL_SET_ERR_MSG_MOD(extack,550				   "Mirroring is supported only per VLAN");551		return -EOPNOTSUPP;552	}553 554	if (flow_rule_match_has_control_flags(rule, extack))555		return -EOPNOTSUPP;556 557	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {558		struct flow_match_vlan match;559 560		flow_rule_match_vlan(rule, &match);561 562		if (match.mask->vlan_priority != 0 ||563		    match.mask->vlan_dei != 0) {564			NL_SET_ERR_MSG_MOD(extack,565					   "Only matching on VLAN ID supported");566			return -EOPNOTSUPP;567		}568 569		if (match.mask->vlan_id != 0xFFF) {570			NL_SET_ERR_MSG_MOD(extack,571					   "Masked matching not supported");572			return -EOPNOTSUPP;573		}574 575		*vlan = (u16)match.key->vlan_id;576		ret = 0;577	}578 579	return ret;580}581 582static int583dpaa2_switch_cls_flower_replace_mirror(struct dpaa2_switch_filter_block *block,584				       struct flow_cls_offload *cls)585{586	struct netlink_ext_ack *extack = cls->common.extack;587	struct dpaa2_switch_mirror_entry *mirror_entry;588	struct ethsw_core *ethsw = block->ethsw;589	struct dpaa2_switch_mirror_entry *tmp;590	struct flow_action_entry *cls_act;591	struct list_head *pos, *n;592	bool mirror_port_enabled;593	u16 if_id, vlan;594	int err;595 596	mirror_port_enabled = (ethsw->mirror_port != ethsw->sw_attr.num_ifs);597	cls_act = &cls->rule->action.entries[0];598 599	/* Offload rules only when the destination is a DPAA2 switch port */600	if (!dpaa2_switch_port_dev_check(cls_act->dev)) {601		NL_SET_ERR_MSG_MOD(extack,602				   "Destination not a DPAA2 switch port");603		return -EOPNOTSUPP;604	}605	if_id = dpaa2_switch_get_index(ethsw, cls_act->dev);606 607	/* We have a single mirror port but can configure egress mirroring on608	 * all the other switch ports. We need to allow mirroring rules only609	 * when the destination port is the same.610	 */611	if (mirror_port_enabled && ethsw->mirror_port != if_id) {612		NL_SET_ERR_MSG_MOD(extack,613				   "Multiple mirror ports not supported");614		return -EBUSY;615	}616 617	/* Parse the key */618	err = dpaa2_switch_flower_parse_mirror_key(cls, &vlan);619	if (err)620		return err;621 622	/* Make sure that we don't already have a mirror rule with the same623	 * configuration.624	 */625	list_for_each_safe(pos, n, &block->mirror_entries) {626		tmp = list_entry(pos, struct dpaa2_switch_mirror_entry, list);627 628		if (tmp->cfg.filter == DPSW_REFLECTION_FILTER_INGRESS_VLAN &&629		    tmp->cfg.vlan_id == vlan) {630			NL_SET_ERR_MSG_MOD(extack,631					   "VLAN mirror filter already installed");632			return -EBUSY;633		}634	}635 636	mirror_entry = kzalloc(sizeof(*mirror_entry), GFP_KERNEL);637	if (!mirror_entry)638		return -ENOMEM;639 640	mirror_entry->cfg.filter = DPSW_REFLECTION_FILTER_INGRESS_VLAN;641	mirror_entry->cfg.vlan_id = vlan;642	mirror_entry->cookie = cls->cookie;643 644	return dpaa2_switch_block_add_mirror(block, mirror_entry, if_id,645					     extack);646}647 648int dpaa2_switch_cls_flower_replace(struct dpaa2_switch_filter_block *block,649				    struct flow_cls_offload *cls)650{651	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);652	struct netlink_ext_ack *extack = cls->common.extack;653	struct flow_action_entry *act;654 655	if (!flow_offload_has_one_action(&rule->action)) {656		NL_SET_ERR_MSG(extack, "Only singular actions are supported");657		return -EOPNOTSUPP;658	}659 660	act = &rule->action.entries[0];661	switch (act->id) {662	case FLOW_ACTION_REDIRECT:663	case FLOW_ACTION_TRAP:664	case FLOW_ACTION_DROP:665		return dpaa2_switch_cls_flower_replace_acl(block, cls);666	case FLOW_ACTION_MIRRED:667		return dpaa2_switch_cls_flower_replace_mirror(block, cls);668	default:669		NL_SET_ERR_MSG_MOD(extack, "Action not supported");670		return -EOPNOTSUPP;671	}672}673 674int dpaa2_switch_cls_flower_destroy(struct dpaa2_switch_filter_block *block,675				    struct flow_cls_offload *cls)676{677	struct dpaa2_switch_mirror_entry *mirror_entry;678	struct dpaa2_switch_acl_entry *acl_entry;679 680	/* If this filter is a an ACL one, remove it */681	acl_entry = dpaa2_switch_acl_tbl_find_entry_by_cookie(block,682							      cls->cookie);683	if (acl_entry)684		return dpaa2_switch_acl_tbl_remove_entry(block, acl_entry);685 686	/* If not, then it has to be a mirror */687	mirror_entry = dpaa2_switch_mirror_find_entry_by_cookie(block,688								cls->cookie);689	if (mirror_entry)690		return dpaa2_switch_block_remove_mirror(block,691							mirror_entry);692 693	return 0;694}695 696static int697dpaa2_switch_cls_matchall_replace_acl(struct dpaa2_switch_filter_block *block,698				      struct tc_cls_matchall_offload *cls)699{700	struct netlink_ext_ack *extack = cls->common.extack;701	struct ethsw_core *ethsw = block->ethsw;702	struct dpaa2_switch_acl_entry *acl_entry;703	struct flow_action_entry *act;704	int err;705 706	if (dpaa2_switch_acl_tbl_is_full(block)) {707		NL_SET_ERR_MSG(extack, "Maximum filter capacity reached");708		return -ENOMEM;709	}710 711	acl_entry = kzalloc(sizeof(*acl_entry), GFP_KERNEL);712	if (!acl_entry)713		return -ENOMEM;714 715	act = &cls->rule->action.entries[0];716	err = dpaa2_switch_tc_parse_action_acl(ethsw, act,717					       &acl_entry->cfg.result, extack);718	if (err)719		goto free_acl_entry;720 721	acl_entry->prio = cls->common.prio;722	acl_entry->cookie = cls->cookie;723 724	err = dpaa2_switch_acl_tbl_add_entry(block, acl_entry);725	if (err)726		goto free_acl_entry;727 728	return 0;729 730free_acl_entry:731	kfree(acl_entry);732 733	return err;734}735 736static int737dpaa2_switch_cls_matchall_replace_mirror(struct dpaa2_switch_filter_block *block,738					 struct tc_cls_matchall_offload *cls)739{740	struct netlink_ext_ack *extack = cls->common.extack;741	struct dpaa2_switch_mirror_entry *mirror_entry;742	struct ethsw_core *ethsw = block->ethsw;743	struct dpaa2_switch_mirror_entry *tmp;744	struct flow_action_entry *cls_act;745	struct list_head *pos, *n;746	bool mirror_port_enabled;747	u16 if_id;748 749	mirror_port_enabled = (ethsw->mirror_port != ethsw->sw_attr.num_ifs);750	cls_act = &cls->rule->action.entries[0];751 752	/* Offload rules only when the destination is a DPAA2 switch port */753	if (!dpaa2_switch_port_dev_check(cls_act->dev)) {754		NL_SET_ERR_MSG_MOD(extack,755				   "Destination not a DPAA2 switch port");756		return -EOPNOTSUPP;757	}758	if_id = dpaa2_switch_get_index(ethsw, cls_act->dev);759 760	/* We have a single mirror port but can configure egress mirroring on761	 * all the other switch ports. We need to allow mirroring rules only762	 * when the destination port is the same.763	 */764	if (mirror_port_enabled && ethsw->mirror_port != if_id) {765		NL_SET_ERR_MSG_MOD(extack,766				   "Multiple mirror ports not supported");767		return -EBUSY;768	}769 770	/* Make sure that we don't already have a mirror rule with the same771	 * configuration. One matchall rule per block is the maximum.772	 */773	list_for_each_safe(pos, n, &block->mirror_entries) {774		tmp = list_entry(pos, struct dpaa2_switch_mirror_entry, list);775 776		if (tmp->cfg.filter == DPSW_REFLECTION_FILTER_INGRESS_ALL) {777			NL_SET_ERR_MSG_MOD(extack,778					   "Matchall mirror filter already installed");779			return -EBUSY;780		}781	}782 783	mirror_entry = kzalloc(sizeof(*mirror_entry), GFP_KERNEL);784	if (!mirror_entry)785		return -ENOMEM;786 787	mirror_entry->cfg.filter = DPSW_REFLECTION_FILTER_INGRESS_ALL;788	mirror_entry->cookie = cls->cookie;789 790	return dpaa2_switch_block_add_mirror(block, mirror_entry, if_id,791					     extack);792}793 794int dpaa2_switch_cls_matchall_replace(struct dpaa2_switch_filter_block *block,795				      struct tc_cls_matchall_offload *cls)796{797	struct netlink_ext_ack *extack = cls->common.extack;798	struct flow_action_entry *act;799 800	if (!flow_offload_has_one_action(&cls->rule->action)) {801		NL_SET_ERR_MSG(extack, "Only singular actions are supported");802		return -EOPNOTSUPP;803	}804 805	act = &cls->rule->action.entries[0];806	switch (act->id) {807	case FLOW_ACTION_REDIRECT:808	case FLOW_ACTION_TRAP:809	case FLOW_ACTION_DROP:810		return dpaa2_switch_cls_matchall_replace_acl(block, cls);811	case FLOW_ACTION_MIRRED:812		return dpaa2_switch_cls_matchall_replace_mirror(block, cls);813	default:814		NL_SET_ERR_MSG_MOD(extack, "Action not supported");815		return -EOPNOTSUPP;816	}817}818 819int dpaa2_switch_block_offload_mirror(struct dpaa2_switch_filter_block *block,820				      struct ethsw_port_priv *port_priv)821{822	struct ethsw_core *ethsw = port_priv->ethsw_data;823	struct dpaa2_switch_mirror_entry *tmp;824	int err;825 826	list_for_each_entry(tmp, &block->mirror_entries, list) {827		err = dpsw_if_add_reflection(ethsw->mc_io, 0,828					     ethsw->dpsw_handle,829					     port_priv->idx, &tmp->cfg);830		if (err)831			goto unwind_add;832	}833 834	return 0;835 836unwind_add:837	list_for_each_entry(tmp, &block->mirror_entries, list)838		dpsw_if_remove_reflection(ethsw->mc_io, 0,839					  ethsw->dpsw_handle,840					  port_priv->idx, &tmp->cfg);841 842	return err;843}844 845int dpaa2_switch_block_unoffload_mirror(struct dpaa2_switch_filter_block *block,846					struct ethsw_port_priv *port_priv)847{848	struct ethsw_core *ethsw = port_priv->ethsw_data;849	struct dpaa2_switch_mirror_entry *tmp;850	int err;851 852	list_for_each_entry(tmp, &block->mirror_entries, list) {853		err = dpsw_if_remove_reflection(ethsw->mc_io, 0,854						ethsw->dpsw_handle,855						port_priv->idx, &tmp->cfg);856		if (err)857			goto unwind_remove;858	}859 860	return 0;861 862unwind_remove:863	list_for_each_entry(tmp, &block->mirror_entries, list)864		dpsw_if_add_reflection(ethsw->mc_io, 0, ethsw->dpsw_handle,865				       port_priv->idx, &tmp->cfg);866 867	return err;868}869 870int dpaa2_switch_cls_matchall_destroy(struct dpaa2_switch_filter_block *block,871				      struct tc_cls_matchall_offload *cls)872{873	struct dpaa2_switch_mirror_entry *mirror_entry;874	struct dpaa2_switch_acl_entry *acl_entry;875 876	/* If this filter is a an ACL one, remove it */877	acl_entry = dpaa2_switch_acl_tbl_find_entry_by_cookie(block,878							      cls->cookie);879	if (acl_entry)880		return dpaa2_switch_acl_tbl_remove_entry(block,881							 acl_entry);882 883	/* If not, then it has to be a mirror */884	mirror_entry = dpaa2_switch_mirror_find_entry_by_cookie(block,885								cls->cookie);886	if (mirror_entry)887		return dpaa2_switch_block_remove_mirror(block,888							mirror_entry);889 890	return 0;891}892