162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "ice_lib.h"
562306a36Sopenharmony_ci#include "ice_switch.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define ICE_ETH_DA_OFFSET		0
862306a36Sopenharmony_ci#define ICE_ETH_ETHTYPE_OFFSET		12
962306a36Sopenharmony_ci#define ICE_ETH_VLAN_TCI_OFFSET		14
1062306a36Sopenharmony_ci#define ICE_MAX_VLAN_ID			0xFFF
1162306a36Sopenharmony_ci#define ICE_IPV6_ETHER_ID		0x86DD
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* Dummy ethernet header needed in the ice_aqc_sw_rules_elem
1462306a36Sopenharmony_ci * struct to configure any switch filter rules.
1562306a36Sopenharmony_ci * {DA (6 bytes), SA(6 bytes),
1662306a36Sopenharmony_ci * Ether type (2 bytes for header without VLAN tag) OR
1762306a36Sopenharmony_ci * VLAN tag (4 bytes for header with VLAN tag) }
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Word on Hardcoded values
2062306a36Sopenharmony_ci * byte 0 = 0x2: to identify it as locally administered DA MAC
2162306a36Sopenharmony_ci * byte 6 = 0x2: to identify it as locally administered SA MAC
2262306a36Sopenharmony_ci * byte 12 = 0x81 & byte 13 = 0x00:
2362306a36Sopenharmony_ci *      In case of VLAN filter first two bytes defines ether type (0x8100)
2462306a36Sopenharmony_ci *      and remaining two bytes are placeholder for programming a given VLAN ID
2562306a36Sopenharmony_ci *      In case of Ether type filter it is treated as header without VLAN tag
2662306a36Sopenharmony_ci *      and byte 12 and 13 is used to program a given Ether type instead
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_cistatic const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
2962306a36Sopenharmony_ci							0x2, 0, 0, 0, 0, 0,
3062306a36Sopenharmony_ci							0x81, 0, 0, 0};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cienum {
3362306a36Sopenharmony_ci	ICE_PKT_OUTER_IPV6	= BIT(0),
3462306a36Sopenharmony_ci	ICE_PKT_TUN_GTPC	= BIT(1),
3562306a36Sopenharmony_ci	ICE_PKT_TUN_GTPU	= BIT(2),
3662306a36Sopenharmony_ci	ICE_PKT_TUN_NVGRE	= BIT(3),
3762306a36Sopenharmony_ci	ICE_PKT_TUN_UDP		= BIT(4),
3862306a36Sopenharmony_ci	ICE_PKT_INNER_IPV6	= BIT(5),
3962306a36Sopenharmony_ci	ICE_PKT_INNER_TCP	= BIT(6),
4062306a36Sopenharmony_ci	ICE_PKT_INNER_UDP	= BIT(7),
4162306a36Sopenharmony_ci	ICE_PKT_GTP_NOPAY	= BIT(8),
4262306a36Sopenharmony_ci	ICE_PKT_KMALLOC		= BIT(9),
4362306a36Sopenharmony_ci	ICE_PKT_PPPOE		= BIT(10),
4462306a36Sopenharmony_ci	ICE_PKT_L2TPV3		= BIT(11),
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct ice_dummy_pkt_offsets {
4862306a36Sopenharmony_ci	enum ice_protocol_type type;
4962306a36Sopenharmony_ci	u16 offset; /* ICE_PROTOCOL_LAST indicates end of list */
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct ice_dummy_pkt_profile {
5362306a36Sopenharmony_ci	const struct ice_dummy_pkt_offsets *offsets;
5462306a36Sopenharmony_ci	const u8 *pkt;
5562306a36Sopenharmony_ci	u32 match;
5662306a36Sopenharmony_ci	u16 pkt_len;
5762306a36Sopenharmony_ci	u16 offsets_len;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define ICE_DECLARE_PKT_OFFSETS(type)					\
6162306a36Sopenharmony_ci	static const struct ice_dummy_pkt_offsets			\
6262306a36Sopenharmony_ci	ice_dummy_##type##_packet_offsets[]
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define ICE_DECLARE_PKT_TEMPLATE(type)					\
6562306a36Sopenharmony_ci	static const u8 ice_dummy_##type##_packet[]
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define ICE_PKT_PROFILE(type, m) {					\
6862306a36Sopenharmony_ci	.match		= (m),						\
6962306a36Sopenharmony_ci	.pkt		= ice_dummy_##type##_packet,			\
7062306a36Sopenharmony_ci	.pkt_len	= sizeof(ice_dummy_##type##_packet),		\
7162306a36Sopenharmony_ci	.offsets	= ice_dummy_##type##_packet_offsets,		\
7262306a36Sopenharmony_ci	.offsets_len	= sizeof(ice_dummy_##type##_packet_offsets),	\
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(vlan) = {
7662306a36Sopenharmony_ci	{ ICE_VLAN_OFOS,        12 },
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(vlan) = {
8062306a36Sopenharmony_ci	0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(qinq) = {
8462306a36Sopenharmony_ci	{ ICE_VLAN_EX,          12 },
8562306a36Sopenharmony_ci	{ ICE_VLAN_IN,          16 },
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(qinq) = {
8962306a36Sopenharmony_ci	0x91, 0x00, 0x00, 0x00, /* ICE_VLAN_EX 12 */
9062306a36Sopenharmony_ci	0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_IN 16 */
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(gre_tcp) = {
9462306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
9562306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
9662306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
9762306a36Sopenharmony_ci	{ ICE_NVGRE,		34 },
9862306a36Sopenharmony_ci	{ ICE_MAC_IL,		42 },
9962306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		54 },
10062306a36Sopenharmony_ci	{ ICE_IPV4_IL,		56 },
10162306a36Sopenharmony_ci	{ ICE_TCP_IL,		76 },
10262306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(gre_tcp) = {
10662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_OFOS 0 */
10762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
10862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x3E,	/* ICE_IPV4_OFOS 14 */
11362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
11462306a36Sopenharmony_ci	0x00, 0x2F, 0x00, 0x00,
11562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
11662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	0x80, 0x00, 0x65, 0x58,	/* ICE_NVGRE 34 */
11962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_IL 42 */
12262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
12362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_IL 54 */
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x14,	/* ICE_IPV4_IL 56 */
12862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
12962306a36Sopenharmony_ci	0x00, 0x06, 0x00, 0x00,
13062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
13162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,	/* ICE_TCP_IL 76 */
13462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
13562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
13662306a36Sopenharmony_ci	0x50, 0x02, 0x20, 0x00,
13762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(gre_udp) = {
14162306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
14262306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
14362306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
14462306a36Sopenharmony_ci	{ ICE_NVGRE,		34 },
14562306a36Sopenharmony_ci	{ ICE_MAC_IL,		42 },
14662306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		54 },
14762306a36Sopenharmony_ci	{ ICE_IPV4_IL,		56 },
14862306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		76 },
14962306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(gre_udp) = {
15362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_OFOS 0 */
15462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
15562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x3E,	/* ICE_IPV4_OFOS 14 */
16062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
16162306a36Sopenharmony_ci	0x00, 0x2F, 0x00, 0x00,
16262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
16362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	0x80, 0x00, 0x65, 0x58,	/* ICE_NVGRE 34 */
16662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_IL 42 */
16962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
17062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_IL 54 */
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x14,	/* ICE_IPV4_IL 56 */
17562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
17662306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
17762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
17862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,	/* ICE_UDP_ILOS 76 */
18162306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(udp_tun_tcp) = {
18562306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
18662306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
18762306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
18862306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
18962306a36Sopenharmony_ci	{ ICE_VXLAN,		42 },
19062306a36Sopenharmony_ci	{ ICE_GENEVE,		42 },
19162306a36Sopenharmony_ci	{ ICE_VXLAN_GPE,	42 },
19262306a36Sopenharmony_ci	{ ICE_MAC_IL,		50 },
19362306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		62 },
19462306a36Sopenharmony_ci	{ ICE_IPV4_IL,		64 },
19562306a36Sopenharmony_ci	{ ICE_TCP_IL,		84 },
19662306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(udp_tun_tcp) = {
20062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
20162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
20262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */
20762306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
20862306a36Sopenharmony_ci	0x40, 0x11, 0x00, 0x00,
20962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
21062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
21362306a36Sopenharmony_ci	0x00, 0x46, 0x00, 0x00,
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
21662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
21962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
22062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_IL 62 */
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_IL 64 */
22562306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
22662306a36Sopenharmony_ci	0x40, 0x06, 0x00, 0x00,
22762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
22862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 84 */
23162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
23262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
23362306a36Sopenharmony_ci	0x50, 0x02, 0x20, 0x00,
23462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(udp_tun_udp) = {
23862306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
23962306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
24062306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
24162306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
24262306a36Sopenharmony_ci	{ ICE_VXLAN,		42 },
24362306a36Sopenharmony_ci	{ ICE_GENEVE,		42 },
24462306a36Sopenharmony_ci	{ ICE_VXLAN_GPE,	42 },
24562306a36Sopenharmony_ci	{ ICE_MAC_IL,		50 },
24662306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		62 },
24762306a36Sopenharmony_ci	{ ICE_IPV4_IL,		64 },
24862306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		84 },
24962306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
25062306a36Sopenharmony_ci};
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(udp_tun_udp) = {
25362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
25462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
25562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x4e, /* ICE_IPV4_OFOS 14 */
26062306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
26162306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
26262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
26362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
26662306a36Sopenharmony_ci	0x00, 0x3a, 0x00, 0x00,
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
26962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
27262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
27362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_IL 62 */
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_IL 64 */
27862306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
27962306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
28062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
28162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 84 */
28462306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(gre_ipv6_tcp) = {
28862306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
28962306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
29062306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
29162306a36Sopenharmony_ci	{ ICE_NVGRE,		34 },
29262306a36Sopenharmony_ci	{ ICE_MAC_IL,		42 },
29362306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		54 },
29462306a36Sopenharmony_ci	{ ICE_IPV6_IL,		56 },
29562306a36Sopenharmony_ci	{ ICE_TCP_IL,		96 },
29662306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(gre_ipv6_tcp) = {
30062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
30162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
30262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x66, /* ICE_IPV4_OFOS 14 */
30762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
30862306a36Sopenharmony_ci	0x00, 0x2F, 0x00, 0x00,
30962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
31062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */
31362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */
31662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
31762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	0x86, 0xdd,		/* ICE_ETYPE_IL 54 */
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 56 */
32262306a36Sopenharmony_ci	0x00, 0x08, 0x06, 0x40,
32362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
32462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
32562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
32662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
32762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
32862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
32962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
33062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 96 */
33362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
33462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
33562306a36Sopenharmony_ci	0x50, 0x02, 0x20, 0x00,
33662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(gre_ipv6_udp) = {
34062306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
34162306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
34262306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
34362306a36Sopenharmony_ci	{ ICE_NVGRE,		34 },
34462306a36Sopenharmony_ci	{ ICE_MAC_IL,		42 },
34562306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		54 },
34662306a36Sopenharmony_ci	{ ICE_IPV6_IL,		56 },
34762306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		96 },
34862306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
34962306a36Sopenharmony_ci};
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(gre_ipv6_udp) = {
35262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
35362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
35462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */
35962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
36062306a36Sopenharmony_ci	0x00, 0x2F, 0x00, 0x00,
36162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
36262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */
36562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */
36862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
36962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	0x86, 0xdd,		/* ICE_ETYPE_IL 54 */
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 56 */
37462306a36Sopenharmony_ci	0x00, 0x08, 0x11, 0x40,
37562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
37662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
37762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
37862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
37962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
38062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
38162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
38262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 96 */
38562306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
38662306a36Sopenharmony_ci};
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(udp_tun_ipv6_tcp) = {
38962306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
39062306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
39162306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
39262306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
39362306a36Sopenharmony_ci	{ ICE_VXLAN,		42 },
39462306a36Sopenharmony_ci	{ ICE_GENEVE,		42 },
39562306a36Sopenharmony_ci	{ ICE_VXLAN_GPE,	42 },
39662306a36Sopenharmony_ci	{ ICE_MAC_IL,		50 },
39762306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		62 },
39862306a36Sopenharmony_ci	{ ICE_IPV6_IL,		64 },
39962306a36Sopenharmony_ci	{ ICE_TCP_IL,		104 },
40062306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
40162306a36Sopenharmony_ci};
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(udp_tun_ipv6_tcp) = {
40462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
40562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
40662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x6e, /* ICE_IPV4_OFOS 14 */
41162306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
41262306a36Sopenharmony_ci	0x40, 0x11, 0x00, 0x00,
41362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
41462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
41762306a36Sopenharmony_ci	0x00, 0x5a, 0x00, 0x00,
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
42062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
42362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
42462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	0x86, 0xdd,		/* ICE_ETYPE_IL 62 */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 64 */
42962306a36Sopenharmony_ci	0x00, 0x08, 0x06, 0x40,
43062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 104 */
44062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
44162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
44262306a36Sopenharmony_ci	0x50, 0x02, 0x20, 0x00,
44362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(udp_tun_ipv6_udp) = {
44762306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
44862306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
44962306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
45062306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
45162306a36Sopenharmony_ci	{ ICE_VXLAN,		42 },
45262306a36Sopenharmony_ci	{ ICE_GENEVE,		42 },
45362306a36Sopenharmony_ci	{ ICE_VXLAN_GPE,	42 },
45462306a36Sopenharmony_ci	{ ICE_MAC_IL,		50 },
45562306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		62 },
45662306a36Sopenharmony_ci	{ ICE_IPV6_IL,		64 },
45762306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		104 },
45862306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
45962306a36Sopenharmony_ci};
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(udp_tun_ipv6_udp) = {
46262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
46362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
46462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x62, /* ICE_IPV4_OFOS 14 */
46962306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
47062306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
47162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
47262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
47562306a36Sopenharmony_ci	0x00, 0x4e, 0x00, 0x00,
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
47862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
48162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
48262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	0x86, 0xdd,		/* ICE_ETYPE_IL 62 */
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 64 */
48762306a36Sopenharmony_ci	0x00, 0x08, 0x11, 0x40,
48862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
48962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 104 */
49862306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
49962306a36Sopenharmony_ci};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/* offset info for MAC + IPv4 + UDP dummy packet */
50262306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(udp) = {
50362306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
50462306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
50562306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
50662306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		34 },
50762306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
50862306a36Sopenharmony_ci};
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci/* Dummy packet for MAC + IPv4 + UDP */
51162306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(udp) = {
51262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
51362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
51462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 14 */
51962306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
52062306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
52162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
52262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 34 */
52562306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
52862306a36Sopenharmony_ci};
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/* offset info for MAC + IPv4 + TCP dummy packet */
53162306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(tcp) = {
53262306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
53362306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
53462306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
53562306a36Sopenharmony_ci	{ ICE_TCP_IL,		34 },
53662306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
53762306a36Sopenharmony_ci};
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci/* Dummy packet for MAC + IPv4 + TCP */
54062306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(tcp) = {
54162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
54262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
54362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 14 */
54862306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
54962306a36Sopenharmony_ci	0x00, 0x06, 0x00, 0x00,
55062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
55162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 34 */
55462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
55562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
55662306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
55762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
56062306a36Sopenharmony_ci};
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(tcp_ipv6) = {
56362306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
56462306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
56562306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
56662306a36Sopenharmony_ci	{ ICE_TCP_IL,		54 },
56762306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
56862306a36Sopenharmony_ci};
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(tcp_ipv6) = {
57162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
57262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
57362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */
57862306a36Sopenharmony_ci	0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
57962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 54 */
58962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
59062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
59162306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
59262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
59562306a36Sopenharmony_ci};
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci/* IPv6 + UDP */
59862306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(udp_ipv6) = {
59962306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
60062306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
60162306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
60262306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		54 },
60362306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
60462306a36Sopenharmony_ci};
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci/* IPv6 + UDP dummy packet */
60762306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(udp_ipv6) = {
60862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
60962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
61062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */
61562306a36Sopenharmony_ci	0x00, 0x10, 0x11, 0x00, /* Next header UDP */
61662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
61762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
61862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
61962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
62062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
62162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
62262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
62362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 54 */
62662306a36Sopenharmony_ci	0x00, 0x10, 0x00, 0x00,
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* needed for ESP packets */
62962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
63262306a36Sopenharmony_ci};
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner TCP */
63562306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_tcp) = {
63662306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
63762306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
63862306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
63962306a36Sopenharmony_ci	{ ICE_GTP,		42 },
64062306a36Sopenharmony_ci	{ ICE_IPV4_IL,		62 },
64162306a36Sopenharmony_ci	{ ICE_TCP_IL,		82 },
64262306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
64362306a36Sopenharmony_ci};
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4_tcp) = {
64662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
64762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
64862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
64962306a36Sopenharmony_ci	0x08, 0x00,
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x58, /* IP 14 */
65262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
65362306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
65462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
65562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 34 */
65862306a36Sopenharmony_ci	0x00, 0x44, 0x00, 0x00,
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x34, /* ICE_GTP Header 42 */
66162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
66262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */
66562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x28, /* IP 62 */
66862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
66962306a36Sopenharmony_ci	0x00, 0x06, 0x00, 0x00,
67062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
67162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* TCP 82 */
67462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
67562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
67662306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
67762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
68062306a36Sopenharmony_ci};
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci/* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner UDP */
68362306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_udp) = {
68462306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
68562306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
68662306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
68762306a36Sopenharmony_ci	{ ICE_GTP,		42 },
68862306a36Sopenharmony_ci	{ ICE_IPV4_IL,		62 },
68962306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		82 },
69062306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
69162306a36Sopenharmony_ci};
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4_udp) = {
69462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
69562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
69662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
69762306a36Sopenharmony_ci	0x08, 0x00,
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x4c, /* IP 14 */
70062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
70162306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
70262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
70362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 34 */
70662306a36Sopenharmony_ci	0x00, 0x38, 0x00, 0x00,
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x28, /* ICE_GTP Header 42 */
70962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
71062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */
71362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x1c, /* IP 62 */
71662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
71762306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
71862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
71962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* UDP 82 */
72262306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
72562306a36Sopenharmony_ci};
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci/* Outer IPv6 + Outer UDP + GTP + Inner IPv4 + Inner TCP */
72862306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv6_tcp) = {
72962306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
73062306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
73162306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
73262306a36Sopenharmony_ci	{ ICE_GTP,		42 },
73362306a36Sopenharmony_ci	{ ICE_IPV6_IL,		62 },
73462306a36Sopenharmony_ci	{ ICE_TCP_IL,		102 },
73562306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
73662306a36Sopenharmony_ci};
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv6_tcp) = {
73962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
74062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
74162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
74262306a36Sopenharmony_ci	0x08, 0x00,
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x6c, /* IP 14 */
74562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
74662306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
74762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
74862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 34 */
75162306a36Sopenharmony_ci	0x00, 0x58, 0x00, 0x00,
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x48, /* ICE_GTP Header 42 */
75462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
75562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */
75862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 62 */
76162306a36Sopenharmony_ci	0x00, 0x14, 0x06, 0x00,
76262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
76962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* TCP 102 */
77262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
77362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
77462306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
77562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
77862306a36Sopenharmony_ci};
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv6_udp) = {
78162306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
78262306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
78362306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
78462306a36Sopenharmony_ci	{ ICE_GTP,		42 },
78562306a36Sopenharmony_ci	{ ICE_IPV6_IL,		62 },
78662306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		102 },
78762306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
78862306a36Sopenharmony_ci};
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv6_udp) = {
79162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
79262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
79362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
79462306a36Sopenharmony_ci	0x08, 0x00,
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x60, /* IP 14 */
79762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
79862306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
79962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
80062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 34 */
80362306a36Sopenharmony_ci	0x00, 0x4c, 0x00, 0x00,
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x3c, /* ICE_GTP Header 42 */
80662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
80762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */
81062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 62 */
81362306a36Sopenharmony_ci	0x00, 0x08, 0x11, 0x00,
81462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
81562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
81662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
81762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
81862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
81962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
82062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
82162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* UDP 102 */
82462306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
82762306a36Sopenharmony_ci};
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv4_tcp) = {
83062306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
83162306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
83262306a36Sopenharmony_ci	{ ICE_UDP_OF,		54 },
83362306a36Sopenharmony_ci	{ ICE_GTP,		62 },
83462306a36Sopenharmony_ci	{ ICE_IPV4_IL,		82 },
83562306a36Sopenharmony_ci	{ ICE_TCP_IL,		102 },
83662306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
83762306a36Sopenharmony_ci};
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv4_tcp) = {
84062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
84162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
84262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
84362306a36Sopenharmony_ci	0x86, 0xdd,
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 14 */
84662306a36Sopenharmony_ci	0x00, 0x44, 0x11, 0x00,
84762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
84862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
84962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
85062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
85162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
85262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
85362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
85462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 54 */
85762306a36Sopenharmony_ci	0x00, 0x44, 0x00, 0x00,
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x34, /* ICE_GTP Header 62 */
86062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
86162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */
86462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x28, /* IP 82 */
86762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
86862306a36Sopenharmony_ci	0x00, 0x06, 0x00, 0x00,
86962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
87062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* TCP 102 */
87362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
87462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
87562306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
87662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
87962306a36Sopenharmony_ci};
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv4_udp) = {
88262306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
88362306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
88462306a36Sopenharmony_ci	{ ICE_UDP_OF,		54 },
88562306a36Sopenharmony_ci	{ ICE_GTP,		62 },
88662306a36Sopenharmony_ci	{ ICE_IPV4_IL,		82 },
88762306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		102 },
88862306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
88962306a36Sopenharmony_ci};
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv4_udp) = {
89262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
89362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
89462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
89562306a36Sopenharmony_ci	0x86, 0xdd,
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 14 */
89862306a36Sopenharmony_ci	0x00, 0x38, 0x11, 0x00,
89962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 54 */
90962306a36Sopenharmony_ci	0x00, 0x38, 0x00, 0x00,
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x28, /* ICE_GTP Header 62 */
91262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
91362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */
91662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x1c, /* IP 82 */
91962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
92062306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
92162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
92262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* UDP 102 */
92562306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
92862306a36Sopenharmony_ci};
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv6_tcp) = {
93162306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
93262306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
93362306a36Sopenharmony_ci	{ ICE_UDP_OF,		54 },
93462306a36Sopenharmony_ci	{ ICE_GTP,		62 },
93562306a36Sopenharmony_ci	{ ICE_IPV6_IL,		82 },
93662306a36Sopenharmony_ci	{ ICE_TCP_IL,		122 },
93762306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
93862306a36Sopenharmony_ci};
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv6_tcp) = {
94162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
94262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
94362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
94462306a36Sopenharmony_ci	0x86, 0xdd,
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 14 */
94762306a36Sopenharmony_ci	0x00, 0x58, 0x11, 0x00,
94862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
94962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 54 */
95862306a36Sopenharmony_ci	0x00, 0x58, 0x00, 0x00,
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x48, /* ICE_GTP Header 62 */
96162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
96262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */
96562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 82 */
96862306a36Sopenharmony_ci	0x00, 0x14, 0x06, 0x00,
96962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* TCP 122 */
97962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
98062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
98162306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
98262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
98562306a36Sopenharmony_ci};
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv6_udp) = {
98862306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
98962306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
99062306a36Sopenharmony_ci	{ ICE_UDP_OF,		54 },
99162306a36Sopenharmony_ci	{ ICE_GTP,		62 },
99262306a36Sopenharmony_ci	{ ICE_IPV6_IL,		82 },
99362306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		122 },
99462306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
99562306a36Sopenharmony_ci};
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv6_udp) = {
99862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */
99962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
100062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
100162306a36Sopenharmony_ci	0x86, 0xdd,
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 14 */
100462306a36Sopenharmony_ci	0x00, 0x4c, 0x11, 0x00,
100562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
100662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
100762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
100862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
100962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
101062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
101162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
101262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	0x00, 0x00, 0x08, 0x68, /* UDP 54 */
101562306a36Sopenharmony_ci	0x00, 0x4c, 0x00, 0x00,
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x3c, /* ICE_GTP Header 62 */
101862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
101962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */
102262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* IPv6 82 */
102562306a36Sopenharmony_ci	0x00, 0x08, 0x11, 0x00,
102662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
102762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
102862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
102962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
103062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
103162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
103262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
103362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* UDP 122 */
103662306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	0x00, 0x00, /* 2 bytes for 4 byte alignment */
103962306a36Sopenharmony_ci};
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4) = {
104262306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
104362306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
104462306a36Sopenharmony_ci	{ ICE_UDP_OF,		34 },
104562306a36Sopenharmony_ci	{ ICE_GTP_NO_PAY,	42 },
104662306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
104762306a36Sopenharmony_ci};
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4) = {
105062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
105162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
105262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
105362306a36Sopenharmony_ci	0x08, 0x00,
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x44, /* ICE_IPV4_OFOS 14 */
105662306a36Sopenharmony_ci	0x00, 0x00, 0x40, 0x00,
105762306a36Sopenharmony_ci	0x40, 0x11, 0x00, 0x00,
105862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
105962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	0x08, 0x68, 0x08, 0x68, /* ICE_UDP_OF 34 */
106262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	0x34, 0xff, 0x00, 0x28, /* ICE_GTP 42 */
106562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
106662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x85,
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00, /* PDU Session extension header */
106962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 62 */
107262306a36Sopenharmony_ci	0x00, 0x00, 0x40, 0x00,
107362306a36Sopenharmony_ci	0x40, 0x00, 0x00, 0x00,
107462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
107562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
107662306a36Sopenharmony_ci	0x00, 0x00,
107762306a36Sopenharmony_ci};
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv6_gtp) = {
108062306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
108162306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
108262306a36Sopenharmony_ci	{ ICE_UDP_OF,		54 },
108362306a36Sopenharmony_ci	{ ICE_GTP_NO_PAY,	62 },
108462306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
108562306a36Sopenharmony_ci};
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv6_gtp) = {
108862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
108962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
109062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
109162306a36Sopenharmony_ci	0x86, 0xdd,
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 14 */
109462306a36Sopenharmony_ci	0x00, 0x6c, 0x11, 0x00, /* Next header UDP*/
109562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
109662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
109762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
109862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
109962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
110062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
110162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
110262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	0x08, 0x68, 0x08, 0x68, /* ICE_UDP_OF 54 */
110562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	0x30, 0x00, 0x00, 0x28, /* ICE_GTP 62 */
110862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	0x00, 0x00,
111162306a36Sopenharmony_ci};
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_tcp) = {
111462306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
111562306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
111662306a36Sopenharmony_ci	{ ICE_PPPOE,		14 },
111762306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	22 },
111862306a36Sopenharmony_ci	{ ICE_TCP_IL,		42 },
111962306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
112062306a36Sopenharmony_ci};
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(pppoe_ipv4_tcp) = {
112362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
112462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
112562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	0x88, 0x64,		/* ICE_ETYPE_OL 12 */
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */
113062306a36Sopenharmony_ci	0x00, 0x16,
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	0x00, 0x21,		/* PPP Link Layer 20 */
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 22 */
113562306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
113662306a36Sopenharmony_ci	0x00, 0x06, 0x00, 0x00,
113762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
113862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 42 */
114162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
114262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
114362306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
114462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	0x00, 0x00,		/* 2 bytes for 4 bytes alignment */
114762306a36Sopenharmony_ci};
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_udp) = {
115062306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
115162306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
115262306a36Sopenharmony_ci	{ ICE_PPPOE,		14 },
115362306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	22 },
115462306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		42 },
115562306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
115662306a36Sopenharmony_ci};
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(pppoe_ipv4_udp) = {
115962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
116062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
116162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	0x88, 0x64,		/* ICE_ETYPE_OL 12 */
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */
116662306a36Sopenharmony_ci	0x00, 0x16,
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	0x00, 0x21,		/* PPP Link Layer 20 */
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 22 */
117162306a36Sopenharmony_ci	0x00, 0x01, 0x00, 0x00,
117262306a36Sopenharmony_ci	0x00, 0x11, 0x00, 0x00,
117362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
117462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 42 */
117762306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	0x00, 0x00,		/* 2 bytes for 4 bytes alignment */
118062306a36Sopenharmony_ci};
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(pppoe_ipv6_tcp) = {
118362306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
118462306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
118562306a36Sopenharmony_ci	{ ICE_PPPOE,		14 },
118662306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	22 },
118762306a36Sopenharmony_ci	{ ICE_TCP_IL,		62 },
118862306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
118962306a36Sopenharmony_ci};
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_tcp) = {
119262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
119362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
119462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	0x88, 0x64,		/* ICE_ETYPE_OL 12 */
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */
119962306a36Sopenharmony_ci	0x00, 0x2a,
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	0x00, 0x57,		/* PPP Link Layer 20 */
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 22 */
120462306a36Sopenharmony_ci	0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
120562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
120662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
120762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
120862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
120962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 62 */
121562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121762306a36Sopenharmony_ci	0x50, 0x00, 0x00, 0x00,
121862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	0x00, 0x00,		/* 2 bytes for 4 bytes alignment */
122162306a36Sopenharmony_ci};
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(pppoe_ipv6_udp) = {
122462306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
122562306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
122662306a36Sopenharmony_ci	{ ICE_PPPOE,		14 },
122762306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	22 },
122862306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		62 },
122962306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
123062306a36Sopenharmony_ci};
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_udp) = {
123362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
123462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
123562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	0x88, 0x64,		/* ICE_ETYPE_OL 12 */
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */
124062306a36Sopenharmony_ci	0x00, 0x2a,
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	0x00, 0x57,		/* PPP Link Layer 20 */
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 22 */
124562306a36Sopenharmony_ci	0x00, 0x08, 0x11, 0x00, /* Next header UDP*/
124662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
124762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
124862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
124962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
125062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
125162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
125262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
125362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 62 */
125662306a36Sopenharmony_ci	0x00, 0x08, 0x00, 0x00,
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	0x00, 0x00,		/* 2 bytes for 4 bytes alignment */
125962306a36Sopenharmony_ci};
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv4_l2tpv3) = {
126262306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
126362306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
126462306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	14 },
126562306a36Sopenharmony_ci	{ ICE_L2TPV3,		34 },
126662306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
126762306a36Sopenharmony_ci};
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv4_l2tpv3) = {
127062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
127162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
127262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	0x45, 0x00, 0x00, 0x20, /* ICE_IPV4_IL 14 */
127762306a36Sopenharmony_ci	0x00, 0x00, 0x40, 0x00,
127862306a36Sopenharmony_ci	0x40, 0x73, 0x00, 0x00,
127962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
128062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 34 */
128362306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
128462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
128562306a36Sopenharmony_ci	0x00, 0x00,		/* 2 bytes for 4 bytes alignment */
128662306a36Sopenharmony_ci};
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ciICE_DECLARE_PKT_OFFSETS(ipv6_l2tpv3) = {
128962306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		0 },
129062306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		12 },
129162306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	14 },
129262306a36Sopenharmony_ci	{ ICE_L2TPV3,		54 },
129362306a36Sopenharmony_ci	{ ICE_PROTOCOL_LAST,	0 },
129462306a36Sopenharmony_ci};
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ciICE_DECLARE_PKT_TEMPLATE(ipv6_l2tpv3) = {
129762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
129862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
129962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 14 */
130462306a36Sopenharmony_ci	0x00, 0x0c, 0x73, 0x40,
130562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
130662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
130762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
130862306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
130962306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
131062306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
131162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
131262306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 54 */
131562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
131662306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00,
131762306a36Sopenharmony_ci	0x00, 0x00,		/* 2 bytes for 4 bytes alignment */
131862306a36Sopenharmony_ci};
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
132162306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPU | ICE_PKT_OUTER_IPV6 |
132262306a36Sopenharmony_ci				  ICE_PKT_GTP_NOPAY),
132362306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_gtpu_ipv6_udp, ICE_PKT_TUN_GTPU |
132462306a36Sopenharmony_ci					    ICE_PKT_OUTER_IPV6 |
132562306a36Sopenharmony_ci					    ICE_PKT_INNER_IPV6 |
132662306a36Sopenharmony_ci					    ICE_PKT_INNER_UDP),
132762306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_gtpu_ipv6_tcp, ICE_PKT_TUN_GTPU |
132862306a36Sopenharmony_ci					    ICE_PKT_OUTER_IPV6 |
132962306a36Sopenharmony_ci					    ICE_PKT_INNER_IPV6),
133062306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_gtpu_ipv4_udp, ICE_PKT_TUN_GTPU |
133162306a36Sopenharmony_ci					    ICE_PKT_OUTER_IPV6 |
133262306a36Sopenharmony_ci					    ICE_PKT_INNER_UDP),
133362306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU |
133462306a36Sopenharmony_ci					    ICE_PKT_OUTER_IPV6),
133562306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPU | ICE_PKT_GTP_NOPAY),
133662306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_gtpu_ipv6_udp, ICE_PKT_TUN_GTPU |
133762306a36Sopenharmony_ci					    ICE_PKT_INNER_IPV6 |
133862306a36Sopenharmony_ci					    ICE_PKT_INNER_UDP),
133962306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_gtpu_ipv6_tcp, ICE_PKT_TUN_GTPU |
134062306a36Sopenharmony_ci					    ICE_PKT_INNER_IPV6),
134162306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_gtpu_ipv4_udp, ICE_PKT_TUN_GTPU |
134262306a36Sopenharmony_ci					    ICE_PKT_INNER_UDP),
134362306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU),
134462306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPC | ICE_PKT_OUTER_IPV6),
134562306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPC),
134662306a36Sopenharmony_ci	ICE_PKT_PROFILE(pppoe_ipv6_udp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6 |
134762306a36Sopenharmony_ci					ICE_PKT_INNER_UDP),
134862306a36Sopenharmony_ci	ICE_PKT_PROFILE(pppoe_ipv6_tcp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6),
134962306a36Sopenharmony_ci	ICE_PKT_PROFILE(pppoe_ipv4_udp, ICE_PKT_PPPOE | ICE_PKT_INNER_UDP),
135062306a36Sopenharmony_ci	ICE_PKT_PROFILE(pppoe_ipv4_tcp, ICE_PKT_PPPOE),
135162306a36Sopenharmony_ci	ICE_PKT_PROFILE(gre_ipv6_tcp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_IPV6 |
135262306a36Sopenharmony_ci				      ICE_PKT_INNER_TCP),
135362306a36Sopenharmony_ci	ICE_PKT_PROFILE(gre_tcp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_TCP),
135462306a36Sopenharmony_ci	ICE_PKT_PROFILE(gre_ipv6_udp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_IPV6),
135562306a36Sopenharmony_ci	ICE_PKT_PROFILE(gre_udp, ICE_PKT_TUN_NVGRE),
135662306a36Sopenharmony_ci	ICE_PKT_PROFILE(udp_tun_ipv6_tcp, ICE_PKT_TUN_UDP |
135762306a36Sopenharmony_ci					  ICE_PKT_INNER_IPV6 |
135862306a36Sopenharmony_ci					  ICE_PKT_INNER_TCP),
135962306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv6_l2tpv3, ICE_PKT_L2TPV3 | ICE_PKT_OUTER_IPV6),
136062306a36Sopenharmony_ci	ICE_PKT_PROFILE(ipv4_l2tpv3, ICE_PKT_L2TPV3),
136162306a36Sopenharmony_ci	ICE_PKT_PROFILE(udp_tun_tcp, ICE_PKT_TUN_UDP | ICE_PKT_INNER_TCP),
136262306a36Sopenharmony_ci	ICE_PKT_PROFILE(udp_tun_ipv6_udp, ICE_PKT_TUN_UDP |
136362306a36Sopenharmony_ci					  ICE_PKT_INNER_IPV6),
136462306a36Sopenharmony_ci	ICE_PKT_PROFILE(udp_tun_udp, ICE_PKT_TUN_UDP),
136562306a36Sopenharmony_ci	ICE_PKT_PROFILE(udp_ipv6, ICE_PKT_OUTER_IPV6 | ICE_PKT_INNER_UDP),
136662306a36Sopenharmony_ci	ICE_PKT_PROFILE(udp, ICE_PKT_INNER_UDP),
136762306a36Sopenharmony_ci	ICE_PKT_PROFILE(tcp_ipv6, ICE_PKT_OUTER_IPV6),
136862306a36Sopenharmony_ci	ICE_PKT_PROFILE(tcp, 0),
136962306a36Sopenharmony_ci};
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci/* this is a recipe to profile association bitmap */
137262306a36Sopenharmony_cistatic DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES],
137362306a36Sopenharmony_ci			  ICE_MAX_NUM_PROFILES);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci/* this is a profile to recipe association bitmap */
137662306a36Sopenharmony_cistatic DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES],
137762306a36Sopenharmony_ci			  ICE_MAX_NUM_RECIPES);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci/**
138062306a36Sopenharmony_ci * ice_init_def_sw_recp - initialize the recipe book keeping tables
138162306a36Sopenharmony_ci * @hw: pointer to the HW struct
138262306a36Sopenharmony_ci *
138362306a36Sopenharmony_ci * Allocate memory for the entire recipe table and initialize the structures/
138462306a36Sopenharmony_ci * entries corresponding to basic recipes.
138562306a36Sopenharmony_ci */
138662306a36Sopenharmony_ciint ice_init_def_sw_recp(struct ice_hw *hw)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	struct ice_sw_recipe *recps;
138962306a36Sopenharmony_ci	u8 i;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES,
139262306a36Sopenharmony_ci			     sizeof(*recps), GFP_KERNEL);
139362306a36Sopenharmony_ci	if (!recps)
139462306a36Sopenharmony_ci		return -ENOMEM;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
139762306a36Sopenharmony_ci		recps[i].root_rid = i;
139862306a36Sopenharmony_ci		INIT_LIST_HEAD(&recps[i].filt_rules);
139962306a36Sopenharmony_ci		INIT_LIST_HEAD(&recps[i].filt_replay_rules);
140062306a36Sopenharmony_ci		INIT_LIST_HEAD(&recps[i].rg_list);
140162306a36Sopenharmony_ci		mutex_init(&recps[i].filt_rule_lock);
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	hw->switch_info->recp_list = recps;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return 0;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci/**
141062306a36Sopenharmony_ci * ice_aq_get_sw_cfg - get switch configuration
141162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
141262306a36Sopenharmony_ci * @buf: pointer to the result buffer
141362306a36Sopenharmony_ci * @buf_size: length of the buffer available for response
141462306a36Sopenharmony_ci * @req_desc: pointer to requested descriptor
141562306a36Sopenharmony_ci * @num_elems: pointer to number of elements
141662306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
141762306a36Sopenharmony_ci *
141862306a36Sopenharmony_ci * Get switch configuration (0x0200) to be placed in buf.
141962306a36Sopenharmony_ci * This admin command returns information such as initial VSI/port number
142062306a36Sopenharmony_ci * and switch ID it belongs to.
142162306a36Sopenharmony_ci *
142262306a36Sopenharmony_ci * NOTE: *req_desc is both an input/output parameter.
142362306a36Sopenharmony_ci * The caller of this function first calls this function with *request_desc set
142462306a36Sopenharmony_ci * to 0. If the response from f/w has *req_desc set to 0, all the switch
142562306a36Sopenharmony_ci * configuration information has been returned; if non-zero (meaning not all
142662306a36Sopenharmony_ci * the information was returned), the caller should call this function again
142762306a36Sopenharmony_ci * with *req_desc set to the previous value returned by f/w to get the
142862306a36Sopenharmony_ci * next block of switch configuration information.
142962306a36Sopenharmony_ci *
143062306a36Sopenharmony_ci * *num_elems is output only parameter. This reflects the number of elements
143162306a36Sopenharmony_ci * in response buffer. The caller of this function to use *num_elems while
143262306a36Sopenharmony_ci * parsing the response buffer.
143362306a36Sopenharmony_ci */
143462306a36Sopenharmony_cistatic int
143562306a36Sopenharmony_ciice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf,
143662306a36Sopenharmony_ci		  u16 buf_size, u16 *req_desc, u16 *num_elems,
143762306a36Sopenharmony_ci		  struct ice_sq_cd *cd)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct ice_aqc_get_sw_cfg *cmd;
144062306a36Sopenharmony_ci	struct ice_aq_desc desc;
144162306a36Sopenharmony_ci	int status;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);
144462306a36Sopenharmony_ci	cmd = &desc.params.get_sw_conf;
144562306a36Sopenharmony_ci	cmd->element = cpu_to_le16(*req_desc);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
144862306a36Sopenharmony_ci	if (!status) {
144962306a36Sopenharmony_ci		*req_desc = le16_to_cpu(cmd->element);
145062306a36Sopenharmony_ci		*num_elems = le16_to_cpu(cmd->num_elems);
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	return status;
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci/**
145762306a36Sopenharmony_ci * ice_aq_add_vsi
145862306a36Sopenharmony_ci * @hw: pointer to the HW struct
145962306a36Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
146062306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
146162306a36Sopenharmony_ci *
146262306a36Sopenharmony_ci * Add a VSI context to the hardware (0x0210)
146362306a36Sopenharmony_ci */
146462306a36Sopenharmony_cistatic int
146562306a36Sopenharmony_ciice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
146662306a36Sopenharmony_ci	       struct ice_sq_cd *cd)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	struct ice_aqc_add_update_free_vsi_resp *res;
146962306a36Sopenharmony_ci	struct ice_aqc_add_get_update_free_vsi *cmd;
147062306a36Sopenharmony_ci	struct ice_aq_desc desc;
147162306a36Sopenharmony_ci	int status;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	cmd = &desc.params.vsi_cmd;
147462306a36Sopenharmony_ci	res = &desc.params.add_update_free_vsi_res;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (!vsi_ctx->alloc_from_pool)
147962306a36Sopenharmony_ci		cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num |
148062306a36Sopenharmony_ci					   ICE_AQ_VSI_IS_VALID);
148162306a36Sopenharmony_ci	cmd->vf_id = vsi_ctx->vf_num;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
148862306a36Sopenharmony_ci				 sizeof(vsi_ctx->info), cd);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	if (!status) {
149162306a36Sopenharmony_ci		vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M;
149262306a36Sopenharmony_ci		vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used);
149362306a36Sopenharmony_ci		vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free);
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	return status;
149762306a36Sopenharmony_ci}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci/**
150062306a36Sopenharmony_ci * ice_aq_free_vsi
150162306a36Sopenharmony_ci * @hw: pointer to the HW struct
150262306a36Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
150362306a36Sopenharmony_ci * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
150462306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
150562306a36Sopenharmony_ci *
150662306a36Sopenharmony_ci * Free VSI context info from hardware (0x0213)
150762306a36Sopenharmony_ci */
150862306a36Sopenharmony_cistatic int
150962306a36Sopenharmony_ciice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
151062306a36Sopenharmony_ci		bool keep_vsi_alloc, struct ice_sq_cd *cd)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	struct ice_aqc_add_update_free_vsi_resp *resp;
151362306a36Sopenharmony_ci	struct ice_aqc_add_get_update_free_vsi *cmd;
151462306a36Sopenharmony_ci	struct ice_aq_desc desc;
151562306a36Sopenharmony_ci	int status;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	cmd = &desc.params.vsi_cmd;
151862306a36Sopenharmony_ci	resp = &desc.params.add_update_free_vsi_res;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
152362306a36Sopenharmony_ci	if (keep_vsi_alloc)
152462306a36Sopenharmony_ci		cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
152762306a36Sopenharmony_ci	if (!status) {
152862306a36Sopenharmony_ci		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
152962306a36Sopenharmony_ci		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
153062306a36Sopenharmony_ci	}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	return status;
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci/**
153662306a36Sopenharmony_ci * ice_aq_update_vsi
153762306a36Sopenharmony_ci * @hw: pointer to the HW struct
153862306a36Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
153962306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
154062306a36Sopenharmony_ci *
154162306a36Sopenharmony_ci * Update VSI context in the hardware (0x0211)
154262306a36Sopenharmony_ci */
154362306a36Sopenharmony_cistatic int
154462306a36Sopenharmony_ciice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
154562306a36Sopenharmony_ci		  struct ice_sq_cd *cd)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct ice_aqc_add_update_free_vsi_resp *resp;
154862306a36Sopenharmony_ci	struct ice_aqc_add_get_update_free_vsi *cmd;
154962306a36Sopenharmony_ci	struct ice_aq_desc desc;
155062306a36Sopenharmony_ci	int status;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	cmd = &desc.params.vsi_cmd;
155362306a36Sopenharmony_ci	resp = &desc.params.add_update_free_vsi_res;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
156262306a36Sopenharmony_ci				 sizeof(vsi_ctx->info), cd);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	if (!status) {
156562306a36Sopenharmony_ci		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
156662306a36Sopenharmony_ci		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
156762306a36Sopenharmony_ci	}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	return status;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci/**
157362306a36Sopenharmony_ci * ice_is_vsi_valid - check whether the VSI is valid or not
157462306a36Sopenharmony_ci * @hw: pointer to the HW struct
157562306a36Sopenharmony_ci * @vsi_handle: VSI handle
157662306a36Sopenharmony_ci *
157762306a36Sopenharmony_ci * check whether the VSI is valid or not
157862306a36Sopenharmony_ci */
157962306a36Sopenharmony_cibool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci/**
158562306a36Sopenharmony_ci * ice_get_hw_vsi_num - return the HW VSI number
158662306a36Sopenharmony_ci * @hw: pointer to the HW struct
158762306a36Sopenharmony_ci * @vsi_handle: VSI handle
158862306a36Sopenharmony_ci *
158962306a36Sopenharmony_ci * return the HW VSI number
159062306a36Sopenharmony_ci * Caution: call this function only if VSI is valid (ice_is_vsi_valid)
159162306a36Sopenharmony_ci */
159262306a36Sopenharmony_ciu16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	return hw->vsi_ctx[vsi_handle]->vsi_num;
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci/**
159862306a36Sopenharmony_ci * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle
159962306a36Sopenharmony_ci * @hw: pointer to the HW struct
160062306a36Sopenharmony_ci * @vsi_handle: VSI handle
160162306a36Sopenharmony_ci *
160262306a36Sopenharmony_ci * return the VSI context entry for a given VSI handle
160362306a36Sopenharmony_ci */
160462306a36Sopenharmony_cistruct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];
160762306a36Sopenharmony_ci}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci/**
161062306a36Sopenharmony_ci * ice_save_vsi_ctx - save the VSI context for a given VSI handle
161162306a36Sopenharmony_ci * @hw: pointer to the HW struct
161262306a36Sopenharmony_ci * @vsi_handle: VSI handle
161362306a36Sopenharmony_ci * @vsi: VSI context pointer
161462306a36Sopenharmony_ci *
161562306a36Sopenharmony_ci * save the VSI context entry for a given VSI handle
161662306a36Sopenharmony_ci */
161762306a36Sopenharmony_cistatic void
161862306a36Sopenharmony_ciice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	hw->vsi_ctx[vsi_handle] = vsi;
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci/**
162462306a36Sopenharmony_ci * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs
162562306a36Sopenharmony_ci * @hw: pointer to the HW struct
162662306a36Sopenharmony_ci * @vsi_handle: VSI handle
162762306a36Sopenharmony_ci */
162862306a36Sopenharmony_cistatic void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	struct ice_vsi_ctx *vsi = ice_get_vsi_ctx(hw, vsi_handle);
163162306a36Sopenharmony_ci	u8 i;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	if (!vsi)
163462306a36Sopenharmony_ci		return;
163562306a36Sopenharmony_ci	ice_for_each_traffic_class(i) {
163662306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
163762306a36Sopenharmony_ci		vsi->lan_q_ctx[i] = NULL;
163862306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]);
163962306a36Sopenharmony_ci		vsi->rdma_q_ctx[i] = NULL;
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci/**
164462306a36Sopenharmony_ci * ice_clear_vsi_ctx - clear the VSI context entry
164562306a36Sopenharmony_ci * @hw: pointer to the HW struct
164662306a36Sopenharmony_ci * @vsi_handle: VSI handle
164762306a36Sopenharmony_ci *
164862306a36Sopenharmony_ci * clear the VSI context entry
164962306a36Sopenharmony_ci */
165062306a36Sopenharmony_cistatic void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	struct ice_vsi_ctx *vsi;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	vsi = ice_get_vsi_ctx(hw, vsi_handle);
165562306a36Sopenharmony_ci	if (vsi) {
165662306a36Sopenharmony_ci		ice_clear_vsi_q_ctx(hw, vsi_handle);
165762306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi);
165862306a36Sopenharmony_ci		hw->vsi_ctx[vsi_handle] = NULL;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci/**
166362306a36Sopenharmony_ci * ice_clear_all_vsi_ctx - clear all the VSI context entries
166462306a36Sopenharmony_ci * @hw: pointer to the HW struct
166562306a36Sopenharmony_ci */
166662306a36Sopenharmony_civoid ice_clear_all_vsi_ctx(struct ice_hw *hw)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	u16 i;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_VSI; i++)
167162306a36Sopenharmony_ci		ice_clear_vsi_ctx(hw, i);
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci/**
167562306a36Sopenharmony_ci * ice_add_vsi - add VSI context to the hardware and VSI handle list
167662306a36Sopenharmony_ci * @hw: pointer to the HW struct
167762306a36Sopenharmony_ci * @vsi_handle: unique VSI handle provided by drivers
167862306a36Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
167962306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
168062306a36Sopenharmony_ci *
168162306a36Sopenharmony_ci * Add a VSI context to the hardware also add it into the VSI handle list.
168262306a36Sopenharmony_ci * If this function gets called after reset for existing VSIs then update
168362306a36Sopenharmony_ci * with the new HW VSI number in the corresponding VSI handle list entry.
168462306a36Sopenharmony_ci */
168562306a36Sopenharmony_ciint
168662306a36Sopenharmony_ciice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
168762306a36Sopenharmony_ci	    struct ice_sq_cd *cd)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	struct ice_vsi_ctx *tmp_vsi_ctx;
169062306a36Sopenharmony_ci	int status;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	if (vsi_handle >= ICE_MAX_VSI)
169362306a36Sopenharmony_ci		return -EINVAL;
169462306a36Sopenharmony_ci	status = ice_aq_add_vsi(hw, vsi_ctx, cd);
169562306a36Sopenharmony_ci	if (status)
169662306a36Sopenharmony_ci		return status;
169762306a36Sopenharmony_ci	tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
169862306a36Sopenharmony_ci	if (!tmp_vsi_ctx) {
169962306a36Sopenharmony_ci		/* Create a new VSI context */
170062306a36Sopenharmony_ci		tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw),
170162306a36Sopenharmony_ci					   sizeof(*tmp_vsi_ctx), GFP_KERNEL);
170262306a36Sopenharmony_ci		if (!tmp_vsi_ctx) {
170362306a36Sopenharmony_ci			ice_aq_free_vsi(hw, vsi_ctx, false, cd);
170462306a36Sopenharmony_ci			return -ENOMEM;
170562306a36Sopenharmony_ci		}
170662306a36Sopenharmony_ci		*tmp_vsi_ctx = *vsi_ctx;
170762306a36Sopenharmony_ci		ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);
170862306a36Sopenharmony_ci	} else {
170962306a36Sopenharmony_ci		/* update with new HW VSI num */
171062306a36Sopenharmony_ci		tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;
171162306a36Sopenharmony_ci	}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	return 0;
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/**
171762306a36Sopenharmony_ci * ice_free_vsi- free VSI context from hardware and VSI handle list
171862306a36Sopenharmony_ci * @hw: pointer to the HW struct
171962306a36Sopenharmony_ci * @vsi_handle: unique VSI handle
172062306a36Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
172162306a36Sopenharmony_ci * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
172262306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
172362306a36Sopenharmony_ci *
172462306a36Sopenharmony_ci * Free VSI context info from hardware as well as from VSI handle list
172562306a36Sopenharmony_ci */
172662306a36Sopenharmony_ciint
172762306a36Sopenharmony_ciice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
172862306a36Sopenharmony_ci	     bool keep_vsi_alloc, struct ice_sq_cd *cd)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	int status;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
173362306a36Sopenharmony_ci		return -EINVAL;
173462306a36Sopenharmony_ci	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
173562306a36Sopenharmony_ci	status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);
173662306a36Sopenharmony_ci	if (!status)
173762306a36Sopenharmony_ci		ice_clear_vsi_ctx(hw, vsi_handle);
173862306a36Sopenharmony_ci	return status;
173962306a36Sopenharmony_ci}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci/**
174262306a36Sopenharmony_ci * ice_update_vsi
174362306a36Sopenharmony_ci * @hw: pointer to the HW struct
174462306a36Sopenharmony_ci * @vsi_handle: unique VSI handle
174562306a36Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
174662306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
174762306a36Sopenharmony_ci *
174862306a36Sopenharmony_ci * Update VSI context in the hardware
174962306a36Sopenharmony_ci */
175062306a36Sopenharmony_ciint
175162306a36Sopenharmony_ciice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
175262306a36Sopenharmony_ci	       struct ice_sq_cd *cd)
175362306a36Sopenharmony_ci{
175462306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
175562306a36Sopenharmony_ci		return -EINVAL;
175662306a36Sopenharmony_ci	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
175762306a36Sopenharmony_ci	return ice_aq_update_vsi(hw, vsi_ctx, cd);
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci/**
176162306a36Sopenharmony_ci * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI
176262306a36Sopenharmony_ci * @hw: pointer to HW struct
176362306a36Sopenharmony_ci * @vsi_handle: VSI SW index
176462306a36Sopenharmony_ci * @enable: boolean for enable/disable
176562306a36Sopenharmony_ci */
176662306a36Sopenharmony_ciint
176762306a36Sopenharmony_ciice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct ice_vsi_ctx *ctx, *cached_ctx;
177062306a36Sopenharmony_ci	int status;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	cached_ctx = ice_get_vsi_ctx(hw, vsi_handle);
177362306a36Sopenharmony_ci	if (!cached_ctx)
177462306a36Sopenharmony_ci		return -ENOENT;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
177762306a36Sopenharmony_ci	if (!ctx)
177862306a36Sopenharmony_ci		return -ENOMEM;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss;
178162306a36Sopenharmony_ci	ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc;
178262306a36Sopenharmony_ci	ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (enable)
178762306a36Sopenharmony_ci		ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
178862306a36Sopenharmony_ci	else
178962306a36Sopenharmony_ci		ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	status = ice_update_vsi(hw, vsi_handle, ctx, NULL);
179262306a36Sopenharmony_ci	if (!status) {
179362306a36Sopenharmony_ci		cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags;
179462306a36Sopenharmony_ci		cached_ctx->info.valid_sections |= ctx->info.valid_sections;
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	kfree(ctx);
179862306a36Sopenharmony_ci	return status;
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci/**
180262306a36Sopenharmony_ci * ice_aq_alloc_free_vsi_list
180362306a36Sopenharmony_ci * @hw: pointer to the HW struct
180462306a36Sopenharmony_ci * @vsi_list_id: VSI list ID returned or used for lookup
180562306a36Sopenharmony_ci * @lkup_type: switch rule filter lookup type
180662306a36Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
180762306a36Sopenharmony_ci *
180862306a36Sopenharmony_ci * allocates or free a VSI list resource
180962306a36Sopenharmony_ci */
181062306a36Sopenharmony_cistatic int
181162306a36Sopenharmony_ciice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
181262306a36Sopenharmony_ci			   enum ice_sw_lkup_type lkup_type,
181362306a36Sopenharmony_ci			   enum ice_adminq_opc opc)
181462306a36Sopenharmony_ci{
181562306a36Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *sw_buf;
181662306a36Sopenharmony_ci	struct ice_aqc_res_elem *vsi_ele;
181762306a36Sopenharmony_ci	u16 buf_len;
181862306a36Sopenharmony_ci	int status;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	buf_len = struct_size(sw_buf, elem, 1);
182162306a36Sopenharmony_ci	sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL);
182262306a36Sopenharmony_ci	if (!sw_buf)
182362306a36Sopenharmony_ci		return -ENOMEM;
182462306a36Sopenharmony_ci	sw_buf->num_elems = cpu_to_le16(1);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	if (lkup_type == ICE_SW_LKUP_MAC ||
182762306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
182862306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
182962306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
183062306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC ||
183162306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
183262306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_DFLT) {
183362306a36Sopenharmony_ci		sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
183462306a36Sopenharmony_ci	} else if (lkup_type == ICE_SW_LKUP_VLAN) {
183562306a36Sopenharmony_ci		if (opc == ice_aqc_opc_alloc_res)
183662306a36Sopenharmony_ci			sw_buf->res_type =
183762306a36Sopenharmony_ci				cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE |
183862306a36Sopenharmony_ci					    ICE_AQC_RES_TYPE_FLAG_SHARED);
183962306a36Sopenharmony_ci		else
184062306a36Sopenharmony_ci			sw_buf->res_type =
184162306a36Sopenharmony_ci				cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
184262306a36Sopenharmony_ci	} else {
184362306a36Sopenharmony_ci		status = -EINVAL;
184462306a36Sopenharmony_ci		goto ice_aq_alloc_free_vsi_list_exit;
184562306a36Sopenharmony_ci	}
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	if (opc == ice_aqc_opc_free_res)
184862306a36Sopenharmony_ci		sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, sw_buf, buf_len, opc);
185162306a36Sopenharmony_ci	if (status)
185262306a36Sopenharmony_ci		goto ice_aq_alloc_free_vsi_list_exit;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	if (opc == ice_aqc_opc_alloc_res) {
185562306a36Sopenharmony_ci		vsi_ele = &sw_buf->elem[0];
185662306a36Sopenharmony_ci		*vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp);
185762306a36Sopenharmony_ci	}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ciice_aq_alloc_free_vsi_list_exit:
186062306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), sw_buf);
186162306a36Sopenharmony_ci	return status;
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci/**
186562306a36Sopenharmony_ci * ice_aq_sw_rules - add/update/remove switch rules
186662306a36Sopenharmony_ci * @hw: pointer to the HW struct
186762306a36Sopenharmony_ci * @rule_list: pointer to switch rule population list
186862306a36Sopenharmony_ci * @rule_list_sz: total size of the rule list in bytes
186962306a36Sopenharmony_ci * @num_rules: number of switch rules in the rule_list
187062306a36Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
187162306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
187262306a36Sopenharmony_ci *
187362306a36Sopenharmony_ci * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware
187462306a36Sopenharmony_ci */
187562306a36Sopenharmony_ciint
187662306a36Sopenharmony_ciice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
187762306a36Sopenharmony_ci		u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd)
187862306a36Sopenharmony_ci{
187962306a36Sopenharmony_ci	struct ice_aq_desc desc;
188062306a36Sopenharmony_ci	int status;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	if (opc != ice_aqc_opc_add_sw_rules &&
188362306a36Sopenharmony_ci	    opc != ice_aqc_opc_update_sw_rules &&
188462306a36Sopenharmony_ci	    opc != ice_aqc_opc_remove_sw_rules)
188562306a36Sopenharmony_ci		return -EINVAL;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, opc);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
189062306a36Sopenharmony_ci	desc.params.sw_rules.num_rules_fltr_entry_index =
189162306a36Sopenharmony_ci		cpu_to_le16(num_rules);
189262306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd);
189362306a36Sopenharmony_ci	if (opc != ice_aqc_opc_add_sw_rules &&
189462306a36Sopenharmony_ci	    hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
189562306a36Sopenharmony_ci		status = -ENOENT;
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	return status;
189862306a36Sopenharmony_ci}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci/**
190162306a36Sopenharmony_ci * ice_aq_add_recipe - add switch recipe
190262306a36Sopenharmony_ci * @hw: pointer to the HW struct
190362306a36Sopenharmony_ci * @s_recipe_list: pointer to switch rule population list
190462306a36Sopenharmony_ci * @num_recipes: number of switch recipes in the list
190562306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
190662306a36Sopenharmony_ci *
190762306a36Sopenharmony_ci * Add(0x0290)
190862306a36Sopenharmony_ci */
190962306a36Sopenharmony_ciint
191062306a36Sopenharmony_ciice_aq_add_recipe(struct ice_hw *hw,
191162306a36Sopenharmony_ci		  struct ice_aqc_recipe_data_elem *s_recipe_list,
191262306a36Sopenharmony_ci		  u16 num_recipes, struct ice_sq_cd *cd)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	struct ice_aqc_add_get_recipe *cmd;
191562306a36Sopenharmony_ci	struct ice_aq_desc desc;
191662306a36Sopenharmony_ci	u16 buf_size;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	cmd = &desc.params.add_get_recipe;
191962306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_recipe);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	cmd->num_sub_recipes = cpu_to_le16(num_recipes);
192262306a36Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	buf_size = num_recipes * sizeof(*s_recipe_list);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	return ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd);
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci/**
193062306a36Sopenharmony_ci * ice_aq_get_recipe - get switch recipe
193162306a36Sopenharmony_ci * @hw: pointer to the HW struct
193262306a36Sopenharmony_ci * @s_recipe_list: pointer to switch rule population list
193362306a36Sopenharmony_ci * @num_recipes: pointer to the number of recipes (input and output)
193462306a36Sopenharmony_ci * @recipe_root: root recipe number of recipe(s) to retrieve
193562306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
193662306a36Sopenharmony_ci *
193762306a36Sopenharmony_ci * Get(0x0292)
193862306a36Sopenharmony_ci *
193962306a36Sopenharmony_ci * On input, *num_recipes should equal the number of entries in s_recipe_list.
194062306a36Sopenharmony_ci * On output, *num_recipes will equal the number of entries returned in
194162306a36Sopenharmony_ci * s_recipe_list.
194262306a36Sopenharmony_ci *
194362306a36Sopenharmony_ci * The caller must supply enough space in s_recipe_list to hold all possible
194462306a36Sopenharmony_ci * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES.
194562306a36Sopenharmony_ci */
194662306a36Sopenharmony_ciint
194762306a36Sopenharmony_ciice_aq_get_recipe(struct ice_hw *hw,
194862306a36Sopenharmony_ci		  struct ice_aqc_recipe_data_elem *s_recipe_list,
194962306a36Sopenharmony_ci		  u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	struct ice_aqc_add_get_recipe *cmd;
195262306a36Sopenharmony_ci	struct ice_aq_desc desc;
195362306a36Sopenharmony_ci	u16 buf_size;
195462306a36Sopenharmony_ci	int status;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	if (*num_recipes != ICE_MAX_NUM_RECIPES)
195762306a36Sopenharmony_ci		return -EINVAL;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	cmd = &desc.params.add_get_recipe;
196062306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	cmd->return_index = cpu_to_le16(recipe_root);
196362306a36Sopenharmony_ci	cmd->num_sub_recipes = 0;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	buf_size = *num_recipes * sizeof(*s_recipe_list);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd);
196862306a36Sopenharmony_ci	*num_recipes = le16_to_cpu(cmd->num_sub_recipes);
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	return status;
197162306a36Sopenharmony_ci}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci/**
197462306a36Sopenharmony_ci * ice_update_recipe_lkup_idx - update a default recipe based on the lkup_idx
197562306a36Sopenharmony_ci * @hw: pointer to the HW struct
197662306a36Sopenharmony_ci * @params: parameters used to update the default recipe
197762306a36Sopenharmony_ci *
197862306a36Sopenharmony_ci * This function only supports updating default recipes and it only supports
197962306a36Sopenharmony_ci * updating a single recipe based on the lkup_idx at a time.
198062306a36Sopenharmony_ci *
198162306a36Sopenharmony_ci * This is done as a read-modify-write operation. First, get the current recipe
198262306a36Sopenharmony_ci * contents based on the recipe's ID. Then modify the field vector index and
198362306a36Sopenharmony_ci * mask if it's valid at the lkup_idx. Finally, use the add recipe AQ to update
198462306a36Sopenharmony_ci * the pre-existing recipe with the modifications.
198562306a36Sopenharmony_ci */
198662306a36Sopenharmony_ciint
198762306a36Sopenharmony_ciice_update_recipe_lkup_idx(struct ice_hw *hw,
198862306a36Sopenharmony_ci			   struct ice_update_recipe_lkup_idx_params *params)
198962306a36Sopenharmony_ci{
199062306a36Sopenharmony_ci	struct ice_aqc_recipe_data_elem *rcp_list;
199162306a36Sopenharmony_ci	u16 num_recps = ICE_MAX_NUM_RECIPES;
199262306a36Sopenharmony_ci	int status;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	rcp_list = kcalloc(num_recps, sizeof(*rcp_list), GFP_KERNEL);
199562306a36Sopenharmony_ci	if (!rcp_list)
199662306a36Sopenharmony_ci		return -ENOMEM;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	/* read current recipe list from firmware */
199962306a36Sopenharmony_ci	rcp_list->recipe_indx = params->rid;
200062306a36Sopenharmony_ci	status = ice_aq_get_recipe(hw, rcp_list, &num_recps, params->rid, NULL);
200162306a36Sopenharmony_ci	if (status) {
200262306a36Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "Failed to get recipe %d, status %d\n",
200362306a36Sopenharmony_ci			  params->rid, status);
200462306a36Sopenharmony_ci		goto error_out;
200562306a36Sopenharmony_ci	}
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	/* only modify existing recipe's lkup_idx and mask if valid, while
200862306a36Sopenharmony_ci	 * leaving all other fields the same, then update the recipe firmware
200962306a36Sopenharmony_ci	 */
201062306a36Sopenharmony_ci	rcp_list->content.lkup_indx[params->lkup_idx] = params->fv_idx;
201162306a36Sopenharmony_ci	if (params->mask_valid)
201262306a36Sopenharmony_ci		rcp_list->content.mask[params->lkup_idx] =
201362306a36Sopenharmony_ci			cpu_to_le16(params->mask);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	if (params->ignore_valid)
201662306a36Sopenharmony_ci		rcp_list->content.lkup_indx[params->lkup_idx] |=
201762306a36Sopenharmony_ci			ICE_AQ_RECIPE_LKUP_IGNORE;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	status = ice_aq_add_recipe(hw, &rcp_list[0], 1, NULL);
202062306a36Sopenharmony_ci	if (status)
202162306a36Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "Failed to update recipe %d lkup_idx %d fv_idx %d mask %d mask_valid %s, status %d\n",
202262306a36Sopenharmony_ci			  params->rid, params->lkup_idx, params->fv_idx,
202362306a36Sopenharmony_ci			  params->mask, params->mask_valid ? "true" : "false",
202462306a36Sopenharmony_ci			  status);
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_cierror_out:
202762306a36Sopenharmony_ci	kfree(rcp_list);
202862306a36Sopenharmony_ci	return status;
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci/**
203262306a36Sopenharmony_ci * ice_aq_map_recipe_to_profile - Map recipe to packet profile
203362306a36Sopenharmony_ci * @hw: pointer to the HW struct
203462306a36Sopenharmony_ci * @profile_id: package profile ID to associate the recipe with
203562306a36Sopenharmony_ci * @r_bitmap: Recipe bitmap filled in and need to be returned as response
203662306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
203762306a36Sopenharmony_ci * Recipe to profile association (0x0291)
203862306a36Sopenharmony_ci */
203962306a36Sopenharmony_ciint
204062306a36Sopenharmony_ciice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
204162306a36Sopenharmony_ci			     struct ice_sq_cd *cd)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	struct ice_aqc_recipe_to_profile *cmd;
204462306a36Sopenharmony_ci	struct ice_aq_desc desc;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	cmd = &desc.params.recipe_to_profile;
204762306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_recipe_to_profile);
204862306a36Sopenharmony_ci	cmd->profile_id = cpu_to_le16(profile_id);
204962306a36Sopenharmony_ci	/* Set the recipe ID bit in the bitmask to let the device know which
205062306a36Sopenharmony_ci	 * profile we are associating the recipe to
205162306a36Sopenharmony_ci	 */
205262306a36Sopenharmony_ci	memcpy(cmd->recipe_assoc, r_bitmap, sizeof(cmd->recipe_assoc));
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci/**
205862306a36Sopenharmony_ci * ice_aq_get_recipe_to_profile - Map recipe to packet profile
205962306a36Sopenharmony_ci * @hw: pointer to the HW struct
206062306a36Sopenharmony_ci * @profile_id: package profile ID to associate the recipe with
206162306a36Sopenharmony_ci * @r_bitmap: Recipe bitmap filled in and need to be returned as response
206262306a36Sopenharmony_ci * @cd: pointer to command details structure or NULL
206362306a36Sopenharmony_ci * Associate profile ID with given recipe (0x0293)
206462306a36Sopenharmony_ci */
206562306a36Sopenharmony_ciint
206662306a36Sopenharmony_ciice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
206762306a36Sopenharmony_ci			     struct ice_sq_cd *cd)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct ice_aqc_recipe_to_profile *cmd;
207062306a36Sopenharmony_ci	struct ice_aq_desc desc;
207162306a36Sopenharmony_ci	int status;
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	cmd = &desc.params.recipe_to_profile;
207462306a36Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile);
207562306a36Sopenharmony_ci	cmd->profile_id = cpu_to_le16(profile_id);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
207862306a36Sopenharmony_ci	if (!status)
207962306a36Sopenharmony_ci		memcpy(r_bitmap, cmd->recipe_assoc, sizeof(cmd->recipe_assoc));
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	return status;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci/**
208562306a36Sopenharmony_ci * ice_alloc_recipe - add recipe resource
208662306a36Sopenharmony_ci * @hw: pointer to the hardware structure
208762306a36Sopenharmony_ci * @rid: recipe ID returned as response to AQ call
208862306a36Sopenharmony_ci */
208962306a36Sopenharmony_ciint ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
209062306a36Sopenharmony_ci{
209162306a36Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *sw_buf;
209262306a36Sopenharmony_ci	u16 buf_len;
209362306a36Sopenharmony_ci	int status;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	buf_len = struct_size(sw_buf, elem, 1);
209662306a36Sopenharmony_ci	sw_buf = kzalloc(buf_len, GFP_KERNEL);
209762306a36Sopenharmony_ci	if (!sw_buf)
209862306a36Sopenharmony_ci		return -ENOMEM;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	sw_buf->num_elems = cpu_to_le16(1);
210162306a36Sopenharmony_ci	sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
210262306a36Sopenharmony_ci					ICE_AQC_RES_TYPE_S) |
210362306a36Sopenharmony_ci					ICE_AQC_RES_TYPE_FLAG_SHARED);
210462306a36Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
210562306a36Sopenharmony_ci				       ice_aqc_opc_alloc_res);
210662306a36Sopenharmony_ci	if (!status)
210762306a36Sopenharmony_ci		*rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp);
210862306a36Sopenharmony_ci	kfree(sw_buf);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	return status;
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci/**
211462306a36Sopenharmony_ci * ice_get_recp_to_prof_map - updates recipe to profile mapping
211562306a36Sopenharmony_ci * @hw: pointer to hardware structure
211662306a36Sopenharmony_ci *
211762306a36Sopenharmony_ci * This function is used to populate recipe_to_profile matrix where index to
211862306a36Sopenharmony_ci * this array is the recipe ID and the element is the mapping of which profiles
211962306a36Sopenharmony_ci * is this recipe mapped to.
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_cistatic void ice_get_recp_to_prof_map(struct ice_hw *hw)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
212462306a36Sopenharmony_ci	u16 i;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) {
212762306a36Sopenharmony_ci		u16 j;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci		bitmap_zero(profile_to_recipe[i], ICE_MAX_NUM_RECIPES);
213062306a36Sopenharmony_ci		bitmap_zero(r_bitmap, ICE_MAX_NUM_RECIPES);
213162306a36Sopenharmony_ci		if (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL))
213262306a36Sopenharmony_ci			continue;
213362306a36Sopenharmony_ci		bitmap_copy(profile_to_recipe[i], r_bitmap,
213462306a36Sopenharmony_ci			    ICE_MAX_NUM_RECIPES);
213562306a36Sopenharmony_ci		for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES)
213662306a36Sopenharmony_ci			set_bit(i, recipe_to_profile[j]);
213762306a36Sopenharmony_ci	}
213862306a36Sopenharmony_ci}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci/**
214162306a36Sopenharmony_ci * ice_collect_result_idx - copy result index values
214262306a36Sopenharmony_ci * @buf: buffer that contains the result index
214362306a36Sopenharmony_ci * @recp: the recipe struct to copy data into
214462306a36Sopenharmony_ci */
214562306a36Sopenharmony_cistatic void
214662306a36Sopenharmony_ciice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
214762306a36Sopenharmony_ci		       struct ice_sw_recipe *recp)
214862306a36Sopenharmony_ci{
214962306a36Sopenharmony_ci	if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
215062306a36Sopenharmony_ci		set_bit(buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
215162306a36Sopenharmony_ci			recp->res_idxs);
215262306a36Sopenharmony_ci}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci/**
215562306a36Sopenharmony_ci * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries
215662306a36Sopenharmony_ci * @hw: pointer to hardware structure
215762306a36Sopenharmony_ci * @recps: struct that we need to populate
215862306a36Sopenharmony_ci * @rid: recipe ID that we are populating
215962306a36Sopenharmony_ci * @refresh_required: true if we should get recipe to profile mapping from FW
216062306a36Sopenharmony_ci *
216162306a36Sopenharmony_ci * This function is used to populate all the necessary entries into our
216262306a36Sopenharmony_ci * bookkeeping so that we have a current list of all the recipes that are
216362306a36Sopenharmony_ci * programmed in the firmware.
216462306a36Sopenharmony_ci */
216562306a36Sopenharmony_cistatic int
216662306a36Sopenharmony_ciice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
216762306a36Sopenharmony_ci		    bool *refresh_required)
216862306a36Sopenharmony_ci{
216962306a36Sopenharmony_ci	DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS);
217062306a36Sopenharmony_ci	struct ice_aqc_recipe_data_elem *tmp;
217162306a36Sopenharmony_ci	u16 num_recps = ICE_MAX_NUM_RECIPES;
217262306a36Sopenharmony_ci	struct ice_prot_lkup_ext *lkup_exts;
217362306a36Sopenharmony_ci	u8 fv_word_idx = 0;
217462306a36Sopenharmony_ci	u16 sub_recps;
217562306a36Sopenharmony_ci	int status;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	bitmap_zero(result_bm, ICE_MAX_FV_WORDS);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	/* we need a buffer big enough to accommodate all the recipes */
218062306a36Sopenharmony_ci	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
218162306a36Sopenharmony_ci	if (!tmp)
218262306a36Sopenharmony_ci		return -ENOMEM;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	tmp[0].recipe_indx = rid;
218562306a36Sopenharmony_ci	status = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL);
218662306a36Sopenharmony_ci	/* non-zero status meaning recipe doesn't exist */
218762306a36Sopenharmony_ci	if (status)
218862306a36Sopenharmony_ci		goto err_unroll;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	/* Get recipe to profile map so that we can get the fv from lkups that
219162306a36Sopenharmony_ci	 * we read for a recipe from FW. Since we want to minimize the number of
219262306a36Sopenharmony_ci	 * times we make this FW call, just make one call and cache the copy
219362306a36Sopenharmony_ci	 * until a new recipe is added. This operation is only required the
219462306a36Sopenharmony_ci	 * first time to get the changes from FW. Then to search existing
219562306a36Sopenharmony_ci	 * entries we don't need to update the cache again until another recipe
219662306a36Sopenharmony_ci	 * gets added.
219762306a36Sopenharmony_ci	 */
219862306a36Sopenharmony_ci	if (*refresh_required) {
219962306a36Sopenharmony_ci		ice_get_recp_to_prof_map(hw);
220062306a36Sopenharmony_ci		*refresh_required = false;
220162306a36Sopenharmony_ci	}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	/* Start populating all the entries for recps[rid] based on lkups from
220462306a36Sopenharmony_ci	 * firmware. Note that we are only creating the root recipe in our
220562306a36Sopenharmony_ci	 * database.
220662306a36Sopenharmony_ci	 */
220762306a36Sopenharmony_ci	lkup_exts = &recps[rid].lkup_exts;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	for (sub_recps = 0; sub_recps < num_recps; sub_recps++) {
221062306a36Sopenharmony_ci		struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps];
221162306a36Sopenharmony_ci		struct ice_recp_grp_entry *rg_entry;
221262306a36Sopenharmony_ci		u8 i, prof, idx, prot = 0;
221362306a36Sopenharmony_ci		bool is_root;
221462306a36Sopenharmony_ci		u16 off = 0;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci		rg_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rg_entry),
221762306a36Sopenharmony_ci					GFP_KERNEL);
221862306a36Sopenharmony_ci		if (!rg_entry) {
221962306a36Sopenharmony_ci			status = -ENOMEM;
222062306a36Sopenharmony_ci			goto err_unroll;
222162306a36Sopenharmony_ci		}
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		idx = root_bufs.recipe_indx;
222462306a36Sopenharmony_ci		is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci		/* Mark all result indices in this chain */
222762306a36Sopenharmony_ci		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
222862306a36Sopenharmony_ci			set_bit(root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
222962306a36Sopenharmony_ci				result_bm);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci		/* get the first profile that is associated with rid */
223262306a36Sopenharmony_ci		prof = find_first_bit(recipe_to_profile[idx],
223362306a36Sopenharmony_ci				      ICE_MAX_NUM_PROFILES);
223462306a36Sopenharmony_ci		for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) {
223562306a36Sopenharmony_ci			u8 lkup_indx = root_bufs.content.lkup_indx[i + 1];
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci			rg_entry->fv_idx[i] = lkup_indx;
223862306a36Sopenharmony_ci			rg_entry->fv_mask[i] =
223962306a36Sopenharmony_ci				le16_to_cpu(root_bufs.content.mask[i + 1]);
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci			/* If the recipe is a chained recipe then all its
224262306a36Sopenharmony_ci			 * child recipe's result will have a result index.
224362306a36Sopenharmony_ci			 * To fill fv_words we should not use those result
224462306a36Sopenharmony_ci			 * index, we only need the protocol ids and offsets.
224562306a36Sopenharmony_ci			 * We will skip all the fv_idx which stores result
224662306a36Sopenharmony_ci			 * index in them. We also need to skip any fv_idx which
224762306a36Sopenharmony_ci			 * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a
224862306a36Sopenharmony_ci			 * valid offset value.
224962306a36Sopenharmony_ci			 */
225062306a36Sopenharmony_ci			if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) ||
225162306a36Sopenharmony_ci			    rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE ||
225262306a36Sopenharmony_ci			    rg_entry->fv_idx[i] == 0)
225362306a36Sopenharmony_ci				continue;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci			ice_find_prot_off(hw, ICE_BLK_SW, prof,
225662306a36Sopenharmony_ci					  rg_entry->fv_idx[i], &prot, &off);
225762306a36Sopenharmony_ci			lkup_exts->fv_words[fv_word_idx].prot_id = prot;
225862306a36Sopenharmony_ci			lkup_exts->fv_words[fv_word_idx].off = off;
225962306a36Sopenharmony_ci			lkup_exts->field_mask[fv_word_idx] =
226062306a36Sopenharmony_ci				rg_entry->fv_mask[i];
226162306a36Sopenharmony_ci			fv_word_idx++;
226262306a36Sopenharmony_ci		}
226362306a36Sopenharmony_ci		/* populate rg_list with the data from the child entry of this
226462306a36Sopenharmony_ci		 * recipe
226562306a36Sopenharmony_ci		 */
226662306a36Sopenharmony_ci		list_add(&rg_entry->l_entry, &recps[rid].rg_list);
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci		/* Propagate some data to the recipe database */
226962306a36Sopenharmony_ci		recps[idx].is_root = !!is_root;
227062306a36Sopenharmony_ci		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
227162306a36Sopenharmony_ci		recps[idx].need_pass_l2 = root_bufs.content.act_ctrl &
227262306a36Sopenharmony_ci					  ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
227362306a36Sopenharmony_ci		recps[idx].allow_pass_l2 = root_bufs.content.act_ctrl &
227462306a36Sopenharmony_ci					   ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
227562306a36Sopenharmony_ci		bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
227662306a36Sopenharmony_ci		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
227762306a36Sopenharmony_ci			recps[idx].chain_idx = root_bufs.content.result_indx &
227862306a36Sopenharmony_ci				~ICE_AQ_RECIPE_RESULT_EN;
227962306a36Sopenharmony_ci			set_bit(recps[idx].chain_idx, recps[idx].res_idxs);
228062306a36Sopenharmony_ci		} else {
228162306a36Sopenharmony_ci			recps[idx].chain_idx = ICE_INVAL_CHAIN_IND;
228262306a36Sopenharmony_ci		}
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci		if (!is_root)
228562306a36Sopenharmony_ci			continue;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci		/* Only do the following for root recipes entries */
228862306a36Sopenharmony_ci		memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap,
228962306a36Sopenharmony_ci		       sizeof(recps[idx].r_bitmap));
229062306a36Sopenharmony_ci		recps[idx].root_rid = root_bufs.content.rid &
229162306a36Sopenharmony_ci			~ICE_AQ_RECIPE_ID_IS_ROOT;
229262306a36Sopenharmony_ci		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
229362306a36Sopenharmony_ci	}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	/* Complete initialization of the root recipe entry */
229662306a36Sopenharmony_ci	lkup_exts->n_val_words = fv_word_idx;
229762306a36Sopenharmony_ci	recps[rid].big_recp = (num_recps > 1);
229862306a36Sopenharmony_ci	recps[rid].n_grp_count = (u8)num_recps;
229962306a36Sopenharmony_ci	recps[rid].root_buf = devm_kmemdup(ice_hw_to_dev(hw), tmp,
230062306a36Sopenharmony_ci					   recps[rid].n_grp_count * sizeof(*recps[rid].root_buf),
230162306a36Sopenharmony_ci					   GFP_KERNEL);
230262306a36Sopenharmony_ci	if (!recps[rid].root_buf) {
230362306a36Sopenharmony_ci		status = -ENOMEM;
230462306a36Sopenharmony_ci		goto err_unroll;
230562306a36Sopenharmony_ci	}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	/* Copy result indexes */
230862306a36Sopenharmony_ci	bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS);
230962306a36Sopenharmony_ci	recps[rid].recp_created = true;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_cierr_unroll:
231262306a36Sopenharmony_ci	kfree(tmp);
231362306a36Sopenharmony_ci	return status;
231462306a36Sopenharmony_ci}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci/* ice_init_port_info - Initialize port_info with switch configuration data
231762306a36Sopenharmony_ci * @pi: pointer to port_info
231862306a36Sopenharmony_ci * @vsi_port_num: VSI number or port number
231962306a36Sopenharmony_ci * @type: Type of switch element (port or VSI)
232062306a36Sopenharmony_ci * @swid: switch ID of the switch the element is attached to
232162306a36Sopenharmony_ci * @pf_vf_num: PF or VF number
232262306a36Sopenharmony_ci * @is_vf: true if the element is a VF, false otherwise
232362306a36Sopenharmony_ci */
232462306a36Sopenharmony_cistatic void
232562306a36Sopenharmony_ciice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,
232662306a36Sopenharmony_ci		   u16 swid, u16 pf_vf_num, bool is_vf)
232762306a36Sopenharmony_ci{
232862306a36Sopenharmony_ci	switch (type) {
232962306a36Sopenharmony_ci	case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
233062306a36Sopenharmony_ci		pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);
233162306a36Sopenharmony_ci		pi->sw_id = swid;
233262306a36Sopenharmony_ci		pi->pf_vf_num = pf_vf_num;
233362306a36Sopenharmony_ci		pi->is_vf = is_vf;
233462306a36Sopenharmony_ci		break;
233562306a36Sopenharmony_ci	default:
233662306a36Sopenharmony_ci		ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n");
233762306a36Sopenharmony_ci		break;
233862306a36Sopenharmony_ci	}
233962306a36Sopenharmony_ci}
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci/* ice_get_initial_sw_cfg - Get initial port and default VSI data
234262306a36Sopenharmony_ci * @hw: pointer to the hardware structure
234362306a36Sopenharmony_ci */
234462306a36Sopenharmony_ciint ice_get_initial_sw_cfg(struct ice_hw *hw)
234562306a36Sopenharmony_ci{
234662306a36Sopenharmony_ci	struct ice_aqc_get_sw_cfg_resp_elem *rbuf;
234762306a36Sopenharmony_ci	u16 req_desc = 0;
234862306a36Sopenharmony_ci	u16 num_elems;
234962306a36Sopenharmony_ci	int status;
235062306a36Sopenharmony_ci	u16 i;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	rbuf = kzalloc(ICE_SW_CFG_MAX_BUF_LEN, GFP_KERNEL);
235362306a36Sopenharmony_ci	if (!rbuf)
235462306a36Sopenharmony_ci		return -ENOMEM;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	/* Multiple calls to ice_aq_get_sw_cfg may be required
235762306a36Sopenharmony_ci	 * to get all the switch configuration information. The need
235862306a36Sopenharmony_ci	 * for additional calls is indicated by ice_aq_get_sw_cfg
235962306a36Sopenharmony_ci	 * writing a non-zero value in req_desc
236062306a36Sopenharmony_ci	 */
236162306a36Sopenharmony_ci	do {
236262306a36Sopenharmony_ci		struct ice_aqc_get_sw_cfg_resp_elem *ele;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci		status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,
236562306a36Sopenharmony_ci					   &req_desc, &num_elems, NULL);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		if (status)
236862306a36Sopenharmony_ci			break;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci		for (i = 0, ele = rbuf; i < num_elems; i++, ele++) {
237162306a36Sopenharmony_ci			u16 pf_vf_num, swid, vsi_port_num;
237262306a36Sopenharmony_ci			bool is_vf = false;
237362306a36Sopenharmony_ci			u8 res_type;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci			vsi_port_num = le16_to_cpu(ele->vsi_port_num) &
237662306a36Sopenharmony_ci				ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci			pf_vf_num = le16_to_cpu(ele->pf_vf_num) &
237962306a36Sopenharmony_ci				ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci			swid = le16_to_cpu(ele->swid);
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci			if (le16_to_cpu(ele->pf_vf_num) &
238462306a36Sopenharmony_ci			    ICE_AQC_GET_SW_CONF_RESP_IS_VF)
238562306a36Sopenharmony_ci				is_vf = true;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci			res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >>
238862306a36Sopenharmony_ci					ICE_AQC_GET_SW_CONF_RESP_TYPE_S);
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci			if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) {
239162306a36Sopenharmony_ci				/* FW VSI is not needed. Just continue. */
239262306a36Sopenharmony_ci				continue;
239362306a36Sopenharmony_ci			}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci			ice_init_port_info(hw->port_info, vsi_port_num,
239662306a36Sopenharmony_ci					   res_type, swid, pf_vf_num, is_vf);
239762306a36Sopenharmony_ci		}
239862306a36Sopenharmony_ci	} while (req_desc && !status);
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	kfree(rbuf);
240162306a36Sopenharmony_ci	return status;
240262306a36Sopenharmony_ci}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci/**
240562306a36Sopenharmony_ci * ice_fill_sw_info - Helper function to populate lb_en and lan_en
240662306a36Sopenharmony_ci * @hw: pointer to the hardware structure
240762306a36Sopenharmony_ci * @fi: filter info structure to fill/update
240862306a36Sopenharmony_ci *
240962306a36Sopenharmony_ci * This helper function populates the lb_en and lan_en elements of the provided
241062306a36Sopenharmony_ci * ice_fltr_info struct using the switch's type and characteristics of the
241162306a36Sopenharmony_ci * switch rule being configured.
241262306a36Sopenharmony_ci */
241362306a36Sopenharmony_cistatic void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
241462306a36Sopenharmony_ci{
241562306a36Sopenharmony_ci	fi->lb_en = false;
241662306a36Sopenharmony_ci	fi->lan_en = false;
241762306a36Sopenharmony_ci	if ((fi->flag & ICE_FLTR_TX) &&
241862306a36Sopenharmony_ci	    (fi->fltr_act == ICE_FWD_TO_VSI ||
241962306a36Sopenharmony_ci	     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
242062306a36Sopenharmony_ci	     fi->fltr_act == ICE_FWD_TO_Q ||
242162306a36Sopenharmony_ci	     fi->fltr_act == ICE_FWD_TO_QGRP)) {
242262306a36Sopenharmony_ci		/* Setting LB for prune actions will result in replicated
242362306a36Sopenharmony_ci		 * packets to the internal switch that will be dropped.
242462306a36Sopenharmony_ci		 */
242562306a36Sopenharmony_ci		if (fi->lkup_type != ICE_SW_LKUP_VLAN)
242662306a36Sopenharmony_ci			fi->lb_en = true;
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci		/* Set lan_en to TRUE if
242962306a36Sopenharmony_ci		 * 1. The switch is a VEB AND
243062306a36Sopenharmony_ci		 * 2
243162306a36Sopenharmony_ci		 * 2.1 The lookup is a directional lookup like ethertype,
243262306a36Sopenharmony_ci		 * promiscuous, ethertype-MAC, promiscuous-VLAN
243362306a36Sopenharmony_ci		 * and default-port OR
243462306a36Sopenharmony_ci		 * 2.2 The lookup is VLAN, OR
243562306a36Sopenharmony_ci		 * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR
243662306a36Sopenharmony_ci		 * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC.
243762306a36Sopenharmony_ci		 *
243862306a36Sopenharmony_ci		 * OR
243962306a36Sopenharmony_ci		 *
244062306a36Sopenharmony_ci		 * The switch is a VEPA.
244162306a36Sopenharmony_ci		 *
244262306a36Sopenharmony_ci		 * In all other cases, the LAN enable has to be set to false.
244362306a36Sopenharmony_ci		 */
244462306a36Sopenharmony_ci		if (hw->evb_veb) {
244562306a36Sopenharmony_ci			if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE ||
244662306a36Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_PROMISC ||
244762306a36Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
244862306a36Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
244962306a36Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_DFLT ||
245062306a36Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_VLAN ||
245162306a36Sopenharmony_ci			    (fi->lkup_type == ICE_SW_LKUP_MAC &&
245262306a36Sopenharmony_ci			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)) ||
245362306a36Sopenharmony_ci			    (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&
245462306a36Sopenharmony_ci			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)))
245562306a36Sopenharmony_ci				fi->lan_en = true;
245662306a36Sopenharmony_ci		} else {
245762306a36Sopenharmony_ci			fi->lan_en = true;
245862306a36Sopenharmony_ci		}
245962306a36Sopenharmony_ci	}
246062306a36Sopenharmony_ci}
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci/**
246362306a36Sopenharmony_ci * ice_fill_eth_hdr - helper to copy dummy_eth_hdr into supplied buffer
246462306a36Sopenharmony_ci * @eth_hdr: pointer to buffer to populate
246562306a36Sopenharmony_ci */
246662306a36Sopenharmony_civoid ice_fill_eth_hdr(u8 *eth_hdr)
246762306a36Sopenharmony_ci{
246862306a36Sopenharmony_ci	memcpy(eth_hdr, dummy_eth_header, DUMMY_ETH_HDR_LEN);
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci/**
247262306a36Sopenharmony_ci * ice_fill_sw_rule - Helper function to fill switch rule structure
247362306a36Sopenharmony_ci * @hw: pointer to the hardware structure
247462306a36Sopenharmony_ci * @f_info: entry containing packet forwarding information
247562306a36Sopenharmony_ci * @s_rule: switch rule structure to be filled in based on mac_entry
247662306a36Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
247762306a36Sopenharmony_ci */
247862306a36Sopenharmony_cistatic void
247962306a36Sopenharmony_ciice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
248062306a36Sopenharmony_ci		 struct ice_sw_rule_lkup_rx_tx *s_rule,
248162306a36Sopenharmony_ci		 enum ice_adminq_opc opc)
248262306a36Sopenharmony_ci{
248362306a36Sopenharmony_ci	u16 vlan_id = ICE_MAX_VLAN_ID + 1;
248462306a36Sopenharmony_ci	u16 vlan_tpid = ETH_P_8021Q;
248562306a36Sopenharmony_ci	void *daddr = NULL;
248662306a36Sopenharmony_ci	u16 eth_hdr_sz;
248762306a36Sopenharmony_ci	u8 *eth_hdr;
248862306a36Sopenharmony_ci	u32 act = 0;
248962306a36Sopenharmony_ci	__be16 *off;
249062306a36Sopenharmony_ci	u8 q_rgn;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	if (opc == ice_aqc_opc_remove_sw_rules) {
249362306a36Sopenharmony_ci		s_rule->act = 0;
249462306a36Sopenharmony_ci		s_rule->index = cpu_to_le16(f_info->fltr_rule_id);
249562306a36Sopenharmony_ci		s_rule->hdr_len = 0;
249662306a36Sopenharmony_ci		return;
249762306a36Sopenharmony_ci	}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	eth_hdr_sz = sizeof(dummy_eth_header);
250062306a36Sopenharmony_ci	eth_hdr = s_rule->hdr_data;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	/* initialize the ether header with a dummy header */
250362306a36Sopenharmony_ci	memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);
250462306a36Sopenharmony_ci	ice_fill_sw_info(hw, f_info);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	switch (f_info->fltr_act) {
250762306a36Sopenharmony_ci	case ICE_FWD_TO_VSI:
250862306a36Sopenharmony_ci		act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
250962306a36Sopenharmony_ci			ICE_SINGLE_ACT_VSI_ID_M;
251062306a36Sopenharmony_ci		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
251162306a36Sopenharmony_ci			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
251262306a36Sopenharmony_ci				ICE_SINGLE_ACT_VALID_BIT;
251362306a36Sopenharmony_ci		break;
251462306a36Sopenharmony_ci	case ICE_FWD_TO_VSI_LIST:
251562306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_VSI_LIST;
251662306a36Sopenharmony_ci		act |= (f_info->fwd_id.vsi_list_id <<
251762306a36Sopenharmony_ci			ICE_SINGLE_ACT_VSI_LIST_ID_S) &
251862306a36Sopenharmony_ci			ICE_SINGLE_ACT_VSI_LIST_ID_M;
251962306a36Sopenharmony_ci		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
252062306a36Sopenharmony_ci			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
252162306a36Sopenharmony_ci				ICE_SINGLE_ACT_VALID_BIT;
252262306a36Sopenharmony_ci		break;
252362306a36Sopenharmony_ci	case ICE_FWD_TO_Q:
252462306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_TO_Q;
252562306a36Sopenharmony_ci		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
252662306a36Sopenharmony_ci			ICE_SINGLE_ACT_Q_INDEX_M;
252762306a36Sopenharmony_ci		break;
252862306a36Sopenharmony_ci	case ICE_DROP_PACKET:
252962306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
253062306a36Sopenharmony_ci			ICE_SINGLE_ACT_VALID_BIT;
253162306a36Sopenharmony_ci		break;
253262306a36Sopenharmony_ci	case ICE_FWD_TO_QGRP:
253362306a36Sopenharmony_ci		q_rgn = f_info->qgrp_size > 0 ?
253462306a36Sopenharmony_ci			(u8)ilog2(f_info->qgrp_size) : 0;
253562306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_TO_Q;
253662306a36Sopenharmony_ci		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
253762306a36Sopenharmony_ci			ICE_SINGLE_ACT_Q_INDEX_M;
253862306a36Sopenharmony_ci		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
253962306a36Sopenharmony_ci			ICE_SINGLE_ACT_Q_REGION_M;
254062306a36Sopenharmony_ci		break;
254162306a36Sopenharmony_ci	default:
254262306a36Sopenharmony_ci		return;
254362306a36Sopenharmony_ci	}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	if (f_info->lb_en)
254662306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_LB_ENABLE;
254762306a36Sopenharmony_ci	if (f_info->lan_en)
254862306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_LAN_ENABLE;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	switch (f_info->lkup_type) {
255162306a36Sopenharmony_ci	case ICE_SW_LKUP_MAC:
255262306a36Sopenharmony_ci		daddr = f_info->l_data.mac.mac_addr;
255362306a36Sopenharmony_ci		break;
255462306a36Sopenharmony_ci	case ICE_SW_LKUP_VLAN:
255562306a36Sopenharmony_ci		vlan_id = f_info->l_data.vlan.vlan_id;
255662306a36Sopenharmony_ci		if (f_info->l_data.vlan.tpid_valid)
255762306a36Sopenharmony_ci			vlan_tpid = f_info->l_data.vlan.tpid;
255862306a36Sopenharmony_ci		if (f_info->fltr_act == ICE_FWD_TO_VSI ||
255962306a36Sopenharmony_ci		    f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
256062306a36Sopenharmony_ci			act |= ICE_SINGLE_ACT_PRUNE;
256162306a36Sopenharmony_ci			act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS;
256262306a36Sopenharmony_ci		}
256362306a36Sopenharmony_ci		break;
256462306a36Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE_MAC:
256562306a36Sopenharmony_ci		daddr = f_info->l_data.ethertype_mac.mac_addr;
256662306a36Sopenharmony_ci		fallthrough;
256762306a36Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE:
256862306a36Sopenharmony_ci		off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
256962306a36Sopenharmony_ci		*off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype);
257062306a36Sopenharmony_ci		break;
257162306a36Sopenharmony_ci	case ICE_SW_LKUP_MAC_VLAN:
257262306a36Sopenharmony_ci		daddr = f_info->l_data.mac_vlan.mac_addr;
257362306a36Sopenharmony_ci		vlan_id = f_info->l_data.mac_vlan.vlan_id;
257462306a36Sopenharmony_ci		break;
257562306a36Sopenharmony_ci	case ICE_SW_LKUP_PROMISC_VLAN:
257662306a36Sopenharmony_ci		vlan_id = f_info->l_data.mac_vlan.vlan_id;
257762306a36Sopenharmony_ci		fallthrough;
257862306a36Sopenharmony_ci	case ICE_SW_LKUP_PROMISC:
257962306a36Sopenharmony_ci		daddr = f_info->l_data.mac_vlan.mac_addr;
258062306a36Sopenharmony_ci		break;
258162306a36Sopenharmony_ci	default:
258262306a36Sopenharmony_ci		break;
258362306a36Sopenharmony_ci	}
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	s_rule->hdr.type = (f_info->flag & ICE_FLTR_RX) ?
258662306a36Sopenharmony_ci		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) :
258762306a36Sopenharmony_ci		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	/* Recipe set depending on lookup type */
259062306a36Sopenharmony_ci	s_rule->recipe_id = cpu_to_le16(f_info->lkup_type);
259162306a36Sopenharmony_ci	s_rule->src = cpu_to_le16(f_info->src);
259262306a36Sopenharmony_ci	s_rule->act = cpu_to_le32(act);
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	if (daddr)
259562306a36Sopenharmony_ci		ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr);
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	if (!(vlan_id > ICE_MAX_VLAN_ID)) {
259862306a36Sopenharmony_ci		off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
259962306a36Sopenharmony_ci		*off = cpu_to_be16(vlan_id);
260062306a36Sopenharmony_ci		off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
260162306a36Sopenharmony_ci		*off = cpu_to_be16(vlan_tpid);
260262306a36Sopenharmony_ci	}
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	/* Create the switch rule with the final dummy Ethernet header */
260562306a36Sopenharmony_ci	if (opc != ice_aqc_opc_update_sw_rules)
260662306a36Sopenharmony_ci		s_rule->hdr_len = cpu_to_le16(eth_hdr_sz);
260762306a36Sopenharmony_ci}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci/**
261062306a36Sopenharmony_ci * ice_add_marker_act
261162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
261262306a36Sopenharmony_ci * @m_ent: the management entry for which sw marker needs to be added
261362306a36Sopenharmony_ci * @sw_marker: sw marker to tag the Rx descriptor with
261462306a36Sopenharmony_ci * @l_id: large action resource ID
261562306a36Sopenharmony_ci *
261662306a36Sopenharmony_ci * Create a large action to hold software marker and update the switch rule
261762306a36Sopenharmony_ci * entry pointed by m_ent with newly created large action
261862306a36Sopenharmony_ci */
261962306a36Sopenharmony_cistatic int
262062306a36Sopenharmony_ciice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
262162306a36Sopenharmony_ci		   u16 sw_marker, u16 l_id)
262262306a36Sopenharmony_ci{
262362306a36Sopenharmony_ci	struct ice_sw_rule_lkup_rx_tx *rx_tx;
262462306a36Sopenharmony_ci	struct ice_sw_rule_lg_act *lg_act;
262562306a36Sopenharmony_ci	/* For software marker we need 3 large actions
262662306a36Sopenharmony_ci	 * 1. FWD action: FWD TO VSI or VSI LIST
262762306a36Sopenharmony_ci	 * 2. GENERIC VALUE action to hold the profile ID
262862306a36Sopenharmony_ci	 * 3. GENERIC VALUE action to hold the software marker ID
262962306a36Sopenharmony_ci	 */
263062306a36Sopenharmony_ci	const u16 num_lg_acts = 3;
263162306a36Sopenharmony_ci	u16 lg_act_size;
263262306a36Sopenharmony_ci	u16 rules_size;
263362306a36Sopenharmony_ci	int status;
263462306a36Sopenharmony_ci	u32 act;
263562306a36Sopenharmony_ci	u16 id;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
263862306a36Sopenharmony_ci		return -EINVAL;
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	/* Create two back-to-back switch rules and submit them to the HW using
264162306a36Sopenharmony_ci	 * one memory buffer:
264262306a36Sopenharmony_ci	 *    1. Large Action
264362306a36Sopenharmony_ci	 *    2. Look up Tx Rx
264462306a36Sopenharmony_ci	 */
264562306a36Sopenharmony_ci	lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(lg_act, num_lg_acts);
264662306a36Sopenharmony_ci	rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(rx_tx);
264762306a36Sopenharmony_ci	lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL);
264862306a36Sopenharmony_ci	if (!lg_act)
264962306a36Sopenharmony_ci		return -ENOMEM;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	rx_tx = (typeof(rx_tx))((u8 *)lg_act + lg_act_size);
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	/* Fill in the first switch rule i.e. large action */
265462306a36Sopenharmony_ci	lg_act->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT);
265562306a36Sopenharmony_ci	lg_act->index = cpu_to_le16(l_id);
265662306a36Sopenharmony_ci	lg_act->size = cpu_to_le16(num_lg_acts);
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	/* First action VSI forwarding or VSI list forwarding depending on how
265962306a36Sopenharmony_ci	 * many VSIs
266062306a36Sopenharmony_ci	 */
266162306a36Sopenharmony_ci	id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :
266262306a36Sopenharmony_ci		m_ent->fltr_info.fwd_id.hw_vsi_id;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
266562306a36Sopenharmony_ci	act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
266662306a36Sopenharmony_ci	if (m_ent->vsi_count > 1)
266762306a36Sopenharmony_ci		act |= ICE_LG_ACT_VSI_LIST;
266862306a36Sopenharmony_ci	lg_act->act[0] = cpu_to_le32(act);
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	/* Second action descriptor type */
267162306a36Sopenharmony_ci	act = ICE_LG_ACT_GENERIC;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
267462306a36Sopenharmony_ci	lg_act->act[1] = cpu_to_le32(act);
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
267762306a36Sopenharmony_ci	       ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	/* Third action Marker value */
268062306a36Sopenharmony_ci	act |= ICE_LG_ACT_GENERIC;
268162306a36Sopenharmony_ci	act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
268262306a36Sopenharmony_ci		ICE_LG_ACT_GENERIC_VALUE_M;
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	lg_act->act[2] = cpu_to_le32(act);
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	/* call the fill switch rule to fill the lookup Tx Rx structure */
268762306a36Sopenharmony_ci	ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,
268862306a36Sopenharmony_ci			 ice_aqc_opc_update_sw_rules);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	/* Update the action to point to the large action ID */
269162306a36Sopenharmony_ci	rx_tx->act = cpu_to_le32(ICE_SINGLE_ACT_PTR |
269262306a36Sopenharmony_ci				 ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
269362306a36Sopenharmony_ci				  ICE_SINGLE_ACT_PTR_VAL_M));
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	/* Use the filter rule ID of the previously created rule with single
269662306a36Sopenharmony_ci	 * act. Once the update happens, hardware will treat this as large
269762306a36Sopenharmony_ci	 * action
269862306a36Sopenharmony_ci	 */
269962306a36Sopenharmony_ci	rx_tx->index = cpu_to_le16(m_ent->fltr_info.fltr_rule_id);
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	status = ice_aq_sw_rules(hw, lg_act, rules_size, 2,
270262306a36Sopenharmony_ci				 ice_aqc_opc_update_sw_rules, NULL);
270362306a36Sopenharmony_ci	if (!status) {
270462306a36Sopenharmony_ci		m_ent->lg_act_idx = l_id;
270562306a36Sopenharmony_ci		m_ent->sw_marker_id = sw_marker;
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), lg_act);
270962306a36Sopenharmony_ci	return status;
271062306a36Sopenharmony_ci}
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci/**
271362306a36Sopenharmony_ci * ice_create_vsi_list_map
271462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
271562306a36Sopenharmony_ci * @vsi_handle_arr: array of VSI handles to set in the VSI mapping
271662306a36Sopenharmony_ci * @num_vsi: number of VSI handles in the array
271762306a36Sopenharmony_ci * @vsi_list_id: VSI list ID generated as part of allocate resource
271862306a36Sopenharmony_ci *
271962306a36Sopenharmony_ci * Helper function to create a new entry of VSI list ID to VSI mapping
272062306a36Sopenharmony_ci * using the given VSI list ID
272162306a36Sopenharmony_ci */
272262306a36Sopenharmony_cistatic struct ice_vsi_list_map_info *
272362306a36Sopenharmony_ciice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
272462306a36Sopenharmony_ci			u16 vsi_list_id)
272562306a36Sopenharmony_ci{
272662306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
272762306a36Sopenharmony_ci	struct ice_vsi_list_map_info *v_map;
272862306a36Sopenharmony_ci	int i;
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci	v_map = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*v_map), GFP_KERNEL);
273162306a36Sopenharmony_ci	if (!v_map)
273262306a36Sopenharmony_ci		return NULL;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	v_map->vsi_list_id = vsi_list_id;
273562306a36Sopenharmony_ci	v_map->ref_cnt = 1;
273662306a36Sopenharmony_ci	for (i = 0; i < num_vsi; i++)
273762306a36Sopenharmony_ci		set_bit(vsi_handle_arr[i], v_map->vsi_map);
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	list_add(&v_map->list_entry, &sw->vsi_list_map_head);
274062306a36Sopenharmony_ci	return v_map;
274162306a36Sopenharmony_ci}
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci/**
274462306a36Sopenharmony_ci * ice_update_vsi_list_rule
274562306a36Sopenharmony_ci * @hw: pointer to the hardware structure
274662306a36Sopenharmony_ci * @vsi_handle_arr: array of VSI handles to form a VSI list
274762306a36Sopenharmony_ci * @num_vsi: number of VSI handles in the array
274862306a36Sopenharmony_ci * @vsi_list_id: VSI list ID generated as part of allocate resource
274962306a36Sopenharmony_ci * @remove: Boolean value to indicate if this is a remove action
275062306a36Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
275162306a36Sopenharmony_ci * @lkup_type: lookup type of the filter
275262306a36Sopenharmony_ci *
275362306a36Sopenharmony_ci * Call AQ command to add a new switch rule or update existing switch rule
275462306a36Sopenharmony_ci * using the given VSI list ID
275562306a36Sopenharmony_ci */
275662306a36Sopenharmony_cistatic int
275762306a36Sopenharmony_ciice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
275862306a36Sopenharmony_ci			 u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,
275962306a36Sopenharmony_ci			 enum ice_sw_lkup_type lkup_type)
276062306a36Sopenharmony_ci{
276162306a36Sopenharmony_ci	struct ice_sw_rule_vsi_list *s_rule;
276262306a36Sopenharmony_ci	u16 s_rule_size;
276362306a36Sopenharmony_ci	u16 rule_type;
276462306a36Sopenharmony_ci	int status;
276562306a36Sopenharmony_ci	int i;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	if (!num_vsi)
276862306a36Sopenharmony_ci		return -EINVAL;
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	if (lkup_type == ICE_SW_LKUP_MAC ||
277162306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
277262306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
277362306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
277462306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC ||
277562306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
277662306a36Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_DFLT)
277762306a36Sopenharmony_ci		rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR :
277862306a36Sopenharmony_ci			ICE_AQC_SW_RULES_T_VSI_LIST_SET;
277962306a36Sopenharmony_ci	else if (lkup_type == ICE_SW_LKUP_VLAN)
278062306a36Sopenharmony_ci		rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR :
278162306a36Sopenharmony_ci			ICE_AQC_SW_RULES_T_PRUNE_LIST_SET;
278262306a36Sopenharmony_ci	else
278362306a36Sopenharmony_ci		return -EINVAL;
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_ci	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, num_vsi);
278662306a36Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
278762306a36Sopenharmony_ci	if (!s_rule)
278862306a36Sopenharmony_ci		return -ENOMEM;
278962306a36Sopenharmony_ci	for (i = 0; i < num_vsi; i++) {
279062306a36Sopenharmony_ci		if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {
279162306a36Sopenharmony_ci			status = -EINVAL;
279262306a36Sopenharmony_ci			goto exit;
279362306a36Sopenharmony_ci		}
279462306a36Sopenharmony_ci		/* AQ call requires hw_vsi_id(s) */
279562306a36Sopenharmony_ci		s_rule->vsi[i] =
279662306a36Sopenharmony_ci			cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));
279762306a36Sopenharmony_ci	}
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	s_rule->hdr.type = cpu_to_le16(rule_type);
280062306a36Sopenharmony_ci	s_rule->number_vsi = cpu_to_le16(num_vsi);
280162306a36Sopenharmony_ci	s_rule->index = cpu_to_le16(vsi_list_id);
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ciexit:
280662306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
280762306a36Sopenharmony_ci	return status;
280862306a36Sopenharmony_ci}
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci/**
281162306a36Sopenharmony_ci * ice_create_vsi_list_rule - Creates and populates a VSI list rule
281262306a36Sopenharmony_ci * @hw: pointer to the HW struct
281362306a36Sopenharmony_ci * @vsi_handle_arr: array of VSI handles to form a VSI list
281462306a36Sopenharmony_ci * @num_vsi: number of VSI handles in the array
281562306a36Sopenharmony_ci * @vsi_list_id: stores the ID of the VSI list to be created
281662306a36Sopenharmony_ci * @lkup_type: switch rule filter's lookup type
281762306a36Sopenharmony_ci */
281862306a36Sopenharmony_cistatic int
281962306a36Sopenharmony_ciice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
282062306a36Sopenharmony_ci			 u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	int status;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,
282562306a36Sopenharmony_ci					    ice_aqc_opc_alloc_res);
282662306a36Sopenharmony_ci	if (status)
282762306a36Sopenharmony_ci		return status;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	/* Update the newly created VSI list to include the specified VSIs */
283062306a36Sopenharmony_ci	return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,
283162306a36Sopenharmony_ci					*vsi_list_id, false,
283262306a36Sopenharmony_ci					ice_aqc_opc_add_sw_rules, lkup_type);
283362306a36Sopenharmony_ci}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci/**
283662306a36Sopenharmony_ci * ice_create_pkt_fwd_rule
283762306a36Sopenharmony_ci * @hw: pointer to the hardware structure
283862306a36Sopenharmony_ci * @f_entry: entry containing packet forwarding information
283962306a36Sopenharmony_ci *
284062306a36Sopenharmony_ci * Create switch rule with given filter information and add an entry
284162306a36Sopenharmony_ci * to the corresponding filter management list to track this switch rule
284262306a36Sopenharmony_ci * and VSI mapping
284362306a36Sopenharmony_ci */
284462306a36Sopenharmony_cistatic int
284562306a36Sopenharmony_ciice_create_pkt_fwd_rule(struct ice_hw *hw,
284662306a36Sopenharmony_ci			struct ice_fltr_list_entry *f_entry)
284762306a36Sopenharmony_ci{
284862306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
284962306a36Sopenharmony_ci	struct ice_sw_rule_lkup_rx_tx *s_rule;
285062306a36Sopenharmony_ci	enum ice_sw_lkup_type l_type;
285162306a36Sopenharmony_ci	struct ice_sw_recipe *recp;
285262306a36Sopenharmony_ci	int status;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
285562306a36Sopenharmony_ci			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule),
285662306a36Sopenharmony_ci			      GFP_KERNEL);
285762306a36Sopenharmony_ci	if (!s_rule)
285862306a36Sopenharmony_ci		return -ENOMEM;
285962306a36Sopenharmony_ci	fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry),
286062306a36Sopenharmony_ci				GFP_KERNEL);
286162306a36Sopenharmony_ci	if (!fm_entry) {
286262306a36Sopenharmony_ci		status = -ENOMEM;
286362306a36Sopenharmony_ci		goto ice_create_pkt_fwd_rule_exit;
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	fm_entry->fltr_info = f_entry->fltr_info;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	/* Initialize all the fields for the management entry */
286962306a36Sopenharmony_ci	fm_entry->vsi_count = 1;
287062306a36Sopenharmony_ci	fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX;
287162306a36Sopenharmony_ci	fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID;
287262306a36Sopenharmony_ci	fm_entry->counter_index = ICE_INVAL_COUNTER_ID;
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci	ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule,
287562306a36Sopenharmony_ci			 ice_aqc_opc_add_sw_rules);
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule,
287862306a36Sopenharmony_ci				 ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), 1,
287962306a36Sopenharmony_ci				 ice_aqc_opc_add_sw_rules, NULL);
288062306a36Sopenharmony_ci	if (status) {
288162306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fm_entry);
288262306a36Sopenharmony_ci		goto ice_create_pkt_fwd_rule_exit;
288362306a36Sopenharmony_ci	}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	f_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index);
288662306a36Sopenharmony_ci	fm_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index);
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	/* The book keeping entries will get removed when base driver
288962306a36Sopenharmony_ci	 * calls remove filter AQ command
289062306a36Sopenharmony_ci	 */
289162306a36Sopenharmony_ci	l_type = fm_entry->fltr_info.lkup_type;
289262306a36Sopenharmony_ci	recp = &hw->switch_info->recp_list[l_type];
289362306a36Sopenharmony_ci	list_add(&fm_entry->list_entry, &recp->filt_rules);
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ciice_create_pkt_fwd_rule_exit:
289662306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
289762306a36Sopenharmony_ci	return status;
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci/**
290162306a36Sopenharmony_ci * ice_update_pkt_fwd_rule
290262306a36Sopenharmony_ci * @hw: pointer to the hardware structure
290362306a36Sopenharmony_ci * @f_info: filter information for switch rule
290462306a36Sopenharmony_ci *
290562306a36Sopenharmony_ci * Call AQ command to update a previously created switch rule with a
290662306a36Sopenharmony_ci * VSI list ID
290762306a36Sopenharmony_ci */
290862306a36Sopenharmony_cistatic int
290962306a36Sopenharmony_ciice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
291062306a36Sopenharmony_ci{
291162306a36Sopenharmony_ci	struct ice_sw_rule_lkup_rx_tx *s_rule;
291262306a36Sopenharmony_ci	int status;
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
291562306a36Sopenharmony_ci			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule),
291662306a36Sopenharmony_ci			      GFP_KERNEL);
291762306a36Sopenharmony_ci	if (!s_rule)
291862306a36Sopenharmony_ci		return -ENOMEM;
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	s_rule->index = cpu_to_le16(f_info->fltr_rule_id);
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	/* Update switch rule with new rule set to forward VSI list */
292562306a36Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule,
292662306a36Sopenharmony_ci				 ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), 1,
292762306a36Sopenharmony_ci				 ice_aqc_opc_update_sw_rules, NULL);
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
293062306a36Sopenharmony_ci	return status;
293162306a36Sopenharmony_ci}
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci/**
293462306a36Sopenharmony_ci * ice_update_sw_rule_bridge_mode
293562306a36Sopenharmony_ci * @hw: pointer to the HW struct
293662306a36Sopenharmony_ci *
293762306a36Sopenharmony_ci * Updates unicast switch filter rules based on VEB/VEPA mode
293862306a36Sopenharmony_ci */
293962306a36Sopenharmony_ciint ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
294062306a36Sopenharmony_ci{
294162306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
294262306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
294362306a36Sopenharmony_ci	struct list_head *rule_head;
294462306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
294562306a36Sopenharmony_ci	int status = 0;
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
294862306a36Sopenharmony_ci	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci	mutex_lock(rule_lock);
295162306a36Sopenharmony_ci	list_for_each_entry(fm_entry, rule_head, list_entry) {
295262306a36Sopenharmony_ci		struct ice_fltr_info *fi = &fm_entry->fltr_info;
295362306a36Sopenharmony_ci		u8 *addr = fi->l_data.mac.mac_addr;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci		/* Update unicast Tx rules to reflect the selected
295662306a36Sopenharmony_ci		 * VEB/VEPA mode
295762306a36Sopenharmony_ci		 */
295862306a36Sopenharmony_ci		if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) &&
295962306a36Sopenharmony_ci		    (fi->fltr_act == ICE_FWD_TO_VSI ||
296062306a36Sopenharmony_ci		     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
296162306a36Sopenharmony_ci		     fi->fltr_act == ICE_FWD_TO_Q ||
296262306a36Sopenharmony_ci		     fi->fltr_act == ICE_FWD_TO_QGRP)) {
296362306a36Sopenharmony_ci			status = ice_update_pkt_fwd_rule(hw, fi);
296462306a36Sopenharmony_ci			if (status)
296562306a36Sopenharmony_ci				break;
296662306a36Sopenharmony_ci		}
296762306a36Sopenharmony_ci	}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	mutex_unlock(rule_lock);
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	return status;
297262306a36Sopenharmony_ci}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci/**
297562306a36Sopenharmony_ci * ice_add_update_vsi_list
297662306a36Sopenharmony_ci * @hw: pointer to the hardware structure
297762306a36Sopenharmony_ci * @m_entry: pointer to current filter management list entry
297862306a36Sopenharmony_ci * @cur_fltr: filter information from the book keeping entry
297962306a36Sopenharmony_ci * @new_fltr: filter information with the new VSI to be added
298062306a36Sopenharmony_ci *
298162306a36Sopenharmony_ci * Call AQ command to add or update previously created VSI list with new VSI.
298262306a36Sopenharmony_ci *
298362306a36Sopenharmony_ci * Helper function to do book keeping associated with adding filter information
298462306a36Sopenharmony_ci * The algorithm to do the book keeping is described below :
298562306a36Sopenharmony_ci * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.)
298662306a36Sopenharmony_ci *	if only one VSI has been added till now
298762306a36Sopenharmony_ci *		Allocate a new VSI list and add two VSIs
298862306a36Sopenharmony_ci *		to this list using switch rule command
298962306a36Sopenharmony_ci *		Update the previously created switch rule with the
299062306a36Sopenharmony_ci *		newly created VSI list ID
299162306a36Sopenharmony_ci *	if a VSI list was previously created
299262306a36Sopenharmony_ci *		Add the new VSI to the previously created VSI list set
299362306a36Sopenharmony_ci *		using the update switch rule command
299462306a36Sopenharmony_ci */
299562306a36Sopenharmony_cistatic int
299662306a36Sopenharmony_ciice_add_update_vsi_list(struct ice_hw *hw,
299762306a36Sopenharmony_ci			struct ice_fltr_mgmt_list_entry *m_entry,
299862306a36Sopenharmony_ci			struct ice_fltr_info *cur_fltr,
299962306a36Sopenharmony_ci			struct ice_fltr_info *new_fltr)
300062306a36Sopenharmony_ci{
300162306a36Sopenharmony_ci	u16 vsi_list_id = 0;
300262306a36Sopenharmony_ci	int status = 0;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	if ((cur_fltr->fltr_act == ICE_FWD_TO_Q ||
300562306a36Sopenharmony_ci	     cur_fltr->fltr_act == ICE_FWD_TO_QGRP))
300662306a36Sopenharmony_ci		return -EOPNOTSUPP;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	if ((new_fltr->fltr_act == ICE_FWD_TO_Q ||
300962306a36Sopenharmony_ci	     new_fltr->fltr_act == ICE_FWD_TO_QGRP) &&
301062306a36Sopenharmony_ci	    (cur_fltr->fltr_act == ICE_FWD_TO_VSI ||
301162306a36Sopenharmony_ci	     cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST))
301262306a36Sopenharmony_ci		return -EOPNOTSUPP;
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
301562306a36Sopenharmony_ci		/* Only one entry existed in the mapping and it was not already
301662306a36Sopenharmony_ci		 * a part of a VSI list. So, create a VSI list with the old and
301762306a36Sopenharmony_ci		 * new VSIs.
301862306a36Sopenharmony_ci		 */
301962306a36Sopenharmony_ci		struct ice_fltr_info tmp_fltr;
302062306a36Sopenharmony_ci		u16 vsi_handle_arr[2];
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci		/* A rule already exists with the new VSI being added */
302362306a36Sopenharmony_ci		if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id)
302462306a36Sopenharmony_ci			return -EEXIST;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci		vsi_handle_arr[0] = cur_fltr->vsi_handle;
302762306a36Sopenharmony_ci		vsi_handle_arr[1] = new_fltr->vsi_handle;
302862306a36Sopenharmony_ci		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
302962306a36Sopenharmony_ci						  &vsi_list_id,
303062306a36Sopenharmony_ci						  new_fltr->lkup_type);
303162306a36Sopenharmony_ci		if (status)
303262306a36Sopenharmony_ci			return status;
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci		tmp_fltr = *new_fltr;
303562306a36Sopenharmony_ci		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
303662306a36Sopenharmony_ci		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
303762306a36Sopenharmony_ci		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
303862306a36Sopenharmony_ci		/* Update the previous switch rule of "MAC forward to VSI" to
303962306a36Sopenharmony_ci		 * "MAC fwd to VSI list"
304062306a36Sopenharmony_ci		 */
304162306a36Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
304262306a36Sopenharmony_ci		if (status)
304362306a36Sopenharmony_ci			return status;
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci		cur_fltr->fwd_id.vsi_list_id = vsi_list_id;
304662306a36Sopenharmony_ci		cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
304762306a36Sopenharmony_ci		m_entry->vsi_list_info =
304862306a36Sopenharmony_ci			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
304962306a36Sopenharmony_ci						vsi_list_id);
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci		if (!m_entry->vsi_list_info)
305262306a36Sopenharmony_ci			return -ENOMEM;
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci		/* If this entry was large action then the large action needs
305562306a36Sopenharmony_ci		 * to be updated to point to FWD to VSI list
305662306a36Sopenharmony_ci		 */
305762306a36Sopenharmony_ci		if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID)
305862306a36Sopenharmony_ci			status =
305962306a36Sopenharmony_ci			    ice_add_marker_act(hw, m_entry,
306062306a36Sopenharmony_ci					       m_entry->sw_marker_id,
306162306a36Sopenharmony_ci					       m_entry->lg_act_idx);
306262306a36Sopenharmony_ci	} else {
306362306a36Sopenharmony_ci		u16 vsi_handle = new_fltr->vsi_handle;
306462306a36Sopenharmony_ci		enum ice_adminq_opc opcode;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci		if (!m_entry->vsi_list_info)
306762306a36Sopenharmony_ci			return -EIO;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci		/* A rule already exists with the new VSI being added */
307062306a36Sopenharmony_ci		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
307162306a36Sopenharmony_ci			return 0;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci		/* Update the previously created VSI list set with
307462306a36Sopenharmony_ci		 * the new VSI ID passed in
307562306a36Sopenharmony_ci		 */
307662306a36Sopenharmony_ci		vsi_list_id = cur_fltr->fwd_id.vsi_list_id;
307762306a36Sopenharmony_ci		opcode = ice_aqc_opc_update_sw_rules;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
308062306a36Sopenharmony_ci						  vsi_list_id, false, opcode,
308162306a36Sopenharmony_ci						  new_fltr->lkup_type);
308262306a36Sopenharmony_ci		/* update VSI list mapping info with new VSI ID */
308362306a36Sopenharmony_ci		if (!status)
308462306a36Sopenharmony_ci			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
308562306a36Sopenharmony_ci	}
308662306a36Sopenharmony_ci	if (!status)
308762306a36Sopenharmony_ci		m_entry->vsi_count++;
308862306a36Sopenharmony_ci	return status;
308962306a36Sopenharmony_ci}
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci/**
309262306a36Sopenharmony_ci * ice_find_rule_entry - Search a rule entry
309362306a36Sopenharmony_ci * @hw: pointer to the hardware structure
309462306a36Sopenharmony_ci * @recp_id: lookup type for which the specified rule needs to be searched
309562306a36Sopenharmony_ci * @f_info: rule information
309662306a36Sopenharmony_ci *
309762306a36Sopenharmony_ci * Helper function to search for a given rule entry
309862306a36Sopenharmony_ci * Returns pointer to entry storing the rule if found
309962306a36Sopenharmony_ci */
310062306a36Sopenharmony_cistatic struct ice_fltr_mgmt_list_entry *
310162306a36Sopenharmony_ciice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
310262306a36Sopenharmony_ci{
310362306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;
310462306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
310562306a36Sopenharmony_ci	struct list_head *list_head;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	list_head = &sw->recp_list[recp_id].filt_rules;
310862306a36Sopenharmony_ci	list_for_each_entry(list_itr, list_head, list_entry) {
310962306a36Sopenharmony_ci		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
311062306a36Sopenharmony_ci			    sizeof(f_info->l_data)) &&
311162306a36Sopenharmony_ci		    f_info->flag == list_itr->fltr_info.flag) {
311262306a36Sopenharmony_ci			ret = list_itr;
311362306a36Sopenharmony_ci			break;
311462306a36Sopenharmony_ci		}
311562306a36Sopenharmony_ci	}
311662306a36Sopenharmony_ci	return ret;
311762306a36Sopenharmony_ci}
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci/**
312062306a36Sopenharmony_ci * ice_find_vsi_list_entry - Search VSI list map with VSI count 1
312162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
312262306a36Sopenharmony_ci * @recp_id: lookup type for which VSI lists needs to be searched
312362306a36Sopenharmony_ci * @vsi_handle: VSI handle to be found in VSI list
312462306a36Sopenharmony_ci * @vsi_list_id: VSI list ID found containing vsi_handle
312562306a36Sopenharmony_ci *
312662306a36Sopenharmony_ci * Helper function to search a VSI list with single entry containing given VSI
312762306a36Sopenharmony_ci * handle element. This can be extended further to search VSI list with more
312862306a36Sopenharmony_ci * than 1 vsi_count. Returns pointer to VSI list entry if found.
312962306a36Sopenharmony_ci */
313062306a36Sopenharmony_cistruct ice_vsi_list_map_info *
313162306a36Sopenharmony_ciice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
313262306a36Sopenharmony_ci			u16 *vsi_list_id)
313362306a36Sopenharmony_ci{
313462306a36Sopenharmony_ci	struct ice_vsi_list_map_info *map_info = NULL;
313562306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
313662306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_itr;
313762306a36Sopenharmony_ci	struct list_head *list_head;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	list_head = &sw->recp_list[recp_id].filt_rules;
314062306a36Sopenharmony_ci	list_for_each_entry(list_itr, list_head, list_entry) {
314162306a36Sopenharmony_ci		if (list_itr->vsi_list_info) {
314262306a36Sopenharmony_ci			map_info = list_itr->vsi_list_info;
314362306a36Sopenharmony_ci			if (test_bit(vsi_handle, map_info->vsi_map)) {
314462306a36Sopenharmony_ci				*vsi_list_id = map_info->vsi_list_id;
314562306a36Sopenharmony_ci				return map_info;
314662306a36Sopenharmony_ci			}
314762306a36Sopenharmony_ci		}
314862306a36Sopenharmony_ci	}
314962306a36Sopenharmony_ci	return NULL;
315062306a36Sopenharmony_ci}
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci/**
315362306a36Sopenharmony_ci * ice_add_rule_internal - add rule for a given lookup type
315462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
315562306a36Sopenharmony_ci * @recp_id: lookup type (recipe ID) for which rule has to be added
315662306a36Sopenharmony_ci * @f_entry: structure containing MAC forwarding information
315762306a36Sopenharmony_ci *
315862306a36Sopenharmony_ci * Adds or updates the rule lists for a given recipe
315962306a36Sopenharmony_ci */
316062306a36Sopenharmony_cistatic int
316162306a36Sopenharmony_ciice_add_rule_internal(struct ice_hw *hw, u8 recp_id,
316262306a36Sopenharmony_ci		      struct ice_fltr_list_entry *f_entry)
316362306a36Sopenharmony_ci{
316462306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
316562306a36Sopenharmony_ci	struct ice_fltr_info *new_fltr, *cur_fltr;
316662306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *m_entry;
316762306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
316862306a36Sopenharmony_ci	int status = 0;
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
317162306a36Sopenharmony_ci		return -EINVAL;
317262306a36Sopenharmony_ci	f_entry->fltr_info.fwd_id.hw_vsi_id =
317362306a36Sopenharmony_ci		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	mutex_lock(rule_lock);
317862306a36Sopenharmony_ci	new_fltr = &f_entry->fltr_info;
317962306a36Sopenharmony_ci	if (new_fltr->flag & ICE_FLTR_RX)
318062306a36Sopenharmony_ci		new_fltr->src = hw->port_info->lport;
318162306a36Sopenharmony_ci	else if (new_fltr->flag & ICE_FLTR_TX)
318262306a36Sopenharmony_ci		new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	m_entry = ice_find_rule_entry(hw, recp_id, new_fltr);
318562306a36Sopenharmony_ci	if (!m_entry) {
318662306a36Sopenharmony_ci		mutex_unlock(rule_lock);
318762306a36Sopenharmony_ci		return ice_create_pkt_fwd_rule(hw, f_entry);
318862306a36Sopenharmony_ci	}
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_ci	cur_fltr = &m_entry->fltr_info;
319162306a36Sopenharmony_ci	status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);
319262306a36Sopenharmony_ci	mutex_unlock(rule_lock);
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	return status;
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci/**
319862306a36Sopenharmony_ci * ice_remove_vsi_list_rule
319962306a36Sopenharmony_ci * @hw: pointer to the hardware structure
320062306a36Sopenharmony_ci * @vsi_list_id: VSI list ID generated as part of allocate resource
320162306a36Sopenharmony_ci * @lkup_type: switch rule filter lookup type
320262306a36Sopenharmony_ci *
320362306a36Sopenharmony_ci * The VSI list should be emptied before this function is called to remove the
320462306a36Sopenharmony_ci * VSI list.
320562306a36Sopenharmony_ci */
320662306a36Sopenharmony_cistatic int
320762306a36Sopenharmony_ciice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
320862306a36Sopenharmony_ci			 enum ice_sw_lkup_type lkup_type)
320962306a36Sopenharmony_ci{
321062306a36Sopenharmony_ci	struct ice_sw_rule_vsi_list *s_rule;
321162306a36Sopenharmony_ci	u16 s_rule_size;
321262306a36Sopenharmony_ci	int status;
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, 0);
321562306a36Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
321662306a36Sopenharmony_ci	if (!s_rule)
321762306a36Sopenharmony_ci		return -ENOMEM;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);
322062306a36Sopenharmony_ci	s_rule->index = cpu_to_le16(vsi_list_id);
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	/* Free the vsi_list resource that we allocated. It is assumed that the
322362306a36Sopenharmony_ci	 * list is empty at this point.
322462306a36Sopenharmony_ci	 */
322562306a36Sopenharmony_ci	status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
322662306a36Sopenharmony_ci					    ice_aqc_opc_free_res);
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
322962306a36Sopenharmony_ci	return status;
323062306a36Sopenharmony_ci}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci/**
323362306a36Sopenharmony_ci * ice_rem_update_vsi_list
323462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
323562306a36Sopenharmony_ci * @vsi_handle: VSI handle of the VSI to remove
323662306a36Sopenharmony_ci * @fm_list: filter management entry for which the VSI list management needs to
323762306a36Sopenharmony_ci *           be done
323862306a36Sopenharmony_ci */
323962306a36Sopenharmony_cistatic int
324062306a36Sopenharmony_ciice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
324162306a36Sopenharmony_ci			struct ice_fltr_mgmt_list_entry *fm_list)
324262306a36Sopenharmony_ci{
324362306a36Sopenharmony_ci	enum ice_sw_lkup_type lkup_type;
324462306a36Sopenharmony_ci	u16 vsi_list_id;
324562306a36Sopenharmony_ci	int status = 0;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||
324862306a36Sopenharmony_ci	    fm_list->vsi_count == 0)
324962306a36Sopenharmony_ci		return -EINVAL;
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	/* A rule with the VSI being removed does not exist */
325262306a36Sopenharmony_ci	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
325362306a36Sopenharmony_ci		return -ENOENT;
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	lkup_type = fm_list->fltr_info.lkup_type;
325662306a36Sopenharmony_ci	vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;
325762306a36Sopenharmony_ci	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
325862306a36Sopenharmony_ci					  ice_aqc_opc_update_sw_rules,
325962306a36Sopenharmony_ci					  lkup_type);
326062306a36Sopenharmony_ci	if (status)
326162306a36Sopenharmony_ci		return status;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	fm_list->vsi_count--;
326462306a36Sopenharmony_ci	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {
326762306a36Sopenharmony_ci		struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;
326862306a36Sopenharmony_ci		struct ice_vsi_list_map_info *vsi_list_info =
326962306a36Sopenharmony_ci			fm_list->vsi_list_info;
327062306a36Sopenharmony_ci		u16 rem_vsi_handle;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
327362306a36Sopenharmony_ci						ICE_MAX_VSI);
327462306a36Sopenharmony_ci		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
327562306a36Sopenharmony_ci			return -EIO;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci		/* Make sure VSI list is empty before removing it below */
327862306a36Sopenharmony_ci		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
327962306a36Sopenharmony_ci						  vsi_list_id, true,
328062306a36Sopenharmony_ci						  ice_aqc_opc_update_sw_rules,
328162306a36Sopenharmony_ci						  lkup_type);
328262306a36Sopenharmony_ci		if (status)
328362306a36Sopenharmony_ci			return status;
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci		tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;
328662306a36Sopenharmony_ci		tmp_fltr_info.fwd_id.hw_vsi_id =
328762306a36Sopenharmony_ci			ice_get_hw_vsi_num(hw, rem_vsi_handle);
328862306a36Sopenharmony_ci		tmp_fltr_info.vsi_handle = rem_vsi_handle;
328962306a36Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);
329062306a36Sopenharmony_ci		if (status) {
329162306a36Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
329262306a36Sopenharmony_ci				  tmp_fltr_info.fwd_id.hw_vsi_id, status);
329362306a36Sopenharmony_ci			return status;
329462306a36Sopenharmony_ci		}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci		fm_list->fltr_info = tmp_fltr_info;
329762306a36Sopenharmony_ci	}
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||
330062306a36Sopenharmony_ci	    (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {
330162306a36Sopenharmony_ci		struct ice_vsi_list_map_info *vsi_list_info =
330262306a36Sopenharmony_ci			fm_list->vsi_list_info;
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci		/* Remove the VSI list since it is no longer used */
330562306a36Sopenharmony_ci		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
330662306a36Sopenharmony_ci		if (status) {
330762306a36Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
330862306a36Sopenharmony_ci				  vsi_list_id, status);
330962306a36Sopenharmony_ci			return status;
331062306a36Sopenharmony_ci		}
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci		list_del(&vsi_list_info->list_entry);
331362306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
331462306a36Sopenharmony_ci		fm_list->vsi_list_info = NULL;
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci	return status;
331862306a36Sopenharmony_ci}
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci/**
332162306a36Sopenharmony_ci * ice_remove_rule_internal - Remove a filter rule of a given type
332262306a36Sopenharmony_ci * @hw: pointer to the hardware structure
332362306a36Sopenharmony_ci * @recp_id: recipe ID for which the rule needs to removed
332462306a36Sopenharmony_ci * @f_entry: rule entry containing filter information
332562306a36Sopenharmony_ci */
332662306a36Sopenharmony_cistatic int
332762306a36Sopenharmony_ciice_remove_rule_internal(struct ice_hw *hw, u8 recp_id,
332862306a36Sopenharmony_ci			 struct ice_fltr_list_entry *f_entry)
332962306a36Sopenharmony_ci{
333062306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
333162306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_elem;
333262306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
333362306a36Sopenharmony_ci	bool remove_rule = false;
333462306a36Sopenharmony_ci	u16 vsi_handle;
333562306a36Sopenharmony_ci	int status = 0;
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
333862306a36Sopenharmony_ci		return -EINVAL;
333962306a36Sopenharmony_ci	f_entry->fltr_info.fwd_id.hw_vsi_id =
334062306a36Sopenharmony_ci		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
334362306a36Sopenharmony_ci	mutex_lock(rule_lock);
334462306a36Sopenharmony_ci	list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info);
334562306a36Sopenharmony_ci	if (!list_elem) {
334662306a36Sopenharmony_ci		status = -ENOENT;
334762306a36Sopenharmony_ci		goto exit;
334862306a36Sopenharmony_ci	}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
335162306a36Sopenharmony_ci		remove_rule = true;
335262306a36Sopenharmony_ci	} else if (!list_elem->vsi_list_info) {
335362306a36Sopenharmony_ci		status = -ENOENT;
335462306a36Sopenharmony_ci		goto exit;
335562306a36Sopenharmony_ci	} else if (list_elem->vsi_list_info->ref_cnt > 1) {
335662306a36Sopenharmony_ci		/* a ref_cnt > 1 indicates that the vsi_list is being
335762306a36Sopenharmony_ci		 * shared by multiple rules. Decrement the ref_cnt and
335862306a36Sopenharmony_ci		 * remove this rule, but do not modify the list, as it
335962306a36Sopenharmony_ci		 * is in-use by other rules.
336062306a36Sopenharmony_ci		 */
336162306a36Sopenharmony_ci		list_elem->vsi_list_info->ref_cnt--;
336262306a36Sopenharmony_ci		remove_rule = true;
336362306a36Sopenharmony_ci	} else {
336462306a36Sopenharmony_ci		/* a ref_cnt of 1 indicates the vsi_list is only used
336562306a36Sopenharmony_ci		 * by one rule. However, the original removal request is only
336662306a36Sopenharmony_ci		 * for a single VSI. Update the vsi_list first, and only
336762306a36Sopenharmony_ci		 * remove the rule if there are no further VSIs in this list.
336862306a36Sopenharmony_ci		 */
336962306a36Sopenharmony_ci		vsi_handle = f_entry->fltr_info.vsi_handle;
337062306a36Sopenharmony_ci		status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);
337162306a36Sopenharmony_ci		if (status)
337262306a36Sopenharmony_ci			goto exit;
337362306a36Sopenharmony_ci		/* if VSI count goes to zero after updating the VSI list */
337462306a36Sopenharmony_ci		if (list_elem->vsi_count == 0)
337562306a36Sopenharmony_ci			remove_rule = true;
337662306a36Sopenharmony_ci	}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	if (remove_rule) {
337962306a36Sopenharmony_ci		/* Remove the lookup rule */
338062306a36Sopenharmony_ci		struct ice_sw_rule_lkup_rx_tx *s_rule;
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci		s_rule = devm_kzalloc(ice_hw_to_dev(hw),
338362306a36Sopenharmony_ci				      ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule),
338462306a36Sopenharmony_ci				      GFP_KERNEL);
338562306a36Sopenharmony_ci		if (!s_rule) {
338662306a36Sopenharmony_ci			status = -ENOMEM;
338762306a36Sopenharmony_ci			goto exit;
338862306a36Sopenharmony_ci		}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci		ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,
339162306a36Sopenharmony_ci				 ice_aqc_opc_remove_sw_rules);
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci		status = ice_aq_sw_rules(hw, s_rule,
339462306a36Sopenharmony_ci					 ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule),
339562306a36Sopenharmony_ci					 1, ice_aqc_opc_remove_sw_rules, NULL);
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci		/* Remove a book keeping from the list */
339862306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), s_rule);
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci		if (status)
340162306a36Sopenharmony_ci			goto exit;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci		list_del(&list_elem->list_entry);
340462306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), list_elem);
340562306a36Sopenharmony_ci	}
340662306a36Sopenharmony_ciexit:
340762306a36Sopenharmony_ci	mutex_unlock(rule_lock);
340862306a36Sopenharmony_ci	return status;
340962306a36Sopenharmony_ci}
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci/**
341262306a36Sopenharmony_ci * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI
341362306a36Sopenharmony_ci * @hw: pointer to the hardware structure
341462306a36Sopenharmony_ci * @vlan_id: VLAN ID
341562306a36Sopenharmony_ci * @vsi_handle: check MAC filter for this VSI
341662306a36Sopenharmony_ci */
341762306a36Sopenharmony_cibool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle)
341862306a36Sopenharmony_ci{
341962306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *entry;
342062306a36Sopenharmony_ci	struct list_head *rule_head;
342162306a36Sopenharmony_ci	struct ice_switch_info *sw;
342262306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
342362306a36Sopenharmony_ci	u16 hw_vsi_id;
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	if (vlan_id > ICE_MAX_VLAN_ID)
342662306a36Sopenharmony_ci		return false;
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
342962306a36Sopenharmony_ci		return false;
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
343262306a36Sopenharmony_ci	sw = hw->switch_info;
343362306a36Sopenharmony_ci	rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
343462306a36Sopenharmony_ci	if (!rule_head)
343562306a36Sopenharmony_ci		return false;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
343862306a36Sopenharmony_ci	mutex_lock(rule_lock);
343962306a36Sopenharmony_ci	list_for_each_entry(entry, rule_head, list_entry) {
344062306a36Sopenharmony_ci		struct ice_fltr_info *f_info = &entry->fltr_info;
344162306a36Sopenharmony_ci		u16 entry_vlan_id = f_info->l_data.vlan.vlan_id;
344262306a36Sopenharmony_ci		struct ice_vsi_list_map_info *map_info;
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci		if (entry_vlan_id > ICE_MAX_VLAN_ID)
344562306a36Sopenharmony_ci			continue;
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci		if (f_info->flag != ICE_FLTR_TX ||
344862306a36Sopenharmony_ci		    f_info->src_id != ICE_SRC_ID_VSI ||
344962306a36Sopenharmony_ci		    f_info->lkup_type != ICE_SW_LKUP_VLAN)
345062306a36Sopenharmony_ci			continue;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci		/* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */
345362306a36Sopenharmony_ci		if (f_info->fltr_act != ICE_FWD_TO_VSI &&
345462306a36Sopenharmony_ci		    f_info->fltr_act != ICE_FWD_TO_VSI_LIST)
345562306a36Sopenharmony_ci			continue;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci		if (f_info->fltr_act == ICE_FWD_TO_VSI) {
345862306a36Sopenharmony_ci			if (hw_vsi_id != f_info->fwd_id.hw_vsi_id)
345962306a36Sopenharmony_ci				continue;
346062306a36Sopenharmony_ci		} else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
346162306a36Sopenharmony_ci			/* If filter_action is FWD_TO_VSI_LIST, make sure
346262306a36Sopenharmony_ci			 * that VSI being checked is part of VSI list
346362306a36Sopenharmony_ci			 */
346462306a36Sopenharmony_ci			if (entry->vsi_count == 1 &&
346562306a36Sopenharmony_ci			    entry->vsi_list_info) {
346662306a36Sopenharmony_ci				map_info = entry->vsi_list_info;
346762306a36Sopenharmony_ci				if (!test_bit(vsi_handle, map_info->vsi_map))
346862306a36Sopenharmony_ci					continue;
346962306a36Sopenharmony_ci			}
347062306a36Sopenharmony_ci		}
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci		if (vlan_id == entry_vlan_id) {
347362306a36Sopenharmony_ci			mutex_unlock(rule_lock);
347462306a36Sopenharmony_ci			return true;
347562306a36Sopenharmony_ci		}
347662306a36Sopenharmony_ci	}
347762306a36Sopenharmony_ci	mutex_unlock(rule_lock);
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci	return false;
348062306a36Sopenharmony_ci}
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci/**
348362306a36Sopenharmony_ci * ice_add_mac - Add a MAC address based filter rule
348462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
348562306a36Sopenharmony_ci * @m_list: list of MAC addresses and forwarding information
348662306a36Sopenharmony_ci */
348762306a36Sopenharmony_ciint ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
348862306a36Sopenharmony_ci{
348962306a36Sopenharmony_ci	struct ice_fltr_list_entry *m_list_itr;
349062306a36Sopenharmony_ci	int status = 0;
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	if (!m_list || !hw)
349362306a36Sopenharmony_ci		return -EINVAL;
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	list_for_each_entry(m_list_itr, m_list, list_entry) {
349662306a36Sopenharmony_ci		u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
349762306a36Sopenharmony_ci		u16 vsi_handle;
349862306a36Sopenharmony_ci		u16 hw_vsi_id;
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci		m_list_itr->fltr_info.flag = ICE_FLTR_TX;
350162306a36Sopenharmony_ci		vsi_handle = m_list_itr->fltr_info.vsi_handle;
350262306a36Sopenharmony_ci		if (!ice_is_vsi_valid(hw, vsi_handle))
350362306a36Sopenharmony_ci			return -EINVAL;
350462306a36Sopenharmony_ci		hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
350562306a36Sopenharmony_ci		m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;
350662306a36Sopenharmony_ci		/* update the src in case it is VSI num */
350762306a36Sopenharmony_ci		if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)
350862306a36Sopenharmony_ci			return -EINVAL;
350962306a36Sopenharmony_ci		m_list_itr->fltr_info.src = hw_vsi_id;
351062306a36Sopenharmony_ci		if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
351162306a36Sopenharmony_ci		    is_zero_ether_addr(add))
351262306a36Sopenharmony_ci			return -EINVAL;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci		m_list_itr->status = ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
351562306a36Sopenharmony_ci							   m_list_itr);
351662306a36Sopenharmony_ci		if (m_list_itr->status)
351762306a36Sopenharmony_ci			return m_list_itr->status;
351862306a36Sopenharmony_ci	}
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	return status;
352162306a36Sopenharmony_ci}
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci/**
352462306a36Sopenharmony_ci * ice_add_vlan_internal - Add one VLAN based filter rule
352562306a36Sopenharmony_ci * @hw: pointer to the hardware structure
352662306a36Sopenharmony_ci * @f_entry: filter entry containing one VLAN information
352762306a36Sopenharmony_ci */
352862306a36Sopenharmony_cistatic int
352962306a36Sopenharmony_ciice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
353062306a36Sopenharmony_ci{
353162306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
353262306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *v_list_itr;
353362306a36Sopenharmony_ci	struct ice_fltr_info *new_fltr, *cur_fltr;
353462306a36Sopenharmony_ci	enum ice_sw_lkup_type lkup_type;
353562306a36Sopenharmony_ci	u16 vsi_list_id = 0, vsi_handle;
353662306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
353762306a36Sopenharmony_ci	int status = 0;
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
354062306a36Sopenharmony_ci		return -EINVAL;
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	f_entry->fltr_info.fwd_id.hw_vsi_id =
354362306a36Sopenharmony_ci		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
354462306a36Sopenharmony_ci	new_fltr = &f_entry->fltr_info;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	/* VLAN ID should only be 12 bits */
354762306a36Sopenharmony_ci	if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
354862306a36Sopenharmony_ci		return -EINVAL;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	if (new_fltr->src_id != ICE_SRC_ID_VSI)
355162306a36Sopenharmony_ci		return -EINVAL;
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	new_fltr->src = new_fltr->fwd_id.hw_vsi_id;
355462306a36Sopenharmony_ci	lkup_type = new_fltr->lkup_type;
355562306a36Sopenharmony_ci	vsi_handle = new_fltr->vsi_handle;
355662306a36Sopenharmony_ci	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
355762306a36Sopenharmony_ci	mutex_lock(rule_lock);
355862306a36Sopenharmony_ci	v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr);
355962306a36Sopenharmony_ci	if (!v_list_itr) {
356062306a36Sopenharmony_ci		struct ice_vsi_list_map_info *map_info = NULL;
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci		if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
356362306a36Sopenharmony_ci			/* All VLAN pruning rules use a VSI list. Check if
356462306a36Sopenharmony_ci			 * there is already a VSI list containing VSI that we
356562306a36Sopenharmony_ci			 * want to add. If found, use the same vsi_list_id for
356662306a36Sopenharmony_ci			 * this new VLAN rule or else create a new list.
356762306a36Sopenharmony_ci			 */
356862306a36Sopenharmony_ci			map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN,
356962306a36Sopenharmony_ci							   vsi_handle,
357062306a36Sopenharmony_ci							   &vsi_list_id);
357162306a36Sopenharmony_ci			if (!map_info) {
357262306a36Sopenharmony_ci				status = ice_create_vsi_list_rule(hw,
357362306a36Sopenharmony_ci								  &vsi_handle,
357462306a36Sopenharmony_ci								  1,
357562306a36Sopenharmony_ci								  &vsi_list_id,
357662306a36Sopenharmony_ci								  lkup_type);
357762306a36Sopenharmony_ci				if (status)
357862306a36Sopenharmony_ci					goto exit;
357962306a36Sopenharmony_ci			}
358062306a36Sopenharmony_ci			/* Convert the action to forwarding to a VSI list. */
358162306a36Sopenharmony_ci			new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
358262306a36Sopenharmony_ci			new_fltr->fwd_id.vsi_list_id = vsi_list_id;
358362306a36Sopenharmony_ci		}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_ci		status = ice_create_pkt_fwd_rule(hw, f_entry);
358662306a36Sopenharmony_ci		if (!status) {
358762306a36Sopenharmony_ci			v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN,
358862306a36Sopenharmony_ci							 new_fltr);
358962306a36Sopenharmony_ci			if (!v_list_itr) {
359062306a36Sopenharmony_ci				status = -ENOENT;
359162306a36Sopenharmony_ci				goto exit;
359262306a36Sopenharmony_ci			}
359362306a36Sopenharmony_ci			/* reuse VSI list for new rule and increment ref_cnt */
359462306a36Sopenharmony_ci			if (map_info) {
359562306a36Sopenharmony_ci				v_list_itr->vsi_list_info = map_info;
359662306a36Sopenharmony_ci				map_info->ref_cnt++;
359762306a36Sopenharmony_ci			} else {
359862306a36Sopenharmony_ci				v_list_itr->vsi_list_info =
359962306a36Sopenharmony_ci					ice_create_vsi_list_map(hw, &vsi_handle,
360062306a36Sopenharmony_ci								1, vsi_list_id);
360162306a36Sopenharmony_ci			}
360262306a36Sopenharmony_ci		}
360362306a36Sopenharmony_ci	} else if (v_list_itr->vsi_list_info->ref_cnt == 1) {
360462306a36Sopenharmony_ci		/* Update existing VSI list to add new VSI ID only if it used
360562306a36Sopenharmony_ci		 * by one VLAN rule.
360662306a36Sopenharmony_ci		 */
360762306a36Sopenharmony_ci		cur_fltr = &v_list_itr->fltr_info;
360862306a36Sopenharmony_ci		status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,
360962306a36Sopenharmony_ci						 new_fltr);
361062306a36Sopenharmony_ci	} else {
361162306a36Sopenharmony_ci		/* If VLAN rule exists and VSI list being used by this rule is
361262306a36Sopenharmony_ci		 * referenced by more than 1 VLAN rule. Then create a new VSI
361362306a36Sopenharmony_ci		 * list appending previous VSI with new VSI and update existing
361462306a36Sopenharmony_ci		 * VLAN rule to point to new VSI list ID
361562306a36Sopenharmony_ci		 */
361662306a36Sopenharmony_ci		struct ice_fltr_info tmp_fltr;
361762306a36Sopenharmony_ci		u16 vsi_handle_arr[2];
361862306a36Sopenharmony_ci		u16 cur_handle;
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci		/* Current implementation only supports reusing VSI list with
362162306a36Sopenharmony_ci		 * one VSI count. We should never hit below condition
362262306a36Sopenharmony_ci		 */
362362306a36Sopenharmony_ci		if (v_list_itr->vsi_count > 1 &&
362462306a36Sopenharmony_ci		    v_list_itr->vsi_list_info->ref_cnt > 1) {
362562306a36Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW, "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n");
362662306a36Sopenharmony_ci			status = -EIO;
362762306a36Sopenharmony_ci			goto exit;
362862306a36Sopenharmony_ci		}
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci		cur_handle =
363162306a36Sopenharmony_ci			find_first_bit(v_list_itr->vsi_list_info->vsi_map,
363262306a36Sopenharmony_ci				       ICE_MAX_VSI);
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci		/* A rule already exists with the new VSI being added */
363562306a36Sopenharmony_ci		if (cur_handle == vsi_handle) {
363662306a36Sopenharmony_ci			status = -EEXIST;
363762306a36Sopenharmony_ci			goto exit;
363862306a36Sopenharmony_ci		}
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci		vsi_handle_arr[0] = cur_handle;
364162306a36Sopenharmony_ci		vsi_handle_arr[1] = vsi_handle;
364262306a36Sopenharmony_ci		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
364362306a36Sopenharmony_ci						  &vsi_list_id, lkup_type);
364462306a36Sopenharmony_ci		if (status)
364562306a36Sopenharmony_ci			goto exit;
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_ci		tmp_fltr = v_list_itr->fltr_info;
364862306a36Sopenharmony_ci		tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;
364962306a36Sopenharmony_ci		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
365062306a36Sopenharmony_ci		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
365162306a36Sopenharmony_ci		/* Update the previous switch rule to a new VSI list which
365262306a36Sopenharmony_ci		 * includes current VSI that is requested
365362306a36Sopenharmony_ci		 */
365462306a36Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
365562306a36Sopenharmony_ci		if (status)
365662306a36Sopenharmony_ci			goto exit;
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci		/* before overriding VSI list map info. decrement ref_cnt of
365962306a36Sopenharmony_ci		 * previous VSI list
366062306a36Sopenharmony_ci		 */
366162306a36Sopenharmony_ci		v_list_itr->vsi_list_info->ref_cnt--;
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci		/* now update to newly created list */
366462306a36Sopenharmony_ci		v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;
366562306a36Sopenharmony_ci		v_list_itr->vsi_list_info =
366662306a36Sopenharmony_ci			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
366762306a36Sopenharmony_ci						vsi_list_id);
366862306a36Sopenharmony_ci		v_list_itr->vsi_count++;
366962306a36Sopenharmony_ci	}
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ciexit:
367262306a36Sopenharmony_ci	mutex_unlock(rule_lock);
367362306a36Sopenharmony_ci	return status;
367462306a36Sopenharmony_ci}
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci/**
367762306a36Sopenharmony_ci * ice_add_vlan - Add VLAN based filter rule
367862306a36Sopenharmony_ci * @hw: pointer to the hardware structure
367962306a36Sopenharmony_ci * @v_list: list of VLAN entries and forwarding information
368062306a36Sopenharmony_ci */
368162306a36Sopenharmony_ciint ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
368262306a36Sopenharmony_ci{
368362306a36Sopenharmony_ci	struct ice_fltr_list_entry *v_list_itr;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	if (!v_list || !hw)
368662306a36Sopenharmony_ci		return -EINVAL;
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	list_for_each_entry(v_list_itr, v_list, list_entry) {
368962306a36Sopenharmony_ci		if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
369062306a36Sopenharmony_ci			return -EINVAL;
369162306a36Sopenharmony_ci		v_list_itr->fltr_info.flag = ICE_FLTR_TX;
369262306a36Sopenharmony_ci		v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr);
369362306a36Sopenharmony_ci		if (v_list_itr->status)
369462306a36Sopenharmony_ci			return v_list_itr->status;
369562306a36Sopenharmony_ci	}
369662306a36Sopenharmony_ci	return 0;
369762306a36Sopenharmony_ci}
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci/**
370062306a36Sopenharmony_ci * ice_add_eth_mac - Add ethertype and MAC based filter rule
370162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
370262306a36Sopenharmony_ci * @em_list: list of ether type MAC filter, MAC is optional
370362306a36Sopenharmony_ci *
370462306a36Sopenharmony_ci * This function requires the caller to populate the entries in
370562306a36Sopenharmony_ci * the filter list with the necessary fields (including flags to
370662306a36Sopenharmony_ci * indicate Tx or Rx rules).
370762306a36Sopenharmony_ci */
370862306a36Sopenharmony_ciint ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
370962306a36Sopenharmony_ci{
371062306a36Sopenharmony_ci	struct ice_fltr_list_entry *em_list_itr;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	if (!em_list || !hw)
371362306a36Sopenharmony_ci		return -EINVAL;
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_ci	list_for_each_entry(em_list_itr, em_list, list_entry) {
371662306a36Sopenharmony_ci		enum ice_sw_lkup_type l_type =
371762306a36Sopenharmony_ci			em_list_itr->fltr_info.lkup_type;
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
372062306a36Sopenharmony_ci		    l_type != ICE_SW_LKUP_ETHERTYPE)
372162306a36Sopenharmony_ci			return -EINVAL;
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci		em_list_itr->status = ice_add_rule_internal(hw, l_type,
372462306a36Sopenharmony_ci							    em_list_itr);
372562306a36Sopenharmony_ci		if (em_list_itr->status)
372662306a36Sopenharmony_ci			return em_list_itr->status;
372762306a36Sopenharmony_ci	}
372862306a36Sopenharmony_ci	return 0;
372962306a36Sopenharmony_ci}
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci/**
373262306a36Sopenharmony_ci * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule
373362306a36Sopenharmony_ci * @hw: pointer to the hardware structure
373462306a36Sopenharmony_ci * @em_list: list of ethertype or ethertype MAC entries
373562306a36Sopenharmony_ci */
373662306a36Sopenharmony_ciint ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list)
373762306a36Sopenharmony_ci{
373862306a36Sopenharmony_ci	struct ice_fltr_list_entry *em_list_itr, *tmp;
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	if (!em_list || !hw)
374162306a36Sopenharmony_ci		return -EINVAL;
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) {
374462306a36Sopenharmony_ci		enum ice_sw_lkup_type l_type =
374562306a36Sopenharmony_ci			em_list_itr->fltr_info.lkup_type;
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
374862306a36Sopenharmony_ci		    l_type != ICE_SW_LKUP_ETHERTYPE)
374962306a36Sopenharmony_ci			return -EINVAL;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci		em_list_itr->status = ice_remove_rule_internal(hw, l_type,
375262306a36Sopenharmony_ci							       em_list_itr);
375362306a36Sopenharmony_ci		if (em_list_itr->status)
375462306a36Sopenharmony_ci			return em_list_itr->status;
375562306a36Sopenharmony_ci	}
375662306a36Sopenharmony_ci	return 0;
375762306a36Sopenharmony_ci}
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci/**
376062306a36Sopenharmony_ci * ice_rem_sw_rule_info
376162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
376262306a36Sopenharmony_ci * @rule_head: pointer to the switch list structure that we want to delete
376362306a36Sopenharmony_ci */
376462306a36Sopenharmony_cistatic void
376562306a36Sopenharmony_ciice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head)
376662306a36Sopenharmony_ci{
376762306a36Sopenharmony_ci	if (!list_empty(rule_head)) {
376862306a36Sopenharmony_ci		struct ice_fltr_mgmt_list_entry *entry;
376962306a36Sopenharmony_ci		struct ice_fltr_mgmt_list_entry *tmp;
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ci		list_for_each_entry_safe(entry, tmp, rule_head, list_entry) {
377262306a36Sopenharmony_ci			list_del(&entry->list_entry);
377362306a36Sopenharmony_ci			devm_kfree(ice_hw_to_dev(hw), entry);
377462306a36Sopenharmony_ci		}
377562306a36Sopenharmony_ci	}
377662306a36Sopenharmony_ci}
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci/**
377962306a36Sopenharmony_ci * ice_rem_adv_rule_info
378062306a36Sopenharmony_ci * @hw: pointer to the hardware structure
378162306a36Sopenharmony_ci * @rule_head: pointer to the switch list structure that we want to delete
378262306a36Sopenharmony_ci */
378362306a36Sopenharmony_cistatic void
378462306a36Sopenharmony_ciice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head)
378562306a36Sopenharmony_ci{
378662306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *tmp_entry;
378762306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *lst_itr;
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci	if (list_empty(rule_head))
379062306a36Sopenharmony_ci		return;
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) {
379362306a36Sopenharmony_ci		list_del(&lst_itr->list_entry);
379462306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups);
379562306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), lst_itr);
379662306a36Sopenharmony_ci	}
379762306a36Sopenharmony_ci}
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci/**
380062306a36Sopenharmony_ci * ice_cfg_dflt_vsi - change state of VSI to set/clear default
380162306a36Sopenharmony_ci * @pi: pointer to the port_info structure
380262306a36Sopenharmony_ci * @vsi_handle: VSI handle to set as default
380362306a36Sopenharmony_ci * @set: true to add the above mentioned switch rule, false to remove it
380462306a36Sopenharmony_ci * @direction: ICE_FLTR_RX or ICE_FLTR_TX
380562306a36Sopenharmony_ci *
380662306a36Sopenharmony_ci * add filter rule to set/unset given VSI as default VSI for the switch
380762306a36Sopenharmony_ci * (represented by swid)
380862306a36Sopenharmony_ci */
380962306a36Sopenharmony_ciint
381062306a36Sopenharmony_ciice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set,
381162306a36Sopenharmony_ci		 u8 direction)
381262306a36Sopenharmony_ci{
381362306a36Sopenharmony_ci	struct ice_fltr_list_entry f_list_entry;
381462306a36Sopenharmony_ci	struct ice_fltr_info f_info;
381562306a36Sopenharmony_ci	struct ice_hw *hw = pi->hw;
381662306a36Sopenharmony_ci	u16 hw_vsi_id;
381762306a36Sopenharmony_ci	int status;
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
382062306a36Sopenharmony_ci		return -EINVAL;
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	memset(&f_info, 0, sizeof(f_info));
382562306a36Sopenharmony_ci
382662306a36Sopenharmony_ci	f_info.lkup_type = ICE_SW_LKUP_DFLT;
382762306a36Sopenharmony_ci	f_info.flag = direction;
382862306a36Sopenharmony_ci	f_info.fltr_act = ICE_FWD_TO_VSI;
382962306a36Sopenharmony_ci	f_info.fwd_id.hw_vsi_id = hw_vsi_id;
383062306a36Sopenharmony_ci	f_info.vsi_handle = vsi_handle;
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	if (f_info.flag & ICE_FLTR_RX) {
383362306a36Sopenharmony_ci		f_info.src = hw->port_info->lport;
383462306a36Sopenharmony_ci		f_info.src_id = ICE_SRC_ID_LPORT;
383562306a36Sopenharmony_ci	} else if (f_info.flag & ICE_FLTR_TX) {
383662306a36Sopenharmony_ci		f_info.src_id = ICE_SRC_ID_VSI;
383762306a36Sopenharmony_ci		f_info.src = hw_vsi_id;
383862306a36Sopenharmony_ci	}
383962306a36Sopenharmony_ci	f_list_entry.fltr_info = f_info;
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci	if (set)
384262306a36Sopenharmony_ci		status = ice_add_rule_internal(hw, ICE_SW_LKUP_DFLT,
384362306a36Sopenharmony_ci					       &f_list_entry);
384462306a36Sopenharmony_ci	else
384562306a36Sopenharmony_ci		status = ice_remove_rule_internal(hw, ICE_SW_LKUP_DFLT,
384662306a36Sopenharmony_ci						  &f_list_entry);
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_ci	return status;
384962306a36Sopenharmony_ci}
385062306a36Sopenharmony_ci
385162306a36Sopenharmony_ci/**
385262306a36Sopenharmony_ci * ice_vsi_uses_fltr - Determine if given VSI uses specified filter
385362306a36Sopenharmony_ci * @fm_entry: filter entry to inspect
385462306a36Sopenharmony_ci * @vsi_handle: VSI handle to compare with filter info
385562306a36Sopenharmony_ci */
385662306a36Sopenharmony_cistatic bool
385762306a36Sopenharmony_ciice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)
385862306a36Sopenharmony_ci{
385962306a36Sopenharmony_ci	return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
386062306a36Sopenharmony_ci		 fm_entry->fltr_info.vsi_handle == vsi_handle) ||
386162306a36Sopenharmony_ci		(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
386262306a36Sopenharmony_ci		 fm_entry->vsi_list_info &&
386362306a36Sopenharmony_ci		 (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map))));
386462306a36Sopenharmony_ci}
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci/**
386762306a36Sopenharmony_ci * ice_check_if_dflt_vsi - check if VSI is default VSI
386862306a36Sopenharmony_ci * @pi: pointer to the port_info structure
386962306a36Sopenharmony_ci * @vsi_handle: vsi handle to check for in filter list
387062306a36Sopenharmony_ci * @rule_exists: indicates if there are any VSI's in the rule list
387162306a36Sopenharmony_ci *
387262306a36Sopenharmony_ci * checks if the VSI is in a default VSI list, and also indicates
387362306a36Sopenharmony_ci * if the default VSI list is empty
387462306a36Sopenharmony_ci */
387562306a36Sopenharmony_cibool
387662306a36Sopenharmony_ciice_check_if_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle,
387762306a36Sopenharmony_ci		      bool *rule_exists)
387862306a36Sopenharmony_ci{
387962306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
388062306a36Sopenharmony_ci	struct ice_sw_recipe *recp_list;
388162306a36Sopenharmony_ci	struct list_head *rule_head;
388262306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
388362306a36Sopenharmony_ci	bool ret = false;
388462306a36Sopenharmony_ci
388562306a36Sopenharmony_ci	recp_list = &pi->hw->switch_info->recp_list[ICE_SW_LKUP_DFLT];
388662306a36Sopenharmony_ci	rule_lock = &recp_list->filt_rule_lock;
388762306a36Sopenharmony_ci	rule_head = &recp_list->filt_rules;
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	mutex_lock(rule_lock);
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci	if (rule_exists && !list_empty(rule_head))
389262306a36Sopenharmony_ci		*rule_exists = true;
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_ci	list_for_each_entry(fm_entry, rule_head, list_entry) {
389562306a36Sopenharmony_ci		if (ice_vsi_uses_fltr(fm_entry, vsi_handle)) {
389662306a36Sopenharmony_ci			ret = true;
389762306a36Sopenharmony_ci			break;
389862306a36Sopenharmony_ci		}
389962306a36Sopenharmony_ci	}
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	mutex_unlock(rule_lock);
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	return ret;
390462306a36Sopenharmony_ci}
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci/**
390762306a36Sopenharmony_ci * ice_remove_mac - remove a MAC address based filter rule
390862306a36Sopenharmony_ci * @hw: pointer to the hardware structure
390962306a36Sopenharmony_ci * @m_list: list of MAC addresses and forwarding information
391062306a36Sopenharmony_ci *
391162306a36Sopenharmony_ci * This function removes either a MAC filter rule or a specific VSI from a
391262306a36Sopenharmony_ci * VSI list for a multicast MAC address.
391362306a36Sopenharmony_ci *
391462306a36Sopenharmony_ci * Returns -ENOENT if a given entry was not added by ice_add_mac. Caller should
391562306a36Sopenharmony_ci * be aware that this call will only work if all the entries passed into m_list
391662306a36Sopenharmony_ci * were added previously. It will not attempt to do a partial remove of entries
391762306a36Sopenharmony_ci * that were found.
391862306a36Sopenharmony_ci */
391962306a36Sopenharmony_ciint ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
392062306a36Sopenharmony_ci{
392162306a36Sopenharmony_ci	struct ice_fltr_list_entry *list_itr, *tmp;
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci	if (!m_list)
392462306a36Sopenharmony_ci		return -EINVAL;
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) {
392762306a36Sopenharmony_ci		enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
392862306a36Sopenharmony_ci		u16 vsi_handle;
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_ci		if (l_type != ICE_SW_LKUP_MAC)
393162306a36Sopenharmony_ci			return -EINVAL;
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci		vsi_handle = list_itr->fltr_info.vsi_handle;
393462306a36Sopenharmony_ci		if (!ice_is_vsi_valid(hw, vsi_handle))
393562306a36Sopenharmony_ci			return -EINVAL;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci		list_itr->fltr_info.fwd_id.hw_vsi_id =
393862306a36Sopenharmony_ci					ice_get_hw_vsi_num(hw, vsi_handle);
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci		list_itr->status = ice_remove_rule_internal(hw,
394162306a36Sopenharmony_ci							    ICE_SW_LKUP_MAC,
394262306a36Sopenharmony_ci							    list_itr);
394362306a36Sopenharmony_ci		if (list_itr->status)
394462306a36Sopenharmony_ci			return list_itr->status;
394562306a36Sopenharmony_ci	}
394662306a36Sopenharmony_ci	return 0;
394762306a36Sopenharmony_ci}
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci/**
395062306a36Sopenharmony_ci * ice_remove_vlan - Remove VLAN based filter rule
395162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
395262306a36Sopenharmony_ci * @v_list: list of VLAN entries and forwarding information
395362306a36Sopenharmony_ci */
395462306a36Sopenharmony_ciint ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)
395562306a36Sopenharmony_ci{
395662306a36Sopenharmony_ci	struct ice_fltr_list_entry *v_list_itr, *tmp;
395762306a36Sopenharmony_ci
395862306a36Sopenharmony_ci	if (!v_list || !hw)
395962306a36Sopenharmony_ci		return -EINVAL;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
396262306a36Sopenharmony_ci		enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci		if (l_type != ICE_SW_LKUP_VLAN)
396562306a36Sopenharmony_ci			return -EINVAL;
396662306a36Sopenharmony_ci		v_list_itr->status = ice_remove_rule_internal(hw,
396762306a36Sopenharmony_ci							      ICE_SW_LKUP_VLAN,
396862306a36Sopenharmony_ci							      v_list_itr);
396962306a36Sopenharmony_ci		if (v_list_itr->status)
397062306a36Sopenharmony_ci			return v_list_itr->status;
397162306a36Sopenharmony_ci	}
397262306a36Sopenharmony_ci	return 0;
397362306a36Sopenharmony_ci}
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci/**
397662306a36Sopenharmony_ci * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list
397762306a36Sopenharmony_ci * @hw: pointer to the hardware structure
397862306a36Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
397962306a36Sopenharmony_ci * @vsi_list_head: pointer to the list to add entry to
398062306a36Sopenharmony_ci * @fi: pointer to fltr_info of filter entry to copy & add
398162306a36Sopenharmony_ci *
398262306a36Sopenharmony_ci * Helper function, used when creating a list of filters to remove from
398362306a36Sopenharmony_ci * a specific VSI. The entry added to vsi_list_head is a COPY of the
398462306a36Sopenharmony_ci * original filter entry, with the exception of fltr_info.fltr_act and
398562306a36Sopenharmony_ci * fltr_info.fwd_id fields. These are set such that later logic can
398662306a36Sopenharmony_ci * extract which VSI to remove the fltr from, and pass on that information.
398762306a36Sopenharmony_ci */
398862306a36Sopenharmony_cistatic int
398962306a36Sopenharmony_ciice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
399062306a36Sopenharmony_ci			       struct list_head *vsi_list_head,
399162306a36Sopenharmony_ci			       struct ice_fltr_info *fi)
399262306a36Sopenharmony_ci{
399362306a36Sopenharmony_ci	struct ice_fltr_list_entry *tmp;
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	/* this memory is freed up in the caller function
399662306a36Sopenharmony_ci	 * once filters for this VSI are removed
399762306a36Sopenharmony_ci	 */
399862306a36Sopenharmony_ci	tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL);
399962306a36Sopenharmony_ci	if (!tmp)
400062306a36Sopenharmony_ci		return -ENOMEM;
400162306a36Sopenharmony_ci
400262306a36Sopenharmony_ci	tmp->fltr_info = *fi;
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	/* Overwrite these fields to indicate which VSI to remove filter from,
400562306a36Sopenharmony_ci	 * so find and remove logic can extract the information from the
400662306a36Sopenharmony_ci	 * list entries. Note that original entries will still have proper
400762306a36Sopenharmony_ci	 * values.
400862306a36Sopenharmony_ci	 */
400962306a36Sopenharmony_ci	tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
401062306a36Sopenharmony_ci	tmp->fltr_info.vsi_handle = vsi_handle;
401162306a36Sopenharmony_ci	tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci	list_add(&tmp->list_entry, vsi_list_head);
401462306a36Sopenharmony_ci
401562306a36Sopenharmony_ci	return 0;
401662306a36Sopenharmony_ci}
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_ci/**
401962306a36Sopenharmony_ci * ice_add_to_vsi_fltr_list - Add VSI filters to the list
402062306a36Sopenharmony_ci * @hw: pointer to the hardware structure
402162306a36Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
402262306a36Sopenharmony_ci * @lkup_list_head: pointer to the list that has certain lookup type filters
402362306a36Sopenharmony_ci * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle
402462306a36Sopenharmony_ci *
402562306a36Sopenharmony_ci * Locates all filters in lkup_list_head that are used by the given VSI,
402662306a36Sopenharmony_ci * and adds COPIES of those entries to vsi_list_head (intended to be used
402762306a36Sopenharmony_ci * to remove the listed filters).
402862306a36Sopenharmony_ci * Note that this means all entries in vsi_list_head must be explicitly
402962306a36Sopenharmony_ci * deallocated by the caller when done with list.
403062306a36Sopenharmony_ci */
403162306a36Sopenharmony_cistatic int
403262306a36Sopenharmony_ciice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
403362306a36Sopenharmony_ci			 struct list_head *lkup_list_head,
403462306a36Sopenharmony_ci			 struct list_head *vsi_list_head)
403562306a36Sopenharmony_ci{
403662306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
403762306a36Sopenharmony_ci	int status = 0;
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	/* check to make sure VSI ID is valid and within boundary */
404062306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
404162306a36Sopenharmony_ci		return -EINVAL;
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	list_for_each_entry(fm_entry, lkup_list_head, list_entry) {
404462306a36Sopenharmony_ci		if (!ice_vsi_uses_fltr(fm_entry, vsi_handle))
404562306a36Sopenharmony_ci			continue;
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
404862306a36Sopenharmony_ci							vsi_list_head,
404962306a36Sopenharmony_ci							&fm_entry->fltr_info);
405062306a36Sopenharmony_ci		if (status)
405162306a36Sopenharmony_ci			return status;
405262306a36Sopenharmony_ci	}
405362306a36Sopenharmony_ci	return status;
405462306a36Sopenharmony_ci}
405562306a36Sopenharmony_ci
405662306a36Sopenharmony_ci/**
405762306a36Sopenharmony_ci * ice_determine_promisc_mask
405862306a36Sopenharmony_ci * @fi: filter info to parse
405962306a36Sopenharmony_ci *
406062306a36Sopenharmony_ci * Helper function to determine which ICE_PROMISC_ mask corresponds
406162306a36Sopenharmony_ci * to given filter into.
406262306a36Sopenharmony_ci */
406362306a36Sopenharmony_cistatic u8 ice_determine_promisc_mask(struct ice_fltr_info *fi)
406462306a36Sopenharmony_ci{
406562306a36Sopenharmony_ci	u16 vid = fi->l_data.mac_vlan.vlan_id;
406662306a36Sopenharmony_ci	u8 *macaddr = fi->l_data.mac.mac_addr;
406762306a36Sopenharmony_ci	bool is_tx_fltr = false;
406862306a36Sopenharmony_ci	u8 promisc_mask = 0;
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci	if (fi->flag == ICE_FLTR_TX)
407162306a36Sopenharmony_ci		is_tx_fltr = true;
407262306a36Sopenharmony_ci
407362306a36Sopenharmony_ci	if (is_broadcast_ether_addr(macaddr))
407462306a36Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
407562306a36Sopenharmony_ci			ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX;
407662306a36Sopenharmony_ci	else if (is_multicast_ether_addr(macaddr))
407762306a36Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
407862306a36Sopenharmony_ci			ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX;
407962306a36Sopenharmony_ci	else if (is_unicast_ether_addr(macaddr))
408062306a36Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
408162306a36Sopenharmony_ci			ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX;
408262306a36Sopenharmony_ci	if (vid)
408362306a36Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
408462306a36Sopenharmony_ci			ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX;
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	return promisc_mask;
408762306a36Sopenharmony_ci}
408862306a36Sopenharmony_ci
408962306a36Sopenharmony_ci/**
409062306a36Sopenharmony_ci * ice_remove_promisc - Remove promisc based filter rules
409162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
409262306a36Sopenharmony_ci * @recp_id: recipe ID for which the rule needs to removed
409362306a36Sopenharmony_ci * @v_list: list of promisc entries
409462306a36Sopenharmony_ci */
409562306a36Sopenharmony_cistatic int
409662306a36Sopenharmony_ciice_remove_promisc(struct ice_hw *hw, u8 recp_id, struct list_head *v_list)
409762306a36Sopenharmony_ci{
409862306a36Sopenharmony_ci	struct ice_fltr_list_entry *v_list_itr, *tmp;
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_ci	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
410162306a36Sopenharmony_ci		v_list_itr->status =
410262306a36Sopenharmony_ci			ice_remove_rule_internal(hw, recp_id, v_list_itr);
410362306a36Sopenharmony_ci		if (v_list_itr->status)
410462306a36Sopenharmony_ci			return v_list_itr->status;
410562306a36Sopenharmony_ci	}
410662306a36Sopenharmony_ci	return 0;
410762306a36Sopenharmony_ci}
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_ci/**
411062306a36Sopenharmony_ci * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI
411162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
411262306a36Sopenharmony_ci * @vsi_handle: VSI handle to clear mode
411362306a36Sopenharmony_ci * @promisc_mask: mask of promiscuous config bits to clear
411462306a36Sopenharmony_ci * @vid: VLAN ID to clear VLAN promiscuous
411562306a36Sopenharmony_ci */
411662306a36Sopenharmony_ciint
411762306a36Sopenharmony_ciice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
411862306a36Sopenharmony_ci		      u16 vid)
411962306a36Sopenharmony_ci{
412062306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
412162306a36Sopenharmony_ci	struct ice_fltr_list_entry *fm_entry, *tmp;
412262306a36Sopenharmony_ci	struct list_head remove_list_head;
412362306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *itr;
412462306a36Sopenharmony_ci	struct list_head *rule_head;
412562306a36Sopenharmony_ci	struct mutex *rule_lock;	/* Lock to protect filter rule list */
412662306a36Sopenharmony_ci	int status = 0;
412762306a36Sopenharmony_ci	u8 recipe_id;
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
413062306a36Sopenharmony_ci		return -EINVAL;
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_ci	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX))
413362306a36Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
413462306a36Sopenharmony_ci	else
413562306a36Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC;
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci	rule_head = &sw->recp_list[recipe_id].filt_rules;
413862306a36Sopenharmony_ci	rule_lock = &sw->recp_list[recipe_id].filt_rule_lock;
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_ci	INIT_LIST_HEAD(&remove_list_head);
414162306a36Sopenharmony_ci
414262306a36Sopenharmony_ci	mutex_lock(rule_lock);
414362306a36Sopenharmony_ci	list_for_each_entry(itr, rule_head, list_entry) {
414462306a36Sopenharmony_ci		struct ice_fltr_info *fltr_info;
414562306a36Sopenharmony_ci		u8 fltr_promisc_mask = 0;
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_ci		if (!ice_vsi_uses_fltr(itr, vsi_handle))
414862306a36Sopenharmony_ci			continue;
414962306a36Sopenharmony_ci		fltr_info = &itr->fltr_info;
415062306a36Sopenharmony_ci
415162306a36Sopenharmony_ci		if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN &&
415262306a36Sopenharmony_ci		    vid != fltr_info->l_data.mac_vlan.vlan_id)
415362306a36Sopenharmony_ci			continue;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci		fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info);
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci		/* Skip if filter is not completely specified by given mask */
415862306a36Sopenharmony_ci		if (fltr_promisc_mask & ~promisc_mask)
415962306a36Sopenharmony_ci			continue;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
416262306a36Sopenharmony_ci							&remove_list_head,
416362306a36Sopenharmony_ci							fltr_info);
416462306a36Sopenharmony_ci		if (status) {
416562306a36Sopenharmony_ci			mutex_unlock(rule_lock);
416662306a36Sopenharmony_ci			goto free_fltr_list;
416762306a36Sopenharmony_ci		}
416862306a36Sopenharmony_ci	}
416962306a36Sopenharmony_ci	mutex_unlock(rule_lock);
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci	status = ice_remove_promisc(hw, recipe_id, &remove_list_head);
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_cifree_fltr_list:
417462306a36Sopenharmony_ci	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
417562306a36Sopenharmony_ci		list_del(&fm_entry->list_entry);
417662306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fm_entry);
417762306a36Sopenharmony_ci	}
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci	return status;
418062306a36Sopenharmony_ci}
418162306a36Sopenharmony_ci
418262306a36Sopenharmony_ci/**
418362306a36Sopenharmony_ci * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
418462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
418562306a36Sopenharmony_ci * @vsi_handle: VSI handle to configure
418662306a36Sopenharmony_ci * @promisc_mask: mask of promiscuous config bits
418762306a36Sopenharmony_ci * @vid: VLAN ID to set VLAN promiscuous
418862306a36Sopenharmony_ci */
418962306a36Sopenharmony_ciint
419062306a36Sopenharmony_ciice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid)
419162306a36Sopenharmony_ci{
419262306a36Sopenharmony_ci	enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };
419362306a36Sopenharmony_ci	struct ice_fltr_list_entry f_list_entry;
419462306a36Sopenharmony_ci	struct ice_fltr_info new_fltr;
419562306a36Sopenharmony_ci	bool is_tx_fltr;
419662306a36Sopenharmony_ci	int status = 0;
419762306a36Sopenharmony_ci	u16 hw_vsi_id;
419862306a36Sopenharmony_ci	int pkt_type;
419962306a36Sopenharmony_ci	u8 recipe_id;
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
420262306a36Sopenharmony_ci		return -EINVAL;
420362306a36Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_ci	memset(&new_fltr, 0, sizeof(new_fltr));
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_ci	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) {
420862306a36Sopenharmony_ci		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;
420962306a36Sopenharmony_ci		new_fltr.l_data.mac_vlan.vlan_id = vid;
421062306a36Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
421162306a36Sopenharmony_ci	} else {
421262306a36Sopenharmony_ci		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC;
421362306a36Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC;
421462306a36Sopenharmony_ci	}
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_ci	/* Separate filters must be set for each direction/packet type
421762306a36Sopenharmony_ci	 * combination, so we will loop over the mask value, store the
421862306a36Sopenharmony_ci	 * individual type, and clear it out in the input mask as it
421962306a36Sopenharmony_ci	 * is found.
422062306a36Sopenharmony_ci	 */
422162306a36Sopenharmony_ci	while (promisc_mask) {
422262306a36Sopenharmony_ci		u8 *mac_addr;
422362306a36Sopenharmony_ci
422462306a36Sopenharmony_ci		pkt_type = 0;
422562306a36Sopenharmony_ci		is_tx_fltr = false;
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci		if (promisc_mask & ICE_PROMISC_UCAST_RX) {
422862306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_UCAST_RX;
422962306a36Sopenharmony_ci			pkt_type = UCAST_FLTR;
423062306a36Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_UCAST_TX) {
423162306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_UCAST_TX;
423262306a36Sopenharmony_ci			pkt_type = UCAST_FLTR;
423362306a36Sopenharmony_ci			is_tx_fltr = true;
423462306a36Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_MCAST_RX) {
423562306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_MCAST_RX;
423662306a36Sopenharmony_ci			pkt_type = MCAST_FLTR;
423762306a36Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_MCAST_TX) {
423862306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_MCAST_TX;
423962306a36Sopenharmony_ci			pkt_type = MCAST_FLTR;
424062306a36Sopenharmony_ci			is_tx_fltr = true;
424162306a36Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_BCAST_RX) {
424262306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_BCAST_RX;
424362306a36Sopenharmony_ci			pkt_type = BCAST_FLTR;
424462306a36Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_BCAST_TX) {
424562306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_BCAST_TX;
424662306a36Sopenharmony_ci			pkt_type = BCAST_FLTR;
424762306a36Sopenharmony_ci			is_tx_fltr = true;
424862306a36Sopenharmony_ci		}
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci		/* Check for VLAN promiscuous flag */
425162306a36Sopenharmony_ci		if (promisc_mask & ICE_PROMISC_VLAN_RX) {
425262306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_VLAN_RX;
425362306a36Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_VLAN_TX) {
425462306a36Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_VLAN_TX;
425562306a36Sopenharmony_ci			is_tx_fltr = true;
425662306a36Sopenharmony_ci		}
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci		/* Set filter DA based on packet type */
425962306a36Sopenharmony_ci		mac_addr = new_fltr.l_data.mac.mac_addr;
426062306a36Sopenharmony_ci		if (pkt_type == BCAST_FLTR) {
426162306a36Sopenharmony_ci			eth_broadcast_addr(mac_addr);
426262306a36Sopenharmony_ci		} else if (pkt_type == MCAST_FLTR ||
426362306a36Sopenharmony_ci			   pkt_type == UCAST_FLTR) {
426462306a36Sopenharmony_ci			/* Use the dummy ether header DA */
426562306a36Sopenharmony_ci			ether_addr_copy(mac_addr, dummy_eth_header);
426662306a36Sopenharmony_ci			if (pkt_type == MCAST_FLTR)
426762306a36Sopenharmony_ci				mac_addr[0] |= 0x1;	/* Set multicast bit */
426862306a36Sopenharmony_ci		}
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci		/* Need to reset this to zero for all iterations */
427162306a36Sopenharmony_ci		new_fltr.flag = 0;
427262306a36Sopenharmony_ci		if (is_tx_fltr) {
427362306a36Sopenharmony_ci			new_fltr.flag |= ICE_FLTR_TX;
427462306a36Sopenharmony_ci			new_fltr.src = hw_vsi_id;
427562306a36Sopenharmony_ci		} else {
427662306a36Sopenharmony_ci			new_fltr.flag |= ICE_FLTR_RX;
427762306a36Sopenharmony_ci			new_fltr.src = hw->port_info->lport;
427862306a36Sopenharmony_ci		}
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci		new_fltr.fltr_act = ICE_FWD_TO_VSI;
428162306a36Sopenharmony_ci		new_fltr.vsi_handle = vsi_handle;
428262306a36Sopenharmony_ci		new_fltr.fwd_id.hw_vsi_id = hw_vsi_id;
428362306a36Sopenharmony_ci		f_list_entry.fltr_info = new_fltr;
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci		status = ice_add_rule_internal(hw, recipe_id, &f_list_entry);
428662306a36Sopenharmony_ci		if (status)
428762306a36Sopenharmony_ci			goto set_promisc_exit;
428862306a36Sopenharmony_ci	}
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ciset_promisc_exit:
429162306a36Sopenharmony_ci	return status;
429262306a36Sopenharmony_ci}
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_ci/**
429562306a36Sopenharmony_ci * ice_set_vlan_vsi_promisc
429662306a36Sopenharmony_ci * @hw: pointer to the hardware structure
429762306a36Sopenharmony_ci * @vsi_handle: VSI handle to configure
429862306a36Sopenharmony_ci * @promisc_mask: mask of promiscuous config bits
429962306a36Sopenharmony_ci * @rm_vlan_promisc: Clear VLANs VSI promisc mode
430062306a36Sopenharmony_ci *
430162306a36Sopenharmony_ci * Configure VSI with all associated VLANs to given promiscuous mode(s)
430262306a36Sopenharmony_ci */
430362306a36Sopenharmony_ciint
430462306a36Sopenharmony_ciice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
430562306a36Sopenharmony_ci			 bool rm_vlan_promisc)
430662306a36Sopenharmony_ci{
430762306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
430862306a36Sopenharmony_ci	struct ice_fltr_list_entry *list_itr, *tmp;
430962306a36Sopenharmony_ci	struct list_head vsi_list_head;
431062306a36Sopenharmony_ci	struct list_head *vlan_head;
431162306a36Sopenharmony_ci	struct mutex *vlan_lock; /* Lock to protect filter rule list */
431262306a36Sopenharmony_ci	u16 vlan_id;
431362306a36Sopenharmony_ci	int status;
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci	INIT_LIST_HEAD(&vsi_list_head);
431662306a36Sopenharmony_ci	vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
431762306a36Sopenharmony_ci	vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
431862306a36Sopenharmony_ci	mutex_lock(vlan_lock);
431962306a36Sopenharmony_ci	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,
432062306a36Sopenharmony_ci					  &vsi_list_head);
432162306a36Sopenharmony_ci	mutex_unlock(vlan_lock);
432262306a36Sopenharmony_ci	if (status)
432362306a36Sopenharmony_ci		goto free_fltr_list;
432462306a36Sopenharmony_ci
432562306a36Sopenharmony_ci	list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
432662306a36Sopenharmony_ci		/* Avoid enabling or disabling VLAN zero twice when in double
432762306a36Sopenharmony_ci		 * VLAN mode
432862306a36Sopenharmony_ci		 */
432962306a36Sopenharmony_ci		if (ice_is_dvm_ena(hw) &&
433062306a36Sopenharmony_ci		    list_itr->fltr_info.l_data.vlan.tpid == 0)
433162306a36Sopenharmony_ci			continue;
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci		vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
433462306a36Sopenharmony_ci		if (rm_vlan_promisc)
433562306a36Sopenharmony_ci			status = ice_clear_vsi_promisc(hw, vsi_handle,
433662306a36Sopenharmony_ci						       promisc_mask, vlan_id);
433762306a36Sopenharmony_ci		else
433862306a36Sopenharmony_ci			status = ice_set_vsi_promisc(hw, vsi_handle,
433962306a36Sopenharmony_ci						     promisc_mask, vlan_id);
434062306a36Sopenharmony_ci		if (status && status != -EEXIST)
434162306a36Sopenharmony_ci			break;
434262306a36Sopenharmony_ci	}
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_cifree_fltr_list:
434562306a36Sopenharmony_ci	list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) {
434662306a36Sopenharmony_ci		list_del(&list_itr->list_entry);
434762306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), list_itr);
434862306a36Sopenharmony_ci	}
434962306a36Sopenharmony_ci	return status;
435062306a36Sopenharmony_ci}
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci/**
435362306a36Sopenharmony_ci * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
435462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
435562306a36Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
435662306a36Sopenharmony_ci * @lkup: switch rule filter lookup type
435762306a36Sopenharmony_ci */
435862306a36Sopenharmony_cistatic void
435962306a36Sopenharmony_ciice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
436062306a36Sopenharmony_ci			 enum ice_sw_lkup_type lkup)
436162306a36Sopenharmony_ci{
436262306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
436362306a36Sopenharmony_ci	struct ice_fltr_list_entry *fm_entry;
436462306a36Sopenharmony_ci	struct list_head remove_list_head;
436562306a36Sopenharmony_ci	struct list_head *rule_head;
436662306a36Sopenharmony_ci	struct ice_fltr_list_entry *tmp;
436762306a36Sopenharmony_ci	struct mutex *rule_lock;	/* Lock to protect filter rule list */
436862306a36Sopenharmony_ci	int status;
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	INIT_LIST_HEAD(&remove_list_head);
437162306a36Sopenharmony_ci	rule_lock = &sw->recp_list[lkup].filt_rule_lock;
437262306a36Sopenharmony_ci	rule_head = &sw->recp_list[lkup].filt_rules;
437362306a36Sopenharmony_ci	mutex_lock(rule_lock);
437462306a36Sopenharmony_ci	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,
437562306a36Sopenharmony_ci					  &remove_list_head);
437662306a36Sopenharmony_ci	mutex_unlock(rule_lock);
437762306a36Sopenharmony_ci	if (status)
437862306a36Sopenharmony_ci		goto free_fltr_list;
437962306a36Sopenharmony_ci
438062306a36Sopenharmony_ci	switch (lkup) {
438162306a36Sopenharmony_ci	case ICE_SW_LKUP_MAC:
438262306a36Sopenharmony_ci		ice_remove_mac(hw, &remove_list_head);
438362306a36Sopenharmony_ci		break;
438462306a36Sopenharmony_ci	case ICE_SW_LKUP_VLAN:
438562306a36Sopenharmony_ci		ice_remove_vlan(hw, &remove_list_head);
438662306a36Sopenharmony_ci		break;
438762306a36Sopenharmony_ci	case ICE_SW_LKUP_PROMISC:
438862306a36Sopenharmony_ci	case ICE_SW_LKUP_PROMISC_VLAN:
438962306a36Sopenharmony_ci		ice_remove_promisc(hw, lkup, &remove_list_head);
439062306a36Sopenharmony_ci		break;
439162306a36Sopenharmony_ci	case ICE_SW_LKUP_MAC_VLAN:
439262306a36Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE:
439362306a36Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE_MAC:
439462306a36Sopenharmony_ci	case ICE_SW_LKUP_DFLT:
439562306a36Sopenharmony_ci	case ICE_SW_LKUP_LAST:
439662306a36Sopenharmony_ci	default:
439762306a36Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup);
439862306a36Sopenharmony_ci		break;
439962306a36Sopenharmony_ci	}
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_cifree_fltr_list:
440262306a36Sopenharmony_ci	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
440362306a36Sopenharmony_ci		list_del(&fm_entry->list_entry);
440462306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fm_entry);
440562306a36Sopenharmony_ci	}
440662306a36Sopenharmony_ci}
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_ci/**
440962306a36Sopenharmony_ci * ice_remove_vsi_fltr - Remove all filters for a VSI
441062306a36Sopenharmony_ci * @hw: pointer to the hardware structure
441162306a36Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
441262306a36Sopenharmony_ci */
441362306a36Sopenharmony_civoid ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)
441462306a36Sopenharmony_ci{
441562306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC);
441662306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN);
441762306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC);
441862306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN);
441962306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT);
442062306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE);
442162306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC);
442262306a36Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);
442362306a36Sopenharmony_ci}
442462306a36Sopenharmony_ci
442562306a36Sopenharmony_ci/**
442662306a36Sopenharmony_ci * ice_alloc_res_cntr - allocating resource counter
442762306a36Sopenharmony_ci * @hw: pointer to the hardware structure
442862306a36Sopenharmony_ci * @type: type of resource
442962306a36Sopenharmony_ci * @alloc_shared: if set it is shared else dedicated
443062306a36Sopenharmony_ci * @num_items: number of entries requested for FD resource type
443162306a36Sopenharmony_ci * @counter_id: counter index returned by AQ call
443262306a36Sopenharmony_ci */
443362306a36Sopenharmony_ciint
443462306a36Sopenharmony_ciice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
443562306a36Sopenharmony_ci		   u16 *counter_id)
443662306a36Sopenharmony_ci{
443762306a36Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *buf;
443862306a36Sopenharmony_ci	u16 buf_len;
443962306a36Sopenharmony_ci	int status;
444062306a36Sopenharmony_ci
444162306a36Sopenharmony_ci	/* Allocate resource */
444262306a36Sopenharmony_ci	buf_len = struct_size(buf, elem, 1);
444362306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
444462306a36Sopenharmony_ci	if (!buf)
444562306a36Sopenharmony_ci		return -ENOMEM;
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci	buf->num_elems = cpu_to_le16(num_items);
444862306a36Sopenharmony_ci	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
444962306a36Sopenharmony_ci				      ICE_AQC_RES_TYPE_M) | alloc_shared);
445062306a36Sopenharmony_ci
445162306a36Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_alloc_res);
445262306a36Sopenharmony_ci	if (status)
445362306a36Sopenharmony_ci		goto exit;
445462306a36Sopenharmony_ci
445562306a36Sopenharmony_ci	*counter_id = le16_to_cpu(buf->elem[0].e.sw_resp);
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ciexit:
445862306a36Sopenharmony_ci	kfree(buf);
445962306a36Sopenharmony_ci	return status;
446062306a36Sopenharmony_ci}
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci/**
446362306a36Sopenharmony_ci * ice_free_res_cntr - free resource counter
446462306a36Sopenharmony_ci * @hw: pointer to the hardware structure
446562306a36Sopenharmony_ci * @type: type of resource
446662306a36Sopenharmony_ci * @alloc_shared: if set it is shared else dedicated
446762306a36Sopenharmony_ci * @num_items: number of entries to be freed for FD resource type
446862306a36Sopenharmony_ci * @counter_id: counter ID resource which needs to be freed
446962306a36Sopenharmony_ci */
447062306a36Sopenharmony_ciint
447162306a36Sopenharmony_ciice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
447262306a36Sopenharmony_ci		  u16 counter_id)
447362306a36Sopenharmony_ci{
447462306a36Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *buf;
447562306a36Sopenharmony_ci	u16 buf_len;
447662306a36Sopenharmony_ci	int status;
447762306a36Sopenharmony_ci
447862306a36Sopenharmony_ci	/* Free resource */
447962306a36Sopenharmony_ci	buf_len = struct_size(buf, elem, 1);
448062306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
448162306a36Sopenharmony_ci	if (!buf)
448262306a36Sopenharmony_ci		return -ENOMEM;
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci	buf->num_elems = cpu_to_le16(num_items);
448562306a36Sopenharmony_ci	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
448662306a36Sopenharmony_ci				      ICE_AQC_RES_TYPE_M) | alloc_shared);
448762306a36Sopenharmony_ci	buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_free_res);
449062306a36Sopenharmony_ci	if (status)
449162306a36Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n");
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci	kfree(buf);
449462306a36Sopenharmony_ci	return status;
449562306a36Sopenharmony_ci}
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci#define ICE_PROTOCOL_ENTRY(id, ...) {		\
449862306a36Sopenharmony_ci	.prot_type	= id,			\
449962306a36Sopenharmony_ci	.offs		= {__VA_ARGS__},	\
450062306a36Sopenharmony_ci}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci/**
450362306a36Sopenharmony_ci * ice_share_res - set a resource as shared or dedicated
450462306a36Sopenharmony_ci * @hw: hw struct of original owner of resource
450562306a36Sopenharmony_ci * @type: resource type
450662306a36Sopenharmony_ci * @shared: is the resource being set to shared
450762306a36Sopenharmony_ci * @res_id: resource id (descriptor)
450862306a36Sopenharmony_ci */
450962306a36Sopenharmony_ciint ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id)
451062306a36Sopenharmony_ci{
451162306a36Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *buf;
451262306a36Sopenharmony_ci	u16 buf_len;
451362306a36Sopenharmony_ci	int status;
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_ci	buf_len = struct_size(buf, elem, 1);
451662306a36Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
451762306a36Sopenharmony_ci	if (!buf)
451862306a36Sopenharmony_ci		return -ENOMEM;
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci	buf->num_elems = cpu_to_le16(1);
452162306a36Sopenharmony_ci	if (shared)
452262306a36Sopenharmony_ci		buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
452362306a36Sopenharmony_ci					     ICE_AQC_RES_TYPE_M) |
452462306a36Sopenharmony_ci					    ICE_AQC_RES_TYPE_FLAG_SHARED);
452562306a36Sopenharmony_ci	else
452662306a36Sopenharmony_ci		buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
452762306a36Sopenharmony_ci					     ICE_AQC_RES_TYPE_M) &
452862306a36Sopenharmony_ci					    ~ICE_AQC_RES_TYPE_FLAG_SHARED);
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci	buf->elem[0].e.sw_resp = cpu_to_le16(res_id);
453162306a36Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, buf, buf_len,
453262306a36Sopenharmony_ci				       ice_aqc_opc_share_res);
453362306a36Sopenharmony_ci	if (status)
453462306a36Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "Could not set resource type %u id %u to %s\n",
453562306a36Sopenharmony_ci			  type, res_id, shared ? "SHARED" : "DEDICATED");
453662306a36Sopenharmony_ci
453762306a36Sopenharmony_ci	kfree(buf);
453862306a36Sopenharmony_ci	return status;
453962306a36Sopenharmony_ci}
454062306a36Sopenharmony_ci
454162306a36Sopenharmony_ci/* This is mapping table entry that maps every word within a given protocol
454262306a36Sopenharmony_ci * structure to the real byte offset as per the specification of that
454362306a36Sopenharmony_ci * protocol header.
454462306a36Sopenharmony_ci * for example dst address is 3 words in ethertype header and corresponding
454562306a36Sopenharmony_ci * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8
454662306a36Sopenharmony_ci * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a
454762306a36Sopenharmony_ci * matching entry describing its field. This needs to be updated if new
454862306a36Sopenharmony_ci * structure is added to that union.
454962306a36Sopenharmony_ci */
455062306a36Sopenharmony_cistatic const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
455162306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_MAC_OFOS, 0, 2, 4, 6, 8, 10, 12),
455262306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_MAC_IL, 0, 2, 4, 6, 8, 10, 12),
455362306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_ETYPE_OL, 0),
455462306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_ETYPE_IL, 0),
455562306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_VLAN_OFOS, 2, 0),
455662306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_IPV4_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18),
455762306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_IPV4_IL,	0, 2, 4, 6, 8, 10, 12, 14, 16, 18),
455862306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_IPV6_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
455962306a36Sopenharmony_ci			   20, 22, 24, 26, 28, 30, 32, 34, 36, 38),
456062306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_IPV6_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
456162306a36Sopenharmony_ci			   22, 24, 26, 28, 30, 32, 34, 36, 38),
456262306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_TCP_IL, 0, 2),
456362306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_UDP_OF, 0, 2),
456462306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_UDP_ILOS, 0, 2),
456562306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_VXLAN, 8, 10, 12, 14),
456662306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_GENEVE, 8, 10, 12, 14),
456762306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6),
456862306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22),
456962306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14),
457062306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6),
457162306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10),
457262306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0),
457362306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_VLAN_IN, 2, 0),
457462306a36Sopenharmony_ci	ICE_PROTOCOL_ENTRY(ICE_HW_METADATA,
457562306a36Sopenharmony_ci			   ICE_SOURCE_PORT_MDID_OFFSET,
457662306a36Sopenharmony_ci			   ICE_PTYPE_MDID_OFFSET,
457762306a36Sopenharmony_ci			   ICE_PACKET_LENGTH_MDID_OFFSET,
457862306a36Sopenharmony_ci			   ICE_SOURCE_VSI_MDID_OFFSET,
457962306a36Sopenharmony_ci			   ICE_PKT_VLAN_MDID_OFFSET,
458062306a36Sopenharmony_ci			   ICE_PKT_TUNNEL_MDID_OFFSET,
458162306a36Sopenharmony_ci			   ICE_PKT_TCP_MDID_OFFSET,
458262306a36Sopenharmony_ci			   ICE_PKT_ERROR_MDID_OFFSET),
458362306a36Sopenharmony_ci};
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_cistatic struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
458662306a36Sopenharmony_ci	{ ICE_MAC_OFOS,		ICE_MAC_OFOS_HW },
458762306a36Sopenharmony_ci	{ ICE_MAC_IL,		ICE_MAC_IL_HW },
458862306a36Sopenharmony_ci	{ ICE_ETYPE_OL,		ICE_ETYPE_OL_HW },
458962306a36Sopenharmony_ci	{ ICE_ETYPE_IL,		ICE_ETYPE_IL_HW },
459062306a36Sopenharmony_ci	{ ICE_VLAN_OFOS,	ICE_VLAN_OL_HW },
459162306a36Sopenharmony_ci	{ ICE_IPV4_OFOS,	ICE_IPV4_OFOS_HW },
459262306a36Sopenharmony_ci	{ ICE_IPV4_IL,		ICE_IPV4_IL_HW },
459362306a36Sopenharmony_ci	{ ICE_IPV6_OFOS,	ICE_IPV6_OFOS_HW },
459462306a36Sopenharmony_ci	{ ICE_IPV6_IL,		ICE_IPV6_IL_HW },
459562306a36Sopenharmony_ci	{ ICE_TCP_IL,		ICE_TCP_IL_HW },
459662306a36Sopenharmony_ci	{ ICE_UDP_OF,		ICE_UDP_OF_HW },
459762306a36Sopenharmony_ci	{ ICE_UDP_ILOS,		ICE_UDP_ILOS_HW },
459862306a36Sopenharmony_ci	{ ICE_VXLAN,		ICE_UDP_OF_HW },
459962306a36Sopenharmony_ci	{ ICE_GENEVE,		ICE_UDP_OF_HW },
460062306a36Sopenharmony_ci	{ ICE_NVGRE,		ICE_GRE_OF_HW },
460162306a36Sopenharmony_ci	{ ICE_GTP,		ICE_UDP_OF_HW },
460262306a36Sopenharmony_ci	{ ICE_GTP_NO_PAY,	ICE_UDP_ILOS_HW },
460362306a36Sopenharmony_ci	{ ICE_PPPOE,		ICE_PPPOE_HW },
460462306a36Sopenharmony_ci	{ ICE_L2TPV3,		ICE_L2TPV3_HW },
460562306a36Sopenharmony_ci	{ ICE_VLAN_EX,          ICE_VLAN_OF_HW },
460662306a36Sopenharmony_ci	{ ICE_VLAN_IN,          ICE_VLAN_OL_HW },
460762306a36Sopenharmony_ci	{ ICE_HW_METADATA,      ICE_META_DATA_ID_HW },
460862306a36Sopenharmony_ci};
460962306a36Sopenharmony_ci
461062306a36Sopenharmony_ci/**
461162306a36Sopenharmony_ci * ice_find_recp - find a recipe
461262306a36Sopenharmony_ci * @hw: pointer to the hardware structure
461362306a36Sopenharmony_ci * @lkup_exts: extension sequence to match
461462306a36Sopenharmony_ci * @rinfo: information regarding the rule e.g. priority and action info
461562306a36Sopenharmony_ci *
461662306a36Sopenharmony_ci * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
461762306a36Sopenharmony_ci */
461862306a36Sopenharmony_cistatic u16
461962306a36Sopenharmony_ciice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
462062306a36Sopenharmony_ci	      const struct ice_adv_rule_info *rinfo)
462162306a36Sopenharmony_ci{
462262306a36Sopenharmony_ci	bool refresh_required = true;
462362306a36Sopenharmony_ci	struct ice_sw_recipe *recp;
462462306a36Sopenharmony_ci	u8 i;
462562306a36Sopenharmony_ci
462662306a36Sopenharmony_ci	/* Walk through existing recipes to find a match */
462762306a36Sopenharmony_ci	recp = hw->switch_info->recp_list;
462862306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
462962306a36Sopenharmony_ci		/* If recipe was not created for this ID, in SW bookkeeping,
463062306a36Sopenharmony_ci		 * check if FW has an entry for this recipe. If the FW has an
463162306a36Sopenharmony_ci		 * entry update it in our SW bookkeeping and continue with the
463262306a36Sopenharmony_ci		 * matching.
463362306a36Sopenharmony_ci		 */
463462306a36Sopenharmony_ci		if (!recp[i].recp_created)
463562306a36Sopenharmony_ci			if (ice_get_recp_frm_fw(hw,
463662306a36Sopenharmony_ci						hw->switch_info->recp_list, i,
463762306a36Sopenharmony_ci						&refresh_required))
463862306a36Sopenharmony_ci				continue;
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_ci		/* Skip inverse action recipes */
464162306a36Sopenharmony_ci		if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl &
464262306a36Sopenharmony_ci		    ICE_AQ_RECIPE_ACT_INV_ACT)
464362306a36Sopenharmony_ci			continue;
464462306a36Sopenharmony_ci
464562306a36Sopenharmony_ci		/* if number of words we are looking for match */
464662306a36Sopenharmony_ci		if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) {
464762306a36Sopenharmony_ci			struct ice_fv_word *ar = recp[i].lkup_exts.fv_words;
464862306a36Sopenharmony_ci			struct ice_fv_word *be = lkup_exts->fv_words;
464962306a36Sopenharmony_ci			u16 *cr = recp[i].lkup_exts.field_mask;
465062306a36Sopenharmony_ci			u16 *de = lkup_exts->field_mask;
465162306a36Sopenharmony_ci			bool found = true;
465262306a36Sopenharmony_ci			u8 pe, qr;
465362306a36Sopenharmony_ci
465462306a36Sopenharmony_ci			/* ar, cr, and qr are related to the recipe words, while
465562306a36Sopenharmony_ci			 * be, de, and pe are related to the lookup words
465662306a36Sopenharmony_ci			 */
465762306a36Sopenharmony_ci			for (pe = 0; pe < lkup_exts->n_val_words; pe++) {
465862306a36Sopenharmony_ci				for (qr = 0; qr < recp[i].lkup_exts.n_val_words;
465962306a36Sopenharmony_ci				     qr++) {
466062306a36Sopenharmony_ci					if (ar[qr].off == be[pe].off &&
466162306a36Sopenharmony_ci					    ar[qr].prot_id == be[pe].prot_id &&
466262306a36Sopenharmony_ci					    cr[qr] == de[pe])
466362306a36Sopenharmony_ci						/* Found the "pe"th word in the
466462306a36Sopenharmony_ci						 * given recipe
466562306a36Sopenharmony_ci						 */
466662306a36Sopenharmony_ci						break;
466762306a36Sopenharmony_ci				}
466862306a36Sopenharmony_ci				/* After walking through all the words in the
466962306a36Sopenharmony_ci				 * "i"th recipe if "p"th word was not found then
467062306a36Sopenharmony_ci				 * this recipe is not what we are looking for.
467162306a36Sopenharmony_ci				 * So break out from this loop and try the next
467262306a36Sopenharmony_ci				 * recipe
467362306a36Sopenharmony_ci				 */
467462306a36Sopenharmony_ci				if (qr >= recp[i].lkup_exts.n_val_words) {
467562306a36Sopenharmony_ci					found = false;
467662306a36Sopenharmony_ci					break;
467762306a36Sopenharmony_ci				}
467862306a36Sopenharmony_ci			}
467962306a36Sopenharmony_ci			/* If for "i"th recipe the found was never set to false
468062306a36Sopenharmony_ci			 * then it means we found our match
468162306a36Sopenharmony_ci			 * Also tun type and *_pass_l2 of recipe needs to be
468262306a36Sopenharmony_ci			 * checked
468362306a36Sopenharmony_ci			 */
468462306a36Sopenharmony_ci			if (found && recp[i].tun_type == rinfo->tun_type &&
468562306a36Sopenharmony_ci			    recp[i].need_pass_l2 == rinfo->need_pass_l2 &&
468662306a36Sopenharmony_ci			    recp[i].allow_pass_l2 == rinfo->allow_pass_l2)
468762306a36Sopenharmony_ci				return i; /* Return the recipe ID */
468862306a36Sopenharmony_ci		}
468962306a36Sopenharmony_ci	}
469062306a36Sopenharmony_ci	return ICE_MAX_NUM_RECIPES;
469162306a36Sopenharmony_ci}
469262306a36Sopenharmony_ci
469362306a36Sopenharmony_ci/**
469462306a36Sopenharmony_ci * ice_change_proto_id_to_dvm - change proto id in prot_id_tbl
469562306a36Sopenharmony_ci *
469662306a36Sopenharmony_ci * As protocol id for outer vlan is different in dvm and svm, if dvm is
469762306a36Sopenharmony_ci * supported protocol array record for outer vlan has to be modified to
469862306a36Sopenharmony_ci * reflect the value proper for DVM.
469962306a36Sopenharmony_ci */
470062306a36Sopenharmony_civoid ice_change_proto_id_to_dvm(void)
470162306a36Sopenharmony_ci{
470262306a36Sopenharmony_ci	u8 i;
470362306a36Sopenharmony_ci
470462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++)
470562306a36Sopenharmony_ci		if (ice_prot_id_tbl[i].type == ICE_VLAN_OFOS &&
470662306a36Sopenharmony_ci		    ice_prot_id_tbl[i].protocol_id != ICE_VLAN_OF_HW)
470762306a36Sopenharmony_ci			ice_prot_id_tbl[i].protocol_id = ICE_VLAN_OF_HW;
470862306a36Sopenharmony_ci}
470962306a36Sopenharmony_ci
471062306a36Sopenharmony_ci/**
471162306a36Sopenharmony_ci * ice_prot_type_to_id - get protocol ID from protocol type
471262306a36Sopenharmony_ci * @type: protocol type
471362306a36Sopenharmony_ci * @id: pointer to variable that will receive the ID
471462306a36Sopenharmony_ci *
471562306a36Sopenharmony_ci * Returns true if found, false otherwise
471662306a36Sopenharmony_ci */
471762306a36Sopenharmony_cistatic bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id)
471862306a36Sopenharmony_ci{
471962306a36Sopenharmony_ci	u8 i;
472062306a36Sopenharmony_ci
472162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++)
472262306a36Sopenharmony_ci		if (ice_prot_id_tbl[i].type == type) {
472362306a36Sopenharmony_ci			*id = ice_prot_id_tbl[i].protocol_id;
472462306a36Sopenharmony_ci			return true;
472562306a36Sopenharmony_ci		}
472662306a36Sopenharmony_ci	return false;
472762306a36Sopenharmony_ci}
472862306a36Sopenharmony_ci
472962306a36Sopenharmony_ci/**
473062306a36Sopenharmony_ci * ice_fill_valid_words - count valid words
473162306a36Sopenharmony_ci * @rule: advanced rule with lookup information
473262306a36Sopenharmony_ci * @lkup_exts: byte offset extractions of the words that are valid
473362306a36Sopenharmony_ci *
473462306a36Sopenharmony_ci * calculate valid words in a lookup rule using mask value
473562306a36Sopenharmony_ci */
473662306a36Sopenharmony_cistatic u8
473762306a36Sopenharmony_ciice_fill_valid_words(struct ice_adv_lkup_elem *rule,
473862306a36Sopenharmony_ci		     struct ice_prot_lkup_ext *lkup_exts)
473962306a36Sopenharmony_ci{
474062306a36Sopenharmony_ci	u8 j, word, prot_id, ret_val;
474162306a36Sopenharmony_ci
474262306a36Sopenharmony_ci	if (!ice_prot_type_to_id(rule->type, &prot_id))
474362306a36Sopenharmony_ci		return 0;
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	word = lkup_exts->n_val_words;
474662306a36Sopenharmony_ci
474762306a36Sopenharmony_ci	for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++)
474862306a36Sopenharmony_ci		if (((u16 *)&rule->m_u)[j] &&
474962306a36Sopenharmony_ci		    rule->type < ARRAY_SIZE(ice_prot_ext)) {
475062306a36Sopenharmony_ci			/* No more space to accommodate */
475162306a36Sopenharmony_ci			if (word >= ICE_MAX_CHAIN_WORDS)
475262306a36Sopenharmony_ci				return 0;
475362306a36Sopenharmony_ci			lkup_exts->fv_words[word].off =
475462306a36Sopenharmony_ci				ice_prot_ext[rule->type].offs[j];
475562306a36Sopenharmony_ci			lkup_exts->fv_words[word].prot_id =
475662306a36Sopenharmony_ci				ice_prot_id_tbl[rule->type].protocol_id;
475762306a36Sopenharmony_ci			lkup_exts->field_mask[word] =
475862306a36Sopenharmony_ci				be16_to_cpu(((__force __be16 *)&rule->m_u)[j]);
475962306a36Sopenharmony_ci			word++;
476062306a36Sopenharmony_ci		}
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	ret_val = word - lkup_exts->n_val_words;
476362306a36Sopenharmony_ci	lkup_exts->n_val_words = word;
476462306a36Sopenharmony_ci
476562306a36Sopenharmony_ci	return ret_val;
476662306a36Sopenharmony_ci}
476762306a36Sopenharmony_ci
476862306a36Sopenharmony_ci/**
476962306a36Sopenharmony_ci * ice_create_first_fit_recp_def - Create a recipe grouping
477062306a36Sopenharmony_ci * @hw: pointer to the hardware structure
477162306a36Sopenharmony_ci * @lkup_exts: an array of protocol header extractions
477262306a36Sopenharmony_ci * @rg_list: pointer to a list that stores new recipe groups
477362306a36Sopenharmony_ci * @recp_cnt: pointer to a variable that stores returned number of recipe groups
477462306a36Sopenharmony_ci *
477562306a36Sopenharmony_ci * Using first fit algorithm, take all the words that are still not done
477662306a36Sopenharmony_ci * and start grouping them in 4-word groups. Each group makes up one
477762306a36Sopenharmony_ci * recipe.
477862306a36Sopenharmony_ci */
477962306a36Sopenharmony_cistatic int
478062306a36Sopenharmony_ciice_create_first_fit_recp_def(struct ice_hw *hw,
478162306a36Sopenharmony_ci			      struct ice_prot_lkup_ext *lkup_exts,
478262306a36Sopenharmony_ci			      struct list_head *rg_list,
478362306a36Sopenharmony_ci			      u8 *recp_cnt)
478462306a36Sopenharmony_ci{
478562306a36Sopenharmony_ci	struct ice_pref_recipe_group *grp = NULL;
478662306a36Sopenharmony_ci	u8 j;
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci	*recp_cnt = 0;
478962306a36Sopenharmony_ci
479062306a36Sopenharmony_ci	/* Walk through every word in the rule to check if it is not done. If so
479162306a36Sopenharmony_ci	 * then this word needs to be part of a new recipe.
479262306a36Sopenharmony_ci	 */
479362306a36Sopenharmony_ci	for (j = 0; j < lkup_exts->n_val_words; j++)
479462306a36Sopenharmony_ci		if (!test_bit(j, lkup_exts->done)) {
479562306a36Sopenharmony_ci			if (!grp ||
479662306a36Sopenharmony_ci			    grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) {
479762306a36Sopenharmony_ci				struct ice_recp_grp_entry *entry;
479862306a36Sopenharmony_ci
479962306a36Sopenharmony_ci				entry = devm_kzalloc(ice_hw_to_dev(hw),
480062306a36Sopenharmony_ci						     sizeof(*entry),
480162306a36Sopenharmony_ci						     GFP_KERNEL);
480262306a36Sopenharmony_ci				if (!entry)
480362306a36Sopenharmony_ci					return -ENOMEM;
480462306a36Sopenharmony_ci				list_add(&entry->l_entry, rg_list);
480562306a36Sopenharmony_ci				grp = &entry->r_group;
480662306a36Sopenharmony_ci				(*recp_cnt)++;
480762306a36Sopenharmony_ci			}
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ci			grp->pairs[grp->n_val_pairs].prot_id =
481062306a36Sopenharmony_ci				lkup_exts->fv_words[j].prot_id;
481162306a36Sopenharmony_ci			grp->pairs[grp->n_val_pairs].off =
481262306a36Sopenharmony_ci				lkup_exts->fv_words[j].off;
481362306a36Sopenharmony_ci			grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j];
481462306a36Sopenharmony_ci			grp->n_val_pairs++;
481562306a36Sopenharmony_ci		}
481662306a36Sopenharmony_ci
481762306a36Sopenharmony_ci	return 0;
481862306a36Sopenharmony_ci}
481962306a36Sopenharmony_ci
482062306a36Sopenharmony_ci/**
482162306a36Sopenharmony_ci * ice_fill_fv_word_index - fill in the field vector indices for a recipe group
482262306a36Sopenharmony_ci * @hw: pointer to the hardware structure
482362306a36Sopenharmony_ci * @fv_list: field vector with the extraction sequence information
482462306a36Sopenharmony_ci * @rg_list: recipe groupings with protocol-offset pairs
482562306a36Sopenharmony_ci *
482662306a36Sopenharmony_ci * Helper function to fill in the field vector indices for protocol-offset
482762306a36Sopenharmony_ci * pairs. These indexes are then ultimately programmed into a recipe.
482862306a36Sopenharmony_ci */
482962306a36Sopenharmony_cistatic int
483062306a36Sopenharmony_ciice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list,
483162306a36Sopenharmony_ci		       struct list_head *rg_list)
483262306a36Sopenharmony_ci{
483362306a36Sopenharmony_ci	struct ice_sw_fv_list_entry *fv;
483462306a36Sopenharmony_ci	struct ice_recp_grp_entry *rg;
483562306a36Sopenharmony_ci	struct ice_fv_word *fv_ext;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci	if (list_empty(fv_list))
483862306a36Sopenharmony_ci		return 0;
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci	fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry,
484162306a36Sopenharmony_ci			      list_entry);
484262306a36Sopenharmony_ci	fv_ext = fv->fv_ptr->ew;
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci	list_for_each_entry(rg, rg_list, l_entry) {
484562306a36Sopenharmony_ci		u8 i;
484662306a36Sopenharmony_ci
484762306a36Sopenharmony_ci		for (i = 0; i < rg->r_group.n_val_pairs; i++) {
484862306a36Sopenharmony_ci			struct ice_fv_word *pr;
484962306a36Sopenharmony_ci			bool found = false;
485062306a36Sopenharmony_ci			u16 mask;
485162306a36Sopenharmony_ci			u8 j;
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci			pr = &rg->r_group.pairs[i];
485462306a36Sopenharmony_ci			mask = rg->r_group.mask[i];
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_ci			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
485762306a36Sopenharmony_ci				if (fv_ext[j].prot_id == pr->prot_id &&
485862306a36Sopenharmony_ci				    fv_ext[j].off == pr->off) {
485962306a36Sopenharmony_ci					found = true;
486062306a36Sopenharmony_ci
486162306a36Sopenharmony_ci					/* Store index of field vector */
486262306a36Sopenharmony_ci					rg->fv_idx[i] = j;
486362306a36Sopenharmony_ci					rg->fv_mask[i] = mask;
486462306a36Sopenharmony_ci					break;
486562306a36Sopenharmony_ci				}
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci			/* Protocol/offset could not be found, caller gave an
486862306a36Sopenharmony_ci			 * invalid pair
486962306a36Sopenharmony_ci			 */
487062306a36Sopenharmony_ci			if (!found)
487162306a36Sopenharmony_ci				return -EINVAL;
487262306a36Sopenharmony_ci		}
487362306a36Sopenharmony_ci	}
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci	return 0;
487662306a36Sopenharmony_ci}
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_ci/**
487962306a36Sopenharmony_ci * ice_find_free_recp_res_idx - find free result indexes for recipe
488062306a36Sopenharmony_ci * @hw: pointer to hardware structure
488162306a36Sopenharmony_ci * @profiles: bitmap of profiles that will be associated with the new recipe
488262306a36Sopenharmony_ci * @free_idx: pointer to variable to receive the free index bitmap
488362306a36Sopenharmony_ci *
488462306a36Sopenharmony_ci * The algorithm used here is:
488562306a36Sopenharmony_ci *	1. When creating a new recipe, create a set P which contains all
488662306a36Sopenharmony_ci *	   Profiles that will be associated with our new recipe
488762306a36Sopenharmony_ci *
488862306a36Sopenharmony_ci *	2. For each Profile p in set P:
488962306a36Sopenharmony_ci *	    a. Add all recipes associated with Profile p into set R
489062306a36Sopenharmony_ci *	    b. Optional : PossibleIndexes &= profile[p].possibleIndexes
489162306a36Sopenharmony_ci *		[initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF]
489262306a36Sopenharmony_ci *		i. Or just assume they all have the same possible indexes:
489362306a36Sopenharmony_ci *			44, 45, 46, 47
489462306a36Sopenharmony_ci *			i.e., PossibleIndexes = 0x0000F00000000000
489562306a36Sopenharmony_ci *
489662306a36Sopenharmony_ci *	3. For each Recipe r in set R:
489762306a36Sopenharmony_ci *	    a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes
489862306a36Sopenharmony_ci *	    b. FreeIndexes = UsedIndexes ^ PossibleIndexes
489962306a36Sopenharmony_ci *
490062306a36Sopenharmony_ci *	FreeIndexes will contain the bits indicating the indexes free for use,
490162306a36Sopenharmony_ci *      then the code needs to update the recipe[r].used_result_idx_bits to
490262306a36Sopenharmony_ci *      indicate which indexes were selected for use by this recipe.
490362306a36Sopenharmony_ci */
490462306a36Sopenharmony_cistatic u16
490562306a36Sopenharmony_ciice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
490662306a36Sopenharmony_ci			   unsigned long *free_idx)
490762306a36Sopenharmony_ci{
490862306a36Sopenharmony_ci	DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS);
490962306a36Sopenharmony_ci	DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES);
491062306a36Sopenharmony_ci	DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS);
491162306a36Sopenharmony_ci	u16 bit;
491262306a36Sopenharmony_ci
491362306a36Sopenharmony_ci	bitmap_zero(recipes, ICE_MAX_NUM_RECIPES);
491462306a36Sopenharmony_ci	bitmap_zero(used_idx, ICE_MAX_FV_WORDS);
491562306a36Sopenharmony_ci
491662306a36Sopenharmony_ci	bitmap_fill(possible_idx, ICE_MAX_FV_WORDS);
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	/* For each profile we are going to associate the recipe with, add the
491962306a36Sopenharmony_ci	 * recipes that are associated with that profile. This will give us
492062306a36Sopenharmony_ci	 * the set of recipes that our recipe may collide with. Also, determine
492162306a36Sopenharmony_ci	 * what possible result indexes are usable given this set of profiles.
492262306a36Sopenharmony_ci	 */
492362306a36Sopenharmony_ci	for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) {
492462306a36Sopenharmony_ci		bitmap_or(recipes, recipes, profile_to_recipe[bit],
492562306a36Sopenharmony_ci			  ICE_MAX_NUM_RECIPES);
492662306a36Sopenharmony_ci		bitmap_and(possible_idx, possible_idx,
492762306a36Sopenharmony_ci			   hw->switch_info->prof_res_bm[bit],
492862306a36Sopenharmony_ci			   ICE_MAX_FV_WORDS);
492962306a36Sopenharmony_ci	}
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci	/* For each recipe that our new recipe may collide with, determine
493262306a36Sopenharmony_ci	 * which indexes have been used.
493362306a36Sopenharmony_ci	 */
493462306a36Sopenharmony_ci	for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES)
493562306a36Sopenharmony_ci		bitmap_or(used_idx, used_idx,
493662306a36Sopenharmony_ci			  hw->switch_info->recp_list[bit].res_idxs,
493762306a36Sopenharmony_ci			  ICE_MAX_FV_WORDS);
493862306a36Sopenharmony_ci
493962306a36Sopenharmony_ci	bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS);
494062306a36Sopenharmony_ci
494162306a36Sopenharmony_ci	/* return number of free indexes */
494262306a36Sopenharmony_ci	return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS);
494362306a36Sopenharmony_ci}
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci/**
494662306a36Sopenharmony_ci * ice_add_sw_recipe - function to call AQ calls to create switch recipe
494762306a36Sopenharmony_ci * @hw: pointer to hardware structure
494862306a36Sopenharmony_ci * @rm: recipe management list entry
494962306a36Sopenharmony_ci * @profiles: bitmap of profiles that will be associated.
495062306a36Sopenharmony_ci */
495162306a36Sopenharmony_cistatic int
495262306a36Sopenharmony_ciice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
495362306a36Sopenharmony_ci		  unsigned long *profiles)
495462306a36Sopenharmony_ci{
495562306a36Sopenharmony_ci	DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
495662306a36Sopenharmony_ci	struct ice_aqc_recipe_content *content;
495762306a36Sopenharmony_ci	struct ice_aqc_recipe_data_elem *tmp;
495862306a36Sopenharmony_ci	struct ice_aqc_recipe_data_elem *buf;
495962306a36Sopenharmony_ci	struct ice_recp_grp_entry *entry;
496062306a36Sopenharmony_ci	u16 free_res_idx;
496162306a36Sopenharmony_ci	u16 recipe_count;
496262306a36Sopenharmony_ci	u8 chain_idx;
496362306a36Sopenharmony_ci	u8 recps = 0;
496462306a36Sopenharmony_ci	int status;
496562306a36Sopenharmony_ci
496662306a36Sopenharmony_ci	/* When more than one recipe are required, another recipe is needed to
496762306a36Sopenharmony_ci	 * chain them together. Matching a tunnel metadata ID takes up one of
496862306a36Sopenharmony_ci	 * the match fields in the chaining recipe reducing the number of
496962306a36Sopenharmony_ci	 * chained recipes by one.
497062306a36Sopenharmony_ci	 */
497162306a36Sopenharmony_ci	 /* check number of free result indices */
497262306a36Sopenharmony_ci	bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS);
497362306a36Sopenharmony_ci	free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm);
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_ci	ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n",
497662306a36Sopenharmony_ci		  free_res_idx, rm->n_grp_count);
497762306a36Sopenharmony_ci
497862306a36Sopenharmony_ci	if (rm->n_grp_count > 1) {
497962306a36Sopenharmony_ci		if (rm->n_grp_count > free_res_idx)
498062306a36Sopenharmony_ci			return -ENOSPC;
498162306a36Sopenharmony_ci
498262306a36Sopenharmony_ci		rm->n_grp_count++;
498362306a36Sopenharmony_ci	}
498462306a36Sopenharmony_ci
498562306a36Sopenharmony_ci	if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE)
498662306a36Sopenharmony_ci		return -ENOSPC;
498762306a36Sopenharmony_ci
498862306a36Sopenharmony_ci	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
498962306a36Sopenharmony_ci	if (!tmp)
499062306a36Sopenharmony_ci		return -ENOMEM;
499162306a36Sopenharmony_ci
499262306a36Sopenharmony_ci	buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf),
499362306a36Sopenharmony_ci			   GFP_KERNEL);
499462306a36Sopenharmony_ci	if (!buf) {
499562306a36Sopenharmony_ci		status = -ENOMEM;
499662306a36Sopenharmony_ci		goto err_mem;
499762306a36Sopenharmony_ci	}
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci	bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES);
500062306a36Sopenharmony_ci	recipe_count = ICE_MAX_NUM_RECIPES;
500162306a36Sopenharmony_ci	status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC,
500262306a36Sopenharmony_ci				   NULL);
500362306a36Sopenharmony_ci	if (status || recipe_count == 0)
500462306a36Sopenharmony_ci		goto err_unroll;
500562306a36Sopenharmony_ci
500662306a36Sopenharmony_ci	/* Allocate the recipe resources, and configure them according to the
500762306a36Sopenharmony_ci	 * match fields from protocol headers and extracted field vectors.
500862306a36Sopenharmony_ci	 */
500962306a36Sopenharmony_ci	chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS);
501062306a36Sopenharmony_ci	list_for_each_entry(entry, &rm->rg_list, l_entry) {
501162306a36Sopenharmony_ci		u8 i;
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_ci		status = ice_alloc_recipe(hw, &entry->rid);
501462306a36Sopenharmony_ci		if (status)
501562306a36Sopenharmony_ci			goto err_unroll;
501662306a36Sopenharmony_ci
501762306a36Sopenharmony_ci		content = &buf[recps].content;
501862306a36Sopenharmony_ci
501962306a36Sopenharmony_ci		/* Clear the result index of the located recipe, as this will be
502062306a36Sopenharmony_ci		 * updated, if needed, later in the recipe creation process.
502162306a36Sopenharmony_ci		 */
502262306a36Sopenharmony_ci		tmp[0].content.result_indx = 0;
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci		buf[recps] = tmp[0];
502562306a36Sopenharmony_ci		buf[recps].recipe_indx = (u8)entry->rid;
502662306a36Sopenharmony_ci		/* if the recipe is a non-root recipe RID should be programmed
502762306a36Sopenharmony_ci		 * as 0 for the rules to be applied correctly.
502862306a36Sopenharmony_ci		 */
502962306a36Sopenharmony_ci		content->rid = 0;
503062306a36Sopenharmony_ci		memset(&content->lkup_indx, 0,
503162306a36Sopenharmony_ci		       sizeof(content->lkup_indx));
503262306a36Sopenharmony_ci
503362306a36Sopenharmony_ci		/* All recipes use look-up index 0 to match switch ID. */
503462306a36Sopenharmony_ci		content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
503562306a36Sopenharmony_ci		content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
503662306a36Sopenharmony_ci		/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
503762306a36Sopenharmony_ci		 * to be 0
503862306a36Sopenharmony_ci		 */
503962306a36Sopenharmony_ci		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
504062306a36Sopenharmony_ci			content->lkup_indx[i] = 0x80;
504162306a36Sopenharmony_ci			content->mask[i] = 0;
504262306a36Sopenharmony_ci		}
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci		for (i = 0; i < entry->r_group.n_val_pairs; i++) {
504562306a36Sopenharmony_ci			content->lkup_indx[i + 1] = entry->fv_idx[i];
504662306a36Sopenharmony_ci			content->mask[i + 1] = cpu_to_le16(entry->fv_mask[i]);
504762306a36Sopenharmony_ci		}
504862306a36Sopenharmony_ci
504962306a36Sopenharmony_ci		if (rm->n_grp_count > 1) {
505062306a36Sopenharmony_ci			/* Checks to see if there really is a valid result index
505162306a36Sopenharmony_ci			 * that can be used.
505262306a36Sopenharmony_ci			 */
505362306a36Sopenharmony_ci			if (chain_idx >= ICE_MAX_FV_WORDS) {
505462306a36Sopenharmony_ci				ice_debug(hw, ICE_DBG_SW, "No chain index available\n");
505562306a36Sopenharmony_ci				status = -ENOSPC;
505662306a36Sopenharmony_ci				goto err_unroll;
505762306a36Sopenharmony_ci			}
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci			entry->chain_idx = chain_idx;
506062306a36Sopenharmony_ci			content->result_indx =
506162306a36Sopenharmony_ci				ICE_AQ_RECIPE_RESULT_EN |
506262306a36Sopenharmony_ci				((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
506362306a36Sopenharmony_ci				 ICE_AQ_RECIPE_RESULT_DATA_M);
506462306a36Sopenharmony_ci			clear_bit(chain_idx, result_idx_bm);
506562306a36Sopenharmony_ci			chain_idx = find_first_bit(result_idx_bm,
506662306a36Sopenharmony_ci						   ICE_MAX_FV_WORDS);
506762306a36Sopenharmony_ci		}
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_ci		/* fill recipe dependencies */
507062306a36Sopenharmony_ci		bitmap_zero((unsigned long *)buf[recps].recipe_bitmap,
507162306a36Sopenharmony_ci			    ICE_MAX_NUM_RECIPES);
507262306a36Sopenharmony_ci		set_bit(buf[recps].recipe_indx,
507362306a36Sopenharmony_ci			(unsigned long *)buf[recps].recipe_bitmap);
507462306a36Sopenharmony_ci		content->act_ctrl_fwd_priority = rm->priority;
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci		if (rm->need_pass_l2)
507762306a36Sopenharmony_ci			content->act_ctrl |= ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_ci		if (rm->allow_pass_l2)
508062306a36Sopenharmony_ci			content->act_ctrl |= ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
508162306a36Sopenharmony_ci		recps++;
508262306a36Sopenharmony_ci	}
508362306a36Sopenharmony_ci
508462306a36Sopenharmony_ci	if (rm->n_grp_count == 1) {
508562306a36Sopenharmony_ci		rm->root_rid = buf[0].recipe_indx;
508662306a36Sopenharmony_ci		set_bit(buf[0].recipe_indx, rm->r_bitmap);
508762306a36Sopenharmony_ci		buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT;
508862306a36Sopenharmony_ci		if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) {
508962306a36Sopenharmony_ci			memcpy(buf[0].recipe_bitmap, rm->r_bitmap,
509062306a36Sopenharmony_ci			       sizeof(buf[0].recipe_bitmap));
509162306a36Sopenharmony_ci		} else {
509262306a36Sopenharmony_ci			status = -EINVAL;
509362306a36Sopenharmony_ci			goto err_unroll;
509462306a36Sopenharmony_ci		}
509562306a36Sopenharmony_ci		/* Applicable only for ROOT_RECIPE, set the fwd_priority for
509662306a36Sopenharmony_ci		 * the recipe which is getting created if specified
509762306a36Sopenharmony_ci		 * by user. Usually any advanced switch filter, which results
509862306a36Sopenharmony_ci		 * into new extraction sequence, ended up creating a new recipe
509962306a36Sopenharmony_ci		 * of type ROOT and usually recipes are associated with profiles
510062306a36Sopenharmony_ci		 * Switch rule referreing newly created recipe, needs to have
510162306a36Sopenharmony_ci		 * either/or 'fwd' or 'join' priority, otherwise switch rule
510262306a36Sopenharmony_ci		 * evaluation will not happen correctly. In other words, if
510362306a36Sopenharmony_ci		 * switch rule to be evaluated on priority basis, then recipe
510462306a36Sopenharmony_ci		 * needs to have priority, otherwise it will be evaluated last.
510562306a36Sopenharmony_ci		 */
510662306a36Sopenharmony_ci		buf[0].content.act_ctrl_fwd_priority = rm->priority;
510762306a36Sopenharmony_ci	} else {
510862306a36Sopenharmony_ci		struct ice_recp_grp_entry *last_chain_entry;
510962306a36Sopenharmony_ci		u16 rid, i;
511062306a36Sopenharmony_ci
511162306a36Sopenharmony_ci		/* Allocate the last recipe that will chain the outcomes of the
511262306a36Sopenharmony_ci		 * other recipes together
511362306a36Sopenharmony_ci		 */
511462306a36Sopenharmony_ci		status = ice_alloc_recipe(hw, &rid);
511562306a36Sopenharmony_ci		if (status)
511662306a36Sopenharmony_ci			goto err_unroll;
511762306a36Sopenharmony_ci
511862306a36Sopenharmony_ci		content = &buf[recps].content;
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci		buf[recps].recipe_indx = (u8)rid;
512162306a36Sopenharmony_ci		content->rid = (u8)rid;
512262306a36Sopenharmony_ci		content->rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
512362306a36Sopenharmony_ci		/* the new entry created should also be part of rg_list to
512462306a36Sopenharmony_ci		 * make sure we have complete recipe
512562306a36Sopenharmony_ci		 */
512662306a36Sopenharmony_ci		last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw),
512762306a36Sopenharmony_ci						sizeof(*last_chain_entry),
512862306a36Sopenharmony_ci						GFP_KERNEL);
512962306a36Sopenharmony_ci		if (!last_chain_entry) {
513062306a36Sopenharmony_ci			status = -ENOMEM;
513162306a36Sopenharmony_ci			goto err_unroll;
513262306a36Sopenharmony_ci		}
513362306a36Sopenharmony_ci		last_chain_entry->rid = rid;
513462306a36Sopenharmony_ci		memset(&content->lkup_indx, 0, sizeof(content->lkup_indx));
513562306a36Sopenharmony_ci		/* All recipes use look-up index 0 to match switch ID. */
513662306a36Sopenharmony_ci		content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
513762306a36Sopenharmony_ci		content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
513862306a36Sopenharmony_ci		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
513962306a36Sopenharmony_ci			content->lkup_indx[i] = ICE_AQ_RECIPE_LKUP_IGNORE;
514062306a36Sopenharmony_ci			content->mask[i] = 0;
514162306a36Sopenharmony_ci		}
514262306a36Sopenharmony_ci
514362306a36Sopenharmony_ci		i = 1;
514462306a36Sopenharmony_ci		/* update r_bitmap with the recp that is used for chaining */
514562306a36Sopenharmony_ci		set_bit(rid, rm->r_bitmap);
514662306a36Sopenharmony_ci		/* this is the recipe that chains all the other recipes so it
514762306a36Sopenharmony_ci		 * should not have a chaining ID to indicate the same
514862306a36Sopenharmony_ci		 */
514962306a36Sopenharmony_ci		last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
515062306a36Sopenharmony_ci		list_for_each_entry(entry, &rm->rg_list, l_entry) {
515162306a36Sopenharmony_ci			last_chain_entry->fv_idx[i] = entry->chain_idx;
515262306a36Sopenharmony_ci			content->lkup_indx[i] = entry->chain_idx;
515362306a36Sopenharmony_ci			content->mask[i++] = cpu_to_le16(0xFFFF);
515462306a36Sopenharmony_ci			set_bit(entry->rid, rm->r_bitmap);
515562306a36Sopenharmony_ci		}
515662306a36Sopenharmony_ci		list_add(&last_chain_entry->l_entry, &rm->rg_list);
515762306a36Sopenharmony_ci		if (sizeof(buf[recps].recipe_bitmap) >=
515862306a36Sopenharmony_ci		    sizeof(rm->r_bitmap)) {
515962306a36Sopenharmony_ci			memcpy(buf[recps].recipe_bitmap, rm->r_bitmap,
516062306a36Sopenharmony_ci			       sizeof(buf[recps].recipe_bitmap));
516162306a36Sopenharmony_ci		} else {
516262306a36Sopenharmony_ci			status = -EINVAL;
516362306a36Sopenharmony_ci			goto err_unroll;
516462306a36Sopenharmony_ci		}
516562306a36Sopenharmony_ci		content->act_ctrl_fwd_priority = rm->priority;
516662306a36Sopenharmony_ci
516762306a36Sopenharmony_ci		recps++;
516862306a36Sopenharmony_ci		rm->root_rid = (u8)rid;
516962306a36Sopenharmony_ci	}
517062306a36Sopenharmony_ci	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
517162306a36Sopenharmony_ci	if (status)
517262306a36Sopenharmony_ci		goto err_unroll;
517362306a36Sopenharmony_ci
517462306a36Sopenharmony_ci	status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL);
517562306a36Sopenharmony_ci	ice_release_change_lock(hw);
517662306a36Sopenharmony_ci	if (status)
517762306a36Sopenharmony_ci		goto err_unroll;
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_ci	/* Every recipe that just got created add it to the recipe
518062306a36Sopenharmony_ci	 * book keeping list
518162306a36Sopenharmony_ci	 */
518262306a36Sopenharmony_ci	list_for_each_entry(entry, &rm->rg_list, l_entry) {
518362306a36Sopenharmony_ci		struct ice_switch_info *sw = hw->switch_info;
518462306a36Sopenharmony_ci		bool is_root, idx_found = false;
518562306a36Sopenharmony_ci		struct ice_sw_recipe *recp;
518662306a36Sopenharmony_ci		u16 idx, buf_idx = 0;
518762306a36Sopenharmony_ci
518862306a36Sopenharmony_ci		/* find buffer index for copying some data */
518962306a36Sopenharmony_ci		for (idx = 0; idx < rm->n_grp_count; idx++)
519062306a36Sopenharmony_ci			if (buf[idx].recipe_indx == entry->rid) {
519162306a36Sopenharmony_ci				buf_idx = idx;
519262306a36Sopenharmony_ci				idx_found = true;
519362306a36Sopenharmony_ci			}
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci		if (!idx_found) {
519662306a36Sopenharmony_ci			status = -EIO;
519762306a36Sopenharmony_ci			goto err_unroll;
519862306a36Sopenharmony_ci		}
519962306a36Sopenharmony_ci
520062306a36Sopenharmony_ci		recp = &sw->recp_list[entry->rid];
520162306a36Sopenharmony_ci		is_root = (rm->root_rid == entry->rid);
520262306a36Sopenharmony_ci		recp->is_root = is_root;
520362306a36Sopenharmony_ci
520462306a36Sopenharmony_ci		recp->root_rid = entry->rid;
520562306a36Sopenharmony_ci		recp->big_recp = (is_root && rm->n_grp_count > 1);
520662306a36Sopenharmony_ci
520762306a36Sopenharmony_ci		memcpy(&recp->ext_words, entry->r_group.pairs,
520862306a36Sopenharmony_ci		       entry->r_group.n_val_pairs * sizeof(struct ice_fv_word));
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci		memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap,
521162306a36Sopenharmony_ci		       sizeof(recp->r_bitmap));
521262306a36Sopenharmony_ci
521362306a36Sopenharmony_ci		/* Copy non-result fv index values and masks to recipe. This
521462306a36Sopenharmony_ci		 * call will also update the result recipe bitmask.
521562306a36Sopenharmony_ci		 */
521662306a36Sopenharmony_ci		ice_collect_result_idx(&buf[buf_idx], recp);
521762306a36Sopenharmony_ci
521862306a36Sopenharmony_ci		/* for non-root recipes, also copy to the root, this allows
521962306a36Sopenharmony_ci		 * easier matching of a complete chained recipe
522062306a36Sopenharmony_ci		 */
522162306a36Sopenharmony_ci		if (!is_root)
522262306a36Sopenharmony_ci			ice_collect_result_idx(&buf[buf_idx],
522362306a36Sopenharmony_ci					       &sw->recp_list[rm->root_rid]);
522462306a36Sopenharmony_ci
522562306a36Sopenharmony_ci		recp->n_ext_words = entry->r_group.n_val_pairs;
522662306a36Sopenharmony_ci		recp->chain_idx = entry->chain_idx;
522762306a36Sopenharmony_ci		recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
522862306a36Sopenharmony_ci		recp->n_grp_count = rm->n_grp_count;
522962306a36Sopenharmony_ci		recp->tun_type = rm->tun_type;
523062306a36Sopenharmony_ci		recp->need_pass_l2 = rm->need_pass_l2;
523162306a36Sopenharmony_ci		recp->allow_pass_l2 = rm->allow_pass_l2;
523262306a36Sopenharmony_ci		recp->recp_created = true;
523362306a36Sopenharmony_ci	}
523462306a36Sopenharmony_ci	rm->root_buf = buf;
523562306a36Sopenharmony_ci	kfree(tmp);
523662306a36Sopenharmony_ci	return status;
523762306a36Sopenharmony_ci
523862306a36Sopenharmony_cierr_unroll:
523962306a36Sopenharmony_cierr_mem:
524062306a36Sopenharmony_ci	kfree(tmp);
524162306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), buf);
524262306a36Sopenharmony_ci	return status;
524362306a36Sopenharmony_ci}
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_ci/**
524662306a36Sopenharmony_ci * ice_create_recipe_group - creates recipe group
524762306a36Sopenharmony_ci * @hw: pointer to hardware structure
524862306a36Sopenharmony_ci * @rm: recipe management list entry
524962306a36Sopenharmony_ci * @lkup_exts: lookup elements
525062306a36Sopenharmony_ci */
525162306a36Sopenharmony_cistatic int
525262306a36Sopenharmony_ciice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm,
525362306a36Sopenharmony_ci			struct ice_prot_lkup_ext *lkup_exts)
525462306a36Sopenharmony_ci{
525562306a36Sopenharmony_ci	u8 recp_count = 0;
525662306a36Sopenharmony_ci	int status;
525762306a36Sopenharmony_ci
525862306a36Sopenharmony_ci	rm->n_grp_count = 0;
525962306a36Sopenharmony_ci
526062306a36Sopenharmony_ci	/* Create recipes for words that are marked not done by packing them
526162306a36Sopenharmony_ci	 * as best fit.
526262306a36Sopenharmony_ci	 */
526362306a36Sopenharmony_ci	status = ice_create_first_fit_recp_def(hw, lkup_exts,
526462306a36Sopenharmony_ci					       &rm->rg_list, &recp_count);
526562306a36Sopenharmony_ci	if (!status) {
526662306a36Sopenharmony_ci		rm->n_grp_count += recp_count;
526762306a36Sopenharmony_ci		rm->n_ext_words = lkup_exts->n_val_words;
526862306a36Sopenharmony_ci		memcpy(&rm->ext_words, lkup_exts->fv_words,
526962306a36Sopenharmony_ci		       sizeof(rm->ext_words));
527062306a36Sopenharmony_ci		memcpy(rm->word_masks, lkup_exts->field_mask,
527162306a36Sopenharmony_ci		       sizeof(rm->word_masks));
527262306a36Sopenharmony_ci	}
527362306a36Sopenharmony_ci
527462306a36Sopenharmony_ci	return status;
527562306a36Sopenharmony_ci}
527662306a36Sopenharmony_ci
527762306a36Sopenharmony_ci/* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule
527862306a36Sopenharmony_ci * @hw: pointer to hardware structure
527962306a36Sopenharmony_ci * @rinfo: other information regarding the rule e.g. priority and action info
528062306a36Sopenharmony_ci * @bm: pointer to memory for returning the bitmap of field vectors
528162306a36Sopenharmony_ci */
528262306a36Sopenharmony_cistatic void
528362306a36Sopenharmony_ciice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
528462306a36Sopenharmony_ci			 unsigned long *bm)
528562306a36Sopenharmony_ci{
528662306a36Sopenharmony_ci	enum ice_prof_type prof_type;
528762306a36Sopenharmony_ci
528862306a36Sopenharmony_ci	bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
528962306a36Sopenharmony_ci
529062306a36Sopenharmony_ci	switch (rinfo->tun_type) {
529162306a36Sopenharmony_ci	case ICE_NON_TUN:
529262306a36Sopenharmony_ci		prof_type = ICE_PROF_NON_TUN;
529362306a36Sopenharmony_ci		break;
529462306a36Sopenharmony_ci	case ICE_ALL_TUNNELS:
529562306a36Sopenharmony_ci		prof_type = ICE_PROF_TUN_ALL;
529662306a36Sopenharmony_ci		break;
529762306a36Sopenharmony_ci	case ICE_SW_TUN_GENEVE:
529862306a36Sopenharmony_ci	case ICE_SW_TUN_VXLAN:
529962306a36Sopenharmony_ci		prof_type = ICE_PROF_TUN_UDP;
530062306a36Sopenharmony_ci		break;
530162306a36Sopenharmony_ci	case ICE_SW_TUN_NVGRE:
530262306a36Sopenharmony_ci		prof_type = ICE_PROF_TUN_GRE;
530362306a36Sopenharmony_ci		break;
530462306a36Sopenharmony_ci	case ICE_SW_TUN_GTPU:
530562306a36Sopenharmony_ci		prof_type = ICE_PROF_TUN_GTPU;
530662306a36Sopenharmony_ci		break;
530762306a36Sopenharmony_ci	case ICE_SW_TUN_GTPC:
530862306a36Sopenharmony_ci		prof_type = ICE_PROF_TUN_GTPC;
530962306a36Sopenharmony_ci		break;
531062306a36Sopenharmony_ci	case ICE_SW_TUN_AND_NON_TUN:
531162306a36Sopenharmony_ci	default:
531262306a36Sopenharmony_ci		prof_type = ICE_PROF_ALL;
531362306a36Sopenharmony_ci		break;
531462306a36Sopenharmony_ci	}
531562306a36Sopenharmony_ci
531662306a36Sopenharmony_ci	ice_get_sw_fv_bitmap(hw, prof_type, bm);
531762306a36Sopenharmony_ci}
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci/**
532062306a36Sopenharmony_ci * ice_add_adv_recipe - Add an advanced recipe that is not part of the default
532162306a36Sopenharmony_ci * @hw: pointer to hardware structure
532262306a36Sopenharmony_ci * @lkups: lookup elements or match criteria for the advanced recipe, one
532362306a36Sopenharmony_ci *  structure per protocol header
532462306a36Sopenharmony_ci * @lkups_cnt: number of protocols
532562306a36Sopenharmony_ci * @rinfo: other information regarding the rule e.g. priority and action info
532662306a36Sopenharmony_ci * @rid: return the recipe ID of the recipe created
532762306a36Sopenharmony_ci */
532862306a36Sopenharmony_cistatic int
532962306a36Sopenharmony_ciice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
533062306a36Sopenharmony_ci		   u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid)
533162306a36Sopenharmony_ci{
533262306a36Sopenharmony_ci	DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES);
533362306a36Sopenharmony_ci	DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES);
533462306a36Sopenharmony_ci	struct ice_prot_lkup_ext *lkup_exts;
533562306a36Sopenharmony_ci	struct ice_recp_grp_entry *r_entry;
533662306a36Sopenharmony_ci	struct ice_sw_fv_list_entry *fvit;
533762306a36Sopenharmony_ci	struct ice_recp_grp_entry *r_tmp;
533862306a36Sopenharmony_ci	struct ice_sw_fv_list_entry *tmp;
533962306a36Sopenharmony_ci	struct ice_sw_recipe *rm;
534062306a36Sopenharmony_ci	int status = 0;
534162306a36Sopenharmony_ci	u8 i;
534262306a36Sopenharmony_ci
534362306a36Sopenharmony_ci	if (!lkups_cnt)
534462306a36Sopenharmony_ci		return -EINVAL;
534562306a36Sopenharmony_ci
534662306a36Sopenharmony_ci	lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL);
534762306a36Sopenharmony_ci	if (!lkup_exts)
534862306a36Sopenharmony_ci		return -ENOMEM;
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_ci	/* Determine the number of words to be matched and if it exceeds a
535162306a36Sopenharmony_ci	 * recipe's restrictions
535262306a36Sopenharmony_ci	 */
535362306a36Sopenharmony_ci	for (i = 0; i < lkups_cnt; i++) {
535462306a36Sopenharmony_ci		u16 count;
535562306a36Sopenharmony_ci
535662306a36Sopenharmony_ci		if (lkups[i].type >= ICE_PROTOCOL_LAST) {
535762306a36Sopenharmony_ci			status = -EIO;
535862306a36Sopenharmony_ci			goto err_free_lkup_exts;
535962306a36Sopenharmony_ci		}
536062306a36Sopenharmony_ci
536162306a36Sopenharmony_ci		count = ice_fill_valid_words(&lkups[i], lkup_exts);
536262306a36Sopenharmony_ci		if (!count) {
536362306a36Sopenharmony_ci			status = -EIO;
536462306a36Sopenharmony_ci			goto err_free_lkup_exts;
536562306a36Sopenharmony_ci		}
536662306a36Sopenharmony_ci	}
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci	rm = kzalloc(sizeof(*rm), GFP_KERNEL);
536962306a36Sopenharmony_ci	if (!rm) {
537062306a36Sopenharmony_ci		status = -ENOMEM;
537162306a36Sopenharmony_ci		goto err_free_lkup_exts;
537262306a36Sopenharmony_ci	}
537362306a36Sopenharmony_ci
537462306a36Sopenharmony_ci	/* Get field vectors that contain fields extracted from all the protocol
537562306a36Sopenharmony_ci	 * headers being programmed.
537662306a36Sopenharmony_ci	 */
537762306a36Sopenharmony_ci	INIT_LIST_HEAD(&rm->fv_list);
537862306a36Sopenharmony_ci	INIT_LIST_HEAD(&rm->rg_list);
537962306a36Sopenharmony_ci
538062306a36Sopenharmony_ci	/* Get bitmap of field vectors (profiles) that are compatible with the
538162306a36Sopenharmony_ci	 * rule request; only these will be searched in the subsequent call to
538262306a36Sopenharmony_ci	 * ice_get_sw_fv_list.
538362306a36Sopenharmony_ci	 */
538462306a36Sopenharmony_ci	ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap);
538562306a36Sopenharmony_ci
538662306a36Sopenharmony_ci	status = ice_get_sw_fv_list(hw, lkup_exts, fv_bitmap, &rm->fv_list);
538762306a36Sopenharmony_ci	if (status)
538862306a36Sopenharmony_ci		goto err_unroll;
538962306a36Sopenharmony_ci
539062306a36Sopenharmony_ci	/* Group match words into recipes using preferred recipe grouping
539162306a36Sopenharmony_ci	 * criteria.
539262306a36Sopenharmony_ci	 */
539362306a36Sopenharmony_ci	status = ice_create_recipe_group(hw, rm, lkup_exts);
539462306a36Sopenharmony_ci	if (status)
539562306a36Sopenharmony_ci		goto err_unroll;
539662306a36Sopenharmony_ci
539762306a36Sopenharmony_ci	/* set the recipe priority if specified */
539862306a36Sopenharmony_ci	rm->priority = (u8)rinfo->priority;
539962306a36Sopenharmony_ci
540062306a36Sopenharmony_ci	rm->need_pass_l2 = rinfo->need_pass_l2;
540162306a36Sopenharmony_ci	rm->allow_pass_l2 = rinfo->allow_pass_l2;
540262306a36Sopenharmony_ci
540362306a36Sopenharmony_ci	/* Find offsets from the field vector. Pick the first one for all the
540462306a36Sopenharmony_ci	 * recipes.
540562306a36Sopenharmony_ci	 */
540662306a36Sopenharmony_ci	status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list);
540762306a36Sopenharmony_ci	if (status)
540862306a36Sopenharmony_ci		goto err_unroll;
540962306a36Sopenharmony_ci
541062306a36Sopenharmony_ci	/* get bitmap of all profiles the recipe will be associated with */
541162306a36Sopenharmony_ci	bitmap_zero(profiles, ICE_MAX_NUM_PROFILES);
541262306a36Sopenharmony_ci	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
541362306a36Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id);
541462306a36Sopenharmony_ci		set_bit((u16)fvit->profile_id, profiles);
541562306a36Sopenharmony_ci	}
541662306a36Sopenharmony_ci
541762306a36Sopenharmony_ci	/* Look for a recipe which matches our requested fv / mask list */
541862306a36Sopenharmony_ci	*rid = ice_find_recp(hw, lkup_exts, rinfo);
541962306a36Sopenharmony_ci	if (*rid < ICE_MAX_NUM_RECIPES)
542062306a36Sopenharmony_ci		/* Success if found a recipe that match the existing criteria */
542162306a36Sopenharmony_ci		goto err_unroll;
542262306a36Sopenharmony_ci
542362306a36Sopenharmony_ci	rm->tun_type = rinfo->tun_type;
542462306a36Sopenharmony_ci	/* Recipe we need does not exist, add a recipe */
542562306a36Sopenharmony_ci	status = ice_add_sw_recipe(hw, rm, profiles);
542662306a36Sopenharmony_ci	if (status)
542762306a36Sopenharmony_ci		goto err_unroll;
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_ci	/* Associate all the recipes created with all the profiles in the
543062306a36Sopenharmony_ci	 * common field vector.
543162306a36Sopenharmony_ci	 */
543262306a36Sopenharmony_ci	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
543362306a36Sopenharmony_ci		DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
543462306a36Sopenharmony_ci		u16 j;
543562306a36Sopenharmony_ci
543662306a36Sopenharmony_ci		status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id,
543762306a36Sopenharmony_ci						      (u8 *)r_bitmap, NULL);
543862306a36Sopenharmony_ci		if (status)
543962306a36Sopenharmony_ci			goto err_unroll;
544062306a36Sopenharmony_ci
544162306a36Sopenharmony_ci		bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap,
544262306a36Sopenharmony_ci			  ICE_MAX_NUM_RECIPES);
544362306a36Sopenharmony_ci		status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
544462306a36Sopenharmony_ci		if (status)
544562306a36Sopenharmony_ci			goto err_unroll;
544662306a36Sopenharmony_ci
544762306a36Sopenharmony_ci		status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,
544862306a36Sopenharmony_ci						      (u8 *)r_bitmap,
544962306a36Sopenharmony_ci						      NULL);
545062306a36Sopenharmony_ci		ice_release_change_lock(hw);
545162306a36Sopenharmony_ci
545262306a36Sopenharmony_ci		if (status)
545362306a36Sopenharmony_ci			goto err_unroll;
545462306a36Sopenharmony_ci
545562306a36Sopenharmony_ci		/* Update profile to recipe bitmap array */
545662306a36Sopenharmony_ci		bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap,
545762306a36Sopenharmony_ci			    ICE_MAX_NUM_RECIPES);
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_ci		/* Update recipe to profile bitmap array */
546062306a36Sopenharmony_ci		for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES)
546162306a36Sopenharmony_ci			set_bit((u16)fvit->profile_id, recipe_to_profile[j]);
546262306a36Sopenharmony_ci	}
546362306a36Sopenharmony_ci
546462306a36Sopenharmony_ci	*rid = rm->root_rid;
546562306a36Sopenharmony_ci	memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts,
546662306a36Sopenharmony_ci	       sizeof(*lkup_exts));
546762306a36Sopenharmony_cierr_unroll:
546862306a36Sopenharmony_ci	list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) {
546962306a36Sopenharmony_ci		list_del(&r_entry->l_entry);
547062306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), r_entry);
547162306a36Sopenharmony_ci	}
547262306a36Sopenharmony_ci
547362306a36Sopenharmony_ci	list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) {
547462306a36Sopenharmony_ci		list_del(&fvit->list_entry);
547562306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fvit);
547662306a36Sopenharmony_ci	}
547762306a36Sopenharmony_ci
547862306a36Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), rm->root_buf);
547962306a36Sopenharmony_ci	kfree(rm);
548062306a36Sopenharmony_ci
548162306a36Sopenharmony_cierr_free_lkup_exts:
548262306a36Sopenharmony_ci	kfree(lkup_exts);
548362306a36Sopenharmony_ci
548462306a36Sopenharmony_ci	return status;
548562306a36Sopenharmony_ci}
548662306a36Sopenharmony_ci
548762306a36Sopenharmony_ci/**
548862306a36Sopenharmony_ci * ice_dummy_packet_add_vlan - insert VLAN header to dummy pkt
548962306a36Sopenharmony_ci *
549062306a36Sopenharmony_ci * @dummy_pkt: dummy packet profile pattern to which VLAN tag(s) will be added
549162306a36Sopenharmony_ci * @num_vlan: number of VLAN tags
549262306a36Sopenharmony_ci */
549362306a36Sopenharmony_cistatic struct ice_dummy_pkt_profile *
549462306a36Sopenharmony_ciice_dummy_packet_add_vlan(const struct ice_dummy_pkt_profile *dummy_pkt,
549562306a36Sopenharmony_ci			  u32 num_vlan)
549662306a36Sopenharmony_ci{
549762306a36Sopenharmony_ci	struct ice_dummy_pkt_profile *profile;
549862306a36Sopenharmony_ci	struct ice_dummy_pkt_offsets *offsets;
549962306a36Sopenharmony_ci	u32 buf_len, off, etype_off, i;
550062306a36Sopenharmony_ci	u8 *pkt;
550162306a36Sopenharmony_ci
550262306a36Sopenharmony_ci	if (num_vlan < 1 || num_vlan > 2)
550362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
550462306a36Sopenharmony_ci
550562306a36Sopenharmony_ci	off = num_vlan * VLAN_HLEN;
550662306a36Sopenharmony_ci
550762306a36Sopenharmony_ci	buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet_offsets)) +
550862306a36Sopenharmony_ci		  dummy_pkt->offsets_len;
550962306a36Sopenharmony_ci	offsets = kzalloc(buf_len, GFP_KERNEL);
551062306a36Sopenharmony_ci	if (!offsets)
551162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
551262306a36Sopenharmony_ci
551362306a36Sopenharmony_ci	offsets[0] = dummy_pkt->offsets[0];
551462306a36Sopenharmony_ci	if (num_vlan == 2) {
551562306a36Sopenharmony_ci		offsets[1] = ice_dummy_qinq_packet_offsets[0];
551662306a36Sopenharmony_ci		offsets[2] = ice_dummy_qinq_packet_offsets[1];
551762306a36Sopenharmony_ci	} else if (num_vlan == 1) {
551862306a36Sopenharmony_ci		offsets[1] = ice_dummy_vlan_packet_offsets[0];
551962306a36Sopenharmony_ci	}
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	for (i = 1; dummy_pkt->offsets[i].type != ICE_PROTOCOL_LAST; i++) {
552262306a36Sopenharmony_ci		offsets[i + num_vlan].type = dummy_pkt->offsets[i].type;
552362306a36Sopenharmony_ci		offsets[i + num_vlan].offset =
552462306a36Sopenharmony_ci			dummy_pkt->offsets[i].offset + off;
552562306a36Sopenharmony_ci	}
552662306a36Sopenharmony_ci	offsets[i + num_vlan] = dummy_pkt->offsets[i];
552762306a36Sopenharmony_ci
552862306a36Sopenharmony_ci	etype_off = dummy_pkt->offsets[1].offset;
552962306a36Sopenharmony_ci
553062306a36Sopenharmony_ci	buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet)) +
553162306a36Sopenharmony_ci		  dummy_pkt->pkt_len;
553262306a36Sopenharmony_ci	pkt = kzalloc(buf_len, GFP_KERNEL);
553362306a36Sopenharmony_ci	if (!pkt) {
553462306a36Sopenharmony_ci		kfree(offsets);
553562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
553662306a36Sopenharmony_ci	}
553762306a36Sopenharmony_ci
553862306a36Sopenharmony_ci	memcpy(pkt, dummy_pkt->pkt, etype_off);
553962306a36Sopenharmony_ci	memcpy(pkt + etype_off,
554062306a36Sopenharmony_ci	       num_vlan == 2 ? ice_dummy_qinq_packet : ice_dummy_vlan_packet,
554162306a36Sopenharmony_ci	       off);
554262306a36Sopenharmony_ci	memcpy(pkt + etype_off + off, dummy_pkt->pkt + etype_off,
554362306a36Sopenharmony_ci	       dummy_pkt->pkt_len - etype_off);
554462306a36Sopenharmony_ci
554562306a36Sopenharmony_ci	profile = kzalloc(sizeof(*profile), GFP_KERNEL);
554662306a36Sopenharmony_ci	if (!profile) {
554762306a36Sopenharmony_ci		kfree(offsets);
554862306a36Sopenharmony_ci		kfree(pkt);
554962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
555062306a36Sopenharmony_ci	}
555162306a36Sopenharmony_ci
555262306a36Sopenharmony_ci	profile->offsets = offsets;
555362306a36Sopenharmony_ci	profile->pkt = pkt;
555462306a36Sopenharmony_ci	profile->pkt_len = buf_len;
555562306a36Sopenharmony_ci	profile->match |= ICE_PKT_KMALLOC;
555662306a36Sopenharmony_ci
555762306a36Sopenharmony_ci	return profile;
555862306a36Sopenharmony_ci}
555962306a36Sopenharmony_ci
556062306a36Sopenharmony_ci/**
556162306a36Sopenharmony_ci * ice_find_dummy_packet - find dummy packet
556262306a36Sopenharmony_ci *
556362306a36Sopenharmony_ci * @lkups: lookup elements or match criteria for the advanced recipe, one
556462306a36Sopenharmony_ci *	   structure per protocol header
556562306a36Sopenharmony_ci * @lkups_cnt: number of protocols
556662306a36Sopenharmony_ci * @tun_type: tunnel type
556762306a36Sopenharmony_ci *
556862306a36Sopenharmony_ci * Returns the &ice_dummy_pkt_profile corresponding to these lookup params.
556962306a36Sopenharmony_ci */
557062306a36Sopenharmony_cistatic const struct ice_dummy_pkt_profile *
557162306a36Sopenharmony_ciice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
557262306a36Sopenharmony_ci		      enum ice_sw_tunnel_type tun_type)
557362306a36Sopenharmony_ci{
557462306a36Sopenharmony_ci	const struct ice_dummy_pkt_profile *ret = ice_dummy_pkt_profiles;
557562306a36Sopenharmony_ci	u32 match = 0, vlan_count = 0;
557662306a36Sopenharmony_ci	u16 i;
557762306a36Sopenharmony_ci
557862306a36Sopenharmony_ci	switch (tun_type) {
557962306a36Sopenharmony_ci	case ICE_SW_TUN_GTPC:
558062306a36Sopenharmony_ci		match |= ICE_PKT_TUN_GTPC;
558162306a36Sopenharmony_ci		break;
558262306a36Sopenharmony_ci	case ICE_SW_TUN_GTPU:
558362306a36Sopenharmony_ci		match |= ICE_PKT_TUN_GTPU;
558462306a36Sopenharmony_ci		break;
558562306a36Sopenharmony_ci	case ICE_SW_TUN_NVGRE:
558662306a36Sopenharmony_ci		match |= ICE_PKT_TUN_NVGRE;
558762306a36Sopenharmony_ci		break;
558862306a36Sopenharmony_ci	case ICE_SW_TUN_GENEVE:
558962306a36Sopenharmony_ci	case ICE_SW_TUN_VXLAN:
559062306a36Sopenharmony_ci		match |= ICE_PKT_TUN_UDP;
559162306a36Sopenharmony_ci		break;
559262306a36Sopenharmony_ci	default:
559362306a36Sopenharmony_ci		break;
559462306a36Sopenharmony_ci	}
559562306a36Sopenharmony_ci
559662306a36Sopenharmony_ci	for (i = 0; i < lkups_cnt; i++) {
559762306a36Sopenharmony_ci		if (lkups[i].type == ICE_UDP_ILOS)
559862306a36Sopenharmony_ci			match |= ICE_PKT_INNER_UDP;
559962306a36Sopenharmony_ci		else if (lkups[i].type == ICE_TCP_IL)
560062306a36Sopenharmony_ci			match |= ICE_PKT_INNER_TCP;
560162306a36Sopenharmony_ci		else if (lkups[i].type == ICE_IPV6_OFOS)
560262306a36Sopenharmony_ci			match |= ICE_PKT_OUTER_IPV6;
560362306a36Sopenharmony_ci		else if (lkups[i].type == ICE_VLAN_OFOS ||
560462306a36Sopenharmony_ci			 lkups[i].type == ICE_VLAN_EX)
560562306a36Sopenharmony_ci			vlan_count++;
560662306a36Sopenharmony_ci		else if (lkups[i].type == ICE_VLAN_IN)
560762306a36Sopenharmony_ci			vlan_count++;
560862306a36Sopenharmony_ci		else if (lkups[i].type == ICE_ETYPE_OL &&
560962306a36Sopenharmony_ci			 lkups[i].h_u.ethertype.ethtype_id ==
561062306a36Sopenharmony_ci				cpu_to_be16(ICE_IPV6_ETHER_ID) &&
561162306a36Sopenharmony_ci			 lkups[i].m_u.ethertype.ethtype_id ==
561262306a36Sopenharmony_ci				cpu_to_be16(0xFFFF))
561362306a36Sopenharmony_ci			match |= ICE_PKT_OUTER_IPV6;
561462306a36Sopenharmony_ci		else if (lkups[i].type == ICE_ETYPE_IL &&
561562306a36Sopenharmony_ci			 lkups[i].h_u.ethertype.ethtype_id ==
561662306a36Sopenharmony_ci				cpu_to_be16(ICE_IPV6_ETHER_ID) &&
561762306a36Sopenharmony_ci			 lkups[i].m_u.ethertype.ethtype_id ==
561862306a36Sopenharmony_ci				cpu_to_be16(0xFFFF))
561962306a36Sopenharmony_ci			match |= ICE_PKT_INNER_IPV6;
562062306a36Sopenharmony_ci		else if (lkups[i].type == ICE_IPV6_IL)
562162306a36Sopenharmony_ci			match |= ICE_PKT_INNER_IPV6;
562262306a36Sopenharmony_ci		else if (lkups[i].type == ICE_GTP_NO_PAY)
562362306a36Sopenharmony_ci			match |= ICE_PKT_GTP_NOPAY;
562462306a36Sopenharmony_ci		else if (lkups[i].type == ICE_PPPOE) {
562562306a36Sopenharmony_ci			match |= ICE_PKT_PPPOE;
562662306a36Sopenharmony_ci			if (lkups[i].h_u.pppoe_hdr.ppp_prot_id ==
562762306a36Sopenharmony_ci			    htons(PPP_IPV6))
562862306a36Sopenharmony_ci				match |= ICE_PKT_OUTER_IPV6;
562962306a36Sopenharmony_ci		} else if (lkups[i].type == ICE_L2TPV3)
563062306a36Sopenharmony_ci			match |= ICE_PKT_L2TPV3;
563162306a36Sopenharmony_ci	}
563262306a36Sopenharmony_ci
563362306a36Sopenharmony_ci	while (ret->match && (match & ret->match) != ret->match)
563462306a36Sopenharmony_ci		ret++;
563562306a36Sopenharmony_ci
563662306a36Sopenharmony_ci	if (vlan_count != 0)
563762306a36Sopenharmony_ci		ret = ice_dummy_packet_add_vlan(ret, vlan_count);
563862306a36Sopenharmony_ci
563962306a36Sopenharmony_ci	return ret;
564062306a36Sopenharmony_ci}
564162306a36Sopenharmony_ci
564262306a36Sopenharmony_ci/**
564362306a36Sopenharmony_ci * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria
564462306a36Sopenharmony_ci *
564562306a36Sopenharmony_ci * @lkups: lookup elements or match criteria for the advanced recipe, one
564662306a36Sopenharmony_ci *	   structure per protocol header
564762306a36Sopenharmony_ci * @lkups_cnt: number of protocols
564862306a36Sopenharmony_ci * @s_rule: stores rule information from the match criteria
564962306a36Sopenharmony_ci * @profile: dummy packet profile (the template, its size and header offsets)
565062306a36Sopenharmony_ci */
565162306a36Sopenharmony_cistatic int
565262306a36Sopenharmony_ciice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
565362306a36Sopenharmony_ci			  struct ice_sw_rule_lkup_rx_tx *s_rule,
565462306a36Sopenharmony_ci			  const struct ice_dummy_pkt_profile *profile)
565562306a36Sopenharmony_ci{
565662306a36Sopenharmony_ci	u8 *pkt;
565762306a36Sopenharmony_ci	u16 i;
565862306a36Sopenharmony_ci
565962306a36Sopenharmony_ci	/* Start with a packet with a pre-defined/dummy content. Then, fill
566062306a36Sopenharmony_ci	 * in the header values to be looked up or matched.
566162306a36Sopenharmony_ci	 */
566262306a36Sopenharmony_ci	pkt = s_rule->hdr_data;
566362306a36Sopenharmony_ci
566462306a36Sopenharmony_ci	memcpy(pkt, profile->pkt, profile->pkt_len);
566562306a36Sopenharmony_ci
566662306a36Sopenharmony_ci	for (i = 0; i < lkups_cnt; i++) {
566762306a36Sopenharmony_ci		const struct ice_dummy_pkt_offsets *offsets = profile->offsets;
566862306a36Sopenharmony_ci		enum ice_protocol_type type;
566962306a36Sopenharmony_ci		u16 offset = 0, len = 0, j;
567062306a36Sopenharmony_ci		bool found = false;
567162306a36Sopenharmony_ci
567262306a36Sopenharmony_ci		/* find the start of this layer; it should be found since this
567362306a36Sopenharmony_ci		 * was already checked when search for the dummy packet
567462306a36Sopenharmony_ci		 */
567562306a36Sopenharmony_ci		type = lkups[i].type;
567662306a36Sopenharmony_ci		/* metadata isn't present in the packet */
567762306a36Sopenharmony_ci		if (type == ICE_HW_METADATA)
567862306a36Sopenharmony_ci			continue;
567962306a36Sopenharmony_ci
568062306a36Sopenharmony_ci		for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) {
568162306a36Sopenharmony_ci			if (type == offsets[j].type) {
568262306a36Sopenharmony_ci				offset = offsets[j].offset;
568362306a36Sopenharmony_ci				found = true;
568462306a36Sopenharmony_ci				break;
568562306a36Sopenharmony_ci			}
568662306a36Sopenharmony_ci		}
568762306a36Sopenharmony_ci		/* this should never happen in a correct calling sequence */
568862306a36Sopenharmony_ci		if (!found)
568962306a36Sopenharmony_ci			return -EINVAL;
569062306a36Sopenharmony_ci
569162306a36Sopenharmony_ci		switch (lkups[i].type) {
569262306a36Sopenharmony_ci		case ICE_MAC_OFOS:
569362306a36Sopenharmony_ci		case ICE_MAC_IL:
569462306a36Sopenharmony_ci			len = sizeof(struct ice_ether_hdr);
569562306a36Sopenharmony_ci			break;
569662306a36Sopenharmony_ci		case ICE_ETYPE_OL:
569762306a36Sopenharmony_ci		case ICE_ETYPE_IL:
569862306a36Sopenharmony_ci			len = sizeof(struct ice_ethtype_hdr);
569962306a36Sopenharmony_ci			break;
570062306a36Sopenharmony_ci		case ICE_VLAN_OFOS:
570162306a36Sopenharmony_ci		case ICE_VLAN_EX:
570262306a36Sopenharmony_ci		case ICE_VLAN_IN:
570362306a36Sopenharmony_ci			len = sizeof(struct ice_vlan_hdr);
570462306a36Sopenharmony_ci			break;
570562306a36Sopenharmony_ci		case ICE_IPV4_OFOS:
570662306a36Sopenharmony_ci		case ICE_IPV4_IL:
570762306a36Sopenharmony_ci			len = sizeof(struct ice_ipv4_hdr);
570862306a36Sopenharmony_ci			break;
570962306a36Sopenharmony_ci		case ICE_IPV6_OFOS:
571062306a36Sopenharmony_ci		case ICE_IPV6_IL:
571162306a36Sopenharmony_ci			len = sizeof(struct ice_ipv6_hdr);
571262306a36Sopenharmony_ci			break;
571362306a36Sopenharmony_ci		case ICE_TCP_IL:
571462306a36Sopenharmony_ci		case ICE_UDP_OF:
571562306a36Sopenharmony_ci		case ICE_UDP_ILOS:
571662306a36Sopenharmony_ci			len = sizeof(struct ice_l4_hdr);
571762306a36Sopenharmony_ci			break;
571862306a36Sopenharmony_ci		case ICE_SCTP_IL:
571962306a36Sopenharmony_ci			len = sizeof(struct ice_sctp_hdr);
572062306a36Sopenharmony_ci			break;
572162306a36Sopenharmony_ci		case ICE_NVGRE:
572262306a36Sopenharmony_ci			len = sizeof(struct ice_nvgre_hdr);
572362306a36Sopenharmony_ci			break;
572462306a36Sopenharmony_ci		case ICE_VXLAN:
572562306a36Sopenharmony_ci		case ICE_GENEVE:
572662306a36Sopenharmony_ci			len = sizeof(struct ice_udp_tnl_hdr);
572762306a36Sopenharmony_ci			break;
572862306a36Sopenharmony_ci		case ICE_GTP_NO_PAY:
572962306a36Sopenharmony_ci		case ICE_GTP:
573062306a36Sopenharmony_ci			len = sizeof(struct ice_udp_gtp_hdr);
573162306a36Sopenharmony_ci			break;
573262306a36Sopenharmony_ci		case ICE_PPPOE:
573362306a36Sopenharmony_ci			len = sizeof(struct ice_pppoe_hdr);
573462306a36Sopenharmony_ci			break;
573562306a36Sopenharmony_ci		case ICE_L2TPV3:
573662306a36Sopenharmony_ci			len = sizeof(struct ice_l2tpv3_sess_hdr);
573762306a36Sopenharmony_ci			break;
573862306a36Sopenharmony_ci		default:
573962306a36Sopenharmony_ci			return -EINVAL;
574062306a36Sopenharmony_ci		}
574162306a36Sopenharmony_ci
574262306a36Sopenharmony_ci		/* the length should be a word multiple */
574362306a36Sopenharmony_ci		if (len % ICE_BYTES_PER_WORD)
574462306a36Sopenharmony_ci			return -EIO;
574562306a36Sopenharmony_ci
574662306a36Sopenharmony_ci		/* We have the offset to the header start, the length, the
574762306a36Sopenharmony_ci		 * caller's header values and mask. Use this information to
574862306a36Sopenharmony_ci		 * copy the data into the dummy packet appropriately based on
574962306a36Sopenharmony_ci		 * the mask. Note that we need to only write the bits as
575062306a36Sopenharmony_ci		 * indicated by the mask to make sure we don't improperly write
575162306a36Sopenharmony_ci		 * over any significant packet data.
575262306a36Sopenharmony_ci		 */
575362306a36Sopenharmony_ci		for (j = 0; j < len / sizeof(u16); j++) {
575462306a36Sopenharmony_ci			u16 *ptr = (u16 *)(pkt + offset);
575562306a36Sopenharmony_ci			u16 mask = lkups[i].m_raw[j];
575662306a36Sopenharmony_ci
575762306a36Sopenharmony_ci			if (!mask)
575862306a36Sopenharmony_ci				continue;
575962306a36Sopenharmony_ci
576062306a36Sopenharmony_ci			ptr[j] = (ptr[j] & ~mask) | (lkups[i].h_raw[j] & mask);
576162306a36Sopenharmony_ci		}
576262306a36Sopenharmony_ci	}
576362306a36Sopenharmony_ci
576462306a36Sopenharmony_ci	s_rule->hdr_len = cpu_to_le16(profile->pkt_len);
576562306a36Sopenharmony_ci
576662306a36Sopenharmony_ci	return 0;
576762306a36Sopenharmony_ci}
576862306a36Sopenharmony_ci
576962306a36Sopenharmony_ci/**
577062306a36Sopenharmony_ci * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port
577162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
577262306a36Sopenharmony_ci * @tun_type: tunnel type
577362306a36Sopenharmony_ci * @pkt: dummy packet to fill in
577462306a36Sopenharmony_ci * @offsets: offset info for the dummy packet
577562306a36Sopenharmony_ci */
577662306a36Sopenharmony_cistatic int
577762306a36Sopenharmony_ciice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type,
577862306a36Sopenharmony_ci			u8 *pkt, const struct ice_dummy_pkt_offsets *offsets)
577962306a36Sopenharmony_ci{
578062306a36Sopenharmony_ci	u16 open_port, i;
578162306a36Sopenharmony_ci
578262306a36Sopenharmony_ci	switch (tun_type) {
578362306a36Sopenharmony_ci	case ICE_SW_TUN_VXLAN:
578462306a36Sopenharmony_ci		if (!ice_get_open_tunnel_port(hw, &open_port, TNL_VXLAN))
578562306a36Sopenharmony_ci			return -EIO;
578662306a36Sopenharmony_ci		break;
578762306a36Sopenharmony_ci	case ICE_SW_TUN_GENEVE:
578862306a36Sopenharmony_ci		if (!ice_get_open_tunnel_port(hw, &open_port, TNL_GENEVE))
578962306a36Sopenharmony_ci			return -EIO;
579062306a36Sopenharmony_ci		break;
579162306a36Sopenharmony_ci	default:
579262306a36Sopenharmony_ci		/* Nothing needs to be done for this tunnel type */
579362306a36Sopenharmony_ci		return 0;
579462306a36Sopenharmony_ci	}
579562306a36Sopenharmony_ci
579662306a36Sopenharmony_ci	/* Find the outer UDP protocol header and insert the port number */
579762306a36Sopenharmony_ci	for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) {
579862306a36Sopenharmony_ci		if (offsets[i].type == ICE_UDP_OF) {
579962306a36Sopenharmony_ci			struct ice_l4_hdr *hdr;
580062306a36Sopenharmony_ci			u16 offset;
580162306a36Sopenharmony_ci
580262306a36Sopenharmony_ci			offset = offsets[i].offset;
580362306a36Sopenharmony_ci			hdr = (struct ice_l4_hdr *)&pkt[offset];
580462306a36Sopenharmony_ci			hdr->dst_port = cpu_to_be16(open_port);
580562306a36Sopenharmony_ci
580662306a36Sopenharmony_ci			return 0;
580762306a36Sopenharmony_ci		}
580862306a36Sopenharmony_ci	}
580962306a36Sopenharmony_ci
581062306a36Sopenharmony_ci	return -EIO;
581162306a36Sopenharmony_ci}
581262306a36Sopenharmony_ci
581362306a36Sopenharmony_ci/**
581462306a36Sopenharmony_ci * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type
581562306a36Sopenharmony_ci * @hw: pointer to hw structure
581662306a36Sopenharmony_ci * @vlan_type: VLAN tag type
581762306a36Sopenharmony_ci * @pkt: dummy packet to fill in
581862306a36Sopenharmony_ci * @offsets: offset info for the dummy packet
581962306a36Sopenharmony_ci */
582062306a36Sopenharmony_cistatic int
582162306a36Sopenharmony_ciice_fill_adv_packet_vlan(struct ice_hw *hw, u16 vlan_type, u8 *pkt,
582262306a36Sopenharmony_ci			 const struct ice_dummy_pkt_offsets *offsets)
582362306a36Sopenharmony_ci{
582462306a36Sopenharmony_ci	u16 i;
582562306a36Sopenharmony_ci
582662306a36Sopenharmony_ci	/* Check if there is something to do */
582762306a36Sopenharmony_ci	if (!vlan_type || !ice_is_dvm_ena(hw))
582862306a36Sopenharmony_ci		return 0;
582962306a36Sopenharmony_ci
583062306a36Sopenharmony_ci	/* Find VLAN header and insert VLAN TPID */
583162306a36Sopenharmony_ci	for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) {
583262306a36Sopenharmony_ci		if (offsets[i].type == ICE_VLAN_OFOS ||
583362306a36Sopenharmony_ci		    offsets[i].type == ICE_VLAN_EX) {
583462306a36Sopenharmony_ci			struct ice_vlan_hdr *hdr;
583562306a36Sopenharmony_ci			u16 offset;
583662306a36Sopenharmony_ci
583762306a36Sopenharmony_ci			offset = offsets[i].offset;
583862306a36Sopenharmony_ci			hdr = (struct ice_vlan_hdr *)&pkt[offset];
583962306a36Sopenharmony_ci			hdr->type = cpu_to_be16(vlan_type);
584062306a36Sopenharmony_ci
584162306a36Sopenharmony_ci			return 0;
584262306a36Sopenharmony_ci		}
584362306a36Sopenharmony_ci	}
584462306a36Sopenharmony_ci
584562306a36Sopenharmony_ci	return -EIO;
584662306a36Sopenharmony_ci}
584762306a36Sopenharmony_ci
584862306a36Sopenharmony_cistatic bool ice_rules_equal(const struct ice_adv_rule_info *first,
584962306a36Sopenharmony_ci			    const struct ice_adv_rule_info *second)
585062306a36Sopenharmony_ci{
585162306a36Sopenharmony_ci	return first->sw_act.flag == second->sw_act.flag &&
585262306a36Sopenharmony_ci	       first->tun_type == second->tun_type &&
585362306a36Sopenharmony_ci	       first->vlan_type == second->vlan_type &&
585462306a36Sopenharmony_ci	       first->src_vsi == second->src_vsi &&
585562306a36Sopenharmony_ci	       first->need_pass_l2 == second->need_pass_l2 &&
585662306a36Sopenharmony_ci	       first->allow_pass_l2 == second->allow_pass_l2;
585762306a36Sopenharmony_ci}
585862306a36Sopenharmony_ci
585962306a36Sopenharmony_ci/**
586062306a36Sopenharmony_ci * ice_find_adv_rule_entry - Search a rule entry
586162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
586262306a36Sopenharmony_ci * @lkups: lookup elements or match criteria for the advanced recipe, one
586362306a36Sopenharmony_ci *	   structure per protocol header
586462306a36Sopenharmony_ci * @lkups_cnt: number of protocols
586562306a36Sopenharmony_ci * @recp_id: recipe ID for which we are finding the rule
586662306a36Sopenharmony_ci * @rinfo: other information regarding the rule e.g. priority and action info
586762306a36Sopenharmony_ci *
586862306a36Sopenharmony_ci * Helper function to search for a given advance rule entry
586962306a36Sopenharmony_ci * Returns pointer to entry storing the rule if found
587062306a36Sopenharmony_ci */
587162306a36Sopenharmony_cistatic struct ice_adv_fltr_mgmt_list_entry *
587262306a36Sopenharmony_ciice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
587362306a36Sopenharmony_ci			u16 lkups_cnt, u16 recp_id,
587462306a36Sopenharmony_ci			struct ice_adv_rule_info *rinfo)
587562306a36Sopenharmony_ci{
587662306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *list_itr;
587762306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
587862306a36Sopenharmony_ci	int i;
587962306a36Sopenharmony_ci
588062306a36Sopenharmony_ci	list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules,
588162306a36Sopenharmony_ci			    list_entry) {
588262306a36Sopenharmony_ci		bool lkups_matched = true;
588362306a36Sopenharmony_ci
588462306a36Sopenharmony_ci		if (lkups_cnt != list_itr->lkups_cnt)
588562306a36Sopenharmony_ci			continue;
588662306a36Sopenharmony_ci		for (i = 0; i < list_itr->lkups_cnt; i++)
588762306a36Sopenharmony_ci			if (memcmp(&list_itr->lkups[i], &lkups[i],
588862306a36Sopenharmony_ci				   sizeof(*lkups))) {
588962306a36Sopenharmony_ci				lkups_matched = false;
589062306a36Sopenharmony_ci				break;
589162306a36Sopenharmony_ci			}
589262306a36Sopenharmony_ci		if (ice_rules_equal(rinfo, &list_itr->rule_info) &&
589362306a36Sopenharmony_ci		    lkups_matched)
589462306a36Sopenharmony_ci			return list_itr;
589562306a36Sopenharmony_ci	}
589662306a36Sopenharmony_ci	return NULL;
589762306a36Sopenharmony_ci}
589862306a36Sopenharmony_ci
589962306a36Sopenharmony_ci/**
590062306a36Sopenharmony_ci * ice_adv_add_update_vsi_list
590162306a36Sopenharmony_ci * @hw: pointer to the hardware structure
590262306a36Sopenharmony_ci * @m_entry: pointer to current adv filter management list entry
590362306a36Sopenharmony_ci * @cur_fltr: filter information from the book keeping entry
590462306a36Sopenharmony_ci * @new_fltr: filter information with the new VSI to be added
590562306a36Sopenharmony_ci *
590662306a36Sopenharmony_ci * Call AQ command to add or update previously created VSI list with new VSI.
590762306a36Sopenharmony_ci *
590862306a36Sopenharmony_ci * Helper function to do book keeping associated with adding filter information
590962306a36Sopenharmony_ci * The algorithm to do the booking keeping is described below :
591062306a36Sopenharmony_ci * When a VSI needs to subscribe to a given advanced filter
591162306a36Sopenharmony_ci *	if only one VSI has been added till now
591262306a36Sopenharmony_ci *		Allocate a new VSI list and add two VSIs
591362306a36Sopenharmony_ci *		to this list using switch rule command
591462306a36Sopenharmony_ci *		Update the previously created switch rule with the
591562306a36Sopenharmony_ci *		newly created VSI list ID
591662306a36Sopenharmony_ci *	if a VSI list was previously created
591762306a36Sopenharmony_ci *		Add the new VSI to the previously created VSI list set
591862306a36Sopenharmony_ci *		using the update switch rule command
591962306a36Sopenharmony_ci */
592062306a36Sopenharmony_cistatic int
592162306a36Sopenharmony_ciice_adv_add_update_vsi_list(struct ice_hw *hw,
592262306a36Sopenharmony_ci			    struct ice_adv_fltr_mgmt_list_entry *m_entry,
592362306a36Sopenharmony_ci			    struct ice_adv_rule_info *cur_fltr,
592462306a36Sopenharmony_ci			    struct ice_adv_rule_info *new_fltr)
592562306a36Sopenharmony_ci{
592662306a36Sopenharmony_ci	u16 vsi_list_id = 0;
592762306a36Sopenharmony_ci	int status;
592862306a36Sopenharmony_ci
592962306a36Sopenharmony_ci	if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||
593062306a36Sopenharmony_ci	    cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
593162306a36Sopenharmony_ci	    cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET)
593262306a36Sopenharmony_ci		return -EOPNOTSUPP;
593362306a36Sopenharmony_ci
593462306a36Sopenharmony_ci	if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||
593562306a36Sopenharmony_ci	     new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) &&
593662306a36Sopenharmony_ci	    (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI ||
593762306a36Sopenharmony_ci	     cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST))
593862306a36Sopenharmony_ci		return -EOPNOTSUPP;
593962306a36Sopenharmony_ci
594062306a36Sopenharmony_ci	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
594162306a36Sopenharmony_ci		 /* Only one entry existed in the mapping and it was not already
594262306a36Sopenharmony_ci		  * a part of a VSI list. So, create a VSI list with the old and
594362306a36Sopenharmony_ci		  * new VSIs.
594462306a36Sopenharmony_ci		  */
594562306a36Sopenharmony_ci		struct ice_fltr_info tmp_fltr;
594662306a36Sopenharmony_ci		u16 vsi_handle_arr[2];
594762306a36Sopenharmony_ci
594862306a36Sopenharmony_ci		/* A rule already exists with the new VSI being added */
594962306a36Sopenharmony_ci		if (cur_fltr->sw_act.fwd_id.hw_vsi_id ==
595062306a36Sopenharmony_ci		    new_fltr->sw_act.fwd_id.hw_vsi_id)
595162306a36Sopenharmony_ci			return -EEXIST;
595262306a36Sopenharmony_ci
595362306a36Sopenharmony_ci		vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle;
595462306a36Sopenharmony_ci		vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle;
595562306a36Sopenharmony_ci		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
595662306a36Sopenharmony_ci						  &vsi_list_id,
595762306a36Sopenharmony_ci						  ICE_SW_LKUP_LAST);
595862306a36Sopenharmony_ci		if (status)
595962306a36Sopenharmony_ci			return status;
596062306a36Sopenharmony_ci
596162306a36Sopenharmony_ci		memset(&tmp_fltr, 0, sizeof(tmp_fltr));
596262306a36Sopenharmony_ci		tmp_fltr.flag = m_entry->rule_info.sw_act.flag;
596362306a36Sopenharmony_ci		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
596462306a36Sopenharmony_ci		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
596562306a36Sopenharmony_ci		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
596662306a36Sopenharmony_ci		tmp_fltr.lkup_type = ICE_SW_LKUP_LAST;
596762306a36Sopenharmony_ci
596862306a36Sopenharmony_ci		/* Update the previous switch rule of "forward to VSI" to
596962306a36Sopenharmony_ci		 * "fwd to VSI list"
597062306a36Sopenharmony_ci		 */
597162306a36Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
597262306a36Sopenharmony_ci		if (status)
597362306a36Sopenharmony_ci			return status;
597462306a36Sopenharmony_ci
597562306a36Sopenharmony_ci		cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id;
597662306a36Sopenharmony_ci		cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST;
597762306a36Sopenharmony_ci		m_entry->vsi_list_info =
597862306a36Sopenharmony_ci			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
597962306a36Sopenharmony_ci						vsi_list_id);
598062306a36Sopenharmony_ci	} else {
598162306a36Sopenharmony_ci		u16 vsi_handle = new_fltr->sw_act.vsi_handle;
598262306a36Sopenharmony_ci
598362306a36Sopenharmony_ci		if (!m_entry->vsi_list_info)
598462306a36Sopenharmony_ci			return -EIO;
598562306a36Sopenharmony_ci
598662306a36Sopenharmony_ci		/* A rule already exists with the new VSI being added */
598762306a36Sopenharmony_ci		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
598862306a36Sopenharmony_ci			return 0;
598962306a36Sopenharmony_ci
599062306a36Sopenharmony_ci		/* Update the previously created VSI list set with
599162306a36Sopenharmony_ci		 * the new VSI ID passed in
599262306a36Sopenharmony_ci		 */
599362306a36Sopenharmony_ci		vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id;
599462306a36Sopenharmony_ci
599562306a36Sopenharmony_ci		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
599662306a36Sopenharmony_ci						  vsi_list_id, false,
599762306a36Sopenharmony_ci						  ice_aqc_opc_update_sw_rules,
599862306a36Sopenharmony_ci						  ICE_SW_LKUP_LAST);
599962306a36Sopenharmony_ci		/* update VSI list mapping info with new VSI ID */
600062306a36Sopenharmony_ci		if (!status)
600162306a36Sopenharmony_ci			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
600262306a36Sopenharmony_ci	}
600362306a36Sopenharmony_ci	if (!status)
600462306a36Sopenharmony_ci		m_entry->vsi_count++;
600562306a36Sopenharmony_ci	return status;
600662306a36Sopenharmony_ci}
600762306a36Sopenharmony_ci
600862306a36Sopenharmony_civoid ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup)
600962306a36Sopenharmony_ci{
601062306a36Sopenharmony_ci	lkup->type = ICE_HW_METADATA;
601162306a36Sopenharmony_ci	lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID21] |=
601262306a36Sopenharmony_ci		cpu_to_be16(ICE_PKT_TUNNEL_MASK);
601362306a36Sopenharmony_ci}
601462306a36Sopenharmony_ci
601562306a36Sopenharmony_civoid ice_rule_add_direction_metadata(struct ice_adv_lkup_elem *lkup)
601662306a36Sopenharmony_ci{
601762306a36Sopenharmony_ci	lkup->type = ICE_HW_METADATA;
601862306a36Sopenharmony_ci	lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |=
601962306a36Sopenharmony_ci		cpu_to_be16(ICE_PKT_FROM_NETWORK);
602062306a36Sopenharmony_ci}
602162306a36Sopenharmony_ci
602262306a36Sopenharmony_civoid ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup)
602362306a36Sopenharmony_ci{
602462306a36Sopenharmony_ci	lkup->type = ICE_HW_METADATA;
602562306a36Sopenharmony_ci	lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |=
602662306a36Sopenharmony_ci		cpu_to_be16(ICE_PKT_VLAN_MASK);
602762306a36Sopenharmony_ci}
602862306a36Sopenharmony_ci
602962306a36Sopenharmony_civoid ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup)
603062306a36Sopenharmony_ci{
603162306a36Sopenharmony_ci	lkup->type = ICE_HW_METADATA;
603262306a36Sopenharmony_ci	lkup->m_u.metadata.source_vsi = cpu_to_be16(ICE_MDID_SOURCE_VSI_MASK);
603362306a36Sopenharmony_ci}
603462306a36Sopenharmony_ci
603562306a36Sopenharmony_ci/**
603662306a36Sopenharmony_ci * ice_add_adv_rule - helper function to create an advanced switch rule
603762306a36Sopenharmony_ci * @hw: pointer to the hardware structure
603862306a36Sopenharmony_ci * @lkups: information on the words that needs to be looked up. All words
603962306a36Sopenharmony_ci * together makes one recipe
604062306a36Sopenharmony_ci * @lkups_cnt: num of entries in the lkups array
604162306a36Sopenharmony_ci * @rinfo: other information related to the rule that needs to be programmed
604262306a36Sopenharmony_ci * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be
604362306a36Sopenharmony_ci *               ignored is case of error.
604462306a36Sopenharmony_ci *
604562306a36Sopenharmony_ci * This function can program only 1 rule at a time. The lkups is used to
604662306a36Sopenharmony_ci * describe the all the words that forms the "lookup" portion of the recipe.
604762306a36Sopenharmony_ci * These words can span multiple protocols. Callers to this function need to
604862306a36Sopenharmony_ci * pass in a list of protocol headers with lookup information along and mask
604962306a36Sopenharmony_ci * that determines which words are valid from the given protocol header.
605062306a36Sopenharmony_ci * rinfo describes other information related to this rule such as forwarding
605162306a36Sopenharmony_ci * IDs, priority of this rule, etc.
605262306a36Sopenharmony_ci */
605362306a36Sopenharmony_ciint
605462306a36Sopenharmony_ciice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
605562306a36Sopenharmony_ci		 u16 lkups_cnt, struct ice_adv_rule_info *rinfo,
605662306a36Sopenharmony_ci		 struct ice_rule_query_data *added_entry)
605762306a36Sopenharmony_ci{
605862306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL;
605962306a36Sopenharmony_ci	struct ice_sw_rule_lkup_rx_tx *s_rule = NULL;
606062306a36Sopenharmony_ci	const struct ice_dummy_pkt_profile *profile;
606162306a36Sopenharmony_ci	u16 rid = 0, i, rule_buf_sz, vsi_handle;
606262306a36Sopenharmony_ci	struct list_head *rule_head;
606362306a36Sopenharmony_ci	struct ice_switch_info *sw;
606462306a36Sopenharmony_ci	u16 word_cnt;
606562306a36Sopenharmony_ci	u32 act = 0;
606662306a36Sopenharmony_ci	int status;
606762306a36Sopenharmony_ci	u8 q_rgn;
606862306a36Sopenharmony_ci
606962306a36Sopenharmony_ci	/* Initialize profile to result index bitmap */
607062306a36Sopenharmony_ci	if (!hw->switch_info->prof_res_bm_init) {
607162306a36Sopenharmony_ci		hw->switch_info->prof_res_bm_init = 1;
607262306a36Sopenharmony_ci		ice_init_prof_result_bm(hw);
607362306a36Sopenharmony_ci	}
607462306a36Sopenharmony_ci
607562306a36Sopenharmony_ci	if (!lkups_cnt)
607662306a36Sopenharmony_ci		return -EINVAL;
607762306a36Sopenharmony_ci
607862306a36Sopenharmony_ci	/* get # of words we need to match */
607962306a36Sopenharmony_ci	word_cnt = 0;
608062306a36Sopenharmony_ci	for (i = 0; i < lkups_cnt; i++) {
608162306a36Sopenharmony_ci		u16 j;
608262306a36Sopenharmony_ci
608362306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(lkups->m_raw); j++)
608462306a36Sopenharmony_ci			if (lkups[i].m_raw[j])
608562306a36Sopenharmony_ci				word_cnt++;
608662306a36Sopenharmony_ci	}
608762306a36Sopenharmony_ci
608862306a36Sopenharmony_ci	if (!word_cnt)
608962306a36Sopenharmony_ci		return -EINVAL;
609062306a36Sopenharmony_ci
609162306a36Sopenharmony_ci	if (word_cnt > ICE_MAX_CHAIN_WORDS)
609262306a36Sopenharmony_ci		return -ENOSPC;
609362306a36Sopenharmony_ci
609462306a36Sopenharmony_ci	/* locate a dummy packet */
609562306a36Sopenharmony_ci	profile = ice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type);
609662306a36Sopenharmony_ci	if (IS_ERR(profile))
609762306a36Sopenharmony_ci		return PTR_ERR(profile);
609862306a36Sopenharmony_ci
609962306a36Sopenharmony_ci	if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
610062306a36Sopenharmony_ci	      rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
610162306a36Sopenharmony_ci	      rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
610262306a36Sopenharmony_ci	      rinfo->sw_act.fltr_act == ICE_DROP_PACKET ||
610362306a36Sopenharmony_ci	      rinfo->sw_act.fltr_act == ICE_NOP)) {
610462306a36Sopenharmony_ci		status = -EIO;
610562306a36Sopenharmony_ci		goto free_pkt_profile;
610662306a36Sopenharmony_ci	}
610762306a36Sopenharmony_ci
610862306a36Sopenharmony_ci	vsi_handle = rinfo->sw_act.vsi_handle;
610962306a36Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle)) {
611062306a36Sopenharmony_ci		status =  -EINVAL;
611162306a36Sopenharmony_ci		goto free_pkt_profile;
611262306a36Sopenharmony_ci	}
611362306a36Sopenharmony_ci
611462306a36Sopenharmony_ci	if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
611562306a36Sopenharmony_ci	    rinfo->sw_act.fltr_act == ICE_NOP)
611662306a36Sopenharmony_ci		rinfo->sw_act.fwd_id.hw_vsi_id =
611762306a36Sopenharmony_ci			ice_get_hw_vsi_num(hw, vsi_handle);
611862306a36Sopenharmony_ci
611962306a36Sopenharmony_ci	if (rinfo->src_vsi)
612062306a36Sopenharmony_ci		rinfo->sw_act.src = ice_get_hw_vsi_num(hw, rinfo->src_vsi);
612162306a36Sopenharmony_ci	else
612262306a36Sopenharmony_ci		rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle);
612362306a36Sopenharmony_ci
612462306a36Sopenharmony_ci	status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid);
612562306a36Sopenharmony_ci	if (status)
612662306a36Sopenharmony_ci		goto free_pkt_profile;
612762306a36Sopenharmony_ci	m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
612862306a36Sopenharmony_ci	if (m_entry) {
612962306a36Sopenharmony_ci		/* we have to add VSI to VSI_LIST and increment vsi_count.
613062306a36Sopenharmony_ci		 * Also Update VSI list so that we can change forwarding rule
613162306a36Sopenharmony_ci		 * if the rule already exists, we will check if it exists with
613262306a36Sopenharmony_ci		 * same vsi_id, if not then add it to the VSI list if it already
613362306a36Sopenharmony_ci		 * exists if not then create a VSI list and add the existing VSI
613462306a36Sopenharmony_ci		 * ID and the new VSI ID to the list
613562306a36Sopenharmony_ci		 * We will add that VSI to the list
613662306a36Sopenharmony_ci		 */
613762306a36Sopenharmony_ci		status = ice_adv_add_update_vsi_list(hw, m_entry,
613862306a36Sopenharmony_ci						     &m_entry->rule_info,
613962306a36Sopenharmony_ci						     rinfo);
614062306a36Sopenharmony_ci		if (added_entry) {
614162306a36Sopenharmony_ci			added_entry->rid = rid;
614262306a36Sopenharmony_ci			added_entry->rule_id = m_entry->rule_info.fltr_rule_id;
614362306a36Sopenharmony_ci			added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
614462306a36Sopenharmony_ci		}
614562306a36Sopenharmony_ci		goto free_pkt_profile;
614662306a36Sopenharmony_ci	}
614762306a36Sopenharmony_ci	rule_buf_sz = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, profile->pkt_len);
614862306a36Sopenharmony_ci	s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
614962306a36Sopenharmony_ci	if (!s_rule) {
615062306a36Sopenharmony_ci		status = -ENOMEM;
615162306a36Sopenharmony_ci		goto free_pkt_profile;
615262306a36Sopenharmony_ci	}
615362306a36Sopenharmony_ci	if (!rinfo->flags_info.act_valid) {
615462306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_LAN_ENABLE;
615562306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_LB_ENABLE;
615662306a36Sopenharmony_ci	} else {
615762306a36Sopenharmony_ci		act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
615862306a36Sopenharmony_ci						ICE_SINGLE_ACT_LB_ENABLE);
615962306a36Sopenharmony_ci	}
616062306a36Sopenharmony_ci
616162306a36Sopenharmony_ci	switch (rinfo->sw_act.fltr_act) {
616262306a36Sopenharmony_ci	case ICE_FWD_TO_VSI:
616362306a36Sopenharmony_ci		act |= (rinfo->sw_act.fwd_id.hw_vsi_id <<
616462306a36Sopenharmony_ci			ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M;
616562306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;
616662306a36Sopenharmony_ci		break;
616762306a36Sopenharmony_ci	case ICE_FWD_TO_Q:
616862306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_TO_Q;
616962306a36Sopenharmony_ci		act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
617062306a36Sopenharmony_ci		       ICE_SINGLE_ACT_Q_INDEX_M;
617162306a36Sopenharmony_ci		break;
617262306a36Sopenharmony_ci	case ICE_FWD_TO_QGRP:
617362306a36Sopenharmony_ci		q_rgn = rinfo->sw_act.qgrp_size > 0 ?
617462306a36Sopenharmony_ci			(u8)ilog2(rinfo->sw_act.qgrp_size) : 0;
617562306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_TO_Q;
617662306a36Sopenharmony_ci		act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
617762306a36Sopenharmony_ci		       ICE_SINGLE_ACT_Q_INDEX_M;
617862306a36Sopenharmony_ci		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
617962306a36Sopenharmony_ci		       ICE_SINGLE_ACT_Q_REGION_M;
618062306a36Sopenharmony_ci		break;
618162306a36Sopenharmony_ci	case ICE_DROP_PACKET:
618262306a36Sopenharmony_ci		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
618362306a36Sopenharmony_ci		       ICE_SINGLE_ACT_VALID_BIT;
618462306a36Sopenharmony_ci		break;
618562306a36Sopenharmony_ci	case ICE_NOP:
618662306a36Sopenharmony_ci		act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
618762306a36Sopenharmony_ci				  rinfo->sw_act.fwd_id.hw_vsi_id);
618862306a36Sopenharmony_ci		act &= ~ICE_SINGLE_ACT_VALID_BIT;
618962306a36Sopenharmony_ci		break;
619062306a36Sopenharmony_ci	default:
619162306a36Sopenharmony_ci		status = -EIO;
619262306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
619362306a36Sopenharmony_ci	}
619462306a36Sopenharmony_ci
619562306a36Sopenharmony_ci	/* If there is no matching criteria for direction there
619662306a36Sopenharmony_ci	 * is only one difference between Rx and Tx:
619762306a36Sopenharmony_ci	 * - get switch id base on VSI number from source field (Tx)
619862306a36Sopenharmony_ci	 * - get switch id base on port number (Rx)
619962306a36Sopenharmony_ci	 *
620062306a36Sopenharmony_ci	 * If matching on direction metadata is chose rule direction is
620162306a36Sopenharmony_ci	 * extracted from type value set here.
620262306a36Sopenharmony_ci	 */
620362306a36Sopenharmony_ci	if (rinfo->sw_act.flag & ICE_FLTR_TX) {
620462306a36Sopenharmony_ci		s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
620562306a36Sopenharmony_ci		s_rule->src = cpu_to_le16(rinfo->sw_act.src);
620662306a36Sopenharmony_ci	} else {
620762306a36Sopenharmony_ci		s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
620862306a36Sopenharmony_ci		s_rule->src = cpu_to_le16(hw->port_info->lport);
620962306a36Sopenharmony_ci	}
621062306a36Sopenharmony_ci
621162306a36Sopenharmony_ci	s_rule->recipe_id = cpu_to_le16(rid);
621262306a36Sopenharmony_ci	s_rule->act = cpu_to_le32(act);
621362306a36Sopenharmony_ci
621462306a36Sopenharmony_ci	status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, profile);
621562306a36Sopenharmony_ci	if (status)
621662306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
621762306a36Sopenharmony_ci
621862306a36Sopenharmony_ci	status = ice_fill_adv_packet_tun(hw, rinfo->tun_type, s_rule->hdr_data,
621962306a36Sopenharmony_ci					 profile->offsets);
622062306a36Sopenharmony_ci	if (status)
622162306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
622262306a36Sopenharmony_ci
622362306a36Sopenharmony_ci	status = ice_fill_adv_packet_vlan(hw, rinfo->vlan_type,
622462306a36Sopenharmony_ci					  s_rule->hdr_data,
622562306a36Sopenharmony_ci					  profile->offsets);
622662306a36Sopenharmony_ci	if (status)
622762306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
622862306a36Sopenharmony_ci
622962306a36Sopenharmony_ci	status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
623062306a36Sopenharmony_ci				 rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,
623162306a36Sopenharmony_ci				 NULL);
623262306a36Sopenharmony_ci	if (status)
623362306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
623462306a36Sopenharmony_ci	adv_fltr = devm_kzalloc(ice_hw_to_dev(hw),
623562306a36Sopenharmony_ci				sizeof(struct ice_adv_fltr_mgmt_list_entry),
623662306a36Sopenharmony_ci				GFP_KERNEL);
623762306a36Sopenharmony_ci	if (!adv_fltr) {
623862306a36Sopenharmony_ci		status = -ENOMEM;
623962306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
624062306a36Sopenharmony_ci	}
624162306a36Sopenharmony_ci
624262306a36Sopenharmony_ci	adv_fltr->lkups = devm_kmemdup(ice_hw_to_dev(hw), lkups,
624362306a36Sopenharmony_ci				       lkups_cnt * sizeof(*lkups), GFP_KERNEL);
624462306a36Sopenharmony_ci	if (!adv_fltr->lkups) {
624562306a36Sopenharmony_ci		status = -ENOMEM;
624662306a36Sopenharmony_ci		goto err_ice_add_adv_rule;
624762306a36Sopenharmony_ci	}
624862306a36Sopenharmony_ci
624962306a36Sopenharmony_ci	adv_fltr->lkups_cnt = lkups_cnt;
625062306a36Sopenharmony_ci	adv_fltr->rule_info = *rinfo;
625162306a36Sopenharmony_ci	adv_fltr->rule_info.fltr_rule_id = le16_to_cpu(s_rule->index);
625262306a36Sopenharmony_ci	sw = hw->switch_info;
625362306a36Sopenharmony_ci	sw->recp_list[rid].adv_rule = true;
625462306a36Sopenharmony_ci	rule_head = &sw->recp_list[rid].filt_rules;
625562306a36Sopenharmony_ci
625662306a36Sopenharmony_ci	if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
625762306a36Sopenharmony_ci		adv_fltr->vsi_count = 1;
625862306a36Sopenharmony_ci
625962306a36Sopenharmony_ci	/* Add rule entry to book keeping list */
626062306a36Sopenharmony_ci	list_add(&adv_fltr->list_entry, rule_head);
626162306a36Sopenharmony_ci	if (added_entry) {
626262306a36Sopenharmony_ci		added_entry->rid = rid;
626362306a36Sopenharmony_ci		added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id;
626462306a36Sopenharmony_ci		added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
626562306a36Sopenharmony_ci	}
626662306a36Sopenharmony_cierr_ice_add_adv_rule:
626762306a36Sopenharmony_ci	if (status && adv_fltr) {
626862306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), adv_fltr->lkups);
626962306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), adv_fltr);
627062306a36Sopenharmony_ci	}
627162306a36Sopenharmony_ci
627262306a36Sopenharmony_ci	kfree(s_rule);
627362306a36Sopenharmony_ci
627462306a36Sopenharmony_cifree_pkt_profile:
627562306a36Sopenharmony_ci	if (profile->match & ICE_PKT_KMALLOC) {
627662306a36Sopenharmony_ci		kfree(profile->offsets);
627762306a36Sopenharmony_ci		kfree(profile->pkt);
627862306a36Sopenharmony_ci		kfree(profile);
627962306a36Sopenharmony_ci	}
628062306a36Sopenharmony_ci
628162306a36Sopenharmony_ci	return status;
628262306a36Sopenharmony_ci}
628362306a36Sopenharmony_ci
628462306a36Sopenharmony_ci/**
628562306a36Sopenharmony_ci * ice_replay_vsi_fltr - Replay filters for requested VSI
628662306a36Sopenharmony_ci * @hw: pointer to the hardware structure
628762306a36Sopenharmony_ci * @vsi_handle: driver VSI handle
628862306a36Sopenharmony_ci * @recp_id: Recipe ID for which rules need to be replayed
628962306a36Sopenharmony_ci * @list_head: list for which filters need to be replayed
629062306a36Sopenharmony_ci *
629162306a36Sopenharmony_ci * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.
629262306a36Sopenharmony_ci * It is required to pass valid VSI handle.
629362306a36Sopenharmony_ci */
629462306a36Sopenharmony_cistatic int
629562306a36Sopenharmony_ciice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id,
629662306a36Sopenharmony_ci		    struct list_head *list_head)
629762306a36Sopenharmony_ci{
629862306a36Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *itr;
629962306a36Sopenharmony_ci	int status = 0;
630062306a36Sopenharmony_ci	u16 hw_vsi_id;
630162306a36Sopenharmony_ci
630262306a36Sopenharmony_ci	if (list_empty(list_head))
630362306a36Sopenharmony_ci		return status;
630462306a36Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
630562306a36Sopenharmony_ci
630662306a36Sopenharmony_ci	list_for_each_entry(itr, list_head, list_entry) {
630762306a36Sopenharmony_ci		struct ice_fltr_list_entry f_entry;
630862306a36Sopenharmony_ci
630962306a36Sopenharmony_ci		f_entry.fltr_info = itr->fltr_info;
631062306a36Sopenharmony_ci		if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&
631162306a36Sopenharmony_ci		    itr->fltr_info.vsi_handle == vsi_handle) {
631262306a36Sopenharmony_ci			/* update the src in case it is VSI num */
631362306a36Sopenharmony_ci			if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
631462306a36Sopenharmony_ci				f_entry.fltr_info.src = hw_vsi_id;
631562306a36Sopenharmony_ci			status = ice_add_rule_internal(hw, recp_id, &f_entry);
631662306a36Sopenharmony_ci			if (status)
631762306a36Sopenharmony_ci				goto end;
631862306a36Sopenharmony_ci			continue;
631962306a36Sopenharmony_ci		}
632062306a36Sopenharmony_ci		if (!itr->vsi_list_info ||
632162306a36Sopenharmony_ci		    !test_bit(vsi_handle, itr->vsi_list_info->vsi_map))
632262306a36Sopenharmony_ci			continue;
632362306a36Sopenharmony_ci		/* Clearing it so that the logic can add it back */
632462306a36Sopenharmony_ci		clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);
632562306a36Sopenharmony_ci		f_entry.fltr_info.vsi_handle = vsi_handle;
632662306a36Sopenharmony_ci		f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
632762306a36Sopenharmony_ci		/* update the src in case it is VSI num */
632862306a36Sopenharmony_ci		if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
632962306a36Sopenharmony_ci			f_entry.fltr_info.src = hw_vsi_id;
633062306a36Sopenharmony_ci		if (recp_id == ICE_SW_LKUP_VLAN)
633162306a36Sopenharmony_ci			status = ice_add_vlan_internal(hw, &f_entry);
633262306a36Sopenharmony_ci		else
633362306a36Sopenharmony_ci			status = ice_add_rule_internal(hw, recp_id, &f_entry);
633462306a36Sopenharmony_ci		if (status)
633562306a36Sopenharmony_ci			goto end;
633662306a36Sopenharmony_ci	}
633762306a36Sopenharmony_ciend:
633862306a36Sopenharmony_ci	return status;
633962306a36Sopenharmony_ci}
634062306a36Sopenharmony_ci
634162306a36Sopenharmony_ci/**
634262306a36Sopenharmony_ci * ice_adv_rem_update_vsi_list
634362306a36Sopenharmony_ci * @hw: pointer to the hardware structure
634462306a36Sopenharmony_ci * @vsi_handle: VSI handle of the VSI to remove
634562306a36Sopenharmony_ci * @fm_list: filter management entry for which the VSI list management needs to
634662306a36Sopenharmony_ci *	     be done
634762306a36Sopenharmony_ci */
634862306a36Sopenharmony_cistatic int
634962306a36Sopenharmony_ciice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
635062306a36Sopenharmony_ci			    struct ice_adv_fltr_mgmt_list_entry *fm_list)
635162306a36Sopenharmony_ci{
635262306a36Sopenharmony_ci	struct ice_vsi_list_map_info *vsi_list_info;
635362306a36Sopenharmony_ci	enum ice_sw_lkup_type lkup_type;
635462306a36Sopenharmony_ci	u16 vsi_list_id;
635562306a36Sopenharmony_ci	int status;
635662306a36Sopenharmony_ci
635762306a36Sopenharmony_ci	if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST ||
635862306a36Sopenharmony_ci	    fm_list->vsi_count == 0)
635962306a36Sopenharmony_ci		return -EINVAL;
636062306a36Sopenharmony_ci
636162306a36Sopenharmony_ci	/* A rule with the VSI being removed does not exist */
636262306a36Sopenharmony_ci	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
636362306a36Sopenharmony_ci		return -ENOENT;
636462306a36Sopenharmony_ci
636562306a36Sopenharmony_ci	lkup_type = ICE_SW_LKUP_LAST;
636662306a36Sopenharmony_ci	vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id;
636762306a36Sopenharmony_ci	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
636862306a36Sopenharmony_ci					  ice_aqc_opc_update_sw_rules,
636962306a36Sopenharmony_ci					  lkup_type);
637062306a36Sopenharmony_ci	if (status)
637162306a36Sopenharmony_ci		return status;
637262306a36Sopenharmony_ci
637362306a36Sopenharmony_ci	fm_list->vsi_count--;
637462306a36Sopenharmony_ci	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
637562306a36Sopenharmony_ci	vsi_list_info = fm_list->vsi_list_info;
637662306a36Sopenharmony_ci	if (fm_list->vsi_count == 1) {
637762306a36Sopenharmony_ci		struct ice_fltr_info tmp_fltr;
637862306a36Sopenharmony_ci		u16 rem_vsi_handle;
637962306a36Sopenharmony_ci
638062306a36Sopenharmony_ci		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
638162306a36Sopenharmony_ci						ICE_MAX_VSI);
638262306a36Sopenharmony_ci		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
638362306a36Sopenharmony_ci			return -EIO;
638462306a36Sopenharmony_ci
638562306a36Sopenharmony_ci		/* Make sure VSI list is empty before removing it below */
638662306a36Sopenharmony_ci		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
638762306a36Sopenharmony_ci						  vsi_list_id, true,
638862306a36Sopenharmony_ci						  ice_aqc_opc_update_sw_rules,
638962306a36Sopenharmony_ci						  lkup_type);
639062306a36Sopenharmony_ci		if (status)
639162306a36Sopenharmony_ci			return status;
639262306a36Sopenharmony_ci
639362306a36Sopenharmony_ci		memset(&tmp_fltr, 0, sizeof(tmp_fltr));
639462306a36Sopenharmony_ci		tmp_fltr.flag = fm_list->rule_info.sw_act.flag;
639562306a36Sopenharmony_ci		tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id;
639662306a36Sopenharmony_ci		fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI;
639762306a36Sopenharmony_ci		tmp_fltr.fltr_act = ICE_FWD_TO_VSI;
639862306a36Sopenharmony_ci		tmp_fltr.fwd_id.hw_vsi_id =
639962306a36Sopenharmony_ci			ice_get_hw_vsi_num(hw, rem_vsi_handle);
640062306a36Sopenharmony_ci		fm_list->rule_info.sw_act.fwd_id.hw_vsi_id =
640162306a36Sopenharmony_ci			ice_get_hw_vsi_num(hw, rem_vsi_handle);
640262306a36Sopenharmony_ci		fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle;
640362306a36Sopenharmony_ci
640462306a36Sopenharmony_ci		/* Update the previous switch rule of "MAC forward to VSI" to
640562306a36Sopenharmony_ci		 * "MAC fwd to VSI list"
640662306a36Sopenharmony_ci		 */
640762306a36Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
640862306a36Sopenharmony_ci		if (status) {
640962306a36Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
641062306a36Sopenharmony_ci				  tmp_fltr.fwd_id.hw_vsi_id, status);
641162306a36Sopenharmony_ci			return status;
641262306a36Sopenharmony_ci		}
641362306a36Sopenharmony_ci		fm_list->vsi_list_info->ref_cnt--;
641462306a36Sopenharmony_ci
641562306a36Sopenharmony_ci		/* Remove the VSI list since it is no longer used */
641662306a36Sopenharmony_ci		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
641762306a36Sopenharmony_ci		if (status) {
641862306a36Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
641962306a36Sopenharmony_ci				  vsi_list_id, status);
642062306a36Sopenharmony_ci			return status;
642162306a36Sopenharmony_ci		}
642262306a36Sopenharmony_ci
642362306a36Sopenharmony_ci		list_del(&vsi_list_info->list_entry);
642462306a36Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
642562306a36Sopenharmony_ci		fm_list->vsi_list_info = NULL;
642662306a36Sopenharmony_ci	}
642762306a36Sopenharmony_ci
642862306a36Sopenharmony_ci	return status;
642962306a36Sopenharmony_ci}
643062306a36Sopenharmony_ci
643162306a36Sopenharmony_ci/**
643262306a36Sopenharmony_ci * ice_rem_adv_rule - removes existing advanced switch rule
643362306a36Sopenharmony_ci * @hw: pointer to the hardware structure
643462306a36Sopenharmony_ci * @lkups: information on the words that needs to be looked up. All words
643562306a36Sopenharmony_ci *         together makes one recipe
643662306a36Sopenharmony_ci * @lkups_cnt: num of entries in the lkups array
643762306a36Sopenharmony_ci * @rinfo: Its the pointer to the rule information for the rule
643862306a36Sopenharmony_ci *
643962306a36Sopenharmony_ci * This function can be used to remove 1 rule at a time. The lkups is
644062306a36Sopenharmony_ci * used to describe all the words that forms the "lookup" portion of the
644162306a36Sopenharmony_ci * rule. These words can span multiple protocols. Callers to this function
644262306a36Sopenharmony_ci * need to pass in a list of protocol headers with lookup information along
644362306a36Sopenharmony_ci * and mask that determines which words are valid from the given protocol
644462306a36Sopenharmony_ci * header. rinfo describes other information related to this rule such as
644562306a36Sopenharmony_ci * forwarding IDs, priority of this rule, etc.
644662306a36Sopenharmony_ci */
644762306a36Sopenharmony_cistatic int
644862306a36Sopenharmony_ciice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
644962306a36Sopenharmony_ci		 u16 lkups_cnt, struct ice_adv_rule_info *rinfo)
645062306a36Sopenharmony_ci{
645162306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *list_elem;
645262306a36Sopenharmony_ci	struct ice_prot_lkup_ext lkup_exts;
645362306a36Sopenharmony_ci	bool remove_rule = false;
645462306a36Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
645562306a36Sopenharmony_ci	u16 i, rid, vsi_handle;
645662306a36Sopenharmony_ci	int status = 0;
645762306a36Sopenharmony_ci
645862306a36Sopenharmony_ci	memset(&lkup_exts, 0, sizeof(lkup_exts));
645962306a36Sopenharmony_ci	for (i = 0; i < lkups_cnt; i++) {
646062306a36Sopenharmony_ci		u16 count;
646162306a36Sopenharmony_ci
646262306a36Sopenharmony_ci		if (lkups[i].type >= ICE_PROTOCOL_LAST)
646362306a36Sopenharmony_ci			return -EIO;
646462306a36Sopenharmony_ci
646562306a36Sopenharmony_ci		count = ice_fill_valid_words(&lkups[i], &lkup_exts);
646662306a36Sopenharmony_ci		if (!count)
646762306a36Sopenharmony_ci			return -EIO;
646862306a36Sopenharmony_ci	}
646962306a36Sopenharmony_ci
647062306a36Sopenharmony_ci	rid = ice_find_recp(hw, &lkup_exts, rinfo);
647162306a36Sopenharmony_ci	/* If did not find a recipe that match the existing criteria */
647262306a36Sopenharmony_ci	if (rid == ICE_MAX_NUM_RECIPES)
647362306a36Sopenharmony_ci		return -EINVAL;
647462306a36Sopenharmony_ci
647562306a36Sopenharmony_ci	rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock;
647662306a36Sopenharmony_ci	list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
647762306a36Sopenharmony_ci	/* the rule is already removed */
647862306a36Sopenharmony_ci	if (!list_elem)
647962306a36Sopenharmony_ci		return 0;
648062306a36Sopenharmony_ci	mutex_lock(rule_lock);
648162306a36Sopenharmony_ci	if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) {
648262306a36Sopenharmony_ci		remove_rule = true;
648362306a36Sopenharmony_ci	} else if (list_elem->vsi_count > 1) {
648462306a36Sopenharmony_ci		remove_rule = false;
648562306a36Sopenharmony_ci		vsi_handle = rinfo->sw_act.vsi_handle;
648662306a36Sopenharmony_ci		status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem);
648762306a36Sopenharmony_ci	} else {
648862306a36Sopenharmony_ci		vsi_handle = rinfo->sw_act.vsi_handle;
648962306a36Sopenharmony_ci		status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem);
649062306a36Sopenharmony_ci		if (status) {
649162306a36Sopenharmony_ci			mutex_unlock(rule_lock);
649262306a36Sopenharmony_ci			return status;
649362306a36Sopenharmony_ci		}
649462306a36Sopenharmony_ci		if (list_elem->vsi_count == 0)
649562306a36Sopenharmony_ci			remove_rule = true;
649662306a36Sopenharmony_ci	}
649762306a36Sopenharmony_ci	mutex_unlock(rule_lock);
649862306a36Sopenharmony_ci	if (remove_rule) {
649962306a36Sopenharmony_ci		struct ice_sw_rule_lkup_rx_tx *s_rule;
650062306a36Sopenharmony_ci		u16 rule_buf_sz;
650162306a36Sopenharmony_ci
650262306a36Sopenharmony_ci		rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule);
650362306a36Sopenharmony_ci		s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
650462306a36Sopenharmony_ci		if (!s_rule)
650562306a36Sopenharmony_ci			return -ENOMEM;
650662306a36Sopenharmony_ci		s_rule->act = 0;
650762306a36Sopenharmony_ci		s_rule->index = cpu_to_le16(list_elem->rule_info.fltr_rule_id);
650862306a36Sopenharmony_ci		s_rule->hdr_len = 0;
650962306a36Sopenharmony_ci		status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
651062306a36Sopenharmony_ci					 rule_buf_sz, 1,
651162306a36Sopenharmony_ci					 ice_aqc_opc_remove_sw_rules, NULL);
651262306a36Sopenharmony_ci		if (!status || status == -ENOENT) {
651362306a36Sopenharmony_ci			struct ice_switch_info *sw = hw->switch_info;
651462306a36Sopenharmony_ci
651562306a36Sopenharmony_ci			mutex_lock(rule_lock);
651662306a36Sopenharmony_ci			list_del(&list_elem->list_entry);
651762306a36Sopenharmony_ci			devm_kfree(ice_hw_to_dev(hw), list_elem->lkups);
651862306a36Sopenharmony_ci			devm_kfree(ice_hw_to_dev(hw), list_elem);
651962306a36Sopenharmony_ci			mutex_unlock(rule_lock);
652062306a36Sopenharmony_ci			if (list_empty(&sw->recp_list[rid].filt_rules))
652162306a36Sopenharmony_ci				sw->recp_list[rid].adv_rule = false;
652262306a36Sopenharmony_ci		}
652362306a36Sopenharmony_ci		kfree(s_rule);
652462306a36Sopenharmony_ci	}
652562306a36Sopenharmony_ci	return status;
652662306a36Sopenharmony_ci}
652762306a36Sopenharmony_ci
652862306a36Sopenharmony_ci/**
652962306a36Sopenharmony_ci * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID
653062306a36Sopenharmony_ci * @hw: pointer to the hardware structure
653162306a36Sopenharmony_ci * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID
653262306a36Sopenharmony_ci *
653362306a36Sopenharmony_ci * This function is used to remove 1 rule at a time. The removal is based on
653462306a36Sopenharmony_ci * the remove_entry parameter. This function will remove rule for a given
653562306a36Sopenharmony_ci * vsi_handle with a given rule_id which is passed as parameter in remove_entry
653662306a36Sopenharmony_ci */
653762306a36Sopenharmony_ciint
653862306a36Sopenharmony_ciice_rem_adv_rule_by_id(struct ice_hw *hw,
653962306a36Sopenharmony_ci		       struct ice_rule_query_data *remove_entry)
654062306a36Sopenharmony_ci{
654162306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *list_itr;
654262306a36Sopenharmony_ci	struct list_head *list_head;
654362306a36Sopenharmony_ci	struct ice_adv_rule_info rinfo;
654462306a36Sopenharmony_ci	struct ice_switch_info *sw;
654562306a36Sopenharmony_ci
654662306a36Sopenharmony_ci	sw = hw->switch_info;
654762306a36Sopenharmony_ci	if (!sw->recp_list[remove_entry->rid].recp_created)
654862306a36Sopenharmony_ci		return -EINVAL;
654962306a36Sopenharmony_ci	list_head = &sw->recp_list[remove_entry->rid].filt_rules;
655062306a36Sopenharmony_ci	list_for_each_entry(list_itr, list_head, list_entry) {
655162306a36Sopenharmony_ci		if (list_itr->rule_info.fltr_rule_id ==
655262306a36Sopenharmony_ci		    remove_entry->rule_id) {
655362306a36Sopenharmony_ci			rinfo = list_itr->rule_info;
655462306a36Sopenharmony_ci			rinfo.sw_act.vsi_handle = remove_entry->vsi_handle;
655562306a36Sopenharmony_ci			return ice_rem_adv_rule(hw, list_itr->lkups,
655662306a36Sopenharmony_ci						list_itr->lkups_cnt, &rinfo);
655762306a36Sopenharmony_ci		}
655862306a36Sopenharmony_ci	}
655962306a36Sopenharmony_ci	/* either list is empty or unable to find rule */
656062306a36Sopenharmony_ci	return -ENOENT;
656162306a36Sopenharmony_ci}
656262306a36Sopenharmony_ci
656362306a36Sopenharmony_ci/**
656462306a36Sopenharmony_ci * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI
656562306a36Sopenharmony_ci * @hw: pointer to the hardware structure
656662306a36Sopenharmony_ci * @vsi_handle: driver VSI handle
656762306a36Sopenharmony_ci * @list_head: list for which filters need to be replayed
656862306a36Sopenharmony_ci *
656962306a36Sopenharmony_ci * Replay the advanced rule for the given VSI.
657062306a36Sopenharmony_ci */
657162306a36Sopenharmony_cistatic int
657262306a36Sopenharmony_ciice_replay_vsi_adv_rule(struct ice_hw *hw, u16 vsi_handle,
657362306a36Sopenharmony_ci			struct list_head *list_head)
657462306a36Sopenharmony_ci{
657562306a36Sopenharmony_ci	struct ice_rule_query_data added_entry = { 0 };
657662306a36Sopenharmony_ci	struct ice_adv_fltr_mgmt_list_entry *adv_fltr;
657762306a36Sopenharmony_ci	int status = 0;
657862306a36Sopenharmony_ci
657962306a36Sopenharmony_ci	if (list_empty(list_head))
658062306a36Sopenharmony_ci		return status;
658162306a36Sopenharmony_ci	list_for_each_entry(adv_fltr, list_head, list_entry) {
658262306a36Sopenharmony_ci		struct ice_adv_rule_info *rinfo = &adv_fltr->rule_info;
658362306a36Sopenharmony_ci		u16 lk_cnt = adv_fltr->lkups_cnt;
658462306a36Sopenharmony_ci
658562306a36Sopenharmony_ci		if (vsi_handle != rinfo->sw_act.vsi_handle)
658662306a36Sopenharmony_ci			continue;
658762306a36Sopenharmony_ci		status = ice_add_adv_rule(hw, adv_fltr->lkups, lk_cnt, rinfo,
658862306a36Sopenharmony_ci					  &added_entry);
658962306a36Sopenharmony_ci		if (status)
659062306a36Sopenharmony_ci			break;
659162306a36Sopenharmony_ci	}
659262306a36Sopenharmony_ci	return status;
659362306a36Sopenharmony_ci}
659462306a36Sopenharmony_ci
659562306a36Sopenharmony_ci/**
659662306a36Sopenharmony_ci * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists
659762306a36Sopenharmony_ci * @hw: pointer to the hardware structure
659862306a36Sopenharmony_ci * @vsi_handle: driver VSI handle
659962306a36Sopenharmony_ci *
660062306a36Sopenharmony_ci * Replays filters for requested VSI via vsi_handle.
660162306a36Sopenharmony_ci */
660262306a36Sopenharmony_ciint ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle)
660362306a36Sopenharmony_ci{
660462306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
660562306a36Sopenharmony_ci	int status;
660662306a36Sopenharmony_ci	u8 i;
660762306a36Sopenharmony_ci
660862306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
660962306a36Sopenharmony_ci		struct list_head *head;
661062306a36Sopenharmony_ci
661162306a36Sopenharmony_ci		head = &sw->recp_list[i].filt_replay_rules;
661262306a36Sopenharmony_ci		if (!sw->recp_list[i].adv_rule)
661362306a36Sopenharmony_ci			status = ice_replay_vsi_fltr(hw, vsi_handle, i, head);
661462306a36Sopenharmony_ci		else
661562306a36Sopenharmony_ci			status = ice_replay_vsi_adv_rule(hw, vsi_handle, head);
661662306a36Sopenharmony_ci		if (status)
661762306a36Sopenharmony_ci			return status;
661862306a36Sopenharmony_ci	}
661962306a36Sopenharmony_ci	return status;
662062306a36Sopenharmony_ci}
662162306a36Sopenharmony_ci
662262306a36Sopenharmony_ci/**
662362306a36Sopenharmony_ci * ice_rm_all_sw_replay_rule_info - deletes filter replay rules
662462306a36Sopenharmony_ci * @hw: pointer to the HW struct
662562306a36Sopenharmony_ci *
662662306a36Sopenharmony_ci * Deletes the filter replay rules.
662762306a36Sopenharmony_ci */
662862306a36Sopenharmony_civoid ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)
662962306a36Sopenharmony_ci{
663062306a36Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
663162306a36Sopenharmony_ci	u8 i;
663262306a36Sopenharmony_ci
663362306a36Sopenharmony_ci	if (!sw)
663462306a36Sopenharmony_ci		return;
663562306a36Sopenharmony_ci
663662306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
663762306a36Sopenharmony_ci		if (!list_empty(&sw->recp_list[i].filt_replay_rules)) {
663862306a36Sopenharmony_ci			struct list_head *l_head;
663962306a36Sopenharmony_ci
664062306a36Sopenharmony_ci			l_head = &sw->recp_list[i].filt_replay_rules;
664162306a36Sopenharmony_ci			if (!sw->recp_list[i].adv_rule)
664262306a36Sopenharmony_ci				ice_rem_sw_rule_info(hw, l_head);
664362306a36Sopenharmony_ci			else
664462306a36Sopenharmony_ci				ice_rem_adv_rule_info(hw, l_head);
664562306a36Sopenharmony_ci		}
664662306a36Sopenharmony_ci	}
664762306a36Sopenharmony_ci}
6648