cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dpaa2-switch-flower.c (23883B)


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