19c20346bSAnirudh Venkataramanan // SPDX-License-Identifier: GPL-2.0
29c20346bSAnirudh Venkataramanan /* Copyright (c) 2018, Intel Corporation. */
39c20346bSAnirudh Venkataramanan 
4348048e7SDave Ertman #include "ice_lib.h"
59c20346bSAnirudh Venkataramanan #include "ice_switch.h"
69c20346bSAnirudh Venkataramanan 
79daf8208SAnirudh Venkataramanan #define ICE_ETH_DA_OFFSET		0
89daf8208SAnirudh Venkataramanan #define ICE_ETH_ETHTYPE_OFFSET		12
99daf8208SAnirudh Venkataramanan #define ICE_ETH_VLAN_TCI_OFFSET		14
109daf8208SAnirudh Venkataramanan #define ICE_MAX_VLAN_ID			0xFFF
110f94570dSGrishma Kotecha #define ICE_IPV6_ETHER_ID		0x86DD
129daf8208SAnirudh Venkataramanan 
139daf8208SAnirudh Venkataramanan /* Dummy ethernet header needed in the ice_aqc_sw_rules_elem
149daf8208SAnirudh Venkataramanan  * struct to configure any switch filter rules.
159daf8208SAnirudh Venkataramanan  * {DA (6 bytes), SA(6 bytes),
169daf8208SAnirudh Venkataramanan  * Ether type (2 bytes for header without VLAN tag) OR
179daf8208SAnirudh Venkataramanan  * VLAN tag (4 bytes for header with VLAN tag) }
189daf8208SAnirudh Venkataramanan  *
199daf8208SAnirudh Venkataramanan  * Word on Hardcoded values
209daf8208SAnirudh Venkataramanan  * byte 0 = 0x2: to identify it as locally administered DA MAC
219daf8208SAnirudh Venkataramanan  * byte 6 = 0x2: to identify it as locally administered SA MAC
229daf8208SAnirudh Venkataramanan  * byte 12 = 0x81 & byte 13 = 0x00:
239daf8208SAnirudh Venkataramanan  *	In case of VLAN filter first two bytes defines ether type (0x8100)
24f9867df6SAnirudh Venkataramanan  *	and remaining two bytes are placeholder for programming a given VLAN ID
259daf8208SAnirudh Venkataramanan  *	In case of Ether type filter it is treated as header without VLAN tag
269daf8208SAnirudh Venkataramanan  *	and byte 12 and 13 is used to program a given Ether type instead
279daf8208SAnirudh Venkataramanan  */
289daf8208SAnirudh Venkataramanan #define DUMMY_ETH_HDR_LEN		16
299daf8208SAnirudh Venkataramanan static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
309daf8208SAnirudh Venkataramanan 							0x2, 0, 0, 0, 0, 0,
319daf8208SAnirudh Venkataramanan 							0x81, 0, 0, 0};
329daf8208SAnirudh Venkataramanan 
330f94570dSGrishma Kotecha struct ice_dummy_pkt_offsets {
340f94570dSGrishma Kotecha 	enum ice_protocol_type type;
350f94570dSGrishma Kotecha 	u16 offset; /* ICE_PROTOCOL_LAST indicates end of list */
360f94570dSGrishma Kotecha };
370f94570dSGrishma Kotecha 
38f0a35040SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_gre_tcp_packet_offsets[] = {
39f0a35040SMichal Swiatkowski 	{ ICE_MAC_OFOS,		0 },
40f0a35040SMichal Swiatkowski 	{ ICE_ETYPE_OL,		12 },
41f0a35040SMichal Swiatkowski 	{ ICE_IPV4_OFOS,	14 },
42f0a35040SMichal Swiatkowski 	{ ICE_NVGRE,		34 },
43f0a35040SMichal Swiatkowski 	{ ICE_MAC_IL,		42 },
44f0a35040SMichal Swiatkowski 	{ ICE_IPV4_IL,		56 },
45f0a35040SMichal Swiatkowski 	{ ICE_TCP_IL,		76 },
46f0a35040SMichal Swiatkowski 	{ ICE_PROTOCOL_LAST,	0 },
47f0a35040SMichal Swiatkowski };
48f0a35040SMichal Swiatkowski 
49f0a35040SMichal Swiatkowski static const u8 dummy_gre_tcp_packet[] = {
50f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_OFOS 0 */
51f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
52f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
53f0a35040SMichal Swiatkowski 
54f0a35040SMichal Swiatkowski 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
55f0a35040SMichal Swiatkowski 
56f0a35040SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x3E,	/* ICE_IPV4_OFOS 14 */
57f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
58f0a35040SMichal Swiatkowski 	0x00, 0x2F, 0x00, 0x00,
59f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
60f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
61f0a35040SMichal Swiatkowski 
62f0a35040SMichal Swiatkowski 	0x80, 0x00, 0x65, 0x58,	/* ICE_NVGRE 34 */
63f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
64f0a35040SMichal Swiatkowski 
65f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_IL 42 */
66f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
67f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
68f0a35040SMichal Swiatkowski 	0x08, 0x00,
69f0a35040SMichal Swiatkowski 
70f0a35040SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x14,	/* ICE_IPV4_IL 56 */
71f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
72f0a35040SMichal Swiatkowski 	0x00, 0x06, 0x00, 0x00,
73f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
74f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
75f0a35040SMichal Swiatkowski 
76f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,	/* ICE_TCP_IL 76 */
77f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
78f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
79f0a35040SMichal Swiatkowski 	0x50, 0x02, 0x20, 0x00,
80f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00
81f0a35040SMichal Swiatkowski };
82f0a35040SMichal Swiatkowski 
83f0a35040SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_gre_udp_packet_offsets[] = {
84f0a35040SMichal Swiatkowski 	{ ICE_MAC_OFOS,		0 },
85f0a35040SMichal Swiatkowski 	{ ICE_ETYPE_OL,		12 },
86f0a35040SMichal Swiatkowski 	{ ICE_IPV4_OFOS,	14 },
87f0a35040SMichal Swiatkowski 	{ ICE_NVGRE,		34 },
88f0a35040SMichal Swiatkowski 	{ ICE_MAC_IL,		42 },
89f0a35040SMichal Swiatkowski 	{ ICE_IPV4_IL,		56 },
90f0a35040SMichal Swiatkowski 	{ ICE_UDP_ILOS,		76 },
91f0a35040SMichal Swiatkowski 	{ ICE_PROTOCOL_LAST,	0 },
92f0a35040SMichal Swiatkowski };
93f0a35040SMichal Swiatkowski 
94f0a35040SMichal Swiatkowski static const u8 dummy_gre_udp_packet[] = {
95f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_OFOS 0 */
96f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
97f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
98f0a35040SMichal Swiatkowski 
99f0a35040SMichal Swiatkowski 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
100f0a35040SMichal Swiatkowski 
101f0a35040SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x3E,	/* ICE_IPV4_OFOS 14 */
102f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
103f0a35040SMichal Swiatkowski 	0x00, 0x2F, 0x00, 0x00,
104f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
105f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
106f0a35040SMichal Swiatkowski 
107f0a35040SMichal Swiatkowski 	0x80, 0x00, 0x65, 0x58,	/* ICE_NVGRE 34 */
108f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
109f0a35040SMichal Swiatkowski 
110f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,	/* ICE_MAC_IL 42 */
111f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
112f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
113f0a35040SMichal Swiatkowski 	0x08, 0x00,
114f0a35040SMichal Swiatkowski 
115f0a35040SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x14,	/* ICE_IPV4_IL 56 */
116f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
117f0a35040SMichal Swiatkowski 	0x00, 0x11, 0x00, 0x00,
118f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
119f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
120f0a35040SMichal Swiatkowski 
121f0a35040SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,	/* ICE_UDP_ILOS 76 */
122f0a35040SMichal Swiatkowski 	0x00, 0x08, 0x00, 0x00,
123f0a35040SMichal Swiatkowski };
124f0a35040SMichal Swiatkowski 
1258b032a55SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_udp_tun_tcp_packet_offsets[] = {
1268b032a55SMichal Swiatkowski 	{ ICE_MAC_OFOS,		0 },
1278b032a55SMichal Swiatkowski 	{ ICE_ETYPE_OL,		12 },
1288b032a55SMichal Swiatkowski 	{ ICE_IPV4_OFOS,	14 },
1298b032a55SMichal Swiatkowski 	{ ICE_UDP_OF,		34 },
1308b032a55SMichal Swiatkowski 	{ ICE_VXLAN,		42 },
1318b032a55SMichal Swiatkowski 	{ ICE_GENEVE,		42 },
1328b032a55SMichal Swiatkowski 	{ ICE_VXLAN_GPE,	42 },
1338b032a55SMichal Swiatkowski 	{ ICE_MAC_IL,		50 },
1348b032a55SMichal Swiatkowski 	{ ICE_IPV4_IL,		64 },
1358b032a55SMichal Swiatkowski 	{ ICE_TCP_IL,		84 },
1368b032a55SMichal Swiatkowski 	{ ICE_PROTOCOL_LAST,	0 },
1378b032a55SMichal Swiatkowski };
1388b032a55SMichal Swiatkowski 
1398b032a55SMichal Swiatkowski static const u8 dummy_udp_tun_tcp_packet[] = {
1408b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
1418b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1428b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1438b032a55SMichal Swiatkowski 
1448b032a55SMichal Swiatkowski 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
1458b032a55SMichal Swiatkowski 
1468b032a55SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */
1478b032a55SMichal Swiatkowski 	0x00, 0x01, 0x00, 0x00,
1488b032a55SMichal Swiatkowski 	0x40, 0x11, 0x00, 0x00,
1498b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1508b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1518b032a55SMichal Swiatkowski 
1528b032a55SMichal Swiatkowski 	0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
1538b032a55SMichal Swiatkowski 	0x00, 0x46, 0x00, 0x00,
1548b032a55SMichal Swiatkowski 
1558b032a55SMichal Swiatkowski 	0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
1568b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1578b032a55SMichal Swiatkowski 
1588b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
1598b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1608b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1618b032a55SMichal Swiatkowski 	0x08, 0x00,
1628b032a55SMichal Swiatkowski 
1638b032a55SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_IL 64 */
1648b032a55SMichal Swiatkowski 	0x00, 0x01, 0x00, 0x00,
1658b032a55SMichal Swiatkowski 	0x40, 0x06, 0x00, 0x00,
1668b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1678b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1688b032a55SMichal Swiatkowski 
1698b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 84 */
1708b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1718b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1728b032a55SMichal Swiatkowski 	0x50, 0x02, 0x20, 0x00,
1738b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00
1748b032a55SMichal Swiatkowski };
1758b032a55SMichal Swiatkowski 
1768b032a55SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_udp_tun_udp_packet_offsets[] = {
1778b032a55SMichal Swiatkowski 	{ ICE_MAC_OFOS,		0 },
1788b032a55SMichal Swiatkowski 	{ ICE_ETYPE_OL,		12 },
1798b032a55SMichal Swiatkowski 	{ ICE_IPV4_OFOS,	14 },
1808b032a55SMichal Swiatkowski 	{ ICE_UDP_OF,		34 },
1818b032a55SMichal Swiatkowski 	{ ICE_VXLAN,		42 },
1828b032a55SMichal Swiatkowski 	{ ICE_GENEVE,		42 },
1838b032a55SMichal Swiatkowski 	{ ICE_VXLAN_GPE,	42 },
1848b032a55SMichal Swiatkowski 	{ ICE_MAC_IL,		50 },
1858b032a55SMichal Swiatkowski 	{ ICE_IPV4_IL,		64 },
1868b032a55SMichal Swiatkowski 	{ ICE_UDP_ILOS,		84 },
1878b032a55SMichal Swiatkowski 	{ ICE_PROTOCOL_LAST,	0 },
1888b032a55SMichal Swiatkowski };
1898b032a55SMichal Swiatkowski 
1908b032a55SMichal Swiatkowski static const u8 dummy_udp_tun_udp_packet[] = {
1918b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
1928b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1938b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
1948b032a55SMichal Swiatkowski 
1958b032a55SMichal Swiatkowski 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
1968b032a55SMichal Swiatkowski 
1978b032a55SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x4e, /* ICE_IPV4_OFOS 14 */
1988b032a55SMichal Swiatkowski 	0x00, 0x01, 0x00, 0x00,
1998b032a55SMichal Swiatkowski 	0x00, 0x11, 0x00, 0x00,
2008b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2018b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2028b032a55SMichal Swiatkowski 
2038b032a55SMichal Swiatkowski 	0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
2048b032a55SMichal Swiatkowski 	0x00, 0x3a, 0x00, 0x00,
2058b032a55SMichal Swiatkowski 
2068b032a55SMichal Swiatkowski 	0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
2078b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2088b032a55SMichal Swiatkowski 
2098b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
2108b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2118b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2128b032a55SMichal Swiatkowski 	0x08, 0x00,
2138b032a55SMichal Swiatkowski 
2148b032a55SMichal Swiatkowski 	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_IL 64 */
2158b032a55SMichal Swiatkowski 	0x00, 0x01, 0x00, 0x00,
2168b032a55SMichal Swiatkowski 	0x00, 0x11, 0x00, 0x00,
2178b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2188b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00,
2198b032a55SMichal Swiatkowski 
2208b032a55SMichal Swiatkowski 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 84 */
2218b032a55SMichal Swiatkowski 	0x00, 0x08, 0x00, 0x00,
2228b032a55SMichal Swiatkowski };
2238b032a55SMichal Swiatkowski 
2240f94570dSGrishma Kotecha /* offset info for MAC + IPv4 + UDP dummy packet */
2250f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_udp_packet_offsets[] = {
2260f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
2270f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
2280f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	14 },
2290f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		34 },
2300f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
2310f94570dSGrishma Kotecha };
2320f94570dSGrishma Kotecha 
2330f94570dSGrishma Kotecha /* Dummy packet for MAC + IPv4 + UDP */
2340f94570dSGrishma Kotecha static const u8 dummy_udp_packet[] = {
2350f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
2360f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2370f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2380f94570dSGrishma Kotecha 
2390f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
2400f94570dSGrishma Kotecha 
2410f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 14 */
2420f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
2430f94570dSGrishma Kotecha 	0x00, 0x11, 0x00, 0x00,
2440f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2450f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2460f94570dSGrishma Kotecha 
2470f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 34 */
2480f94570dSGrishma Kotecha 	0x00, 0x08, 0x00, 0x00,
2490f94570dSGrishma Kotecha 
2500f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
2510f94570dSGrishma Kotecha };
2520f94570dSGrishma Kotecha 
2530f94570dSGrishma Kotecha /* offset info for MAC + VLAN + IPv4 + UDP dummy packet */
2540f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_vlan_udp_packet_offsets[] = {
2550f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
2560f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
2570f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
2580f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	18 },
2590f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		38 },
2600f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
2610f94570dSGrishma Kotecha };
2620f94570dSGrishma Kotecha 
2630f94570dSGrishma Kotecha /* C-tag (801.1Q), IPv4:UDP dummy packet */
2640f94570dSGrishma Kotecha static const u8 dummy_vlan_udp_packet[] = {
2650f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
2660f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2670f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2680f94570dSGrishma Kotecha 
2690f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
2700f94570dSGrishma Kotecha 
2710f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 16 */
2720f94570dSGrishma Kotecha 
2730f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 18 */
2740f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
2750f94570dSGrishma Kotecha 	0x00, 0x11, 0x00, 0x00,
2760f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2770f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2780f94570dSGrishma Kotecha 
2790f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 38 */
2800f94570dSGrishma Kotecha 	0x00, 0x08, 0x00, 0x00,
2810f94570dSGrishma Kotecha 
2820f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
2830f94570dSGrishma Kotecha };
2840f94570dSGrishma Kotecha 
2850f94570dSGrishma Kotecha /* offset info for MAC + IPv4 + TCP dummy packet */
2860f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_tcp_packet_offsets[] = {
2870f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
2880f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
2890f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	14 },
2900f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		34 },
2910f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
2920f94570dSGrishma Kotecha };
2930f94570dSGrishma Kotecha 
2940f94570dSGrishma Kotecha /* Dummy packet for MAC + IPv4 + TCP */
2950f94570dSGrishma Kotecha static const u8 dummy_tcp_packet[] = {
2960f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
2970f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2980f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2990f94570dSGrishma Kotecha 
3000f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
3010f94570dSGrishma Kotecha 
3020f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 14 */
3030f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
3040f94570dSGrishma Kotecha 	0x00, 0x06, 0x00, 0x00,
3050f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3060f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3070f94570dSGrishma Kotecha 
3080f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 34 */
3090f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3100f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3110f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
3120f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3130f94570dSGrishma Kotecha 
3140f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
3150f94570dSGrishma Kotecha };
3160f94570dSGrishma Kotecha 
3170f94570dSGrishma Kotecha /* offset info for MAC + VLAN (C-tag, 802.1Q) + IPv4 + TCP dummy packet */
3180f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_vlan_tcp_packet_offsets[] = {
3190f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
3200f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
3210f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
3220f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	18 },
3230f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		38 },
3240f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
3250f94570dSGrishma Kotecha };
3260f94570dSGrishma Kotecha 
3270f94570dSGrishma Kotecha /* C-tag (801.1Q), IPv4:TCP dummy packet */
3280f94570dSGrishma Kotecha static const u8 dummy_vlan_tcp_packet[] = {
3290f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
3300f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3310f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3320f94570dSGrishma Kotecha 
3330f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00,	/* ICE_VLAN_OFOS 12 */
3340f94570dSGrishma Kotecha 
3350f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 16 */
3360f94570dSGrishma Kotecha 
3370f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 18 */
3380f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
3390f94570dSGrishma Kotecha 	0x00, 0x06, 0x00, 0x00,
3400f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3410f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3420f94570dSGrishma Kotecha 
3430f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 38 */
3440f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3450f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3460f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
3470f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3480f94570dSGrishma Kotecha 
3490f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
3500f94570dSGrishma Kotecha };
3510f94570dSGrishma Kotecha 
3520f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_tcp_ipv6_packet_offsets[] = {
3530f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
3540f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
3550f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	14 },
3560f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		54 },
3570f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
3580f94570dSGrishma Kotecha };
3590f94570dSGrishma Kotecha 
3600f94570dSGrishma Kotecha static const u8 dummy_tcp_ipv6_packet[] = {
3610f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
3620f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3630f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3640f94570dSGrishma Kotecha 
3650f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
3660f94570dSGrishma Kotecha 
3670f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */
3680f94570dSGrishma Kotecha 	0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
3690f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3700f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3710f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3720f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3730f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3740f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3750f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3760f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3770f94570dSGrishma Kotecha 
3780f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 54 */
3790f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3800f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3810f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
3820f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3830f94570dSGrishma Kotecha 
3840f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
3850f94570dSGrishma Kotecha };
3860f94570dSGrishma Kotecha 
3870f94570dSGrishma Kotecha /* C-tag (802.1Q): IPv6 + TCP */
3880f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets
3890f94570dSGrishma Kotecha dummy_vlan_tcp_ipv6_packet_offsets[] = {
3900f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
3910f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
3920f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
3930f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	18 },
3940f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		58 },
3950f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
3960f94570dSGrishma Kotecha };
3970f94570dSGrishma Kotecha 
3980f94570dSGrishma Kotecha /* C-tag (802.1Q), IPv6 + TCP dummy packet */
3990f94570dSGrishma Kotecha static const u8 dummy_vlan_tcp_ipv6_packet[] = {
4000f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
4010f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4020f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4030f94570dSGrishma Kotecha 
4040f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00,	/* ICE_VLAN_OFOS 12 */
4050f94570dSGrishma Kotecha 
4060f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 16 */
4070f94570dSGrishma Kotecha 
4080f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */
4090f94570dSGrishma Kotecha 	0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
4100f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4110f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4120f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4130f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4140f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4150f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4160f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4170f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4180f94570dSGrishma Kotecha 
4190f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 58 */
4200f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4210f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4220f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
4230f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4240f94570dSGrishma Kotecha 
4250f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
4260f94570dSGrishma Kotecha };
4270f94570dSGrishma Kotecha 
4280f94570dSGrishma Kotecha /* IPv6 + UDP */
4290f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_udp_ipv6_packet_offsets[] = {
4300f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
4310f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
4320f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	14 },
4330f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		54 },
4340f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
4350f94570dSGrishma Kotecha };
4360f94570dSGrishma Kotecha 
4370f94570dSGrishma Kotecha /* IPv6 + UDP dummy packet */
4380f94570dSGrishma Kotecha static const u8 dummy_udp_ipv6_packet[] = {
4390f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
4400f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4410f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4420f94570dSGrishma Kotecha 
4430f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
4440f94570dSGrishma Kotecha 
4450f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */
4460f94570dSGrishma Kotecha 	0x00, 0x10, 0x11, 0x00, /* Next header UDP */
4470f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4480f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4490f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4500f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4510f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4520f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4530f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4540f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4550f94570dSGrishma Kotecha 
4560f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 54 */
4570f94570dSGrishma Kotecha 	0x00, 0x10, 0x00, 0x00,
4580f94570dSGrishma Kotecha 
4590f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* needed for ESP packets */
4600f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4610f94570dSGrishma Kotecha 
4620f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
4630f94570dSGrishma Kotecha };
4640f94570dSGrishma Kotecha 
4650f94570dSGrishma Kotecha /* C-tag (802.1Q): IPv6 + UDP */
4660f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets
4670f94570dSGrishma Kotecha dummy_vlan_udp_ipv6_packet_offsets[] = {
4680f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
4690f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
4700f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
4710f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	18 },
4720f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		58 },
4730f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
4740f94570dSGrishma Kotecha };
4750f94570dSGrishma Kotecha 
4760f94570dSGrishma Kotecha /* C-tag (802.1Q), IPv6 + UDP dummy packet */
4770f94570dSGrishma Kotecha static const u8 dummy_vlan_udp_ipv6_packet[] = {
4780f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
4790f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4800f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4810f94570dSGrishma Kotecha 
4820f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00,/* ICE_VLAN_OFOS 12 */
4830f94570dSGrishma Kotecha 
4840f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 16 */
4850f94570dSGrishma Kotecha 
4860f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */
4870f94570dSGrishma Kotecha 	0x00, 0x08, 0x11, 0x00, /* Next header UDP */
4880f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4890f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4900f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4910f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4920f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4930f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4940f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4950f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
4960f94570dSGrishma Kotecha 
4970f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 58 */
4980f94570dSGrishma Kotecha 	0x00, 0x08, 0x00, 0x00,
4990f94570dSGrishma Kotecha 
5000f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
5010f94570dSGrishma Kotecha };
5020f94570dSGrishma Kotecha 
5039daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE \
50466486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr) + \
50566486d89SBruce Allan 	 (DUMMY_ETH_HDR_LEN * \
50666486d89SBruce Allan 	  sizeof(((struct ice_sw_rule_lkup_rx_tx *)0)->hdr[0])))
5079daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_RX_TX_NO_HDR_SIZE \
50866486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr))
5099daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_LG_ACT_SIZE(n) \
51066486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lg_act.act) + \
51166486d89SBruce Allan 	 ((n) * sizeof(((struct ice_sw_rule_lg_act *)0)->act[0])))
5129daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_VSI_LIST_SIZE(n) \
51366486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.vsi_list.vsi) + \
51466486d89SBruce Allan 	 ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi[0])))
5159daf8208SAnirudh Venkataramanan 
516fd2a6b71SDan Nowlin /* this is a recipe to profile association bitmap */
517fd2a6b71SDan Nowlin static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES],
518fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_PROFILES);
519fd2a6b71SDan Nowlin 
520fd2a6b71SDan Nowlin /* this is a profile to recipe association bitmap */
521fd2a6b71SDan Nowlin static DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES],
522fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_RECIPES);
523fd2a6b71SDan Nowlin 
5249daf8208SAnirudh Venkataramanan /**
52580d144c9SAnirudh Venkataramanan  * ice_init_def_sw_recp - initialize the recipe book keeping tables
526f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
52780d144c9SAnirudh Venkataramanan  *
52880d144c9SAnirudh Venkataramanan  * Allocate memory for the entire recipe table and initialize the structures/
52980d144c9SAnirudh Venkataramanan  * entries corresponding to basic recipes.
53080d144c9SAnirudh Venkataramanan  */
5315e24d598STony Nguyen int ice_init_def_sw_recp(struct ice_hw *hw)
53280d144c9SAnirudh Venkataramanan {
53380d144c9SAnirudh Venkataramanan 	struct ice_sw_recipe *recps;
53480d144c9SAnirudh Venkataramanan 	u8 i;
53580d144c9SAnirudh Venkataramanan 
53680d144c9SAnirudh Venkataramanan 	recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES,
537c6dfd690SBruce Allan 			     sizeof(*recps), GFP_KERNEL);
53880d144c9SAnirudh Venkataramanan 	if (!recps)
539d54699e2STony Nguyen 		return -ENOMEM;
54080d144c9SAnirudh Venkataramanan 
541450052a4SDan Nowlin 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
54280d144c9SAnirudh Venkataramanan 		recps[i].root_rid = i;
54380d144c9SAnirudh Venkataramanan 		INIT_LIST_HEAD(&recps[i].filt_rules);
544334cb062SAnirudh Venkataramanan 		INIT_LIST_HEAD(&recps[i].filt_replay_rules);
545450052a4SDan Nowlin 		INIT_LIST_HEAD(&recps[i].rg_list);
54680d144c9SAnirudh Venkataramanan 		mutex_init(&recps[i].filt_rule_lock);
54780d144c9SAnirudh Venkataramanan 	}
54880d144c9SAnirudh Venkataramanan 
54980d144c9SAnirudh Venkataramanan 	hw->switch_info->recp_list = recps;
55080d144c9SAnirudh Venkataramanan 
55180d144c9SAnirudh Venkataramanan 	return 0;
55280d144c9SAnirudh Venkataramanan }
55380d144c9SAnirudh Venkataramanan 
55480d144c9SAnirudh Venkataramanan /**
5559c20346bSAnirudh Venkataramanan  * ice_aq_get_sw_cfg - get switch configuration
5569c20346bSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
5579c20346bSAnirudh Venkataramanan  * @buf: pointer to the result buffer
5589c20346bSAnirudh Venkataramanan  * @buf_size: length of the buffer available for response
5599c20346bSAnirudh Venkataramanan  * @req_desc: pointer to requested descriptor
5609c20346bSAnirudh Venkataramanan  * @num_elems: pointer to number of elements
5619c20346bSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
5629c20346bSAnirudh Venkataramanan  *
563b3c38904SBruce Allan  * Get switch configuration (0x0200) to be placed in buf.
5649c20346bSAnirudh Venkataramanan  * This admin command returns information such as initial VSI/port number
5659c20346bSAnirudh Venkataramanan  * and switch ID it belongs to.
5669c20346bSAnirudh Venkataramanan  *
5679c20346bSAnirudh Venkataramanan  * NOTE: *req_desc is both an input/output parameter.
5689c20346bSAnirudh Venkataramanan  * The caller of this function first calls this function with *request_desc set
5699c20346bSAnirudh Venkataramanan  * to 0. If the response from f/w has *req_desc set to 0, all the switch
5709c20346bSAnirudh Venkataramanan  * configuration information has been returned; if non-zero (meaning not all
5719c20346bSAnirudh Venkataramanan  * the information was returned), the caller should call this function again
5729c20346bSAnirudh Venkataramanan  * with *req_desc set to the previous value returned by f/w to get the
5739c20346bSAnirudh Venkataramanan  * next block of switch configuration information.
5749c20346bSAnirudh Venkataramanan  *
5759c20346bSAnirudh Venkataramanan  * *num_elems is output only parameter. This reflects the number of elements
5769c20346bSAnirudh Venkataramanan  * in response buffer. The caller of this function to use *num_elems while
5779c20346bSAnirudh Venkataramanan  * parsing the response buffer.
5789c20346bSAnirudh Venkataramanan  */
5795e24d598STony Nguyen static int
580b3c38904SBruce Allan ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf,
5819c20346bSAnirudh Venkataramanan 		  u16 buf_size, u16 *req_desc, u16 *num_elems,
5829c20346bSAnirudh Venkataramanan 		  struct ice_sq_cd *cd)
5839c20346bSAnirudh Venkataramanan {
5849c20346bSAnirudh Venkataramanan 	struct ice_aqc_get_sw_cfg *cmd;
5859c20346bSAnirudh Venkataramanan 	struct ice_aq_desc desc;
5865e24d598STony Nguyen 	int status;
5879c20346bSAnirudh Venkataramanan 
5889c20346bSAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);
5899c20346bSAnirudh Venkataramanan 	cmd = &desc.params.get_sw_conf;
5909c20346bSAnirudh Venkataramanan 	cmd->element = cpu_to_le16(*req_desc);
5919c20346bSAnirudh Venkataramanan 
5929c20346bSAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
5939c20346bSAnirudh Venkataramanan 	if (!status) {
5949c20346bSAnirudh Venkataramanan 		*req_desc = le16_to_cpu(cmd->element);
5959c20346bSAnirudh Venkataramanan 		*num_elems = le16_to_cpu(cmd->num_elems);
5969c20346bSAnirudh Venkataramanan 	}
5979c20346bSAnirudh Venkataramanan 
5989c20346bSAnirudh Venkataramanan 	return status;
5999c20346bSAnirudh Venkataramanan }
6009c20346bSAnirudh Venkataramanan 
6013a858ba3SAnirudh Venkataramanan /**
6023a858ba3SAnirudh Venkataramanan  * ice_aq_add_vsi
603f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
6043a858ba3SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
6053a858ba3SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
6063a858ba3SAnirudh Venkataramanan  *
6073a858ba3SAnirudh Venkataramanan  * Add a VSI context to the hardware (0x0210)
6083a858ba3SAnirudh Venkataramanan  */
6095e24d598STony Nguyen static int
6103a858ba3SAnirudh Venkataramanan ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
6113a858ba3SAnirudh Venkataramanan 	       struct ice_sq_cd *cd)
6123a858ba3SAnirudh Venkataramanan {
6133a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_update_free_vsi_resp *res;
6143a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_get_update_free_vsi *cmd;
6153a858ba3SAnirudh Venkataramanan 	struct ice_aq_desc desc;
6165e24d598STony Nguyen 	int status;
6173a858ba3SAnirudh Venkataramanan 
6183a858ba3SAnirudh Venkataramanan 	cmd = &desc.params.vsi_cmd;
6190f9d5027SAnirudh Venkataramanan 	res = &desc.params.add_update_free_vsi_res;
6203a858ba3SAnirudh Venkataramanan 
6213a858ba3SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);
6223a858ba3SAnirudh Venkataramanan 
6233a858ba3SAnirudh Venkataramanan 	if (!vsi_ctx->alloc_from_pool)
6243a858ba3SAnirudh Venkataramanan 		cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num |
6253a858ba3SAnirudh Venkataramanan 					   ICE_AQ_VSI_IS_VALID);
6261071a835SAnirudh Venkataramanan 	cmd->vf_id = vsi_ctx->vf_num;
6273a858ba3SAnirudh Venkataramanan 
6283a858ba3SAnirudh Venkataramanan 	cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags);
6293a858ba3SAnirudh Venkataramanan 
6303a858ba3SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
6313a858ba3SAnirudh Venkataramanan 
6323a858ba3SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
6333a858ba3SAnirudh Venkataramanan 				 sizeof(vsi_ctx->info), cd);
6343a858ba3SAnirudh Venkataramanan 
6353a858ba3SAnirudh Venkataramanan 	if (!status) {
6363a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M;
6373a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used);
6383a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free);
6393a858ba3SAnirudh Venkataramanan 	}
6403a858ba3SAnirudh Venkataramanan 
6413a858ba3SAnirudh Venkataramanan 	return status;
6423a858ba3SAnirudh Venkataramanan }
6433a858ba3SAnirudh Venkataramanan 
6443a858ba3SAnirudh Venkataramanan /**
6450f9d5027SAnirudh Venkataramanan  * ice_aq_free_vsi
646f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
6470f9d5027SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
6480f9d5027SAnirudh Venkataramanan  * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
6490f9d5027SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
6500f9d5027SAnirudh Venkataramanan  *
6510f9d5027SAnirudh Venkataramanan  * Free VSI context info from hardware (0x0213)
6520f9d5027SAnirudh Venkataramanan  */
6535e24d598STony Nguyen static int
6540f9d5027SAnirudh Venkataramanan ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
6550f9d5027SAnirudh Venkataramanan 		bool keep_vsi_alloc, struct ice_sq_cd *cd)
6560f9d5027SAnirudh Venkataramanan {
6570f9d5027SAnirudh Venkataramanan 	struct ice_aqc_add_update_free_vsi_resp *resp;
6580f9d5027SAnirudh Venkataramanan 	struct ice_aqc_add_get_update_free_vsi *cmd;
6590f9d5027SAnirudh Venkataramanan 	struct ice_aq_desc desc;
6605e24d598STony Nguyen 	int status;
6610f9d5027SAnirudh Venkataramanan 
6620f9d5027SAnirudh Venkataramanan 	cmd = &desc.params.vsi_cmd;
6630f9d5027SAnirudh Venkataramanan 	resp = &desc.params.add_update_free_vsi_res;
6640f9d5027SAnirudh Venkataramanan 
6650f9d5027SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
6660f9d5027SAnirudh Venkataramanan 
6670f9d5027SAnirudh Venkataramanan 	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
6680f9d5027SAnirudh Venkataramanan 	if (keep_vsi_alloc)
6690f9d5027SAnirudh Venkataramanan 		cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);
6700f9d5027SAnirudh Venkataramanan 
6710f9d5027SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
6720f9d5027SAnirudh Venkataramanan 	if (!status) {
6730f9d5027SAnirudh Venkataramanan 		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
6740f9d5027SAnirudh Venkataramanan 		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
6750f9d5027SAnirudh Venkataramanan 	}
6760f9d5027SAnirudh Venkataramanan 
6770f9d5027SAnirudh Venkataramanan 	return status;
6780f9d5027SAnirudh Venkataramanan }
6790f9d5027SAnirudh Venkataramanan 
6800f9d5027SAnirudh Venkataramanan /**
6813a858ba3SAnirudh Venkataramanan  * ice_aq_update_vsi
682f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
6833a858ba3SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
6843a858ba3SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
6853a858ba3SAnirudh Venkataramanan  *
6863a858ba3SAnirudh Venkataramanan  * Update VSI context in the hardware (0x0211)
6873a858ba3SAnirudh Venkataramanan  */
6885e24d598STony Nguyen static int
6893a858ba3SAnirudh Venkataramanan ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
6903a858ba3SAnirudh Venkataramanan 		  struct ice_sq_cd *cd)
6913a858ba3SAnirudh Venkataramanan {
6923a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_update_free_vsi_resp *resp;
6933a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_get_update_free_vsi *cmd;
6943a858ba3SAnirudh Venkataramanan 	struct ice_aq_desc desc;
6955e24d598STony Nguyen 	int status;
6963a858ba3SAnirudh Venkataramanan 
6973a858ba3SAnirudh Venkataramanan 	cmd = &desc.params.vsi_cmd;
6980f9d5027SAnirudh Venkataramanan 	resp = &desc.params.add_update_free_vsi_res;
6993a858ba3SAnirudh Venkataramanan 
7003a858ba3SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);
7013a858ba3SAnirudh Venkataramanan 
7023a858ba3SAnirudh Venkataramanan 	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
7033a858ba3SAnirudh Venkataramanan 
7043a858ba3SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
7053a858ba3SAnirudh Venkataramanan 
7063a858ba3SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
7073a858ba3SAnirudh Venkataramanan 				 sizeof(vsi_ctx->info), cd);
7083a858ba3SAnirudh Venkataramanan 
7093a858ba3SAnirudh Venkataramanan 	if (!status) {
7103a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
7113a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
7123a858ba3SAnirudh Venkataramanan 	}
7133a858ba3SAnirudh Venkataramanan 
7143a858ba3SAnirudh Venkataramanan 	return status;
7153a858ba3SAnirudh Venkataramanan }
7163a858ba3SAnirudh Venkataramanan 
7173a858ba3SAnirudh Venkataramanan /**
7180f9d5027SAnirudh Venkataramanan  * ice_is_vsi_valid - check whether the VSI is valid or not
719f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
7200f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
7210f9d5027SAnirudh Venkataramanan  *
7220f9d5027SAnirudh Venkataramanan  * check whether the VSI is valid or not
7230f9d5027SAnirudh Venkataramanan  */
7244fb33f31SAnirudh Venkataramanan bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)
7250f9d5027SAnirudh Venkataramanan {
7260f9d5027SAnirudh Venkataramanan 	return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];
7270f9d5027SAnirudh Venkataramanan }
7280f9d5027SAnirudh Venkataramanan 
7290f9d5027SAnirudh Venkataramanan /**
730f9867df6SAnirudh Venkataramanan  * ice_get_hw_vsi_num - return the HW VSI number
731f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
7320f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
7330f9d5027SAnirudh Venkataramanan  *
734f9867df6SAnirudh Venkataramanan  * return the HW VSI number
7350f9d5027SAnirudh Venkataramanan  * Caution: call this function only if VSI is valid (ice_is_vsi_valid)
7360f9d5027SAnirudh Venkataramanan  */
7374fb33f31SAnirudh Venkataramanan u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)
7380f9d5027SAnirudh Venkataramanan {
7390f9d5027SAnirudh Venkataramanan 	return hw->vsi_ctx[vsi_handle]->vsi_num;
7400f9d5027SAnirudh Venkataramanan }
7410f9d5027SAnirudh Venkataramanan 
7420f9d5027SAnirudh Venkataramanan /**
7430f9d5027SAnirudh Venkataramanan  * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle
744f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
7450f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
7460f9d5027SAnirudh Venkataramanan  *
7470f9d5027SAnirudh Venkataramanan  * return the VSI context entry for a given VSI handle
7480f9d5027SAnirudh Venkataramanan  */
7494fb33f31SAnirudh Venkataramanan struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
7500f9d5027SAnirudh Venkataramanan {
7510f9d5027SAnirudh Venkataramanan 	return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];
7520f9d5027SAnirudh Venkataramanan }
7530f9d5027SAnirudh Venkataramanan 
7540f9d5027SAnirudh Venkataramanan /**
7550f9d5027SAnirudh Venkataramanan  * ice_save_vsi_ctx - save the VSI context for a given VSI handle
756f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
7570f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
7580f9d5027SAnirudh Venkataramanan  * @vsi: VSI context pointer
7590f9d5027SAnirudh Venkataramanan  *
7600f9d5027SAnirudh Venkataramanan  * save the VSI context entry for a given VSI handle
7610f9d5027SAnirudh Venkataramanan  */
762c8b7abddSBruce Allan static void
763c8b7abddSBruce Allan ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)
7640f9d5027SAnirudh Venkataramanan {
7650f9d5027SAnirudh Venkataramanan 	hw->vsi_ctx[vsi_handle] = vsi;
7660f9d5027SAnirudh Venkataramanan }
7670f9d5027SAnirudh Venkataramanan 
7680f9d5027SAnirudh Venkataramanan /**
769bb87ee0eSAnirudh Venkataramanan  * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs
770bb87ee0eSAnirudh Venkataramanan  * @hw: pointer to the HW struct
771bb87ee0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle
772bb87ee0eSAnirudh Venkataramanan  */
773bb87ee0eSAnirudh Venkataramanan static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
774bb87ee0eSAnirudh Venkataramanan {
775bb87ee0eSAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi;
776bb87ee0eSAnirudh Venkataramanan 	u8 i;
777bb87ee0eSAnirudh Venkataramanan 
778bb87ee0eSAnirudh Venkataramanan 	vsi = ice_get_vsi_ctx(hw, vsi_handle);
779bb87ee0eSAnirudh Venkataramanan 	if (!vsi)
780bb87ee0eSAnirudh Venkataramanan 		return;
781bb87ee0eSAnirudh Venkataramanan 	ice_for_each_traffic_class(i) {
782bb87ee0eSAnirudh Venkataramanan 		if (vsi->lan_q_ctx[i]) {
783bb87ee0eSAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
784bb87ee0eSAnirudh Venkataramanan 			vsi->lan_q_ctx[i] = NULL;
785bb87ee0eSAnirudh Venkataramanan 		}
786348048e7SDave Ertman 		if (vsi->rdma_q_ctx[i]) {
787348048e7SDave Ertman 			devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]);
788348048e7SDave Ertman 			vsi->rdma_q_ctx[i] = NULL;
789348048e7SDave Ertman 		}
790bb87ee0eSAnirudh Venkataramanan 	}
791bb87ee0eSAnirudh Venkataramanan }
792bb87ee0eSAnirudh Venkataramanan 
793bb87ee0eSAnirudh Venkataramanan /**
7940f9d5027SAnirudh Venkataramanan  * ice_clear_vsi_ctx - clear the VSI context entry
795f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
7960f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
7970f9d5027SAnirudh Venkataramanan  *
7980f9d5027SAnirudh Venkataramanan  * clear the VSI context entry
7990f9d5027SAnirudh Venkataramanan  */
8000f9d5027SAnirudh Venkataramanan static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
8010f9d5027SAnirudh Venkataramanan {
8020f9d5027SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi;
8030f9d5027SAnirudh Venkataramanan 
8040f9d5027SAnirudh Venkataramanan 	vsi = ice_get_vsi_ctx(hw, vsi_handle);
8050f9d5027SAnirudh Venkataramanan 	if (vsi) {
806bb87ee0eSAnirudh Venkataramanan 		ice_clear_vsi_q_ctx(hw, vsi_handle);
8070f9d5027SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), vsi);
8080f9d5027SAnirudh Venkataramanan 		hw->vsi_ctx[vsi_handle] = NULL;
8090f9d5027SAnirudh Venkataramanan 	}
8100f9d5027SAnirudh Venkataramanan }
8110f9d5027SAnirudh Venkataramanan 
8120f9d5027SAnirudh Venkataramanan /**
81333e055fcSVictor Raj  * ice_clear_all_vsi_ctx - clear all the VSI context entries
814f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
81533e055fcSVictor Raj  */
81633e055fcSVictor Raj void ice_clear_all_vsi_ctx(struct ice_hw *hw)
81733e055fcSVictor Raj {
81833e055fcSVictor Raj 	u16 i;
81933e055fcSVictor Raj 
82033e055fcSVictor Raj 	for (i = 0; i < ICE_MAX_VSI; i++)
82133e055fcSVictor Raj 		ice_clear_vsi_ctx(hw, i);
82233e055fcSVictor Raj }
82333e055fcSVictor Raj 
82433e055fcSVictor Raj /**
8250f9d5027SAnirudh Venkataramanan  * ice_add_vsi - add VSI context to the hardware and VSI handle list
826f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
8270f9d5027SAnirudh Venkataramanan  * @vsi_handle: unique VSI handle provided by drivers
8280f9d5027SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
8290f9d5027SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
8300f9d5027SAnirudh Venkataramanan  *
8310f9d5027SAnirudh Venkataramanan  * Add a VSI context to the hardware also add it into the VSI handle list.
8320f9d5027SAnirudh Venkataramanan  * If this function gets called after reset for existing VSIs then update
8330f9d5027SAnirudh Venkataramanan  * with the new HW VSI number in the corresponding VSI handle list entry.
8340f9d5027SAnirudh Venkataramanan  */
8355e24d598STony Nguyen int
8360f9d5027SAnirudh Venkataramanan ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
8370f9d5027SAnirudh Venkataramanan 	    struct ice_sq_cd *cd)
8380f9d5027SAnirudh Venkataramanan {
8390f9d5027SAnirudh Venkataramanan 	struct ice_vsi_ctx *tmp_vsi_ctx;
8405e24d598STony Nguyen 	int status;
8410f9d5027SAnirudh Venkataramanan 
8420f9d5027SAnirudh Venkataramanan 	if (vsi_handle >= ICE_MAX_VSI)
843d54699e2STony Nguyen 		return -EINVAL;
8440f9d5027SAnirudh Venkataramanan 	status = ice_aq_add_vsi(hw, vsi_ctx, cd);
8450f9d5027SAnirudh Venkataramanan 	if (status)
8460f9d5027SAnirudh Venkataramanan 		return status;
8470f9d5027SAnirudh Venkataramanan 	tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
8480f9d5027SAnirudh Venkataramanan 	if (!tmp_vsi_ctx) {
849f9867df6SAnirudh Venkataramanan 		/* Create a new VSI context */
8500f9d5027SAnirudh Venkataramanan 		tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw),
8510f9d5027SAnirudh Venkataramanan 					   sizeof(*tmp_vsi_ctx), GFP_KERNEL);
8520f9d5027SAnirudh Venkataramanan 		if (!tmp_vsi_ctx) {
8530f9d5027SAnirudh Venkataramanan 			ice_aq_free_vsi(hw, vsi_ctx, false, cd);
854d54699e2STony Nguyen 			return -ENOMEM;
8550f9d5027SAnirudh Venkataramanan 		}
8560f9d5027SAnirudh Venkataramanan 		*tmp_vsi_ctx = *vsi_ctx;
8570f9d5027SAnirudh Venkataramanan 		ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);
8580f9d5027SAnirudh Venkataramanan 	} else {
8590f9d5027SAnirudh Venkataramanan 		/* update with new HW VSI num */
8600f9d5027SAnirudh Venkataramanan 		tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;
8610f9d5027SAnirudh Venkataramanan 	}
8620f9d5027SAnirudh Venkataramanan 
8631b5c19c7SBruce Allan 	return 0;
8640f9d5027SAnirudh Venkataramanan }
8650f9d5027SAnirudh Venkataramanan 
8660f9d5027SAnirudh Venkataramanan /**
8670f9d5027SAnirudh Venkataramanan  * ice_free_vsi- free VSI context from hardware and VSI handle list
868f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
8690f9d5027SAnirudh Venkataramanan  * @vsi_handle: unique VSI handle
8703a858ba3SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
8713a858ba3SAnirudh Venkataramanan  * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
8723a858ba3SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
8733a858ba3SAnirudh Venkataramanan  *
8740f9d5027SAnirudh Venkataramanan  * Free VSI context info from hardware as well as from VSI handle list
8753a858ba3SAnirudh Venkataramanan  */
8765e24d598STony Nguyen int
8770f9d5027SAnirudh Venkataramanan ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
8783a858ba3SAnirudh Venkataramanan 	     bool keep_vsi_alloc, struct ice_sq_cd *cd)
8793a858ba3SAnirudh Venkataramanan {
8805e24d598STony Nguyen 	int status;
8813a858ba3SAnirudh Venkataramanan 
8820f9d5027SAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
883d54699e2STony Nguyen 		return -EINVAL;
8840f9d5027SAnirudh Venkataramanan 	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
8850f9d5027SAnirudh Venkataramanan 	status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);
8860f9d5027SAnirudh Venkataramanan 	if (!status)
8870f9d5027SAnirudh Venkataramanan 		ice_clear_vsi_ctx(hw, vsi_handle);
8883a858ba3SAnirudh Venkataramanan 	return status;
8893a858ba3SAnirudh Venkataramanan }
8903a858ba3SAnirudh Venkataramanan 
8919daf8208SAnirudh Venkataramanan /**
8925726ca0eSAnirudh Venkataramanan  * ice_update_vsi
893f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
8945726ca0eSAnirudh Venkataramanan  * @vsi_handle: unique VSI handle
8955726ca0eSAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
8965726ca0eSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
8975726ca0eSAnirudh Venkataramanan  *
8985726ca0eSAnirudh Venkataramanan  * Update VSI context in the hardware
8995726ca0eSAnirudh Venkataramanan  */
9005e24d598STony Nguyen int
9015726ca0eSAnirudh Venkataramanan ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
9025726ca0eSAnirudh Venkataramanan 	       struct ice_sq_cd *cd)
9035726ca0eSAnirudh Venkataramanan {
9045726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
905d54699e2STony Nguyen 		return -EINVAL;
9065726ca0eSAnirudh Venkataramanan 	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
9075726ca0eSAnirudh Venkataramanan 	return ice_aq_update_vsi(hw, vsi_ctx, cd);
9085726ca0eSAnirudh Venkataramanan }
9095726ca0eSAnirudh Venkataramanan 
9105726ca0eSAnirudh Venkataramanan /**
911348048e7SDave Ertman  * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI
912348048e7SDave Ertman  * @hw: pointer to HW struct
913348048e7SDave Ertman  * @vsi_handle: VSI SW index
914348048e7SDave Ertman  * @enable: boolean for enable/disable
915348048e7SDave Ertman  */
916348048e7SDave Ertman int
917348048e7SDave Ertman ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
918348048e7SDave Ertman {
919348048e7SDave Ertman 	struct ice_vsi_ctx *ctx;
920348048e7SDave Ertman 
921348048e7SDave Ertman 	ctx = ice_get_vsi_ctx(hw, vsi_handle);
922348048e7SDave Ertman 	if (!ctx)
923348048e7SDave Ertman 		return -EIO;
924348048e7SDave Ertman 
925348048e7SDave Ertman 	if (enable)
926348048e7SDave Ertman 		ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
927348048e7SDave Ertman 	else
928348048e7SDave Ertman 		ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
929348048e7SDave Ertman 
930d54699e2STony Nguyen 	return ice_update_vsi(hw, vsi_handle, ctx, NULL);
931348048e7SDave Ertman }
932348048e7SDave Ertman 
933348048e7SDave Ertman /**
9349daf8208SAnirudh Venkataramanan  * ice_aq_alloc_free_vsi_list
935f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
936f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID returned or used for lookup
9379daf8208SAnirudh Venkataramanan  * @lkup_type: switch rule filter lookup type
9389daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
9399daf8208SAnirudh Venkataramanan  *
9409daf8208SAnirudh Venkataramanan  * allocates or free a VSI list resource
9419daf8208SAnirudh Venkataramanan  */
9425e24d598STony Nguyen static int
9439daf8208SAnirudh Venkataramanan ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
9449daf8208SAnirudh Venkataramanan 			   enum ice_sw_lkup_type lkup_type,
9459daf8208SAnirudh Venkataramanan 			   enum ice_adminq_opc opc)
9469daf8208SAnirudh Venkataramanan {
9479daf8208SAnirudh Venkataramanan 	struct ice_aqc_alloc_free_res_elem *sw_buf;
9489daf8208SAnirudh Venkataramanan 	struct ice_aqc_res_elem *vsi_ele;
9499daf8208SAnirudh Venkataramanan 	u16 buf_len;
9505518ac2aSTony Nguyen 	int status;
9519daf8208SAnirudh Venkataramanan 
95266486d89SBruce Allan 	buf_len = struct_size(sw_buf, elem, 1);
9539daf8208SAnirudh Venkataramanan 	sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL);
9549daf8208SAnirudh Venkataramanan 	if (!sw_buf)
955d54699e2STony Nguyen 		return -ENOMEM;
9569daf8208SAnirudh Venkataramanan 	sw_buf->num_elems = cpu_to_le16(1);
9579daf8208SAnirudh Venkataramanan 
9589daf8208SAnirudh Venkataramanan 	if (lkup_type == ICE_SW_LKUP_MAC ||
9599daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
9609daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
9619daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
9629daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC ||
9639daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN) {
9649daf8208SAnirudh Venkataramanan 		sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
9659daf8208SAnirudh Venkataramanan 	} else if (lkup_type == ICE_SW_LKUP_VLAN) {
9669daf8208SAnirudh Venkataramanan 		sw_buf->res_type =
9679daf8208SAnirudh Venkataramanan 			cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
9689daf8208SAnirudh Venkataramanan 	} else {
969d54699e2STony Nguyen 		status = -EINVAL;
9709daf8208SAnirudh Venkataramanan 		goto ice_aq_alloc_free_vsi_list_exit;
9719daf8208SAnirudh Venkataramanan 	}
9729daf8208SAnirudh Venkataramanan 
9739daf8208SAnirudh Venkataramanan 	if (opc == ice_aqc_opc_free_res)
9749daf8208SAnirudh Venkataramanan 		sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id);
9759daf8208SAnirudh Venkataramanan 
9769daf8208SAnirudh Venkataramanan 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);
9779daf8208SAnirudh Venkataramanan 	if (status)
9789daf8208SAnirudh Venkataramanan 		goto ice_aq_alloc_free_vsi_list_exit;
9799daf8208SAnirudh Venkataramanan 
9809daf8208SAnirudh Venkataramanan 	if (opc == ice_aqc_opc_alloc_res) {
9819daf8208SAnirudh Venkataramanan 		vsi_ele = &sw_buf->elem[0];
9829daf8208SAnirudh Venkataramanan 		*vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp);
9839daf8208SAnirudh Venkataramanan 	}
9849daf8208SAnirudh Venkataramanan 
9859daf8208SAnirudh Venkataramanan ice_aq_alloc_free_vsi_list_exit:
9869daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), sw_buf);
9879daf8208SAnirudh Venkataramanan 	return status;
9889daf8208SAnirudh Venkataramanan }
9899daf8208SAnirudh Venkataramanan 
9909daf8208SAnirudh Venkataramanan /**
9919daf8208SAnirudh Venkataramanan  * ice_aq_sw_rules - add/update/remove switch rules
992f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
9939daf8208SAnirudh Venkataramanan  * @rule_list: pointer to switch rule population list
9949daf8208SAnirudh Venkataramanan  * @rule_list_sz: total size of the rule list in bytes
9959daf8208SAnirudh Venkataramanan  * @num_rules: number of switch rules in the rule_list
9969daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
9979daf8208SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
9989daf8208SAnirudh Venkataramanan  *
9999daf8208SAnirudh Venkataramanan  * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware
10009daf8208SAnirudh Venkataramanan  */
10015e24d598STony Nguyen int
10029daf8208SAnirudh Venkataramanan ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
10039daf8208SAnirudh Venkataramanan 		u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd)
10049daf8208SAnirudh Venkataramanan {
10059daf8208SAnirudh Venkataramanan 	struct ice_aq_desc desc;
10065e24d598STony Nguyen 	int status;
10079daf8208SAnirudh Venkataramanan 
10089daf8208SAnirudh Venkataramanan 	if (opc != ice_aqc_opc_add_sw_rules &&
10099daf8208SAnirudh Venkataramanan 	    opc != ice_aqc_opc_update_sw_rules &&
10109daf8208SAnirudh Venkataramanan 	    opc != ice_aqc_opc_remove_sw_rules)
1011d54699e2STony Nguyen 		return -EINVAL;
10129daf8208SAnirudh Venkataramanan 
10139daf8208SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, opc);
10149daf8208SAnirudh Venkataramanan 
10159daf8208SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
10169daf8208SAnirudh Venkataramanan 	desc.params.sw_rules.num_rules_fltr_entry_index =
10179daf8208SAnirudh Venkataramanan 		cpu_to_le16(num_rules);
1018ca1fdb88SKiran Patil 	status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd);
1019ca1fdb88SKiran Patil 	if (opc != ice_aqc_opc_add_sw_rules &&
1020ca1fdb88SKiran Patil 	    hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
1021d54699e2STony Nguyen 		status = -ENOENT;
1022ca1fdb88SKiran Patil 
1023ca1fdb88SKiran Patil 	return status;
10249daf8208SAnirudh Venkataramanan }
10259daf8208SAnirudh Venkataramanan 
10267715ec32SGrishma Kotecha /**
10277715ec32SGrishma Kotecha  * ice_aq_add_recipe - add switch recipe
10287715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
10297715ec32SGrishma Kotecha  * @s_recipe_list: pointer to switch rule population list
10307715ec32SGrishma Kotecha  * @num_recipes: number of switch recipes in the list
10317715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
10327715ec32SGrishma Kotecha  *
10337715ec32SGrishma Kotecha  * Add(0x0290)
10347715ec32SGrishma Kotecha  */
10355e24d598STony Nguyen static int
10367715ec32SGrishma Kotecha ice_aq_add_recipe(struct ice_hw *hw,
10377715ec32SGrishma Kotecha 		  struct ice_aqc_recipe_data_elem *s_recipe_list,
10387715ec32SGrishma Kotecha 		  u16 num_recipes, struct ice_sq_cd *cd)
10397715ec32SGrishma Kotecha {
10407715ec32SGrishma Kotecha 	struct ice_aqc_add_get_recipe *cmd;
10417715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
10427715ec32SGrishma Kotecha 	u16 buf_size;
10437715ec32SGrishma Kotecha 
10447715ec32SGrishma Kotecha 	cmd = &desc.params.add_get_recipe;
10457715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_recipe);
10467715ec32SGrishma Kotecha 
10477715ec32SGrishma Kotecha 	cmd->num_sub_recipes = cpu_to_le16(num_recipes);
10487715ec32SGrishma Kotecha 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
10497715ec32SGrishma Kotecha 
10507715ec32SGrishma Kotecha 	buf_size = num_recipes * sizeof(*s_recipe_list);
10517715ec32SGrishma Kotecha 
10527715ec32SGrishma Kotecha 	return ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd);
10537715ec32SGrishma Kotecha }
10547715ec32SGrishma Kotecha 
10557715ec32SGrishma Kotecha /**
10567715ec32SGrishma Kotecha  * ice_aq_get_recipe - get switch recipe
10577715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
10587715ec32SGrishma Kotecha  * @s_recipe_list: pointer to switch rule population list
10597715ec32SGrishma Kotecha  * @num_recipes: pointer to the number of recipes (input and output)
10607715ec32SGrishma Kotecha  * @recipe_root: root recipe number of recipe(s) to retrieve
10617715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
10627715ec32SGrishma Kotecha  *
10637715ec32SGrishma Kotecha  * Get(0x0292)
10647715ec32SGrishma Kotecha  *
10657715ec32SGrishma Kotecha  * On input, *num_recipes should equal the number of entries in s_recipe_list.
10667715ec32SGrishma Kotecha  * On output, *num_recipes will equal the number of entries returned in
10677715ec32SGrishma Kotecha  * s_recipe_list.
10687715ec32SGrishma Kotecha  *
10697715ec32SGrishma Kotecha  * The caller must supply enough space in s_recipe_list to hold all possible
10707715ec32SGrishma Kotecha  * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES.
10717715ec32SGrishma Kotecha  */
10725e24d598STony Nguyen static int
10737715ec32SGrishma Kotecha ice_aq_get_recipe(struct ice_hw *hw,
10747715ec32SGrishma Kotecha 		  struct ice_aqc_recipe_data_elem *s_recipe_list,
10757715ec32SGrishma Kotecha 		  u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd)
10767715ec32SGrishma Kotecha {
10777715ec32SGrishma Kotecha 	struct ice_aqc_add_get_recipe *cmd;
10787715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
10797715ec32SGrishma Kotecha 	u16 buf_size;
10805518ac2aSTony Nguyen 	int status;
10817715ec32SGrishma Kotecha 
10827715ec32SGrishma Kotecha 	if (*num_recipes != ICE_MAX_NUM_RECIPES)
1083d54699e2STony Nguyen 		return -EINVAL;
10847715ec32SGrishma Kotecha 
10857715ec32SGrishma Kotecha 	cmd = &desc.params.add_get_recipe;
10867715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe);
10877715ec32SGrishma Kotecha 
10887715ec32SGrishma Kotecha 	cmd->return_index = cpu_to_le16(recipe_root);
10897715ec32SGrishma Kotecha 	cmd->num_sub_recipes = 0;
10907715ec32SGrishma Kotecha 
10917715ec32SGrishma Kotecha 	buf_size = *num_recipes * sizeof(*s_recipe_list);
10927715ec32SGrishma Kotecha 
10937715ec32SGrishma Kotecha 	status = ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd);
10947715ec32SGrishma Kotecha 	*num_recipes = le16_to_cpu(cmd->num_sub_recipes);
10957715ec32SGrishma Kotecha 
10967715ec32SGrishma Kotecha 	return status;
10977715ec32SGrishma Kotecha }
10987715ec32SGrishma Kotecha 
10997715ec32SGrishma Kotecha /**
11007715ec32SGrishma Kotecha  * ice_aq_map_recipe_to_profile - Map recipe to packet profile
11017715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
11027715ec32SGrishma Kotecha  * @profile_id: package profile ID to associate the recipe with
11037715ec32SGrishma Kotecha  * @r_bitmap: Recipe bitmap filled in and need to be returned as response
11047715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
11057715ec32SGrishma Kotecha  * Recipe to profile association (0x0291)
11067715ec32SGrishma Kotecha  */
11075e24d598STony Nguyen static int
11087715ec32SGrishma Kotecha ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
11097715ec32SGrishma Kotecha 			     struct ice_sq_cd *cd)
11107715ec32SGrishma Kotecha {
11117715ec32SGrishma Kotecha 	struct ice_aqc_recipe_to_profile *cmd;
11127715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
11137715ec32SGrishma Kotecha 
11147715ec32SGrishma Kotecha 	cmd = &desc.params.recipe_to_profile;
11157715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_recipe_to_profile);
11167715ec32SGrishma Kotecha 	cmd->profile_id = cpu_to_le16(profile_id);
11177715ec32SGrishma Kotecha 	/* Set the recipe ID bit in the bitmask to let the device know which
11187715ec32SGrishma Kotecha 	 * profile we are associating the recipe to
11197715ec32SGrishma Kotecha 	 */
11207715ec32SGrishma Kotecha 	memcpy(cmd->recipe_assoc, r_bitmap, sizeof(cmd->recipe_assoc));
11217715ec32SGrishma Kotecha 
11227715ec32SGrishma Kotecha 	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
11237715ec32SGrishma Kotecha }
11247715ec32SGrishma Kotecha 
11257715ec32SGrishma Kotecha /**
11267715ec32SGrishma Kotecha  * ice_aq_get_recipe_to_profile - Map recipe to packet profile
11277715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
11287715ec32SGrishma Kotecha  * @profile_id: package profile ID to associate the recipe with
11297715ec32SGrishma Kotecha  * @r_bitmap: Recipe bitmap filled in and need to be returned as response
11307715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
11317715ec32SGrishma Kotecha  * Associate profile ID with given recipe (0x0293)
11327715ec32SGrishma Kotecha  */
11335e24d598STony Nguyen static int
11347715ec32SGrishma Kotecha ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
11357715ec32SGrishma Kotecha 			     struct ice_sq_cd *cd)
11367715ec32SGrishma Kotecha {
11377715ec32SGrishma Kotecha 	struct ice_aqc_recipe_to_profile *cmd;
11387715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
11395e24d598STony Nguyen 	int status;
11407715ec32SGrishma Kotecha 
11417715ec32SGrishma Kotecha 	cmd = &desc.params.recipe_to_profile;
11427715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile);
11437715ec32SGrishma Kotecha 	cmd->profile_id = cpu_to_le16(profile_id);
11447715ec32SGrishma Kotecha 
11457715ec32SGrishma Kotecha 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
11467715ec32SGrishma Kotecha 	if (!status)
11477715ec32SGrishma Kotecha 		memcpy(r_bitmap, cmd->recipe_assoc, sizeof(cmd->recipe_assoc));
11487715ec32SGrishma Kotecha 
11497715ec32SGrishma Kotecha 	return status;
11507715ec32SGrishma Kotecha }
11517715ec32SGrishma Kotecha 
11527715ec32SGrishma Kotecha /**
11537715ec32SGrishma Kotecha  * ice_alloc_recipe - add recipe resource
11547715ec32SGrishma Kotecha  * @hw: pointer to the hardware structure
11557715ec32SGrishma Kotecha  * @rid: recipe ID returned as response to AQ call
11567715ec32SGrishma Kotecha  */
11575e24d598STony Nguyen static int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
11587715ec32SGrishma Kotecha {
11597715ec32SGrishma Kotecha 	struct ice_aqc_alloc_free_res_elem *sw_buf;
11607715ec32SGrishma Kotecha 	u16 buf_len;
11615518ac2aSTony Nguyen 	int status;
11627715ec32SGrishma Kotecha 
11637715ec32SGrishma Kotecha 	buf_len = struct_size(sw_buf, elem, 1);
11647715ec32SGrishma Kotecha 	sw_buf = kzalloc(buf_len, GFP_KERNEL);
11657715ec32SGrishma Kotecha 	if (!sw_buf)
1166d54699e2STony Nguyen 		return -ENOMEM;
11677715ec32SGrishma Kotecha 
11687715ec32SGrishma Kotecha 	sw_buf->num_elems = cpu_to_le16(1);
11697715ec32SGrishma Kotecha 	sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
11707715ec32SGrishma Kotecha 					ICE_AQC_RES_TYPE_S) |
11717715ec32SGrishma Kotecha 					ICE_AQC_RES_TYPE_FLAG_SHARED);
11727715ec32SGrishma Kotecha 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
11737715ec32SGrishma Kotecha 				       ice_aqc_opc_alloc_res, NULL);
11747715ec32SGrishma Kotecha 	if (!status)
11757715ec32SGrishma Kotecha 		*rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp);
11767715ec32SGrishma Kotecha 	kfree(sw_buf);
11777715ec32SGrishma Kotecha 
11787715ec32SGrishma Kotecha 	return status;
11797715ec32SGrishma Kotecha }
11807715ec32SGrishma Kotecha 
1181fd2a6b71SDan Nowlin /**
1182fd2a6b71SDan Nowlin  * ice_get_recp_to_prof_map - updates recipe to profile mapping
1183fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
1184fd2a6b71SDan Nowlin  *
1185fd2a6b71SDan Nowlin  * This function is used to populate recipe_to_profile matrix where index to
1186fd2a6b71SDan Nowlin  * this array is the recipe ID and the element is the mapping of which profiles
1187fd2a6b71SDan Nowlin  * is this recipe mapped to.
1188fd2a6b71SDan Nowlin  */
1189fd2a6b71SDan Nowlin static void ice_get_recp_to_prof_map(struct ice_hw *hw)
1190fd2a6b71SDan Nowlin {
1191fd2a6b71SDan Nowlin 	DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
1192fd2a6b71SDan Nowlin 	u16 i;
1193fd2a6b71SDan Nowlin 
1194fd2a6b71SDan Nowlin 	for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) {
1195fd2a6b71SDan Nowlin 		u16 j;
1196fd2a6b71SDan Nowlin 
1197fd2a6b71SDan Nowlin 		bitmap_zero(profile_to_recipe[i], ICE_MAX_NUM_RECIPES);
1198fd2a6b71SDan Nowlin 		bitmap_zero(r_bitmap, ICE_MAX_NUM_RECIPES);
1199fd2a6b71SDan Nowlin 		if (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL))
1200fd2a6b71SDan Nowlin 			continue;
1201fd2a6b71SDan Nowlin 		bitmap_copy(profile_to_recipe[i], r_bitmap,
1202fd2a6b71SDan Nowlin 			    ICE_MAX_NUM_RECIPES);
1203fd2a6b71SDan Nowlin 		for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES)
1204fd2a6b71SDan Nowlin 			set_bit(i, recipe_to_profile[j]);
1205fd2a6b71SDan Nowlin 	}
1206fd2a6b71SDan Nowlin }
1207fd2a6b71SDan Nowlin 
1208fd2a6b71SDan Nowlin /**
1209fd2a6b71SDan Nowlin  * ice_collect_result_idx - copy result index values
1210fd2a6b71SDan Nowlin  * @buf: buffer that contains the result index
1211fd2a6b71SDan Nowlin  * @recp: the recipe struct to copy data into
1212fd2a6b71SDan Nowlin  */
1213fd2a6b71SDan Nowlin static void
1214fd2a6b71SDan Nowlin ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
1215fd2a6b71SDan Nowlin 		       struct ice_sw_recipe *recp)
1216fd2a6b71SDan Nowlin {
1217fd2a6b71SDan Nowlin 	if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
1218fd2a6b71SDan Nowlin 		set_bit(buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
1219fd2a6b71SDan Nowlin 			recp->res_idxs);
1220fd2a6b71SDan Nowlin }
1221fd2a6b71SDan Nowlin 
1222fd2a6b71SDan Nowlin /**
1223fd2a6b71SDan Nowlin  * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries
1224fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
1225fd2a6b71SDan Nowlin  * @recps: struct that we need to populate
1226fd2a6b71SDan Nowlin  * @rid: recipe ID that we are populating
1227fd2a6b71SDan Nowlin  * @refresh_required: true if we should get recipe to profile mapping from FW
1228fd2a6b71SDan Nowlin  *
1229fd2a6b71SDan Nowlin  * This function is used to populate all the necessary entries into our
1230fd2a6b71SDan Nowlin  * bookkeeping so that we have a current list of all the recipes that are
1231fd2a6b71SDan Nowlin  * programmed in the firmware.
1232fd2a6b71SDan Nowlin  */
12335e24d598STony Nguyen static int
1234fd2a6b71SDan Nowlin ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
1235fd2a6b71SDan Nowlin 		    bool *refresh_required)
1236fd2a6b71SDan Nowlin {
1237fd2a6b71SDan Nowlin 	DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS);
1238fd2a6b71SDan Nowlin 	struct ice_aqc_recipe_data_elem *tmp;
1239fd2a6b71SDan Nowlin 	u16 num_recps = ICE_MAX_NUM_RECIPES;
1240fd2a6b71SDan Nowlin 	struct ice_prot_lkup_ext *lkup_exts;
1241fd2a6b71SDan Nowlin 	u8 fv_word_idx = 0;
1242fd2a6b71SDan Nowlin 	u16 sub_recps;
12435518ac2aSTony Nguyen 	int status;
1244fd2a6b71SDan Nowlin 
1245fd2a6b71SDan Nowlin 	bitmap_zero(result_bm, ICE_MAX_FV_WORDS);
1246fd2a6b71SDan Nowlin 
1247fd2a6b71SDan Nowlin 	/* we need a buffer big enough to accommodate all the recipes */
1248fd2a6b71SDan Nowlin 	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
1249fd2a6b71SDan Nowlin 	if (!tmp)
1250d54699e2STony Nguyen 		return -ENOMEM;
1251fd2a6b71SDan Nowlin 
1252fd2a6b71SDan Nowlin 	tmp[0].recipe_indx = rid;
1253fd2a6b71SDan Nowlin 	status = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL);
1254fd2a6b71SDan Nowlin 	/* non-zero status meaning recipe doesn't exist */
1255fd2a6b71SDan Nowlin 	if (status)
1256fd2a6b71SDan Nowlin 		goto err_unroll;
1257fd2a6b71SDan Nowlin 
1258fd2a6b71SDan Nowlin 	/* Get recipe to profile map so that we can get the fv from lkups that
1259fd2a6b71SDan Nowlin 	 * we read for a recipe from FW. Since we want to minimize the number of
1260fd2a6b71SDan Nowlin 	 * times we make this FW call, just make one call and cache the copy
1261fd2a6b71SDan Nowlin 	 * until a new recipe is added. This operation is only required the
1262fd2a6b71SDan Nowlin 	 * first time to get the changes from FW. Then to search existing
1263fd2a6b71SDan Nowlin 	 * entries we don't need to update the cache again until another recipe
1264fd2a6b71SDan Nowlin 	 * gets added.
1265fd2a6b71SDan Nowlin 	 */
1266fd2a6b71SDan Nowlin 	if (*refresh_required) {
1267fd2a6b71SDan Nowlin 		ice_get_recp_to_prof_map(hw);
1268fd2a6b71SDan Nowlin 		*refresh_required = false;
1269fd2a6b71SDan Nowlin 	}
1270fd2a6b71SDan Nowlin 
1271fd2a6b71SDan Nowlin 	/* Start populating all the entries for recps[rid] based on lkups from
1272fd2a6b71SDan Nowlin 	 * firmware. Note that we are only creating the root recipe in our
1273fd2a6b71SDan Nowlin 	 * database.
1274fd2a6b71SDan Nowlin 	 */
1275fd2a6b71SDan Nowlin 	lkup_exts = &recps[rid].lkup_exts;
1276fd2a6b71SDan Nowlin 
1277fd2a6b71SDan Nowlin 	for (sub_recps = 0; sub_recps < num_recps; sub_recps++) {
1278fd2a6b71SDan Nowlin 		struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps];
1279fd2a6b71SDan Nowlin 		struct ice_recp_grp_entry *rg_entry;
1280fd2a6b71SDan Nowlin 		u8 i, prof, idx, prot = 0;
1281fd2a6b71SDan Nowlin 		bool is_root;
1282fd2a6b71SDan Nowlin 		u16 off = 0;
1283fd2a6b71SDan Nowlin 
1284fd2a6b71SDan Nowlin 		rg_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rg_entry),
1285fd2a6b71SDan Nowlin 					GFP_KERNEL);
1286fd2a6b71SDan Nowlin 		if (!rg_entry) {
1287d54699e2STony Nguyen 			status = -ENOMEM;
1288fd2a6b71SDan Nowlin 			goto err_unroll;
1289fd2a6b71SDan Nowlin 		}
1290fd2a6b71SDan Nowlin 
1291fd2a6b71SDan Nowlin 		idx = root_bufs.recipe_indx;
1292fd2a6b71SDan Nowlin 		is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT;
1293fd2a6b71SDan Nowlin 
1294fd2a6b71SDan Nowlin 		/* Mark all result indices in this chain */
1295fd2a6b71SDan Nowlin 		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
1296fd2a6b71SDan Nowlin 			set_bit(root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
1297fd2a6b71SDan Nowlin 				result_bm);
1298fd2a6b71SDan Nowlin 
1299fd2a6b71SDan Nowlin 		/* get the first profile that is associated with rid */
1300fd2a6b71SDan Nowlin 		prof = find_first_bit(recipe_to_profile[idx],
1301fd2a6b71SDan Nowlin 				      ICE_MAX_NUM_PROFILES);
1302fd2a6b71SDan Nowlin 		for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) {
1303fd2a6b71SDan Nowlin 			u8 lkup_indx = root_bufs.content.lkup_indx[i + 1];
1304fd2a6b71SDan Nowlin 
1305fd2a6b71SDan Nowlin 			rg_entry->fv_idx[i] = lkup_indx;
1306fd2a6b71SDan Nowlin 			rg_entry->fv_mask[i] =
1307fd2a6b71SDan Nowlin 				le16_to_cpu(root_bufs.content.mask[i + 1]);
1308fd2a6b71SDan Nowlin 
1309fd2a6b71SDan Nowlin 			/* If the recipe is a chained recipe then all its
1310fd2a6b71SDan Nowlin 			 * child recipe's result will have a result index.
1311fd2a6b71SDan Nowlin 			 * To fill fv_words we should not use those result
1312fd2a6b71SDan Nowlin 			 * index, we only need the protocol ids and offsets.
1313fd2a6b71SDan Nowlin 			 * We will skip all the fv_idx which stores result
1314fd2a6b71SDan Nowlin 			 * index in them. We also need to skip any fv_idx which
1315fd2a6b71SDan Nowlin 			 * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a
1316fd2a6b71SDan Nowlin 			 * valid offset value.
1317fd2a6b71SDan Nowlin 			 */
1318fd2a6b71SDan Nowlin 			if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) ||
1319fd2a6b71SDan Nowlin 			    rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE ||
1320fd2a6b71SDan Nowlin 			    rg_entry->fv_idx[i] == 0)
1321fd2a6b71SDan Nowlin 				continue;
1322fd2a6b71SDan Nowlin 
1323fd2a6b71SDan Nowlin 			ice_find_prot_off(hw, ICE_BLK_SW, prof,
1324fd2a6b71SDan Nowlin 					  rg_entry->fv_idx[i], &prot, &off);
1325fd2a6b71SDan Nowlin 			lkup_exts->fv_words[fv_word_idx].prot_id = prot;
1326fd2a6b71SDan Nowlin 			lkup_exts->fv_words[fv_word_idx].off = off;
1327fd2a6b71SDan Nowlin 			lkup_exts->field_mask[fv_word_idx] =
1328fd2a6b71SDan Nowlin 				rg_entry->fv_mask[i];
1329fd2a6b71SDan Nowlin 			fv_word_idx++;
1330fd2a6b71SDan Nowlin 		}
1331fd2a6b71SDan Nowlin 		/* populate rg_list with the data from the child entry of this
1332fd2a6b71SDan Nowlin 		 * recipe
1333fd2a6b71SDan Nowlin 		 */
1334fd2a6b71SDan Nowlin 		list_add(&rg_entry->l_entry, &recps[rid].rg_list);
1335fd2a6b71SDan Nowlin 
1336fd2a6b71SDan Nowlin 		/* Propagate some data to the recipe database */
1337fd2a6b71SDan Nowlin 		recps[idx].is_root = !!is_root;
1338fd2a6b71SDan Nowlin 		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
1339fd2a6b71SDan Nowlin 		bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
1340fd2a6b71SDan Nowlin 		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
1341fd2a6b71SDan Nowlin 			recps[idx].chain_idx = root_bufs.content.result_indx &
1342fd2a6b71SDan Nowlin 				~ICE_AQ_RECIPE_RESULT_EN;
1343fd2a6b71SDan Nowlin 			set_bit(recps[idx].chain_idx, recps[idx].res_idxs);
1344fd2a6b71SDan Nowlin 		} else {
1345fd2a6b71SDan Nowlin 			recps[idx].chain_idx = ICE_INVAL_CHAIN_IND;
1346fd2a6b71SDan Nowlin 		}
1347fd2a6b71SDan Nowlin 
1348fd2a6b71SDan Nowlin 		if (!is_root)
1349fd2a6b71SDan Nowlin 			continue;
1350fd2a6b71SDan Nowlin 
1351fd2a6b71SDan Nowlin 		/* Only do the following for root recipes entries */
1352fd2a6b71SDan Nowlin 		memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap,
1353fd2a6b71SDan Nowlin 		       sizeof(recps[idx].r_bitmap));
1354fd2a6b71SDan Nowlin 		recps[idx].root_rid = root_bufs.content.rid &
1355fd2a6b71SDan Nowlin 			~ICE_AQ_RECIPE_ID_IS_ROOT;
1356fd2a6b71SDan Nowlin 		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
1357fd2a6b71SDan Nowlin 	}
1358fd2a6b71SDan Nowlin 
1359fd2a6b71SDan Nowlin 	/* Complete initialization of the root recipe entry */
1360fd2a6b71SDan Nowlin 	lkup_exts->n_val_words = fv_word_idx;
1361fd2a6b71SDan Nowlin 	recps[rid].big_recp = (num_recps > 1);
1362fd2a6b71SDan Nowlin 	recps[rid].n_grp_count = (u8)num_recps;
1363fd2a6b71SDan Nowlin 	recps[rid].root_buf = devm_kmemdup(ice_hw_to_dev(hw), tmp,
1364fd2a6b71SDan Nowlin 					   recps[rid].n_grp_count * sizeof(*recps[rid].root_buf),
1365fd2a6b71SDan Nowlin 					   GFP_KERNEL);
1366c8e51a01SWang Hai 	if (!recps[rid].root_buf) {
1367d54699e2STony Nguyen 		status = -ENOMEM;
1368fd2a6b71SDan Nowlin 		goto err_unroll;
1369c8e51a01SWang Hai 	}
1370fd2a6b71SDan Nowlin 
1371fd2a6b71SDan Nowlin 	/* Copy result indexes */
1372fd2a6b71SDan Nowlin 	bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS);
1373fd2a6b71SDan Nowlin 	recps[rid].recp_created = true;
1374fd2a6b71SDan Nowlin 
1375fd2a6b71SDan Nowlin err_unroll:
1376fd2a6b71SDan Nowlin 	kfree(tmp);
1377fd2a6b71SDan Nowlin 	return status;
1378fd2a6b71SDan Nowlin }
1379fd2a6b71SDan Nowlin 
13809c20346bSAnirudh Venkataramanan /* ice_init_port_info - Initialize port_info with switch configuration data
13819c20346bSAnirudh Venkataramanan  * @pi: pointer to port_info
13829c20346bSAnirudh Venkataramanan  * @vsi_port_num: VSI number or port number
13839c20346bSAnirudh Venkataramanan  * @type: Type of switch element (port or VSI)
13849c20346bSAnirudh Venkataramanan  * @swid: switch ID of the switch the element is attached to
13859c20346bSAnirudh Venkataramanan  * @pf_vf_num: PF or VF number
13869c20346bSAnirudh Venkataramanan  * @is_vf: true if the element is a VF, false otherwise
13879c20346bSAnirudh Venkataramanan  */
13889c20346bSAnirudh Venkataramanan static void
13899c20346bSAnirudh Venkataramanan ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,
13909c20346bSAnirudh Venkataramanan 		   u16 swid, u16 pf_vf_num, bool is_vf)
13919c20346bSAnirudh Venkataramanan {
13929c20346bSAnirudh Venkataramanan 	switch (type) {
13939c20346bSAnirudh Venkataramanan 	case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
13949c20346bSAnirudh Venkataramanan 		pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);
13959c20346bSAnirudh Venkataramanan 		pi->sw_id = swid;
13969c20346bSAnirudh Venkataramanan 		pi->pf_vf_num = pf_vf_num;
13979c20346bSAnirudh Venkataramanan 		pi->is_vf = is_vf;
13989c20346bSAnirudh Venkataramanan 		pi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
13999c20346bSAnirudh Venkataramanan 		pi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
14009c20346bSAnirudh Venkataramanan 		break;
14019c20346bSAnirudh Venkataramanan 	default:
14029228d8b2SJacob Keller 		ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n");
14039c20346bSAnirudh Venkataramanan 		break;
14049c20346bSAnirudh Venkataramanan 	}
14059c20346bSAnirudh Venkataramanan }
14069c20346bSAnirudh Venkataramanan 
14079c20346bSAnirudh Venkataramanan /* ice_get_initial_sw_cfg - Get initial port and default VSI data
14089c20346bSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
14099c20346bSAnirudh Venkataramanan  */
14105e24d598STony Nguyen int ice_get_initial_sw_cfg(struct ice_hw *hw)
14119c20346bSAnirudh Venkataramanan {
1412b3c38904SBruce Allan 	struct ice_aqc_get_sw_cfg_resp_elem *rbuf;
14139c20346bSAnirudh Venkataramanan 	u16 req_desc = 0;
14149c20346bSAnirudh Venkataramanan 	u16 num_elems;
14155518ac2aSTony Nguyen 	int status;
14169c20346bSAnirudh Venkataramanan 	u16 i;
14179c20346bSAnirudh Venkataramanan 
14189c20346bSAnirudh Venkataramanan 	rbuf = devm_kzalloc(ice_hw_to_dev(hw), ICE_SW_CFG_MAX_BUF_LEN,
14199c20346bSAnirudh Venkataramanan 			    GFP_KERNEL);
14209c20346bSAnirudh Venkataramanan 
14219c20346bSAnirudh Venkataramanan 	if (!rbuf)
1422d54699e2STony Nguyen 		return -ENOMEM;
14239c20346bSAnirudh Venkataramanan 
14249c20346bSAnirudh Venkataramanan 	/* Multiple calls to ice_aq_get_sw_cfg may be required
14259c20346bSAnirudh Venkataramanan 	 * to get all the switch configuration information. The need
14269c20346bSAnirudh Venkataramanan 	 * for additional calls is indicated by ice_aq_get_sw_cfg
14279c20346bSAnirudh Venkataramanan 	 * writing a non-zero value in req_desc
14289c20346bSAnirudh Venkataramanan 	 */
14299c20346bSAnirudh Venkataramanan 	do {
1430b3c38904SBruce Allan 		struct ice_aqc_get_sw_cfg_resp_elem *ele;
1431b3c38904SBruce Allan 
14329c20346bSAnirudh Venkataramanan 		status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,
14339c20346bSAnirudh Venkataramanan 					   &req_desc, &num_elems, NULL);
14349c20346bSAnirudh Venkataramanan 
14359c20346bSAnirudh Venkataramanan 		if (status)
14369c20346bSAnirudh Venkataramanan 			break;
14379c20346bSAnirudh Venkataramanan 
1438b3c38904SBruce Allan 		for (i = 0, ele = rbuf; i < num_elems; i++, ele++) {
14399c20346bSAnirudh Venkataramanan 			u16 pf_vf_num, swid, vsi_port_num;
14409c20346bSAnirudh Venkataramanan 			bool is_vf = false;
14416dae8aa0SBruce Allan 			u8 res_type;
14429c20346bSAnirudh Venkataramanan 
14439c20346bSAnirudh Venkataramanan 			vsi_port_num = le16_to_cpu(ele->vsi_port_num) &
14449c20346bSAnirudh Venkataramanan 				ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;
14459c20346bSAnirudh Venkataramanan 
14469c20346bSAnirudh Venkataramanan 			pf_vf_num = le16_to_cpu(ele->pf_vf_num) &
14479c20346bSAnirudh Venkataramanan 				ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;
14489c20346bSAnirudh Venkataramanan 
14499c20346bSAnirudh Venkataramanan 			swid = le16_to_cpu(ele->swid);
14509c20346bSAnirudh Venkataramanan 
14519c20346bSAnirudh Venkataramanan 			if (le16_to_cpu(ele->pf_vf_num) &
14529c20346bSAnirudh Venkataramanan 			    ICE_AQC_GET_SW_CONF_RESP_IS_VF)
14539c20346bSAnirudh Venkataramanan 				is_vf = true;
14549c20346bSAnirudh Venkataramanan 
145588865fc4SKarol Kolacinski 			res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >>
145688865fc4SKarol Kolacinski 					ICE_AQC_GET_SW_CONF_RESP_TYPE_S);
14579c20346bSAnirudh Venkataramanan 
14586dae8aa0SBruce Allan 			if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) {
14599c20346bSAnirudh Venkataramanan 				/* FW VSI is not needed. Just continue. */
14609c20346bSAnirudh Venkataramanan 				continue;
14619c20346bSAnirudh Venkataramanan 			}
14629c20346bSAnirudh Venkataramanan 
14639c20346bSAnirudh Venkataramanan 			ice_init_port_info(hw->port_info, vsi_port_num,
14646dae8aa0SBruce Allan 					   res_type, swid, pf_vf_num, is_vf);
14659c20346bSAnirudh Venkataramanan 		}
14669c20346bSAnirudh Venkataramanan 	} while (req_desc && !status);
14679c20346bSAnirudh Venkataramanan 
14687a63dae0SBruce Allan 	devm_kfree(ice_hw_to_dev(hw), rbuf);
14699c20346bSAnirudh Venkataramanan 	return status;
14709c20346bSAnirudh Venkataramanan }
14719daf8208SAnirudh Venkataramanan 
14729daf8208SAnirudh Venkataramanan /**
14739daf8208SAnirudh Venkataramanan  * ice_fill_sw_info - Helper function to populate lb_en and lan_en
14749daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
14756a7e6993SYashaswini Raghuram Prathivadi Bhayankaram  * @fi: filter info structure to fill/update
14769daf8208SAnirudh Venkataramanan  *
14779daf8208SAnirudh Venkataramanan  * This helper function populates the lb_en and lan_en elements of the provided
14789daf8208SAnirudh Venkataramanan  * ice_fltr_info struct using the switch's type and characteristics of the
14799daf8208SAnirudh Venkataramanan  * switch rule being configured.
14809daf8208SAnirudh Venkataramanan  */
14816a7e6993SYashaswini Raghuram Prathivadi Bhayankaram static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
14829daf8208SAnirudh Venkataramanan {
14836a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	fi->lb_en = false;
14846a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	fi->lan_en = false;
14856a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	if ((fi->flag & ICE_FLTR_TX) &&
14866a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	    (fi->fltr_act == ICE_FWD_TO_VSI ||
14876a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
14886a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	     fi->fltr_act == ICE_FWD_TO_Q ||
14896a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	     fi->fltr_act == ICE_FWD_TO_QGRP)) {
1490b58dafbcSChristopher N Bednarz 		/* Setting LB for prune actions will result in replicated
1491b58dafbcSChristopher N Bednarz 		 * packets to the internal switch that will be dropped.
1492b58dafbcSChristopher N Bednarz 		 */
1493b58dafbcSChristopher N Bednarz 		if (fi->lkup_type != ICE_SW_LKUP_VLAN)
14946a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 			fi->lb_en = true;
1495b58dafbcSChristopher N Bednarz 
1496277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		/* Set lan_en to TRUE if
14976a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 * 1. The switch is a VEB AND
14986a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2
149926069b44SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.1 The lookup is a directional lookup like ethertype,
1500f9867df6SAnirudh Venkataramanan 		 * promiscuous, ethertype-MAC, promiscuous-VLAN
150126069b44SYashaswini Raghuram Prathivadi Bhayankaram 		 * and default-port OR
150226069b44SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.2 The lookup is VLAN, OR
1503277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR
1504277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC.
15056a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 *
1506277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * OR
1507277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 *
1508277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * The switch is a VEPA.
1509277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 *
1510277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * In all other cases, the LAN enable has to be set to false.
15116a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 */
1512277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		if (hw->evb_veb) {
151326069b44SYashaswini Raghuram Prathivadi Bhayankaram 			if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE ||
151426069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_PROMISC ||
151526069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
151626069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
1517277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_DFLT ||
151826069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_VLAN ||
1519277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			    (fi->lkup_type == ICE_SW_LKUP_MAC &&
1520277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)) ||
15216a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 			    (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&
1522277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)))
15236a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 				fi->lan_en = true;
1524277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		} else {
1525277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			fi->lan_en = true;
1526277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		}
15279daf8208SAnirudh Venkataramanan 	}
15289daf8208SAnirudh Venkataramanan }
15299daf8208SAnirudh Venkataramanan 
15309daf8208SAnirudh Venkataramanan /**
15319daf8208SAnirudh Venkataramanan  * ice_fill_sw_rule - Helper function to fill switch rule structure
15329daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
15339daf8208SAnirudh Venkataramanan  * @f_info: entry containing packet forwarding information
15349daf8208SAnirudh Venkataramanan  * @s_rule: switch rule structure to be filled in based on mac_entry
15359daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
15369daf8208SAnirudh Venkataramanan  */
15379daf8208SAnirudh Venkataramanan static void
15389daf8208SAnirudh Venkataramanan ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
15399daf8208SAnirudh Venkataramanan 		 struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc)
15409daf8208SAnirudh Venkataramanan {
15419daf8208SAnirudh Venkataramanan 	u16 vlan_id = ICE_MAX_VLAN_ID + 1;
15429daf8208SAnirudh Venkataramanan 	void *daddr = NULL;
154374118f7aSZhenning Xiao 	u16 eth_hdr_sz;
154474118f7aSZhenning Xiao 	u8 *eth_hdr;
15459daf8208SAnirudh Venkataramanan 	u32 act = 0;
15469daf8208SAnirudh Venkataramanan 	__be16 *off;
1547be8ff000SAnirudh Venkataramanan 	u8 q_rgn;
15489daf8208SAnirudh Venkataramanan 
15499daf8208SAnirudh Venkataramanan 	if (opc == ice_aqc_opc_remove_sw_rules) {
15509daf8208SAnirudh Venkataramanan 		s_rule->pdata.lkup_tx_rx.act = 0;
15519daf8208SAnirudh Venkataramanan 		s_rule->pdata.lkup_tx_rx.index =
15529daf8208SAnirudh Venkataramanan 			cpu_to_le16(f_info->fltr_rule_id);
15539daf8208SAnirudh Venkataramanan 		s_rule->pdata.lkup_tx_rx.hdr_len = 0;
15549daf8208SAnirudh Venkataramanan 		return;
15559daf8208SAnirudh Venkataramanan 	}
15569daf8208SAnirudh Venkataramanan 
155774118f7aSZhenning Xiao 	eth_hdr_sz = sizeof(dummy_eth_header);
155874118f7aSZhenning Xiao 	eth_hdr = s_rule->pdata.lkup_tx_rx.hdr;
155974118f7aSZhenning Xiao 
15609daf8208SAnirudh Venkataramanan 	/* initialize the ether header with a dummy header */
156174118f7aSZhenning Xiao 	memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);
15629daf8208SAnirudh Venkataramanan 	ice_fill_sw_info(hw, f_info);
15639daf8208SAnirudh Venkataramanan 
15649daf8208SAnirudh Venkataramanan 	switch (f_info->fltr_act) {
15659daf8208SAnirudh Venkataramanan 	case ICE_FWD_TO_VSI:
15665726ca0eSAnirudh Venkataramanan 		act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
15679daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VSI_ID_M;
15689daf8208SAnirudh Venkataramanan 		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
15699daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
15709daf8208SAnirudh Venkataramanan 				ICE_SINGLE_ACT_VALID_BIT;
15719daf8208SAnirudh Venkataramanan 		break;
15729daf8208SAnirudh Venkataramanan 	case ICE_FWD_TO_VSI_LIST:
15739daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_VSI_LIST;
15749daf8208SAnirudh Venkataramanan 		act |= (f_info->fwd_id.vsi_list_id <<
15759daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VSI_LIST_ID_S) &
15769daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VSI_LIST_ID_M;
15779daf8208SAnirudh Venkataramanan 		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
15789daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
15799daf8208SAnirudh Venkataramanan 				ICE_SINGLE_ACT_VALID_BIT;
15809daf8208SAnirudh Venkataramanan 		break;
15819daf8208SAnirudh Venkataramanan 	case ICE_FWD_TO_Q:
15829daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_TO_Q;
15839daf8208SAnirudh Venkataramanan 		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
15849daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_Q_INDEX_M;
15859daf8208SAnirudh Venkataramanan 		break;
15869daf8208SAnirudh Venkataramanan 	case ICE_DROP_PACKET:
1587be8ff000SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
1588be8ff000SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VALID_BIT;
1589be8ff000SAnirudh Venkataramanan 		break;
1590be8ff000SAnirudh Venkataramanan 	case ICE_FWD_TO_QGRP:
1591be8ff000SAnirudh Venkataramanan 		q_rgn = f_info->qgrp_size > 0 ?
1592be8ff000SAnirudh Venkataramanan 			(u8)ilog2(f_info->qgrp_size) : 0;
1593be8ff000SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_TO_Q;
1594be8ff000SAnirudh Venkataramanan 		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
1595be8ff000SAnirudh Venkataramanan 			ICE_SINGLE_ACT_Q_INDEX_M;
1596be8ff000SAnirudh Venkataramanan 		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
1597be8ff000SAnirudh Venkataramanan 			ICE_SINGLE_ACT_Q_REGION_M;
15989daf8208SAnirudh Venkataramanan 		break;
15999daf8208SAnirudh Venkataramanan 	default:
16009daf8208SAnirudh Venkataramanan 		return;
16019daf8208SAnirudh Venkataramanan 	}
16029daf8208SAnirudh Venkataramanan 
16039daf8208SAnirudh Venkataramanan 	if (f_info->lb_en)
16049daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_LB_ENABLE;
16059daf8208SAnirudh Venkataramanan 	if (f_info->lan_en)
16069daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_LAN_ENABLE;
16079daf8208SAnirudh Venkataramanan 
16089daf8208SAnirudh Venkataramanan 	switch (f_info->lkup_type) {
16099daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC:
16109daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.mac.mac_addr;
16119daf8208SAnirudh Venkataramanan 		break;
16129daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_VLAN:
16139daf8208SAnirudh Venkataramanan 		vlan_id = f_info->l_data.vlan.vlan_id;
16149daf8208SAnirudh Venkataramanan 		if (f_info->fltr_act == ICE_FWD_TO_VSI ||
16159daf8208SAnirudh Venkataramanan 		    f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
16169daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_PRUNE;
16179daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS;
16189daf8208SAnirudh Venkataramanan 		}
16199daf8208SAnirudh Venkataramanan 		break;
16209daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE_MAC:
16219daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.ethertype_mac.mac_addr;
16224e83fc93SBruce Allan 		fallthrough;
16239daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE:
1624feee3cb3SBruce Allan 		off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
16259daf8208SAnirudh Venkataramanan 		*off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype);
16269daf8208SAnirudh Venkataramanan 		break;
16279daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC_VLAN:
16289daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.mac_vlan.mac_addr;
16299daf8208SAnirudh Venkataramanan 		vlan_id = f_info->l_data.mac_vlan.vlan_id;
16309daf8208SAnirudh Venkataramanan 		break;
16319daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_PROMISC_VLAN:
16329daf8208SAnirudh Venkataramanan 		vlan_id = f_info->l_data.mac_vlan.vlan_id;
16334e83fc93SBruce Allan 		fallthrough;
16349daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_PROMISC:
16359daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.mac_vlan.mac_addr;
16369daf8208SAnirudh Venkataramanan 		break;
16379daf8208SAnirudh Venkataramanan 	default:
16389daf8208SAnirudh Venkataramanan 		break;
16399daf8208SAnirudh Venkataramanan 	}
16409daf8208SAnirudh Venkataramanan 
16419daf8208SAnirudh Venkataramanan 	s_rule->type = (f_info->flag & ICE_FLTR_RX) ?
16429daf8208SAnirudh Venkataramanan 		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) :
16439daf8208SAnirudh Venkataramanan 		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
16449daf8208SAnirudh Venkataramanan 
16459daf8208SAnirudh Venkataramanan 	/* Recipe set depending on lookup type */
16469daf8208SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(f_info->lkup_type);
16479daf8208SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(f_info->src);
16489daf8208SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act);
16499daf8208SAnirudh Venkataramanan 
16509daf8208SAnirudh Venkataramanan 	if (daddr)
165174118f7aSZhenning Xiao 		ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr);
16529daf8208SAnirudh Venkataramanan 
16539daf8208SAnirudh Venkataramanan 	if (!(vlan_id > ICE_MAX_VLAN_ID)) {
1654feee3cb3SBruce Allan 		off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
16559daf8208SAnirudh Venkataramanan 		*off = cpu_to_be16(vlan_id);
16569daf8208SAnirudh Venkataramanan 	}
16579daf8208SAnirudh Venkataramanan 
16589daf8208SAnirudh Venkataramanan 	/* Create the switch rule with the final dummy Ethernet header */
16599daf8208SAnirudh Venkataramanan 	if (opc != ice_aqc_opc_update_sw_rules)
166074118f7aSZhenning Xiao 		s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(eth_hdr_sz);
16619daf8208SAnirudh Venkataramanan }
16629daf8208SAnirudh Venkataramanan 
16639daf8208SAnirudh Venkataramanan /**
16649daf8208SAnirudh Venkataramanan  * ice_add_marker_act
16659daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
16669daf8208SAnirudh Venkataramanan  * @m_ent: the management entry for which sw marker needs to be added
16679daf8208SAnirudh Venkataramanan  * @sw_marker: sw marker to tag the Rx descriptor with
1668f9867df6SAnirudh Venkataramanan  * @l_id: large action resource ID
16699daf8208SAnirudh Venkataramanan  *
16709daf8208SAnirudh Venkataramanan  * Create a large action to hold software marker and update the switch rule
16719daf8208SAnirudh Venkataramanan  * entry pointed by m_ent with newly created large action
16729daf8208SAnirudh Venkataramanan  */
16735e24d598STony Nguyen static int
16749daf8208SAnirudh Venkataramanan ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
16759daf8208SAnirudh Venkataramanan 		   u16 sw_marker, u16 l_id)
16769daf8208SAnirudh Venkataramanan {
16779daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *lg_act, *rx_tx;
16789daf8208SAnirudh Venkataramanan 	/* For software marker we need 3 large actions
16799daf8208SAnirudh Venkataramanan 	 * 1. FWD action: FWD TO VSI or VSI LIST
1680f9867df6SAnirudh Venkataramanan 	 * 2. GENERIC VALUE action to hold the profile ID
1681f9867df6SAnirudh Venkataramanan 	 * 3. GENERIC VALUE action to hold the software marker ID
16829daf8208SAnirudh Venkataramanan 	 */
16839daf8208SAnirudh Venkataramanan 	const u16 num_lg_acts = 3;
16849daf8208SAnirudh Venkataramanan 	u16 lg_act_size;
16859daf8208SAnirudh Venkataramanan 	u16 rules_size;
16865518ac2aSTony Nguyen 	int status;
16879daf8208SAnirudh Venkataramanan 	u32 act;
16885726ca0eSAnirudh Venkataramanan 	u16 id;
16899daf8208SAnirudh Venkataramanan 
16909daf8208SAnirudh Venkataramanan 	if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
1691d54699e2STony Nguyen 		return -EINVAL;
16929daf8208SAnirudh Venkataramanan 
16939daf8208SAnirudh Venkataramanan 	/* Create two back-to-back switch rules and submit them to the HW using
16949daf8208SAnirudh Venkataramanan 	 * one memory buffer:
16959daf8208SAnirudh Venkataramanan 	 *    1. Large Action
1696d337f2afSAnirudh Venkataramanan 	 *    2. Look up Tx Rx
16979daf8208SAnirudh Venkataramanan 	 */
16989daf8208SAnirudh Venkataramanan 	lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(num_lg_acts);
16999daf8208SAnirudh Venkataramanan 	rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
17009daf8208SAnirudh Venkataramanan 	lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL);
17019daf8208SAnirudh Venkataramanan 	if (!lg_act)
1702d54699e2STony Nguyen 		return -ENOMEM;
17039daf8208SAnirudh Venkataramanan 
17049daf8208SAnirudh Venkataramanan 	rx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size);
17059daf8208SAnirudh Venkataramanan 
17069daf8208SAnirudh Venkataramanan 	/* Fill in the first switch rule i.e. large action */
17079daf8208SAnirudh Venkataramanan 	lg_act->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT);
17089daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.index = cpu_to_le16(l_id);
17099daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.size = cpu_to_le16(num_lg_acts);
17109daf8208SAnirudh Venkataramanan 
17119daf8208SAnirudh Venkataramanan 	/* First action VSI forwarding or VSI list forwarding depending on how
17129daf8208SAnirudh Venkataramanan 	 * many VSIs
17139daf8208SAnirudh Venkataramanan 	 */
17145726ca0eSAnirudh Venkataramanan 	id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :
17155726ca0eSAnirudh Venkataramanan 		m_ent->fltr_info.fwd_id.hw_vsi_id;
17169daf8208SAnirudh Venkataramanan 
17179daf8208SAnirudh Venkataramanan 	act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
171866486d89SBruce Allan 	act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
17199daf8208SAnirudh Venkataramanan 	if (m_ent->vsi_count > 1)
17209daf8208SAnirudh Venkataramanan 		act |= ICE_LG_ACT_VSI_LIST;
17219daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.act[0] = cpu_to_le32(act);
17229daf8208SAnirudh Venkataramanan 
17239daf8208SAnirudh Venkataramanan 	/* Second action descriptor type */
17249daf8208SAnirudh Venkataramanan 	act = ICE_LG_ACT_GENERIC;
17259daf8208SAnirudh Venkataramanan 
17269daf8208SAnirudh Venkataramanan 	act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
17279daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.act[1] = cpu_to_le32(act);
17289daf8208SAnirudh Venkataramanan 
17294381147dSAnirudh Venkataramanan 	act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
17304381147dSAnirudh Venkataramanan 	       ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
17319daf8208SAnirudh Venkataramanan 
17329daf8208SAnirudh Venkataramanan 	/* Third action Marker value */
17339daf8208SAnirudh Venkataramanan 	act |= ICE_LG_ACT_GENERIC;
17349daf8208SAnirudh Venkataramanan 	act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
17359daf8208SAnirudh Venkataramanan 		ICE_LG_ACT_GENERIC_VALUE_M;
17369daf8208SAnirudh Venkataramanan 
17379daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.act[2] = cpu_to_le32(act);
17389daf8208SAnirudh Venkataramanan 
1739d337f2afSAnirudh Venkataramanan 	/* call the fill switch rule to fill the lookup Tx Rx structure */
17409daf8208SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,
17419daf8208SAnirudh Venkataramanan 			 ice_aqc_opc_update_sw_rules);
17429daf8208SAnirudh Venkataramanan 
1743f9867df6SAnirudh Venkataramanan 	/* Update the action to point to the large action ID */
17449daf8208SAnirudh Venkataramanan 	rx_tx->pdata.lkup_tx_rx.act =
17459daf8208SAnirudh Venkataramanan 		cpu_to_le32(ICE_SINGLE_ACT_PTR |
17469daf8208SAnirudh Venkataramanan 			    ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
17479daf8208SAnirudh Venkataramanan 			     ICE_SINGLE_ACT_PTR_VAL_M));
17489daf8208SAnirudh Venkataramanan 
1749f9867df6SAnirudh Venkataramanan 	/* Use the filter rule ID of the previously created rule with single
17509daf8208SAnirudh Venkataramanan 	 * act. Once the update happens, hardware will treat this as large
17519daf8208SAnirudh Venkataramanan 	 * action
17529daf8208SAnirudh Venkataramanan 	 */
17539daf8208SAnirudh Venkataramanan 	rx_tx->pdata.lkup_tx_rx.index =
17549daf8208SAnirudh Venkataramanan 		cpu_to_le16(m_ent->fltr_info.fltr_rule_id);
17559daf8208SAnirudh Venkataramanan 
17569daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, lg_act, rules_size, 2,
17579daf8208SAnirudh Venkataramanan 				 ice_aqc_opc_update_sw_rules, NULL);
17589daf8208SAnirudh Venkataramanan 	if (!status) {
17599daf8208SAnirudh Venkataramanan 		m_ent->lg_act_idx = l_id;
17609daf8208SAnirudh Venkataramanan 		m_ent->sw_marker_id = sw_marker;
17619daf8208SAnirudh Venkataramanan 	}
17629daf8208SAnirudh Venkataramanan 
17639daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), lg_act);
17649daf8208SAnirudh Venkataramanan 	return status;
17659daf8208SAnirudh Venkataramanan }
17669daf8208SAnirudh Venkataramanan 
17679daf8208SAnirudh Venkataramanan /**
17689daf8208SAnirudh Venkataramanan  * ice_create_vsi_list_map
17699daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
17705726ca0eSAnirudh Venkataramanan  * @vsi_handle_arr: array of VSI handles to set in the VSI mapping
17715726ca0eSAnirudh Venkataramanan  * @num_vsi: number of VSI handles in the array
1772f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID generated as part of allocate resource
17739daf8208SAnirudh Venkataramanan  *
1774f9867df6SAnirudh Venkataramanan  * Helper function to create a new entry of VSI list ID to VSI mapping
1775f9867df6SAnirudh Venkataramanan  * using the given VSI list ID
17769daf8208SAnirudh Venkataramanan  */
17779daf8208SAnirudh Venkataramanan static struct ice_vsi_list_map_info *
17785726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
17799daf8208SAnirudh Venkataramanan 			u16 vsi_list_id)
17809daf8208SAnirudh Venkataramanan {
17819daf8208SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
17829daf8208SAnirudh Venkataramanan 	struct ice_vsi_list_map_info *v_map;
17839daf8208SAnirudh Venkataramanan 	int i;
17849daf8208SAnirudh Venkataramanan 
178536ac7911SBruce Allan 	v_map = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*v_map), GFP_KERNEL);
17869daf8208SAnirudh Venkataramanan 	if (!v_map)
17879daf8208SAnirudh Venkataramanan 		return NULL;
17889daf8208SAnirudh Venkataramanan 
17899daf8208SAnirudh Venkataramanan 	v_map->vsi_list_id = vsi_list_id;
17905726ca0eSAnirudh Venkataramanan 	v_map->ref_cnt = 1;
17919daf8208SAnirudh Venkataramanan 	for (i = 0; i < num_vsi; i++)
17925726ca0eSAnirudh Venkataramanan 		set_bit(vsi_handle_arr[i], v_map->vsi_map);
17939daf8208SAnirudh Venkataramanan 
17949daf8208SAnirudh Venkataramanan 	list_add(&v_map->list_entry, &sw->vsi_list_map_head);
17959daf8208SAnirudh Venkataramanan 	return v_map;
17969daf8208SAnirudh Venkataramanan }
17979daf8208SAnirudh Venkataramanan 
17989daf8208SAnirudh Venkataramanan /**
17999daf8208SAnirudh Venkataramanan  * ice_update_vsi_list_rule
18009daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
18015726ca0eSAnirudh Venkataramanan  * @vsi_handle_arr: array of VSI handles to form a VSI list
18025726ca0eSAnirudh Venkataramanan  * @num_vsi: number of VSI handles in the array
1803f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID generated as part of allocate resource
18049daf8208SAnirudh Venkataramanan  * @remove: Boolean value to indicate if this is a remove action
18059daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
18069daf8208SAnirudh Venkataramanan  * @lkup_type: lookup type of the filter
18079daf8208SAnirudh Venkataramanan  *
18089daf8208SAnirudh Venkataramanan  * Call AQ command to add a new switch rule or update existing switch rule
1809f9867df6SAnirudh Venkataramanan  * using the given VSI list ID
18109daf8208SAnirudh Venkataramanan  */
18115e24d598STony Nguyen static int
18125726ca0eSAnirudh Venkataramanan ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
18139daf8208SAnirudh Venkataramanan 			 u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,
18149daf8208SAnirudh Venkataramanan 			 enum ice_sw_lkup_type lkup_type)
18159daf8208SAnirudh Venkataramanan {
18169daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
18179daf8208SAnirudh Venkataramanan 	u16 s_rule_size;
18186dae8aa0SBruce Allan 	u16 rule_type;
18195518ac2aSTony Nguyen 	int status;
18209daf8208SAnirudh Venkataramanan 	int i;
18219daf8208SAnirudh Venkataramanan 
18229daf8208SAnirudh Venkataramanan 	if (!num_vsi)
1823d54699e2STony Nguyen 		return -EINVAL;
18249daf8208SAnirudh Venkataramanan 
18259daf8208SAnirudh Venkataramanan 	if (lkup_type == ICE_SW_LKUP_MAC ||
18269daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
18279daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
18289daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
18299daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC ||
18309daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN)
18316dae8aa0SBruce Allan 		rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR :
18329daf8208SAnirudh Venkataramanan 			ICE_AQC_SW_RULES_T_VSI_LIST_SET;
18339daf8208SAnirudh Venkataramanan 	else if (lkup_type == ICE_SW_LKUP_VLAN)
18346dae8aa0SBruce Allan 		rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR :
18359daf8208SAnirudh Venkataramanan 			ICE_AQC_SW_RULES_T_PRUNE_LIST_SET;
18369daf8208SAnirudh Venkataramanan 	else
1837d54699e2STony Nguyen 		return -EINVAL;
18389daf8208SAnirudh Venkataramanan 
18399daf8208SAnirudh Venkataramanan 	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(num_vsi);
18409daf8208SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
18419daf8208SAnirudh Venkataramanan 	if (!s_rule)
1842d54699e2STony Nguyen 		return -ENOMEM;
18435726ca0eSAnirudh Venkataramanan 	for (i = 0; i < num_vsi; i++) {
18445726ca0eSAnirudh Venkataramanan 		if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {
1845d54699e2STony Nguyen 			status = -EINVAL;
18465726ca0eSAnirudh Venkataramanan 			goto exit;
18475726ca0eSAnirudh Venkataramanan 		}
18485726ca0eSAnirudh Venkataramanan 		/* AQ call requires hw_vsi_id(s) */
18495726ca0eSAnirudh Venkataramanan 		s_rule->pdata.vsi_list.vsi[i] =
18505726ca0eSAnirudh Venkataramanan 			cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));
18515726ca0eSAnirudh Venkataramanan 	}
18529daf8208SAnirudh Venkataramanan 
18536dae8aa0SBruce Allan 	s_rule->type = cpu_to_le16(rule_type);
18549daf8208SAnirudh Venkataramanan 	s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi);
18559daf8208SAnirudh Venkataramanan 	s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
18569daf8208SAnirudh Venkataramanan 
18579daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);
18589daf8208SAnirudh Venkataramanan 
18595726ca0eSAnirudh Venkataramanan exit:
18609daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
18619daf8208SAnirudh Venkataramanan 	return status;
18629daf8208SAnirudh Venkataramanan }
18639daf8208SAnirudh Venkataramanan 
18649daf8208SAnirudh Venkataramanan /**
18659daf8208SAnirudh Venkataramanan  * ice_create_vsi_list_rule - Creates and populates a VSI list rule
1866f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
18675726ca0eSAnirudh Venkataramanan  * @vsi_handle_arr: array of VSI handles to form a VSI list
18685726ca0eSAnirudh Venkataramanan  * @num_vsi: number of VSI handles in the array
18699daf8208SAnirudh Venkataramanan  * @vsi_list_id: stores the ID of the VSI list to be created
18709daf8208SAnirudh Venkataramanan  * @lkup_type: switch rule filter's lookup type
18719daf8208SAnirudh Venkataramanan  */
18725e24d598STony Nguyen static int
18735726ca0eSAnirudh Venkataramanan ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
18749daf8208SAnirudh Venkataramanan 			 u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)
18759daf8208SAnirudh Venkataramanan {
18765e24d598STony Nguyen 	int status;
18779daf8208SAnirudh Venkataramanan 
18789daf8208SAnirudh Venkataramanan 	status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,
18799daf8208SAnirudh Venkataramanan 					    ice_aqc_opc_alloc_res);
18809daf8208SAnirudh Venkataramanan 	if (status)
18819daf8208SAnirudh Venkataramanan 		return status;
18829daf8208SAnirudh Venkataramanan 
18839daf8208SAnirudh Venkataramanan 	/* Update the newly created VSI list to include the specified VSIs */
18845726ca0eSAnirudh Venkataramanan 	return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,
18855726ca0eSAnirudh Venkataramanan 					*vsi_list_id, false,
18865726ca0eSAnirudh Venkataramanan 					ice_aqc_opc_add_sw_rules, lkup_type);
18879daf8208SAnirudh Venkataramanan }
18889daf8208SAnirudh Venkataramanan 
18899daf8208SAnirudh Venkataramanan /**
18909daf8208SAnirudh Venkataramanan  * ice_create_pkt_fwd_rule
18919daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
18929daf8208SAnirudh Venkataramanan  * @f_entry: entry containing packet forwarding information
18939daf8208SAnirudh Venkataramanan  *
18949daf8208SAnirudh Venkataramanan  * Create switch rule with given filter information and add an entry
18959daf8208SAnirudh Venkataramanan  * to the corresponding filter management list to track this switch rule
18969daf8208SAnirudh Venkataramanan  * and VSI mapping
18979daf8208SAnirudh Venkataramanan  */
18985e24d598STony Nguyen static int
18999daf8208SAnirudh Venkataramanan ice_create_pkt_fwd_rule(struct ice_hw *hw,
19009daf8208SAnirudh Venkataramanan 			struct ice_fltr_list_entry *f_entry)
19019daf8208SAnirudh Venkataramanan {
19029daf8208SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *fm_entry;
19039daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
19049daf8208SAnirudh Venkataramanan 	enum ice_sw_lkup_type l_type;
190580d144c9SAnirudh Venkataramanan 	struct ice_sw_recipe *recp;
19065e24d598STony Nguyen 	int status;
19079daf8208SAnirudh Venkataramanan 
19089daf8208SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
19099daf8208SAnirudh Venkataramanan 			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);
19109daf8208SAnirudh Venkataramanan 	if (!s_rule)
1911d54699e2STony Nguyen 		return -ENOMEM;
19129daf8208SAnirudh Venkataramanan 	fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry),
19139daf8208SAnirudh Venkataramanan 				GFP_KERNEL);
19149daf8208SAnirudh Venkataramanan 	if (!fm_entry) {
1915d54699e2STony Nguyen 		status = -ENOMEM;
19169daf8208SAnirudh Venkataramanan 		goto ice_create_pkt_fwd_rule_exit;
19179daf8208SAnirudh Venkataramanan 	}
19189daf8208SAnirudh Venkataramanan 
19199daf8208SAnirudh Venkataramanan 	fm_entry->fltr_info = f_entry->fltr_info;
19209daf8208SAnirudh Venkataramanan 
19219daf8208SAnirudh Venkataramanan 	/* Initialize all the fields for the management entry */
19229daf8208SAnirudh Venkataramanan 	fm_entry->vsi_count = 1;
19239daf8208SAnirudh Venkataramanan 	fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX;
19249daf8208SAnirudh Venkataramanan 	fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID;
19259daf8208SAnirudh Venkataramanan 	fm_entry->counter_index = ICE_INVAL_COUNTER_ID;
19269daf8208SAnirudh Venkataramanan 
19279daf8208SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule,
19289daf8208SAnirudh Venkataramanan 			 ice_aqc_opc_add_sw_rules);
19299daf8208SAnirudh Venkataramanan 
19309daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
19319daf8208SAnirudh Venkataramanan 				 ice_aqc_opc_add_sw_rules, NULL);
19329daf8208SAnirudh Venkataramanan 	if (status) {
19339daf8208SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
19349daf8208SAnirudh Venkataramanan 		goto ice_create_pkt_fwd_rule_exit;
19359daf8208SAnirudh Venkataramanan 	}
19369daf8208SAnirudh Venkataramanan 
19379daf8208SAnirudh Venkataramanan 	f_entry->fltr_info.fltr_rule_id =
19389daf8208SAnirudh Venkataramanan 		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
19399daf8208SAnirudh Venkataramanan 	fm_entry->fltr_info.fltr_rule_id =
19409daf8208SAnirudh Venkataramanan 		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
19419daf8208SAnirudh Venkataramanan 
19429daf8208SAnirudh Venkataramanan 	/* The book keeping entries will get removed when base driver
19439daf8208SAnirudh Venkataramanan 	 * calls remove filter AQ command
19449daf8208SAnirudh Venkataramanan 	 */
19459daf8208SAnirudh Venkataramanan 	l_type = fm_entry->fltr_info.lkup_type;
194680d144c9SAnirudh Venkataramanan 	recp = &hw->switch_info->recp_list[l_type];
194780d144c9SAnirudh Venkataramanan 	list_add(&fm_entry->list_entry, &recp->filt_rules);
194880d144c9SAnirudh Venkataramanan 
19499daf8208SAnirudh Venkataramanan ice_create_pkt_fwd_rule_exit:
19509daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
19519daf8208SAnirudh Venkataramanan 	return status;
19529daf8208SAnirudh Venkataramanan }
19539daf8208SAnirudh Venkataramanan 
19549daf8208SAnirudh Venkataramanan /**
19559daf8208SAnirudh Venkataramanan  * ice_update_pkt_fwd_rule
19569daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
195780d144c9SAnirudh Venkataramanan  * @f_info: filter information for switch rule
19589daf8208SAnirudh Venkataramanan  *
19599daf8208SAnirudh Venkataramanan  * Call AQ command to update a previously created switch rule with a
1960f9867df6SAnirudh Venkataramanan  * VSI list ID
19619daf8208SAnirudh Venkataramanan  */
19625e24d598STony Nguyen static int
196380d144c9SAnirudh Venkataramanan ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
19649daf8208SAnirudh Venkataramanan {
19659daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
19665e24d598STony Nguyen 	int status;
19679daf8208SAnirudh Venkataramanan 
19689daf8208SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
19699daf8208SAnirudh Venkataramanan 			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);
19709daf8208SAnirudh Venkataramanan 	if (!s_rule)
1971d54699e2STony Nguyen 		return -ENOMEM;
19729daf8208SAnirudh Venkataramanan 
197380d144c9SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);
19749daf8208SAnirudh Venkataramanan 
197580d144c9SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(f_info->fltr_rule_id);
19769daf8208SAnirudh Venkataramanan 
19779daf8208SAnirudh Venkataramanan 	/* Update switch rule with new rule set to forward VSI list */
19789daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
19799daf8208SAnirudh Venkataramanan 				 ice_aqc_opc_update_sw_rules, NULL);
19809daf8208SAnirudh Venkataramanan 
19819daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
19829daf8208SAnirudh Venkataramanan 	return status;
19839daf8208SAnirudh Venkataramanan }
19849daf8208SAnirudh Venkataramanan 
19859daf8208SAnirudh Venkataramanan /**
1986b1edc14aSMd Fahad Iqbal Polash  * ice_update_sw_rule_bridge_mode
1987f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
1988b1edc14aSMd Fahad Iqbal Polash  *
1989b1edc14aSMd Fahad Iqbal Polash  * Updates unicast switch filter rules based on VEB/VEPA mode
1990b1edc14aSMd Fahad Iqbal Polash  */
19915e24d598STony Nguyen int ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
1992b1edc14aSMd Fahad Iqbal Polash {
1993b1edc14aSMd Fahad Iqbal Polash 	struct ice_switch_info *sw = hw->switch_info;
1994b1edc14aSMd Fahad Iqbal Polash 	struct ice_fltr_mgmt_list_entry *fm_entry;
1995b1edc14aSMd Fahad Iqbal Polash 	struct list_head *rule_head;
1996b1edc14aSMd Fahad Iqbal Polash 	struct mutex *rule_lock; /* Lock to protect filter rule list */
19975518ac2aSTony Nguyen 	int status = 0;
1998b1edc14aSMd Fahad Iqbal Polash 
1999b1edc14aSMd Fahad Iqbal Polash 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
2000b1edc14aSMd Fahad Iqbal Polash 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
2001b1edc14aSMd Fahad Iqbal Polash 
2002b1edc14aSMd Fahad Iqbal Polash 	mutex_lock(rule_lock);
2003b1edc14aSMd Fahad Iqbal Polash 	list_for_each_entry(fm_entry, rule_head, list_entry) {
2004b1edc14aSMd Fahad Iqbal Polash 		struct ice_fltr_info *fi = &fm_entry->fltr_info;
2005b1edc14aSMd Fahad Iqbal Polash 		u8 *addr = fi->l_data.mac.mac_addr;
2006b1edc14aSMd Fahad Iqbal Polash 
2007b1edc14aSMd Fahad Iqbal Polash 		/* Update unicast Tx rules to reflect the selected
2008b1edc14aSMd Fahad Iqbal Polash 		 * VEB/VEPA mode
2009b1edc14aSMd Fahad Iqbal Polash 		 */
2010b1edc14aSMd Fahad Iqbal Polash 		if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) &&
2011b1edc14aSMd Fahad Iqbal Polash 		    (fi->fltr_act == ICE_FWD_TO_VSI ||
2012b1edc14aSMd Fahad Iqbal Polash 		     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
2013b1edc14aSMd Fahad Iqbal Polash 		     fi->fltr_act == ICE_FWD_TO_Q ||
2014b1edc14aSMd Fahad Iqbal Polash 		     fi->fltr_act == ICE_FWD_TO_QGRP)) {
2015b1edc14aSMd Fahad Iqbal Polash 			status = ice_update_pkt_fwd_rule(hw, fi);
2016b1edc14aSMd Fahad Iqbal Polash 			if (status)
2017b1edc14aSMd Fahad Iqbal Polash 				break;
2018b1edc14aSMd Fahad Iqbal Polash 		}
2019b1edc14aSMd Fahad Iqbal Polash 	}
2020b1edc14aSMd Fahad Iqbal Polash 
2021b1edc14aSMd Fahad Iqbal Polash 	mutex_unlock(rule_lock);
2022b1edc14aSMd Fahad Iqbal Polash 
2023b1edc14aSMd Fahad Iqbal Polash 	return status;
2024b1edc14aSMd Fahad Iqbal Polash }
2025b1edc14aSMd Fahad Iqbal Polash 
2026b1edc14aSMd Fahad Iqbal Polash /**
202780d144c9SAnirudh Venkataramanan  * ice_add_update_vsi_list
20289daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
20299daf8208SAnirudh Venkataramanan  * @m_entry: pointer to current filter management list entry
20309daf8208SAnirudh Venkataramanan  * @cur_fltr: filter information from the book keeping entry
20319daf8208SAnirudh Venkataramanan  * @new_fltr: filter information with the new VSI to be added
20329daf8208SAnirudh Venkataramanan  *
20339daf8208SAnirudh Venkataramanan  * Call AQ command to add or update previously created VSI list with new VSI.
20349daf8208SAnirudh Venkataramanan  *
20359daf8208SAnirudh Venkataramanan  * Helper function to do book keeping associated with adding filter information
2036d337f2afSAnirudh Venkataramanan  * The algorithm to do the book keeping is described below :
20379daf8208SAnirudh Venkataramanan  * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.)
20389daf8208SAnirudh Venkataramanan  *	if only one VSI has been added till now
20399daf8208SAnirudh Venkataramanan  *		Allocate a new VSI list and add two VSIs
20409daf8208SAnirudh Venkataramanan  *		to this list using switch rule command
20419daf8208SAnirudh Venkataramanan  *		Update the previously created switch rule with the
2042f9867df6SAnirudh Venkataramanan  *		newly created VSI list ID
20439daf8208SAnirudh Venkataramanan  *	if a VSI list was previously created
20449daf8208SAnirudh Venkataramanan  *		Add the new VSI to the previously created VSI list set
20459daf8208SAnirudh Venkataramanan  *		using the update switch rule command
20469daf8208SAnirudh Venkataramanan  */
20475e24d598STony Nguyen static int
204880d144c9SAnirudh Venkataramanan ice_add_update_vsi_list(struct ice_hw *hw,
20499daf8208SAnirudh Venkataramanan 			struct ice_fltr_mgmt_list_entry *m_entry,
20509daf8208SAnirudh Venkataramanan 			struct ice_fltr_info *cur_fltr,
20519daf8208SAnirudh Venkataramanan 			struct ice_fltr_info *new_fltr)
20529daf8208SAnirudh Venkataramanan {
20539daf8208SAnirudh Venkataramanan 	u16 vsi_list_id = 0;
20545518ac2aSTony Nguyen 	int status = 0;
20559daf8208SAnirudh Venkataramanan 
20569daf8208SAnirudh Venkataramanan 	if ((cur_fltr->fltr_act == ICE_FWD_TO_Q ||
20579daf8208SAnirudh Venkataramanan 	     cur_fltr->fltr_act == ICE_FWD_TO_QGRP))
2058d54699e2STony Nguyen 		return -EOPNOTSUPP;
20599daf8208SAnirudh Venkataramanan 
20609daf8208SAnirudh Venkataramanan 	if ((new_fltr->fltr_act == ICE_FWD_TO_Q ||
20619daf8208SAnirudh Venkataramanan 	     new_fltr->fltr_act == ICE_FWD_TO_QGRP) &&
20629daf8208SAnirudh Venkataramanan 	    (cur_fltr->fltr_act == ICE_FWD_TO_VSI ||
20639daf8208SAnirudh Venkataramanan 	     cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST))
2064d54699e2STony Nguyen 		return -EOPNOTSUPP;
20659daf8208SAnirudh Venkataramanan 
20669daf8208SAnirudh Venkataramanan 	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
20679daf8208SAnirudh Venkataramanan 		/* Only one entry existed in the mapping and it was not already
20689daf8208SAnirudh Venkataramanan 		 * a part of a VSI list. So, create a VSI list with the old and
20699daf8208SAnirudh Venkataramanan 		 * new VSIs.
20709daf8208SAnirudh Venkataramanan 		 */
207180d144c9SAnirudh Venkataramanan 		struct ice_fltr_info tmp_fltr;
20725726ca0eSAnirudh Venkataramanan 		u16 vsi_handle_arr[2];
20739daf8208SAnirudh Venkataramanan 
20749daf8208SAnirudh Venkataramanan 		/* A rule already exists with the new VSI being added */
20755726ca0eSAnirudh Venkataramanan 		if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id)
2076d54699e2STony Nguyen 			return -EEXIST;
20779daf8208SAnirudh Venkataramanan 
20785726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[0] = cur_fltr->vsi_handle;
20795726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[1] = new_fltr->vsi_handle;
20805726ca0eSAnirudh Venkataramanan 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
20819daf8208SAnirudh Venkataramanan 						  &vsi_list_id,
20829daf8208SAnirudh Venkataramanan 						  new_fltr->lkup_type);
20839daf8208SAnirudh Venkataramanan 		if (status)
20849daf8208SAnirudh Venkataramanan 			return status;
20859daf8208SAnirudh Venkataramanan 
208680d144c9SAnirudh Venkataramanan 		tmp_fltr = *new_fltr;
208780d144c9SAnirudh Venkataramanan 		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
208880d144c9SAnirudh Venkataramanan 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
208980d144c9SAnirudh Venkataramanan 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
20909daf8208SAnirudh Venkataramanan 		/* Update the previous switch rule of "MAC forward to VSI" to
20919daf8208SAnirudh Venkataramanan 		 * "MAC fwd to VSI list"
20929daf8208SAnirudh Venkataramanan 		 */
209380d144c9SAnirudh Venkataramanan 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
20949daf8208SAnirudh Venkataramanan 		if (status)
20959daf8208SAnirudh Venkataramanan 			return status;
20969daf8208SAnirudh Venkataramanan 
20979daf8208SAnirudh Venkataramanan 		cur_fltr->fwd_id.vsi_list_id = vsi_list_id;
20989daf8208SAnirudh Venkataramanan 		cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
20999daf8208SAnirudh Venkataramanan 		m_entry->vsi_list_info =
21005726ca0eSAnirudh Venkataramanan 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
21019daf8208SAnirudh Venkataramanan 						vsi_list_id);
21029daf8208SAnirudh Venkataramanan 
21037a91d3f0SJacek Bułatek 		if (!m_entry->vsi_list_info)
2104d54699e2STony Nguyen 			return -ENOMEM;
21057a91d3f0SJacek Bułatek 
21069daf8208SAnirudh Venkataramanan 		/* If this entry was large action then the large action needs
21079daf8208SAnirudh Venkataramanan 		 * to be updated to point to FWD to VSI list
21089daf8208SAnirudh Venkataramanan 		 */
21099daf8208SAnirudh Venkataramanan 		if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID)
21109daf8208SAnirudh Venkataramanan 			status =
21119daf8208SAnirudh Venkataramanan 			    ice_add_marker_act(hw, m_entry,
21129daf8208SAnirudh Venkataramanan 					       m_entry->sw_marker_id,
21139daf8208SAnirudh Venkataramanan 					       m_entry->lg_act_idx);
21149daf8208SAnirudh Venkataramanan 	} else {
21155726ca0eSAnirudh Venkataramanan 		u16 vsi_handle = new_fltr->vsi_handle;
21169daf8208SAnirudh Venkataramanan 		enum ice_adminq_opc opcode;
21179daf8208SAnirudh Venkataramanan 
2118f25dad19SBruce Allan 		if (!m_entry->vsi_list_info)
2119d54699e2STony Nguyen 			return -EIO;
2120f25dad19SBruce Allan 
21219daf8208SAnirudh Venkataramanan 		/* A rule already exists with the new VSI being added */
21225726ca0eSAnirudh Venkataramanan 		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
21239daf8208SAnirudh Venkataramanan 			return 0;
21249daf8208SAnirudh Venkataramanan 
21259daf8208SAnirudh Venkataramanan 		/* Update the previously created VSI list set with
2126f9867df6SAnirudh Venkataramanan 		 * the new VSI ID passed in
21279daf8208SAnirudh Venkataramanan 		 */
21289daf8208SAnirudh Venkataramanan 		vsi_list_id = cur_fltr->fwd_id.vsi_list_id;
21299daf8208SAnirudh Venkataramanan 		opcode = ice_aqc_opc_update_sw_rules;
21309daf8208SAnirudh Venkataramanan 
21315726ca0eSAnirudh Venkataramanan 		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
21325726ca0eSAnirudh Venkataramanan 						  vsi_list_id, false, opcode,
21339daf8208SAnirudh Venkataramanan 						  new_fltr->lkup_type);
2134f9867df6SAnirudh Venkataramanan 		/* update VSI list mapping info with new VSI ID */
21359daf8208SAnirudh Venkataramanan 		if (!status)
21365726ca0eSAnirudh Venkataramanan 			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
21379daf8208SAnirudh Venkataramanan 	}
21389daf8208SAnirudh Venkataramanan 	if (!status)
21399daf8208SAnirudh Venkataramanan 		m_entry->vsi_count++;
21409daf8208SAnirudh Venkataramanan 	return status;
21419daf8208SAnirudh Venkataramanan }
21429daf8208SAnirudh Venkataramanan 
21439daf8208SAnirudh Venkataramanan /**
214480d144c9SAnirudh Venkataramanan  * ice_find_rule_entry - Search a rule entry
21459daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
214680d144c9SAnirudh Venkataramanan  * @recp_id: lookup type for which the specified rule needs to be searched
214780d144c9SAnirudh Venkataramanan  * @f_info: rule information
21489daf8208SAnirudh Venkataramanan  *
214980d144c9SAnirudh Venkataramanan  * Helper function to search for a given rule entry
215080d144c9SAnirudh Venkataramanan  * Returns pointer to entry storing the rule if found
21519daf8208SAnirudh Venkataramanan  */
21529daf8208SAnirudh Venkataramanan static struct ice_fltr_mgmt_list_entry *
215380d144c9SAnirudh Venkataramanan ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
21549daf8208SAnirudh Venkataramanan {
215580d144c9SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;
21569daf8208SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
215780d144c9SAnirudh Venkataramanan 	struct list_head *list_head;
21589daf8208SAnirudh Venkataramanan 
215980d144c9SAnirudh Venkataramanan 	list_head = &sw->recp_list[recp_id].filt_rules;
216080d144c9SAnirudh Venkataramanan 	list_for_each_entry(list_itr, list_head, list_entry) {
216180d144c9SAnirudh Venkataramanan 		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
216280d144c9SAnirudh Venkataramanan 			    sizeof(f_info->l_data)) &&
216380d144c9SAnirudh Venkataramanan 		    f_info->flag == list_itr->fltr_info.flag) {
216480d144c9SAnirudh Venkataramanan 			ret = list_itr;
21659daf8208SAnirudh Venkataramanan 			break;
21669daf8208SAnirudh Venkataramanan 		}
21679daf8208SAnirudh Venkataramanan 	}
216880d144c9SAnirudh Venkataramanan 	return ret;
21699daf8208SAnirudh Venkataramanan }
21709daf8208SAnirudh Venkataramanan 
21719daf8208SAnirudh Venkataramanan /**
21725726ca0eSAnirudh Venkataramanan  * ice_find_vsi_list_entry - Search VSI list map with VSI count 1
21735726ca0eSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
21745726ca0eSAnirudh Venkataramanan  * @recp_id: lookup type for which VSI lists needs to be searched
21755726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to be found in VSI list
2176f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID found containing vsi_handle
21775726ca0eSAnirudh Venkataramanan  *
21785726ca0eSAnirudh Venkataramanan  * Helper function to search a VSI list with single entry containing given VSI
21795726ca0eSAnirudh Venkataramanan  * handle element. This can be extended further to search VSI list with more
21805726ca0eSAnirudh Venkataramanan  * than 1 vsi_count. Returns pointer to VSI list entry if found.
21815726ca0eSAnirudh Venkataramanan  */
21825726ca0eSAnirudh Venkataramanan static struct ice_vsi_list_map_info *
21835726ca0eSAnirudh Venkataramanan ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
21845726ca0eSAnirudh Venkataramanan 			u16 *vsi_list_id)
21855726ca0eSAnirudh Venkataramanan {
21865726ca0eSAnirudh Venkataramanan 	struct ice_vsi_list_map_info *map_info = NULL;
21875726ca0eSAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
21885726ca0eSAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *list_itr;
21895726ca0eSAnirudh Venkataramanan 	struct list_head *list_head;
21905726ca0eSAnirudh Venkataramanan 
21915726ca0eSAnirudh Venkataramanan 	list_head = &sw->recp_list[recp_id].filt_rules;
21925726ca0eSAnirudh Venkataramanan 	list_for_each_entry(list_itr, list_head, list_entry) {
21935726ca0eSAnirudh Venkataramanan 		if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {
21945726ca0eSAnirudh Venkataramanan 			map_info = list_itr->vsi_list_info;
21955726ca0eSAnirudh Venkataramanan 			if (test_bit(vsi_handle, map_info->vsi_map)) {
21965726ca0eSAnirudh Venkataramanan 				*vsi_list_id = map_info->vsi_list_id;
21975726ca0eSAnirudh Venkataramanan 				return map_info;
21985726ca0eSAnirudh Venkataramanan 			}
21995726ca0eSAnirudh Venkataramanan 		}
22005726ca0eSAnirudh Venkataramanan 	}
22015726ca0eSAnirudh Venkataramanan 	return NULL;
22025726ca0eSAnirudh Venkataramanan }
22035726ca0eSAnirudh Venkataramanan 
22045726ca0eSAnirudh Venkataramanan /**
220580d144c9SAnirudh Venkataramanan  * ice_add_rule_internal - add rule for a given lookup type
22069daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2207f9867df6SAnirudh Venkataramanan  * @recp_id: lookup type (recipe ID) for which rule has to be added
22089daf8208SAnirudh Venkataramanan  * @f_entry: structure containing MAC forwarding information
22099daf8208SAnirudh Venkataramanan  *
221080d144c9SAnirudh Venkataramanan  * Adds or updates the rule lists for a given recipe
22119daf8208SAnirudh Venkataramanan  */
22125e24d598STony Nguyen static int
221380d144c9SAnirudh Venkataramanan ice_add_rule_internal(struct ice_hw *hw, u8 recp_id,
221480d144c9SAnirudh Venkataramanan 		      struct ice_fltr_list_entry *f_entry)
22159daf8208SAnirudh Venkataramanan {
221680d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
22179daf8208SAnirudh Venkataramanan 	struct ice_fltr_info *new_fltr, *cur_fltr;
22189daf8208SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *m_entry;
221980d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
22205e24d598STony Nguyen 	int status = 0;
22219daf8208SAnirudh Venkataramanan 
22225726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
2223d54699e2STony Nguyen 		return -EINVAL;
22245726ca0eSAnirudh Venkataramanan 	f_entry->fltr_info.fwd_id.hw_vsi_id =
22255726ca0eSAnirudh Venkataramanan 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
22265726ca0eSAnirudh Venkataramanan 
222780d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
222880d144c9SAnirudh Venkataramanan 
222980d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
22309daf8208SAnirudh Venkataramanan 	new_fltr = &f_entry->fltr_info;
223180d144c9SAnirudh Venkataramanan 	if (new_fltr->flag & ICE_FLTR_RX)
223280d144c9SAnirudh Venkataramanan 		new_fltr->src = hw->port_info->lport;
223380d144c9SAnirudh Venkataramanan 	else if (new_fltr->flag & ICE_FLTR_TX)
22345726ca0eSAnirudh Venkataramanan 		new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id;
22359daf8208SAnirudh Venkataramanan 
223680d144c9SAnirudh Venkataramanan 	m_entry = ice_find_rule_entry(hw, recp_id, new_fltr);
223780d144c9SAnirudh Venkataramanan 	if (!m_entry) {
223880d144c9SAnirudh Venkataramanan 		mutex_unlock(rule_lock);
22399daf8208SAnirudh Venkataramanan 		return ice_create_pkt_fwd_rule(hw, f_entry);
224080d144c9SAnirudh Venkataramanan 	}
22419daf8208SAnirudh Venkataramanan 
22429daf8208SAnirudh Venkataramanan 	cur_fltr = &m_entry->fltr_info;
224380d144c9SAnirudh Venkataramanan 	status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);
224480d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
22459daf8208SAnirudh Venkataramanan 
224680d144c9SAnirudh Venkataramanan 	return status;
224780d144c9SAnirudh Venkataramanan }
224880d144c9SAnirudh Venkataramanan 
224980d144c9SAnirudh Venkataramanan /**
225080d144c9SAnirudh Venkataramanan  * ice_remove_vsi_list_rule
225180d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2252f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID generated as part of allocate resource
225380d144c9SAnirudh Venkataramanan  * @lkup_type: switch rule filter lookup type
225480d144c9SAnirudh Venkataramanan  *
225580d144c9SAnirudh Venkataramanan  * The VSI list should be emptied before this function is called to remove the
225680d144c9SAnirudh Venkataramanan  * VSI list.
225780d144c9SAnirudh Venkataramanan  */
22585e24d598STony Nguyen static int
225980d144c9SAnirudh Venkataramanan ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
226080d144c9SAnirudh Venkataramanan 			 enum ice_sw_lkup_type lkup_type)
226180d144c9SAnirudh Venkataramanan {
226280d144c9SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
226380d144c9SAnirudh Venkataramanan 	u16 s_rule_size;
22645518ac2aSTony Nguyen 	int status;
226580d144c9SAnirudh Venkataramanan 
226680d144c9SAnirudh Venkataramanan 	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0);
226780d144c9SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
226880d144c9SAnirudh Venkataramanan 	if (!s_rule)
2269d54699e2STony Nguyen 		return -ENOMEM;
227080d144c9SAnirudh Venkataramanan 
227180d144c9SAnirudh Venkataramanan 	s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);
227280d144c9SAnirudh Venkataramanan 	s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
227380d144c9SAnirudh Venkataramanan 
227480d144c9SAnirudh Venkataramanan 	/* Free the vsi_list resource that we allocated. It is assumed that the
227580d144c9SAnirudh Venkataramanan 	 * list is empty at this point.
227680d144c9SAnirudh Venkataramanan 	 */
227780d144c9SAnirudh Venkataramanan 	status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
227880d144c9SAnirudh Venkataramanan 					    ice_aqc_opc_free_res);
227980d144c9SAnirudh Venkataramanan 
228080d144c9SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
228180d144c9SAnirudh Venkataramanan 	return status;
228280d144c9SAnirudh Venkataramanan }
228380d144c9SAnirudh Venkataramanan 
228480d144c9SAnirudh Venkataramanan /**
228580d144c9SAnirudh Venkataramanan  * ice_rem_update_vsi_list
228680d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
22875726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle of the VSI to remove
228880d144c9SAnirudh Venkataramanan  * @fm_list: filter management entry for which the VSI list management needs to
228980d144c9SAnirudh Venkataramanan  *           be done
229080d144c9SAnirudh Venkataramanan  */
22915e24d598STony Nguyen static int
22925726ca0eSAnirudh Venkataramanan ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
229380d144c9SAnirudh Venkataramanan 			struct ice_fltr_mgmt_list_entry *fm_list)
229480d144c9SAnirudh Venkataramanan {
229580d144c9SAnirudh Venkataramanan 	enum ice_sw_lkup_type lkup_type;
229680d144c9SAnirudh Venkataramanan 	u16 vsi_list_id;
22975518ac2aSTony Nguyen 	int status = 0;
229880d144c9SAnirudh Venkataramanan 
229980d144c9SAnirudh Venkataramanan 	if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||
230080d144c9SAnirudh Venkataramanan 	    fm_list->vsi_count == 0)
2301d54699e2STony Nguyen 		return -EINVAL;
230280d144c9SAnirudh Venkataramanan 
230380d144c9SAnirudh Venkataramanan 	/* A rule with the VSI being removed does not exist */
23045726ca0eSAnirudh Venkataramanan 	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
2305d54699e2STony Nguyen 		return -ENOENT;
230680d144c9SAnirudh Venkataramanan 
230780d144c9SAnirudh Venkataramanan 	lkup_type = fm_list->fltr_info.lkup_type;
230880d144c9SAnirudh Venkataramanan 	vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;
23095726ca0eSAnirudh Venkataramanan 	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
231080d144c9SAnirudh Venkataramanan 					  ice_aqc_opc_update_sw_rules,
231180d144c9SAnirudh Venkataramanan 					  lkup_type);
231280d144c9SAnirudh Venkataramanan 	if (status)
231380d144c9SAnirudh Venkataramanan 		return status;
231480d144c9SAnirudh Venkataramanan 
231580d144c9SAnirudh Venkataramanan 	fm_list->vsi_count--;
23165726ca0eSAnirudh Venkataramanan 	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
231780d144c9SAnirudh Venkataramanan 
2318c60cdb13SBrett Creeley 	if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {
2319c60cdb13SBrett Creeley 		struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;
232080d144c9SAnirudh Venkataramanan 		struct ice_vsi_list_map_info *vsi_list_info =
232180d144c9SAnirudh Venkataramanan 			fm_list->vsi_list_info;
23225726ca0eSAnirudh Venkataramanan 		u16 rem_vsi_handle;
232380d144c9SAnirudh Venkataramanan 
23245726ca0eSAnirudh Venkataramanan 		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
232580d144c9SAnirudh Venkataramanan 						ICE_MAX_VSI);
23265726ca0eSAnirudh Venkataramanan 		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
2327d54699e2STony Nguyen 			return -EIO;
2328c60cdb13SBrett Creeley 
2329c60cdb13SBrett Creeley 		/* Make sure VSI list is empty before removing it below */
23305726ca0eSAnirudh Venkataramanan 		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
233180d144c9SAnirudh Venkataramanan 						  vsi_list_id, true,
233280d144c9SAnirudh Venkataramanan 						  ice_aqc_opc_update_sw_rules,
233380d144c9SAnirudh Venkataramanan 						  lkup_type);
233480d144c9SAnirudh Venkataramanan 		if (status)
233580d144c9SAnirudh Venkataramanan 			return status;
233680d144c9SAnirudh Venkataramanan 
2337c60cdb13SBrett Creeley 		tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;
2338c60cdb13SBrett Creeley 		tmp_fltr_info.fwd_id.hw_vsi_id =
2339c60cdb13SBrett Creeley 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
2340c60cdb13SBrett Creeley 		tmp_fltr_info.vsi_handle = rem_vsi_handle;
2341c60cdb13SBrett Creeley 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);
2342c60cdb13SBrett Creeley 		if (status) {
23439228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
2344c60cdb13SBrett Creeley 				  tmp_fltr_info.fwd_id.hw_vsi_id, status);
2345c60cdb13SBrett Creeley 			return status;
2346c60cdb13SBrett Creeley 		}
2347c60cdb13SBrett Creeley 
2348c60cdb13SBrett Creeley 		fm_list->fltr_info = tmp_fltr_info;
2349c60cdb13SBrett Creeley 	}
2350c60cdb13SBrett Creeley 
2351c60cdb13SBrett Creeley 	if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||
2352c60cdb13SBrett Creeley 	    (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {
2353c60cdb13SBrett Creeley 		struct ice_vsi_list_map_info *vsi_list_info =
2354c60cdb13SBrett Creeley 			fm_list->vsi_list_info;
2355c60cdb13SBrett Creeley 
235680d144c9SAnirudh Venkataramanan 		/* Remove the VSI list since it is no longer used */
235780d144c9SAnirudh Venkataramanan 		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
2358c60cdb13SBrett Creeley 		if (status) {
23599228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
2360c60cdb13SBrett Creeley 				  vsi_list_id, status);
236180d144c9SAnirudh Venkataramanan 			return status;
2362c60cdb13SBrett Creeley 		}
236380d144c9SAnirudh Venkataramanan 
236480d144c9SAnirudh Venkataramanan 		list_del(&vsi_list_info->list_entry);
236580d144c9SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
236680d144c9SAnirudh Venkataramanan 		fm_list->vsi_list_info = NULL;
236780d144c9SAnirudh Venkataramanan 	}
236880d144c9SAnirudh Venkataramanan 
236980d144c9SAnirudh Venkataramanan 	return status;
237080d144c9SAnirudh Venkataramanan }
237180d144c9SAnirudh Venkataramanan 
237280d144c9SAnirudh Venkataramanan /**
237380d144c9SAnirudh Venkataramanan  * ice_remove_rule_internal - Remove a filter rule of a given type
237480d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2375f9867df6SAnirudh Venkataramanan  * @recp_id: recipe ID for which the rule needs to removed
237680d144c9SAnirudh Venkataramanan  * @f_entry: rule entry containing filter information
237780d144c9SAnirudh Venkataramanan  */
23785e24d598STony Nguyen static int
237980d144c9SAnirudh Venkataramanan ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id,
238080d144c9SAnirudh Venkataramanan 			 struct ice_fltr_list_entry *f_entry)
238180d144c9SAnirudh Venkataramanan {
238280d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
238380d144c9SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *list_elem;
238480d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
238580d144c9SAnirudh Venkataramanan 	bool remove_rule = false;
23865726ca0eSAnirudh Venkataramanan 	u16 vsi_handle;
23875518ac2aSTony Nguyen 	int status = 0;
23885726ca0eSAnirudh Venkataramanan 
23895726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
2390d54699e2STony Nguyen 		return -EINVAL;
23915726ca0eSAnirudh Venkataramanan 	f_entry->fltr_info.fwd_id.hw_vsi_id =
23925726ca0eSAnirudh Venkataramanan 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
239380d144c9SAnirudh Venkataramanan 
239480d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
239580d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
239680d144c9SAnirudh Venkataramanan 	list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info);
239780d144c9SAnirudh Venkataramanan 	if (!list_elem) {
2398d54699e2STony Nguyen 		status = -ENOENT;
239980d144c9SAnirudh Venkataramanan 		goto exit;
240080d144c9SAnirudh Venkataramanan 	}
240180d144c9SAnirudh Venkataramanan 
240280d144c9SAnirudh Venkataramanan 	if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
240380d144c9SAnirudh Venkataramanan 		remove_rule = true;
24045726ca0eSAnirudh Venkataramanan 	} else if (!list_elem->vsi_list_info) {
2405d54699e2STony Nguyen 		status = -ENOENT;
24065726ca0eSAnirudh Venkataramanan 		goto exit;
2407f9264dd6SJacob Keller 	} else if (list_elem->vsi_list_info->ref_cnt > 1) {
2408f9264dd6SJacob Keller 		/* a ref_cnt > 1 indicates that the vsi_list is being
2409f9264dd6SJacob Keller 		 * shared by multiple rules. Decrement the ref_cnt and
2410f9264dd6SJacob Keller 		 * remove this rule, but do not modify the list, as it
2411f9264dd6SJacob Keller 		 * is in-use by other rules.
2412f9264dd6SJacob Keller 		 */
24135726ca0eSAnirudh Venkataramanan 		list_elem->vsi_list_info->ref_cnt--;
2414f9264dd6SJacob Keller 		remove_rule = true;
2415f9264dd6SJacob Keller 	} else {
2416f9264dd6SJacob Keller 		/* a ref_cnt of 1 indicates the vsi_list is only used
2417f9264dd6SJacob Keller 		 * by one rule. However, the original removal request is only
2418f9264dd6SJacob Keller 		 * for a single VSI. Update the vsi_list first, and only
2419f9264dd6SJacob Keller 		 * remove the rule if there are no further VSIs in this list.
2420f9264dd6SJacob Keller 		 */
24215726ca0eSAnirudh Venkataramanan 		vsi_handle = f_entry->fltr_info.vsi_handle;
24225726ca0eSAnirudh Venkataramanan 		status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);
242380d144c9SAnirudh Venkataramanan 		if (status)
242480d144c9SAnirudh Venkataramanan 			goto exit;
2425f9867df6SAnirudh Venkataramanan 		/* if VSI count goes to zero after updating the VSI list */
242680d144c9SAnirudh Venkataramanan 		if (list_elem->vsi_count == 0)
242780d144c9SAnirudh Venkataramanan 			remove_rule = true;
242880d144c9SAnirudh Venkataramanan 	}
242980d144c9SAnirudh Venkataramanan 
243080d144c9SAnirudh Venkataramanan 	if (remove_rule) {
243180d144c9SAnirudh Venkataramanan 		/* Remove the lookup rule */
243280d144c9SAnirudh Venkataramanan 		struct ice_aqc_sw_rules_elem *s_rule;
243380d144c9SAnirudh Venkataramanan 
243480d144c9SAnirudh Venkataramanan 		s_rule = devm_kzalloc(ice_hw_to_dev(hw),
243580d144c9SAnirudh Venkataramanan 				      ICE_SW_RULE_RX_TX_NO_HDR_SIZE,
243680d144c9SAnirudh Venkataramanan 				      GFP_KERNEL);
243780d144c9SAnirudh Venkataramanan 		if (!s_rule) {
2438d54699e2STony Nguyen 			status = -ENOMEM;
243980d144c9SAnirudh Venkataramanan 			goto exit;
244080d144c9SAnirudh Venkataramanan 		}
244180d144c9SAnirudh Venkataramanan 
244280d144c9SAnirudh Venkataramanan 		ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,
244380d144c9SAnirudh Venkataramanan 				 ice_aqc_opc_remove_sw_rules);
244480d144c9SAnirudh Venkataramanan 
244580d144c9SAnirudh Venkataramanan 		status = ice_aq_sw_rules(hw, s_rule,
244680d144c9SAnirudh Venkataramanan 					 ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1,
244780d144c9SAnirudh Venkataramanan 					 ice_aqc_opc_remove_sw_rules, NULL);
244880d144c9SAnirudh Venkataramanan 
244980d144c9SAnirudh Venkataramanan 		/* Remove a book keeping from the list */
245080d144c9SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), s_rule);
245180d144c9SAnirudh Venkataramanan 
24528132e17dSJeb Cramer 		if (status)
24538132e17dSJeb Cramer 			goto exit;
24548132e17dSJeb Cramer 
245580d144c9SAnirudh Venkataramanan 		list_del(&list_elem->list_entry);
245680d144c9SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), list_elem);
245780d144c9SAnirudh Venkataramanan 	}
245880d144c9SAnirudh Venkataramanan exit:
245980d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
246080d144c9SAnirudh Venkataramanan 	return status;
24619daf8208SAnirudh Venkataramanan }
24629daf8208SAnirudh Venkataramanan 
24639daf8208SAnirudh Venkataramanan /**
24649fea7498SKiran Patil  * ice_mac_fltr_exist - does this MAC filter exist for given VSI
24659fea7498SKiran Patil  * @hw: pointer to the hardware structure
24669fea7498SKiran Patil  * @mac: MAC address to be checked (for MAC filter)
24679fea7498SKiran Patil  * @vsi_handle: check MAC filter for this VSI
24689fea7498SKiran Patil  */
24699fea7498SKiran Patil bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle)
24709fea7498SKiran Patil {
24719fea7498SKiran Patil 	struct ice_fltr_mgmt_list_entry *entry;
24729fea7498SKiran Patil 	struct list_head *rule_head;
24739fea7498SKiran Patil 	struct ice_switch_info *sw;
24749fea7498SKiran Patil 	struct mutex *rule_lock; /* Lock to protect filter rule list */
24759fea7498SKiran Patil 	u16 hw_vsi_id;
24769fea7498SKiran Patil 
24779fea7498SKiran Patil 	if (!ice_is_vsi_valid(hw, vsi_handle))
24789fea7498SKiran Patil 		return false;
24799fea7498SKiran Patil 
24809fea7498SKiran Patil 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
24819fea7498SKiran Patil 	sw = hw->switch_info;
24829fea7498SKiran Patil 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
24839fea7498SKiran Patil 	if (!rule_head)
24849fea7498SKiran Patil 		return false;
24859fea7498SKiran Patil 
24869fea7498SKiran Patil 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
24879fea7498SKiran Patil 	mutex_lock(rule_lock);
24889fea7498SKiran Patil 	list_for_each_entry(entry, rule_head, list_entry) {
24899fea7498SKiran Patil 		struct ice_fltr_info *f_info = &entry->fltr_info;
24909fea7498SKiran Patil 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
24919fea7498SKiran Patil 
24929fea7498SKiran Patil 		if (is_zero_ether_addr(mac_addr))
24939fea7498SKiran Patil 			continue;
24949fea7498SKiran Patil 
24959fea7498SKiran Patil 		if (f_info->flag != ICE_FLTR_TX ||
24969fea7498SKiran Patil 		    f_info->src_id != ICE_SRC_ID_VSI ||
24979fea7498SKiran Patil 		    f_info->lkup_type != ICE_SW_LKUP_MAC ||
24989fea7498SKiran Patil 		    f_info->fltr_act != ICE_FWD_TO_VSI ||
24999fea7498SKiran Patil 		    hw_vsi_id != f_info->fwd_id.hw_vsi_id)
25009fea7498SKiran Patil 			continue;
25019fea7498SKiran Patil 
25029fea7498SKiran Patil 		if (ether_addr_equal(mac, mac_addr)) {
25039fea7498SKiran Patil 			mutex_unlock(rule_lock);
25049fea7498SKiran Patil 			return true;
25059fea7498SKiran Patil 		}
25069fea7498SKiran Patil 	}
25079fea7498SKiran Patil 	mutex_unlock(rule_lock);
25089fea7498SKiran Patil 	return false;
25099fea7498SKiran Patil }
25109fea7498SKiran Patil 
25119fea7498SKiran Patil /**
25129fea7498SKiran Patil  * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI
25139fea7498SKiran Patil  * @hw: pointer to the hardware structure
25149fea7498SKiran Patil  * @vlan_id: VLAN ID
25159fea7498SKiran Patil  * @vsi_handle: check MAC filter for this VSI
25169fea7498SKiran Patil  */
25179fea7498SKiran Patil bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle)
25189fea7498SKiran Patil {
25199fea7498SKiran Patil 	struct ice_fltr_mgmt_list_entry *entry;
25209fea7498SKiran Patil 	struct list_head *rule_head;
25219fea7498SKiran Patil 	struct ice_switch_info *sw;
25229fea7498SKiran Patil 	struct mutex *rule_lock; /* Lock to protect filter rule list */
25239fea7498SKiran Patil 	u16 hw_vsi_id;
25249fea7498SKiran Patil 
25259fea7498SKiran Patil 	if (vlan_id > ICE_MAX_VLAN_ID)
25269fea7498SKiran Patil 		return false;
25279fea7498SKiran Patil 
25289fea7498SKiran Patil 	if (!ice_is_vsi_valid(hw, vsi_handle))
25299fea7498SKiran Patil 		return false;
25309fea7498SKiran Patil 
25319fea7498SKiran Patil 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
25329fea7498SKiran Patil 	sw = hw->switch_info;
25339fea7498SKiran Patil 	rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
25349fea7498SKiran Patil 	if (!rule_head)
25359fea7498SKiran Patil 		return false;
25369fea7498SKiran Patil 
25379fea7498SKiran Patil 	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
25389fea7498SKiran Patil 	mutex_lock(rule_lock);
25399fea7498SKiran Patil 	list_for_each_entry(entry, rule_head, list_entry) {
25409fea7498SKiran Patil 		struct ice_fltr_info *f_info = &entry->fltr_info;
25419fea7498SKiran Patil 		u16 entry_vlan_id = f_info->l_data.vlan.vlan_id;
25429fea7498SKiran Patil 		struct ice_vsi_list_map_info *map_info;
25439fea7498SKiran Patil 
25449fea7498SKiran Patil 		if (entry_vlan_id > ICE_MAX_VLAN_ID)
25459fea7498SKiran Patil 			continue;
25469fea7498SKiran Patil 
25479fea7498SKiran Patil 		if (f_info->flag != ICE_FLTR_TX ||
25489fea7498SKiran Patil 		    f_info->src_id != ICE_SRC_ID_VSI ||
25499fea7498SKiran Patil 		    f_info->lkup_type != ICE_SW_LKUP_VLAN)
25509fea7498SKiran Patil 			continue;
25519fea7498SKiran Patil 
25529fea7498SKiran Patil 		/* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */
25539fea7498SKiran Patil 		if (f_info->fltr_act != ICE_FWD_TO_VSI &&
25549fea7498SKiran Patil 		    f_info->fltr_act != ICE_FWD_TO_VSI_LIST)
25559fea7498SKiran Patil 			continue;
25569fea7498SKiran Patil 
25579fea7498SKiran Patil 		if (f_info->fltr_act == ICE_FWD_TO_VSI) {
25589fea7498SKiran Patil 			if (hw_vsi_id != f_info->fwd_id.hw_vsi_id)
25599fea7498SKiran Patil 				continue;
25609fea7498SKiran Patil 		} else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
25619fea7498SKiran Patil 			/* If filter_action is FWD_TO_VSI_LIST, make sure
25629fea7498SKiran Patil 			 * that VSI being checked is part of VSI list
25639fea7498SKiran Patil 			 */
25649fea7498SKiran Patil 			if (entry->vsi_count == 1 &&
25659fea7498SKiran Patil 			    entry->vsi_list_info) {
25669fea7498SKiran Patil 				map_info = entry->vsi_list_info;
25679fea7498SKiran Patil 				if (!test_bit(vsi_handle, map_info->vsi_map))
25689fea7498SKiran Patil 					continue;
25699fea7498SKiran Patil 			}
25709fea7498SKiran Patil 		}
25719fea7498SKiran Patil 
25729fea7498SKiran Patil 		if (vlan_id == entry_vlan_id) {
25739fea7498SKiran Patil 			mutex_unlock(rule_lock);
25749fea7498SKiran Patil 			return true;
25759fea7498SKiran Patil 		}
25769fea7498SKiran Patil 	}
25779fea7498SKiran Patil 	mutex_unlock(rule_lock);
25789fea7498SKiran Patil 
25799fea7498SKiran Patil 	return false;
25809fea7498SKiran Patil }
25819fea7498SKiran Patil 
25829fea7498SKiran Patil /**
25839daf8208SAnirudh Venkataramanan  * ice_add_mac - Add a MAC address based filter rule
25849daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
25859daf8208SAnirudh Venkataramanan  * @m_list: list of MAC addresses and forwarding information
25869daf8208SAnirudh Venkataramanan  *
25879daf8208SAnirudh Venkataramanan  * IMPORTANT: When the ucast_shared flag is set to false and m_list has
25889daf8208SAnirudh Venkataramanan  * multiple unicast addresses, the function assumes that all the
25899daf8208SAnirudh Venkataramanan  * addresses are unique in a given add_mac call. It doesn't
25909daf8208SAnirudh Venkataramanan  * check for duplicates in this case, removing duplicates from a given
25919daf8208SAnirudh Venkataramanan  * list should be taken care of in the caller of this function.
25929daf8208SAnirudh Venkataramanan  */
25935e24d598STony Nguyen int ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
25949daf8208SAnirudh Venkataramanan {
25959daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule, *r_iter;
25969daf8208SAnirudh Venkataramanan 	struct ice_fltr_list_entry *m_list_itr;
259780d144c9SAnirudh Venkataramanan 	struct list_head *rule_head;
259888865fc4SKarol Kolacinski 	u16 total_elem_left, s_rule_size;
259980d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw;
260080d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
26019daf8208SAnirudh Venkataramanan 	u16 num_unicast = 0;
26025518ac2aSTony Nguyen 	int status = 0;
260388865fc4SKarol Kolacinski 	u8 elem_sent;
26049daf8208SAnirudh Venkataramanan 
26059daf8208SAnirudh Venkataramanan 	if (!m_list || !hw)
2606d54699e2STony Nguyen 		return -EINVAL;
26079daf8208SAnirudh Venkataramanan 
260880d144c9SAnirudh Venkataramanan 	s_rule = NULL;
260980d144c9SAnirudh Venkataramanan 	sw = hw->switch_info;
261080d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
26119daf8208SAnirudh Venkataramanan 	list_for_each_entry(m_list_itr, m_list, list_entry) {
26129daf8208SAnirudh Venkataramanan 		u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
26135726ca0eSAnirudh Venkataramanan 		u16 vsi_handle;
26145726ca0eSAnirudh Venkataramanan 		u16 hw_vsi_id;
26159daf8208SAnirudh Venkataramanan 
261680d144c9SAnirudh Venkataramanan 		m_list_itr->fltr_info.flag = ICE_FLTR_TX;
26175726ca0eSAnirudh Venkataramanan 		vsi_handle = m_list_itr->fltr_info.vsi_handle;
26185726ca0eSAnirudh Venkataramanan 		if (!ice_is_vsi_valid(hw, vsi_handle))
2619d54699e2STony Nguyen 			return -EINVAL;
26205726ca0eSAnirudh Venkataramanan 		hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
26215726ca0eSAnirudh Venkataramanan 		m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;
2622f9867df6SAnirudh Venkataramanan 		/* update the src in case it is VSI num */
26235726ca0eSAnirudh Venkataramanan 		if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)
2624d54699e2STony Nguyen 			return -EINVAL;
26255726ca0eSAnirudh Venkataramanan 		m_list_itr->fltr_info.src = hw_vsi_id;
262680d144c9SAnirudh Venkataramanan 		if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
262780d144c9SAnirudh Venkataramanan 		    is_zero_ether_addr(add))
2628d54699e2STony Nguyen 			return -EINVAL;
26299daf8208SAnirudh Venkataramanan 		if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
26309daf8208SAnirudh Venkataramanan 			/* Don't overwrite the unicast address */
263180d144c9SAnirudh Venkataramanan 			mutex_lock(rule_lock);
263280d144c9SAnirudh Venkataramanan 			if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC,
263380d144c9SAnirudh Venkataramanan 						&m_list_itr->fltr_info)) {
263480d144c9SAnirudh Venkataramanan 				mutex_unlock(rule_lock);
2635d54699e2STony Nguyen 				return -EEXIST;
263680d144c9SAnirudh Venkataramanan 			}
263780d144c9SAnirudh Venkataramanan 			mutex_unlock(rule_lock);
26389daf8208SAnirudh Venkataramanan 			num_unicast++;
26399daf8208SAnirudh Venkataramanan 		} else if (is_multicast_ether_addr(add) ||
26409daf8208SAnirudh Venkataramanan 			   (is_unicast_ether_addr(add) && hw->ucast_shared)) {
264180d144c9SAnirudh Venkataramanan 			m_list_itr->status =
264280d144c9SAnirudh Venkataramanan 				ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
264380d144c9SAnirudh Venkataramanan 						      m_list_itr);
264480d144c9SAnirudh Venkataramanan 			if (m_list_itr->status)
264580d144c9SAnirudh Venkataramanan 				return m_list_itr->status;
26469daf8208SAnirudh Venkataramanan 		}
26479daf8208SAnirudh Venkataramanan 	}
26489daf8208SAnirudh Venkataramanan 
264980d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
26509daf8208SAnirudh Venkataramanan 	/* Exit if no suitable entries were found for adding bulk switch rule */
265180d144c9SAnirudh Venkataramanan 	if (!num_unicast) {
265280d144c9SAnirudh Venkataramanan 		status = 0;
265380d144c9SAnirudh Venkataramanan 		goto ice_add_mac_exit;
265480d144c9SAnirudh Venkataramanan 	}
265580d144c9SAnirudh Venkataramanan 
265680d144c9SAnirudh Venkataramanan 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
26579daf8208SAnirudh Venkataramanan 
26589daf8208SAnirudh Venkataramanan 	/* Allocate switch rule buffer for the bulk update for unicast */
26599daf8208SAnirudh Venkataramanan 	s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
26609daf8208SAnirudh Venkataramanan 	s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,
26619daf8208SAnirudh Venkataramanan 			      GFP_KERNEL);
266280d144c9SAnirudh Venkataramanan 	if (!s_rule) {
2663d54699e2STony Nguyen 		status = -ENOMEM;
266480d144c9SAnirudh Venkataramanan 		goto ice_add_mac_exit;
266580d144c9SAnirudh Venkataramanan 	}
26669daf8208SAnirudh Venkataramanan 
26679daf8208SAnirudh Venkataramanan 	r_iter = s_rule;
26689daf8208SAnirudh Venkataramanan 	list_for_each_entry(m_list_itr, m_list, list_entry) {
26699daf8208SAnirudh Venkataramanan 		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
267080d144c9SAnirudh Venkataramanan 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
26719daf8208SAnirudh Venkataramanan 
267280d144c9SAnirudh Venkataramanan 		if (is_unicast_ether_addr(mac_addr)) {
267380d144c9SAnirudh Venkataramanan 			ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,
267480d144c9SAnirudh Venkataramanan 					 ice_aqc_opc_add_sw_rules);
26759daf8208SAnirudh Venkataramanan 			r_iter = (struct ice_aqc_sw_rules_elem *)
26769daf8208SAnirudh Venkataramanan 				((u8 *)r_iter + s_rule_size);
26779daf8208SAnirudh Venkataramanan 		}
26789daf8208SAnirudh Venkataramanan 	}
26799daf8208SAnirudh Venkataramanan 
26809daf8208SAnirudh Venkataramanan 	/* Call AQ bulk switch rule update for all unicast addresses */
26819daf8208SAnirudh Venkataramanan 	r_iter = s_rule;
26829daf8208SAnirudh Venkataramanan 	/* Call AQ switch rule in AQ_MAX chunk */
26839daf8208SAnirudh Venkataramanan 	for (total_elem_left = num_unicast; total_elem_left > 0;
26849daf8208SAnirudh Venkataramanan 	     total_elem_left -= elem_sent) {
26859daf8208SAnirudh Venkataramanan 		struct ice_aqc_sw_rules_elem *entry = r_iter;
26869daf8208SAnirudh Venkataramanan 
268788865fc4SKarol Kolacinski 		elem_sent = min_t(u8, total_elem_left,
268888865fc4SKarol Kolacinski 				  (ICE_AQ_MAX_BUF_LEN / s_rule_size));
26899daf8208SAnirudh Venkataramanan 		status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,
26909daf8208SAnirudh Venkataramanan 					 elem_sent, ice_aqc_opc_add_sw_rules,
26919daf8208SAnirudh Venkataramanan 					 NULL);
26929daf8208SAnirudh Venkataramanan 		if (status)
26939daf8208SAnirudh Venkataramanan 			goto ice_add_mac_exit;
26949daf8208SAnirudh Venkataramanan 		r_iter = (struct ice_aqc_sw_rules_elem *)
26959daf8208SAnirudh Venkataramanan 			((u8 *)r_iter + (elem_sent * s_rule_size));
26969daf8208SAnirudh Venkataramanan 	}
26979daf8208SAnirudh Venkataramanan 
2698f9867df6SAnirudh Venkataramanan 	/* Fill up rule ID based on the value returned from FW */
26999daf8208SAnirudh Venkataramanan 	r_iter = s_rule;
27009daf8208SAnirudh Venkataramanan 	list_for_each_entry(m_list_itr, m_list, list_entry) {
27019daf8208SAnirudh Venkataramanan 		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
270280d144c9SAnirudh Venkataramanan 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
27039daf8208SAnirudh Venkataramanan 		struct ice_fltr_mgmt_list_entry *fm_entry;
27049daf8208SAnirudh Venkataramanan 
270580d144c9SAnirudh Venkataramanan 		if (is_unicast_ether_addr(mac_addr)) {
27069daf8208SAnirudh Venkataramanan 			f_info->fltr_rule_id =
27079daf8208SAnirudh Venkataramanan 				le16_to_cpu(r_iter->pdata.lkup_tx_rx.index);
27089daf8208SAnirudh Venkataramanan 			f_info->fltr_act = ICE_FWD_TO_VSI;
27099daf8208SAnirudh Venkataramanan 			/* Create an entry to track this MAC address */
27109daf8208SAnirudh Venkataramanan 			fm_entry = devm_kzalloc(ice_hw_to_dev(hw),
27119daf8208SAnirudh Venkataramanan 						sizeof(*fm_entry), GFP_KERNEL);
27129daf8208SAnirudh Venkataramanan 			if (!fm_entry) {
2713d54699e2STony Nguyen 				status = -ENOMEM;
27149daf8208SAnirudh Venkataramanan 				goto ice_add_mac_exit;
27159daf8208SAnirudh Venkataramanan 			}
27169daf8208SAnirudh Venkataramanan 			fm_entry->fltr_info = *f_info;
27179daf8208SAnirudh Venkataramanan 			fm_entry->vsi_count = 1;
27189daf8208SAnirudh Venkataramanan 			/* The book keeping entries will get removed when
27199daf8208SAnirudh Venkataramanan 			 * base driver calls remove filter AQ command
27209daf8208SAnirudh Venkataramanan 			 */
27219daf8208SAnirudh Venkataramanan 
272280d144c9SAnirudh Venkataramanan 			list_add(&fm_entry->list_entry, rule_head);
27239daf8208SAnirudh Venkataramanan 			r_iter = (struct ice_aqc_sw_rules_elem *)
27249daf8208SAnirudh Venkataramanan 				((u8 *)r_iter + s_rule_size);
27259daf8208SAnirudh Venkataramanan 		}
27269daf8208SAnirudh Venkataramanan 	}
27279daf8208SAnirudh Venkataramanan 
27289daf8208SAnirudh Venkataramanan ice_add_mac_exit:
272980d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
273080d144c9SAnirudh Venkataramanan 	if (s_rule)
27319daf8208SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), s_rule);
27329daf8208SAnirudh Venkataramanan 	return status;
27339daf8208SAnirudh Venkataramanan }
27349daf8208SAnirudh Venkataramanan 
27359daf8208SAnirudh Venkataramanan /**
2736d76a60baSAnirudh Venkataramanan  * ice_add_vlan_internal - Add one VLAN based filter rule
2737d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2738d76a60baSAnirudh Venkataramanan  * @f_entry: filter entry containing one VLAN information
2739d76a60baSAnirudh Venkataramanan  */
27405e24d598STony Nguyen static int
2741d76a60baSAnirudh Venkataramanan ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
2742d76a60baSAnirudh Venkataramanan {
274380d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
2744d76a60baSAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *v_list_itr;
27455726ca0eSAnirudh Venkataramanan 	struct ice_fltr_info *new_fltr, *cur_fltr;
27465726ca0eSAnirudh Venkataramanan 	enum ice_sw_lkup_type lkup_type;
27475726ca0eSAnirudh Venkataramanan 	u16 vsi_list_id = 0, vsi_handle;
274880d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
27495e24d598STony Nguyen 	int status = 0;
2750d76a60baSAnirudh Venkataramanan 
27515726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
2752d54699e2STony Nguyen 		return -EINVAL;
27535726ca0eSAnirudh Venkataramanan 
27545726ca0eSAnirudh Venkataramanan 	f_entry->fltr_info.fwd_id.hw_vsi_id =
27555726ca0eSAnirudh Venkataramanan 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
2756d76a60baSAnirudh Venkataramanan 	new_fltr = &f_entry->fltr_info;
27575726ca0eSAnirudh Venkataramanan 
2758f9867df6SAnirudh Venkataramanan 	/* VLAN ID should only be 12 bits */
2759d76a60baSAnirudh Venkataramanan 	if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
2760d54699e2STony Nguyen 		return -EINVAL;
2761d76a60baSAnirudh Venkataramanan 
27625726ca0eSAnirudh Venkataramanan 	if (new_fltr->src_id != ICE_SRC_ID_VSI)
2763d54699e2STony Nguyen 		return -EINVAL;
27645726ca0eSAnirudh Venkataramanan 
27655726ca0eSAnirudh Venkataramanan 	new_fltr->src = new_fltr->fwd_id.hw_vsi_id;
27665726ca0eSAnirudh Venkataramanan 	lkup_type = new_fltr->lkup_type;
27675726ca0eSAnirudh Venkataramanan 	vsi_handle = new_fltr->vsi_handle;
276880d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
276980d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
277080d144c9SAnirudh Venkataramanan 	v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr);
2771d76a60baSAnirudh Venkataramanan 	if (!v_list_itr) {
27725726ca0eSAnirudh Venkataramanan 		struct ice_vsi_list_map_info *map_info = NULL;
2773d76a60baSAnirudh Venkataramanan 
2774d76a60baSAnirudh Venkataramanan 		if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
27755726ca0eSAnirudh Venkataramanan 			/* All VLAN pruning rules use a VSI list. Check if
27765726ca0eSAnirudh Venkataramanan 			 * there is already a VSI list containing VSI that we
27775726ca0eSAnirudh Venkataramanan 			 * want to add. If found, use the same vsi_list_id for
27785726ca0eSAnirudh Venkataramanan 			 * this new VLAN rule or else create a new list.
2779d76a60baSAnirudh Venkataramanan 			 */
27805726ca0eSAnirudh Venkataramanan 			map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN,
27815726ca0eSAnirudh Venkataramanan 							   vsi_handle,
27825726ca0eSAnirudh Venkataramanan 							   &vsi_list_id);
27835726ca0eSAnirudh Venkataramanan 			if (!map_info) {
27845726ca0eSAnirudh Venkataramanan 				status = ice_create_vsi_list_rule(hw,
27855726ca0eSAnirudh Venkataramanan 								  &vsi_handle,
27865726ca0eSAnirudh Venkataramanan 								  1,
2787d76a60baSAnirudh Venkataramanan 								  &vsi_list_id,
2788d76a60baSAnirudh Venkataramanan 								  lkup_type);
2789d76a60baSAnirudh Venkataramanan 				if (status)
279080d144c9SAnirudh Venkataramanan 					goto exit;
27915726ca0eSAnirudh Venkataramanan 			}
27925726ca0eSAnirudh Venkataramanan 			/* Convert the action to forwarding to a VSI list. */
2793d76a60baSAnirudh Venkataramanan 			new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
2794d76a60baSAnirudh Venkataramanan 			new_fltr->fwd_id.vsi_list_id = vsi_list_id;
2795d76a60baSAnirudh Venkataramanan 		}
2796d76a60baSAnirudh Venkataramanan 
2797d76a60baSAnirudh Venkataramanan 		status = ice_create_pkt_fwd_rule(hw, f_entry);
27985726ca0eSAnirudh Venkataramanan 		if (!status) {
279980d144c9SAnirudh Venkataramanan 			v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN,
280080d144c9SAnirudh Venkataramanan 							 new_fltr);
280180d144c9SAnirudh Venkataramanan 			if (!v_list_itr) {
2802d54699e2STony Nguyen 				status = -ENOENT;
280380d144c9SAnirudh Venkataramanan 				goto exit;
280480d144c9SAnirudh Venkataramanan 			}
28055726ca0eSAnirudh Venkataramanan 			/* reuse VSI list for new rule and increment ref_cnt */
28065726ca0eSAnirudh Venkataramanan 			if (map_info) {
28075726ca0eSAnirudh Venkataramanan 				v_list_itr->vsi_list_info = map_info;
28085726ca0eSAnirudh Venkataramanan 				map_info->ref_cnt++;
28095726ca0eSAnirudh Venkataramanan 			} else {
2810d76a60baSAnirudh Venkataramanan 				v_list_itr->vsi_list_info =
28115726ca0eSAnirudh Venkataramanan 					ice_create_vsi_list_map(hw, &vsi_handle,
28125726ca0eSAnirudh Venkataramanan 								1, vsi_list_id);
2813d76a60baSAnirudh Venkataramanan 			}
28145726ca0eSAnirudh Venkataramanan 		}
28155726ca0eSAnirudh Venkataramanan 	} else if (v_list_itr->vsi_list_info->ref_cnt == 1) {
2816f9867df6SAnirudh Venkataramanan 		/* Update existing VSI list to add new VSI ID only if it used
28175726ca0eSAnirudh Venkataramanan 		 * by one VLAN rule.
28185726ca0eSAnirudh Venkataramanan 		 */
28195726ca0eSAnirudh Venkataramanan 		cur_fltr = &v_list_itr->fltr_info;
28205726ca0eSAnirudh Venkataramanan 		status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,
28215726ca0eSAnirudh Venkataramanan 						 new_fltr);
28225726ca0eSAnirudh Venkataramanan 	} else {
28235726ca0eSAnirudh Venkataramanan 		/* If VLAN rule exists and VSI list being used by this rule is
28245726ca0eSAnirudh Venkataramanan 		 * referenced by more than 1 VLAN rule. Then create a new VSI
28255726ca0eSAnirudh Venkataramanan 		 * list appending previous VSI with new VSI and update existing
2826f9867df6SAnirudh Venkataramanan 		 * VLAN rule to point to new VSI list ID
28275726ca0eSAnirudh Venkataramanan 		 */
28285726ca0eSAnirudh Venkataramanan 		struct ice_fltr_info tmp_fltr;
28295726ca0eSAnirudh Venkataramanan 		u16 vsi_handle_arr[2];
28305726ca0eSAnirudh Venkataramanan 		u16 cur_handle;
2831d76a60baSAnirudh Venkataramanan 
28325726ca0eSAnirudh Venkataramanan 		/* Current implementation only supports reusing VSI list with
28335726ca0eSAnirudh Venkataramanan 		 * one VSI count. We should never hit below condition
28345726ca0eSAnirudh Venkataramanan 		 */
28355726ca0eSAnirudh Venkataramanan 		if (v_list_itr->vsi_count > 1 &&
28365726ca0eSAnirudh Venkataramanan 		    v_list_itr->vsi_list_info->ref_cnt > 1) {
28379228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SW, "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n");
2838d54699e2STony Nguyen 			status = -EIO;
283980d144c9SAnirudh Venkataramanan 			goto exit;
2840d76a60baSAnirudh Venkataramanan 		}
2841d76a60baSAnirudh Venkataramanan 
28425726ca0eSAnirudh Venkataramanan 		cur_handle =
28435726ca0eSAnirudh Venkataramanan 			find_first_bit(v_list_itr->vsi_list_info->vsi_map,
28445726ca0eSAnirudh Venkataramanan 				       ICE_MAX_VSI);
28455726ca0eSAnirudh Venkataramanan 
28465726ca0eSAnirudh Venkataramanan 		/* A rule already exists with the new VSI being added */
28475726ca0eSAnirudh Venkataramanan 		if (cur_handle == vsi_handle) {
2848d54699e2STony Nguyen 			status = -EEXIST;
28495726ca0eSAnirudh Venkataramanan 			goto exit;
28505726ca0eSAnirudh Venkataramanan 		}
28515726ca0eSAnirudh Venkataramanan 
28525726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[0] = cur_handle;
28535726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[1] = vsi_handle;
28545726ca0eSAnirudh Venkataramanan 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
28555726ca0eSAnirudh Venkataramanan 						  &vsi_list_id, lkup_type);
28565726ca0eSAnirudh Venkataramanan 		if (status)
28575726ca0eSAnirudh Venkataramanan 			goto exit;
28585726ca0eSAnirudh Venkataramanan 
28595726ca0eSAnirudh Venkataramanan 		tmp_fltr = v_list_itr->fltr_info;
28605726ca0eSAnirudh Venkataramanan 		tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;
28615726ca0eSAnirudh Venkataramanan 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
28625726ca0eSAnirudh Venkataramanan 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
28635726ca0eSAnirudh Venkataramanan 		/* Update the previous switch rule to a new VSI list which
2864df17b7e0SAnirudh Venkataramanan 		 * includes current VSI that is requested
28655726ca0eSAnirudh Venkataramanan 		 */
28665726ca0eSAnirudh Venkataramanan 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
28675726ca0eSAnirudh Venkataramanan 		if (status)
28685726ca0eSAnirudh Venkataramanan 			goto exit;
28695726ca0eSAnirudh Venkataramanan 
28705726ca0eSAnirudh Venkataramanan 		/* before overriding VSI list map info. decrement ref_cnt of
28715726ca0eSAnirudh Venkataramanan 		 * previous VSI list
28725726ca0eSAnirudh Venkataramanan 		 */
28735726ca0eSAnirudh Venkataramanan 		v_list_itr->vsi_list_info->ref_cnt--;
28745726ca0eSAnirudh Venkataramanan 
28755726ca0eSAnirudh Venkataramanan 		/* now update to newly created list */
28765726ca0eSAnirudh Venkataramanan 		v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;
28775726ca0eSAnirudh Venkataramanan 		v_list_itr->vsi_list_info =
28785726ca0eSAnirudh Venkataramanan 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
28795726ca0eSAnirudh Venkataramanan 						vsi_list_id);
28805726ca0eSAnirudh Venkataramanan 		v_list_itr->vsi_count++;
28815726ca0eSAnirudh Venkataramanan 	}
288280d144c9SAnirudh Venkataramanan 
288380d144c9SAnirudh Venkataramanan exit:
288480d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
288580d144c9SAnirudh Venkataramanan 	return status;
2886d76a60baSAnirudh Venkataramanan }
2887d76a60baSAnirudh Venkataramanan 
2888d76a60baSAnirudh Venkataramanan /**
2889d76a60baSAnirudh Venkataramanan  * ice_add_vlan - Add VLAN based filter rule
2890d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2891d76a60baSAnirudh Venkataramanan  * @v_list: list of VLAN entries and forwarding information
2892d76a60baSAnirudh Venkataramanan  */
28935e24d598STony Nguyen int ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
2894d76a60baSAnirudh Venkataramanan {
2895d76a60baSAnirudh Venkataramanan 	struct ice_fltr_list_entry *v_list_itr;
2896d76a60baSAnirudh Venkataramanan 
2897d76a60baSAnirudh Venkataramanan 	if (!v_list || !hw)
2898d54699e2STony Nguyen 		return -EINVAL;
2899d76a60baSAnirudh Venkataramanan 
2900d76a60baSAnirudh Venkataramanan 	list_for_each_entry(v_list_itr, v_list, list_entry) {
2901d76a60baSAnirudh Venkataramanan 		if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
2902d54699e2STony Nguyen 			return -EINVAL;
290380d144c9SAnirudh Venkataramanan 		v_list_itr->fltr_info.flag = ICE_FLTR_TX;
290480d144c9SAnirudh Venkataramanan 		v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr);
290580d144c9SAnirudh Venkataramanan 		if (v_list_itr->status)
290680d144c9SAnirudh Venkataramanan 			return v_list_itr->status;
2907d76a60baSAnirudh Venkataramanan 	}
2908d76a60baSAnirudh Venkataramanan 	return 0;
2909d76a60baSAnirudh Venkataramanan }
2910d76a60baSAnirudh Venkataramanan 
2911d76a60baSAnirudh Venkataramanan /**
2912d95276ceSAkeem G Abodunrin  * ice_add_eth_mac - Add ethertype and MAC based filter rule
2913d95276ceSAkeem G Abodunrin  * @hw: pointer to the hardware structure
2914d95276ceSAkeem G Abodunrin  * @em_list: list of ether type MAC filter, MAC is optional
29152e0e6228SDave Ertman  *
29162e0e6228SDave Ertman  * This function requires the caller to populate the entries in
29172e0e6228SDave Ertman  * the filter list with the necessary fields (including flags to
29182e0e6228SDave Ertman  * indicate Tx or Rx rules).
2919d95276ceSAkeem G Abodunrin  */
29205518ac2aSTony Nguyen int ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
2921d95276ceSAkeem G Abodunrin {
2922d95276ceSAkeem G Abodunrin 	struct ice_fltr_list_entry *em_list_itr;
2923d95276ceSAkeem G Abodunrin 
2924d95276ceSAkeem G Abodunrin 	if (!em_list || !hw)
2925d54699e2STony Nguyen 		return -EINVAL;
2926d95276ceSAkeem G Abodunrin 
2927d95276ceSAkeem G Abodunrin 	list_for_each_entry(em_list_itr, em_list, list_entry) {
2928d95276ceSAkeem G Abodunrin 		enum ice_sw_lkup_type l_type =
2929d95276ceSAkeem G Abodunrin 			em_list_itr->fltr_info.lkup_type;
2930d95276ceSAkeem G Abodunrin 
2931d95276ceSAkeem G Abodunrin 		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
2932d95276ceSAkeem G Abodunrin 		    l_type != ICE_SW_LKUP_ETHERTYPE)
2933d54699e2STony Nguyen 			return -EINVAL;
2934d95276ceSAkeem G Abodunrin 
2935d95276ceSAkeem G Abodunrin 		em_list_itr->status = ice_add_rule_internal(hw, l_type,
2936d95276ceSAkeem G Abodunrin 							    em_list_itr);
2937d95276ceSAkeem G Abodunrin 		if (em_list_itr->status)
2938d95276ceSAkeem G Abodunrin 			return em_list_itr->status;
2939d95276ceSAkeem G Abodunrin 	}
2940d95276ceSAkeem G Abodunrin 	return 0;
2941d95276ceSAkeem G Abodunrin }
2942d95276ceSAkeem G Abodunrin 
2943d95276ceSAkeem G Abodunrin /**
2944d95276ceSAkeem G Abodunrin  * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule
2945d95276ceSAkeem G Abodunrin  * @hw: pointer to the hardware structure
2946d95276ceSAkeem G Abodunrin  * @em_list: list of ethertype or ethertype MAC entries
2947d95276ceSAkeem G Abodunrin  */
29485518ac2aSTony Nguyen int ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list)
2949d95276ceSAkeem G Abodunrin {
2950d95276ceSAkeem G Abodunrin 	struct ice_fltr_list_entry *em_list_itr, *tmp;
2951d95276ceSAkeem G Abodunrin 
2952d95276ceSAkeem G Abodunrin 	if (!em_list || !hw)
2953d54699e2STony Nguyen 		return -EINVAL;
2954d95276ceSAkeem G Abodunrin 
2955d95276ceSAkeem G Abodunrin 	list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) {
2956d95276ceSAkeem G Abodunrin 		enum ice_sw_lkup_type l_type =
2957d95276ceSAkeem G Abodunrin 			em_list_itr->fltr_info.lkup_type;
2958d95276ceSAkeem G Abodunrin 
2959d95276ceSAkeem G Abodunrin 		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
2960d95276ceSAkeem G Abodunrin 		    l_type != ICE_SW_LKUP_ETHERTYPE)
2961d54699e2STony Nguyen 			return -EINVAL;
2962d95276ceSAkeem G Abodunrin 
2963d95276ceSAkeem G Abodunrin 		em_list_itr->status = ice_remove_rule_internal(hw, l_type,
2964d95276ceSAkeem G Abodunrin 							       em_list_itr);
2965d95276ceSAkeem G Abodunrin 		if (em_list_itr->status)
2966d95276ceSAkeem G Abodunrin 			return em_list_itr->status;
2967d95276ceSAkeem G Abodunrin 	}
2968d95276ceSAkeem G Abodunrin 	return 0;
2969d95276ceSAkeem G Abodunrin }
2970d95276ceSAkeem G Abodunrin 
2971d95276ceSAkeem G Abodunrin /**
29720f9d5027SAnirudh Venkataramanan  * ice_rem_sw_rule_info
29730f9d5027SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
29740f9d5027SAnirudh Venkataramanan  * @rule_head: pointer to the switch list structure that we want to delete
29750f9d5027SAnirudh Venkataramanan  */
29760f9d5027SAnirudh Venkataramanan static void
29770f9d5027SAnirudh Venkataramanan ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head)
29780f9d5027SAnirudh Venkataramanan {
29790f9d5027SAnirudh Venkataramanan 	if (!list_empty(rule_head)) {
29800f9d5027SAnirudh Venkataramanan 		struct ice_fltr_mgmt_list_entry *entry;
29810f9d5027SAnirudh Venkataramanan 		struct ice_fltr_mgmt_list_entry *tmp;
29820f9d5027SAnirudh Venkataramanan 
29830f9d5027SAnirudh Venkataramanan 		list_for_each_entry_safe(entry, tmp, rule_head, list_entry) {
29840f9d5027SAnirudh Venkataramanan 			list_del(&entry->list_entry);
29850f9d5027SAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), entry);
29860f9d5027SAnirudh Venkataramanan 		}
29870f9d5027SAnirudh Venkataramanan 	}
29880f9d5027SAnirudh Venkataramanan }
29890f9d5027SAnirudh Venkataramanan 
29900f9d5027SAnirudh Venkataramanan /**
29918b8ef05bSVictor Raj  * ice_rem_adv_rule_info
29928b8ef05bSVictor Raj  * @hw: pointer to the hardware structure
29938b8ef05bSVictor Raj  * @rule_head: pointer to the switch list structure that we want to delete
29948b8ef05bSVictor Raj  */
29958b8ef05bSVictor Raj static void
29968b8ef05bSVictor Raj ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head)
29978b8ef05bSVictor Raj {
29988b8ef05bSVictor Raj 	struct ice_adv_fltr_mgmt_list_entry *tmp_entry;
29998b8ef05bSVictor Raj 	struct ice_adv_fltr_mgmt_list_entry *lst_itr;
30008b8ef05bSVictor Raj 
30018b8ef05bSVictor Raj 	if (list_empty(rule_head))
30028b8ef05bSVictor Raj 		return;
30038b8ef05bSVictor Raj 
30048b8ef05bSVictor Raj 	list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) {
30058b8ef05bSVictor Raj 		list_del(&lst_itr->list_entry);
30068b8ef05bSVictor Raj 		devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups);
30078b8ef05bSVictor Raj 		devm_kfree(ice_hw_to_dev(hw), lst_itr);
30088b8ef05bSVictor Raj 	}
30098b8ef05bSVictor Raj }
30108b8ef05bSVictor Raj 
30118b8ef05bSVictor Raj /**
301280d144c9SAnirudh Venkataramanan  * ice_cfg_dflt_vsi - change state of VSI to set/clear default
3013e94d4478SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
30145726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to set as default
3015e94d4478SAnirudh Venkataramanan  * @set: true to add the above mentioned switch rule, false to remove it
3016e94d4478SAnirudh Venkataramanan  * @direction: ICE_FLTR_RX or ICE_FLTR_TX
301780d144c9SAnirudh Venkataramanan  *
301880d144c9SAnirudh Venkataramanan  * add filter rule to set/unset given VSI as default VSI for the switch
301980d144c9SAnirudh Venkataramanan  * (represented by swid)
3020e94d4478SAnirudh Venkataramanan  */
30215518ac2aSTony Nguyen int ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction)
3022e94d4478SAnirudh Venkataramanan {
3023e94d4478SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
3024e94d4478SAnirudh Venkataramanan 	struct ice_fltr_info f_info;
3025e94d4478SAnirudh Venkataramanan 	enum ice_adminq_opc opcode;
3026e94d4478SAnirudh Venkataramanan 	u16 s_rule_size;
30275726ca0eSAnirudh Venkataramanan 	u16 hw_vsi_id;
30285518ac2aSTony Nguyen 	int status;
30295726ca0eSAnirudh Venkataramanan 
30305726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
3031d54699e2STony Nguyen 		return -EINVAL;
30325726ca0eSAnirudh Venkataramanan 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
3033e94d4478SAnirudh Venkataramanan 
3034e94d4478SAnirudh Venkataramanan 	s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE :
3035e94d4478SAnirudh Venkataramanan 		ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
303666486d89SBruce Allan 
3037e94d4478SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
3038e94d4478SAnirudh Venkataramanan 	if (!s_rule)
3039d54699e2STony Nguyen 		return -ENOMEM;
3040e94d4478SAnirudh Venkataramanan 
3041e94d4478SAnirudh Venkataramanan 	memset(&f_info, 0, sizeof(f_info));
3042e94d4478SAnirudh Venkataramanan 
3043e94d4478SAnirudh Venkataramanan 	f_info.lkup_type = ICE_SW_LKUP_DFLT;
3044e94d4478SAnirudh Venkataramanan 	f_info.flag = direction;
3045e94d4478SAnirudh Venkataramanan 	f_info.fltr_act = ICE_FWD_TO_VSI;
30465726ca0eSAnirudh Venkataramanan 	f_info.fwd_id.hw_vsi_id = hw_vsi_id;
3047e94d4478SAnirudh Venkataramanan 
3048e94d4478SAnirudh Venkataramanan 	if (f_info.flag & ICE_FLTR_RX) {
3049e94d4478SAnirudh Venkataramanan 		f_info.src = hw->port_info->lport;
30505726ca0eSAnirudh Venkataramanan 		f_info.src_id = ICE_SRC_ID_LPORT;
3051e94d4478SAnirudh Venkataramanan 		if (!set)
3052e94d4478SAnirudh Venkataramanan 			f_info.fltr_rule_id =
3053e94d4478SAnirudh Venkataramanan 				hw->port_info->dflt_rx_vsi_rule_id;
3054e94d4478SAnirudh Venkataramanan 	} else if (f_info.flag & ICE_FLTR_TX) {
30555726ca0eSAnirudh Venkataramanan 		f_info.src_id = ICE_SRC_ID_VSI;
30565726ca0eSAnirudh Venkataramanan 		f_info.src = hw_vsi_id;
3057e94d4478SAnirudh Venkataramanan 		if (!set)
3058e94d4478SAnirudh Venkataramanan 			f_info.fltr_rule_id =
3059e94d4478SAnirudh Venkataramanan 				hw->port_info->dflt_tx_vsi_rule_id;
3060e94d4478SAnirudh Venkataramanan 	}
3061e94d4478SAnirudh Venkataramanan 
3062e94d4478SAnirudh Venkataramanan 	if (set)
3063e94d4478SAnirudh Venkataramanan 		opcode = ice_aqc_opc_add_sw_rules;
3064e94d4478SAnirudh Venkataramanan 	else
3065e94d4478SAnirudh Venkataramanan 		opcode = ice_aqc_opc_remove_sw_rules;
3066e94d4478SAnirudh Venkataramanan 
3067e94d4478SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, &f_info, s_rule, opcode);
3068e94d4478SAnirudh Venkataramanan 
3069e94d4478SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opcode, NULL);
3070e94d4478SAnirudh Venkataramanan 	if (status || !(f_info.flag & ICE_FLTR_TX_RX))
3071e94d4478SAnirudh Venkataramanan 		goto out;
3072e94d4478SAnirudh Venkataramanan 	if (set) {
3073e94d4478SAnirudh Venkataramanan 		u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
3074e94d4478SAnirudh Venkataramanan 
3075e94d4478SAnirudh Venkataramanan 		if (f_info.flag & ICE_FLTR_TX) {
30765726ca0eSAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_num = hw_vsi_id;
3077e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_rule_id = index;
3078e94d4478SAnirudh Venkataramanan 		} else if (f_info.flag & ICE_FLTR_RX) {
30795726ca0eSAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_num = hw_vsi_id;
3080e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_rule_id = index;
3081e94d4478SAnirudh Venkataramanan 		}
3082e94d4478SAnirudh Venkataramanan 	} else {
3083e94d4478SAnirudh Venkataramanan 		if (f_info.flag & ICE_FLTR_TX) {
3084e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
3085e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_rule_id = ICE_INVAL_ACT;
3086e94d4478SAnirudh Venkataramanan 		} else if (f_info.flag & ICE_FLTR_RX) {
3087e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
3088e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_rule_id = ICE_INVAL_ACT;
3089e94d4478SAnirudh Venkataramanan 		}
3090e94d4478SAnirudh Venkataramanan 	}
3091e94d4478SAnirudh Venkataramanan 
3092e94d4478SAnirudh Venkataramanan out:
3093e94d4478SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
3094e94d4478SAnirudh Venkataramanan 	return status;
3095e94d4478SAnirudh Venkataramanan }
3096e94d4478SAnirudh Venkataramanan 
3097e94d4478SAnirudh Venkataramanan /**
30988b2c8582SAkeem G Abodunrin  * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry
30998b2c8582SAkeem G Abodunrin  * @hw: pointer to the hardware structure
31008b2c8582SAkeem G Abodunrin  * @recp_id: lookup type for which the specified rule needs to be searched
31018b2c8582SAkeem G Abodunrin  * @f_info: rule information
31028b2c8582SAkeem G Abodunrin  *
31038b2c8582SAkeem G Abodunrin  * Helper function to search for a unicast rule entry - this is to be used
31048b2c8582SAkeem G Abodunrin  * to remove unicast MAC filter that is not shared with other VSIs on the
31058b2c8582SAkeem G Abodunrin  * PF switch.
31068b2c8582SAkeem G Abodunrin  *
31078b2c8582SAkeem G Abodunrin  * Returns pointer to entry storing the rule if found
31088b2c8582SAkeem G Abodunrin  */
31098b2c8582SAkeem G Abodunrin static struct ice_fltr_mgmt_list_entry *
31108b2c8582SAkeem G Abodunrin ice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id,
31118b2c8582SAkeem G Abodunrin 			  struct ice_fltr_info *f_info)
31128b2c8582SAkeem G Abodunrin {
31138b2c8582SAkeem G Abodunrin 	struct ice_switch_info *sw = hw->switch_info;
31148b2c8582SAkeem G Abodunrin 	struct ice_fltr_mgmt_list_entry *list_itr;
31158b2c8582SAkeem G Abodunrin 	struct list_head *list_head;
31168b2c8582SAkeem G Abodunrin 
31178b2c8582SAkeem G Abodunrin 	list_head = &sw->recp_list[recp_id].filt_rules;
31188b2c8582SAkeem G Abodunrin 	list_for_each_entry(list_itr, list_head, list_entry) {
31198b2c8582SAkeem G Abodunrin 		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
31208b2c8582SAkeem G Abodunrin 			    sizeof(f_info->l_data)) &&
31218b2c8582SAkeem G Abodunrin 		    f_info->fwd_id.hw_vsi_id ==
31228b2c8582SAkeem G Abodunrin 		    list_itr->fltr_info.fwd_id.hw_vsi_id &&
31238b2c8582SAkeem G Abodunrin 		    f_info->flag == list_itr->fltr_info.flag)
31248b2c8582SAkeem G Abodunrin 			return list_itr;
31258b2c8582SAkeem G Abodunrin 	}
31268b2c8582SAkeem G Abodunrin 	return NULL;
31278b2c8582SAkeem G Abodunrin }
31288b2c8582SAkeem G Abodunrin 
31298b2c8582SAkeem G Abodunrin /**
313080d144c9SAnirudh Venkataramanan  * ice_remove_mac - remove a MAC address based filter rule
3131d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
313280d144c9SAnirudh Venkataramanan  * @m_list: list of MAC addresses and forwarding information
313380d144c9SAnirudh Venkataramanan  *
313480d144c9SAnirudh Venkataramanan  * This function removes either a MAC filter rule or a specific VSI from a
313580d144c9SAnirudh Venkataramanan  * VSI list for a multicast MAC address.
313680d144c9SAnirudh Venkataramanan  *
31375518ac2aSTony Nguyen  * Returns -ENOENT if a given entry was not added by ice_add_mac. Caller should
31385518ac2aSTony Nguyen  * be aware that this call will only work if all the entries passed into m_list
31395518ac2aSTony Nguyen  * were added previously. It will not attempt to do a partial remove of entries
31405518ac2aSTony Nguyen  * that were found.
3141d76a60baSAnirudh Venkataramanan  */
31425e24d598STony Nguyen int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
3143d76a60baSAnirudh Venkataramanan {
3144072f0c3dSDave Ertman 	struct ice_fltr_list_entry *list_itr, *tmp;
31458b2c8582SAkeem G Abodunrin 	struct mutex *rule_lock; /* Lock to protect filter rule list */
3146d76a60baSAnirudh Venkataramanan 
314780d144c9SAnirudh Venkataramanan 	if (!m_list)
3148d54699e2STony Nguyen 		return -EINVAL;
3149d76a60baSAnirudh Venkataramanan 
31508b2c8582SAkeem G Abodunrin 	rule_lock = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
3151072f0c3dSDave Ertman 	list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) {
315280d144c9SAnirudh Venkataramanan 		enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
31538b2c8582SAkeem G Abodunrin 		u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0];
31548b2c8582SAkeem G Abodunrin 		u16 vsi_handle;
315580d144c9SAnirudh Venkataramanan 
315680d144c9SAnirudh Venkataramanan 		if (l_type != ICE_SW_LKUP_MAC)
3157d54699e2STony Nguyen 			return -EINVAL;
31588b2c8582SAkeem G Abodunrin 
31598b2c8582SAkeem G Abodunrin 		vsi_handle = list_itr->fltr_info.vsi_handle;
31608b2c8582SAkeem G Abodunrin 		if (!ice_is_vsi_valid(hw, vsi_handle))
3161d54699e2STony Nguyen 			return -EINVAL;
31628b2c8582SAkeem G Abodunrin 
31638b2c8582SAkeem G Abodunrin 		list_itr->fltr_info.fwd_id.hw_vsi_id =
31648b2c8582SAkeem G Abodunrin 					ice_get_hw_vsi_num(hw, vsi_handle);
31658b2c8582SAkeem G Abodunrin 		if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
31668b2c8582SAkeem G Abodunrin 			/* Don't remove the unicast address that belongs to
31678b2c8582SAkeem G Abodunrin 			 * another VSI on the switch, since it is not being
31688b2c8582SAkeem G Abodunrin 			 * shared...
31698b2c8582SAkeem G Abodunrin 			 */
31708b2c8582SAkeem G Abodunrin 			mutex_lock(rule_lock);
31718b2c8582SAkeem G Abodunrin 			if (!ice_find_ucast_rule_entry(hw, ICE_SW_LKUP_MAC,
31728b2c8582SAkeem G Abodunrin 						       &list_itr->fltr_info)) {
31738b2c8582SAkeem G Abodunrin 				mutex_unlock(rule_lock);
3174d54699e2STony Nguyen 				return -ENOENT;
31758b2c8582SAkeem G Abodunrin 			}
31768b2c8582SAkeem G Abodunrin 			mutex_unlock(rule_lock);
31778b2c8582SAkeem G Abodunrin 		}
317880d144c9SAnirudh Venkataramanan 		list_itr->status = ice_remove_rule_internal(hw,
317980d144c9SAnirudh Venkataramanan 							    ICE_SW_LKUP_MAC,
318080d144c9SAnirudh Venkataramanan 							    list_itr);
318180d144c9SAnirudh Venkataramanan 		if (list_itr->status)
318280d144c9SAnirudh Venkataramanan 			return list_itr->status;
318380d144c9SAnirudh Venkataramanan 	}
318480d144c9SAnirudh Venkataramanan 	return 0;
3185d76a60baSAnirudh Venkataramanan }
3186d76a60baSAnirudh Venkataramanan 
3187d76a60baSAnirudh Venkataramanan /**
3188d76a60baSAnirudh Venkataramanan  * ice_remove_vlan - Remove VLAN based filter rule
3189d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
3190d76a60baSAnirudh Venkataramanan  * @v_list: list of VLAN entries and forwarding information
3191d76a60baSAnirudh Venkataramanan  */
31925518ac2aSTony Nguyen int ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)
3193d76a60baSAnirudh Venkataramanan {
3194072f0c3dSDave Ertman 	struct ice_fltr_list_entry *v_list_itr, *tmp;
3195d76a60baSAnirudh Venkataramanan 
3196d76a60baSAnirudh Venkataramanan 	if (!v_list || !hw)
3197d54699e2STony Nguyen 		return -EINVAL;
3198d76a60baSAnirudh Venkataramanan 
3199072f0c3dSDave Ertman 	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
320080d144c9SAnirudh Venkataramanan 		enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;
320180d144c9SAnirudh Venkataramanan 
320280d144c9SAnirudh Venkataramanan 		if (l_type != ICE_SW_LKUP_VLAN)
3203d54699e2STony Nguyen 			return -EINVAL;
320480d144c9SAnirudh Venkataramanan 		v_list_itr->status = ice_remove_rule_internal(hw,
320580d144c9SAnirudh Venkataramanan 							      ICE_SW_LKUP_VLAN,
320680d144c9SAnirudh Venkataramanan 							      v_list_itr);
320780d144c9SAnirudh Venkataramanan 		if (v_list_itr->status)
320880d144c9SAnirudh Venkataramanan 			return v_list_itr->status;
3209d76a60baSAnirudh Venkataramanan 	}
321080d144c9SAnirudh Venkataramanan 	return 0;
3211d76a60baSAnirudh Venkataramanan }
321280d144c9SAnirudh Venkataramanan 
321380d144c9SAnirudh Venkataramanan /**
321480d144c9SAnirudh Venkataramanan  * ice_vsi_uses_fltr - Determine if given VSI uses specified filter
321580d144c9SAnirudh Venkataramanan  * @fm_entry: filter entry to inspect
32165726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to compare with filter info
321780d144c9SAnirudh Venkataramanan  */
321880d144c9SAnirudh Venkataramanan static bool
32195726ca0eSAnirudh Venkataramanan ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)
322080d144c9SAnirudh Venkataramanan {
322180d144c9SAnirudh Venkataramanan 	return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
32225726ca0eSAnirudh Venkataramanan 		 fm_entry->fltr_info.vsi_handle == vsi_handle) ||
322380d144c9SAnirudh Venkataramanan 		(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
32247a91d3f0SJacek Bułatek 		 fm_entry->vsi_list_info &&
32255726ca0eSAnirudh Venkataramanan 		 (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map))));
322680d144c9SAnirudh Venkataramanan }
322780d144c9SAnirudh Venkataramanan 
322880d144c9SAnirudh Venkataramanan /**
322980d144c9SAnirudh Venkataramanan  * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list
323080d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
32315726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
323280d144c9SAnirudh Venkataramanan  * @vsi_list_head: pointer to the list to add entry to
323380d144c9SAnirudh Venkataramanan  * @fi: pointer to fltr_info of filter entry to copy & add
323480d144c9SAnirudh Venkataramanan  *
323580d144c9SAnirudh Venkataramanan  * Helper function, used when creating a list of filters to remove from
323680d144c9SAnirudh Venkataramanan  * a specific VSI. The entry added to vsi_list_head is a COPY of the
323780d144c9SAnirudh Venkataramanan  * original filter entry, with the exception of fltr_info.fltr_act and
323880d144c9SAnirudh Venkataramanan  * fltr_info.fwd_id fields. These are set such that later logic can
323980d144c9SAnirudh Venkataramanan  * extract which VSI to remove the fltr from, and pass on that information.
324080d144c9SAnirudh Venkataramanan  */
32415e24d598STony Nguyen static int
32425726ca0eSAnirudh Venkataramanan ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
324380d144c9SAnirudh Venkataramanan 			       struct list_head *vsi_list_head,
324480d144c9SAnirudh Venkataramanan 			       struct ice_fltr_info *fi)
324580d144c9SAnirudh Venkataramanan {
324680d144c9SAnirudh Venkataramanan 	struct ice_fltr_list_entry *tmp;
324780d144c9SAnirudh Venkataramanan 
324880d144c9SAnirudh Venkataramanan 	/* this memory is freed up in the caller function
324980d144c9SAnirudh Venkataramanan 	 * once filters for this VSI are removed
325080d144c9SAnirudh Venkataramanan 	 */
325180d144c9SAnirudh Venkataramanan 	tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL);
325280d144c9SAnirudh Venkataramanan 	if (!tmp)
3253d54699e2STony Nguyen 		return -ENOMEM;
325480d144c9SAnirudh Venkataramanan 
325580d144c9SAnirudh Venkataramanan 	tmp->fltr_info = *fi;
325680d144c9SAnirudh Venkataramanan 
325780d144c9SAnirudh Venkataramanan 	/* Overwrite these fields to indicate which VSI to remove filter from,
325880d144c9SAnirudh Venkataramanan 	 * so find and remove logic can extract the information from the
325980d144c9SAnirudh Venkataramanan 	 * list entries. Note that original entries will still have proper
326080d144c9SAnirudh Venkataramanan 	 * values.
326180d144c9SAnirudh Venkataramanan 	 */
326280d144c9SAnirudh Venkataramanan 	tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
32635726ca0eSAnirudh Venkataramanan 	tmp->fltr_info.vsi_handle = vsi_handle;
32645726ca0eSAnirudh Venkataramanan 	tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
326580d144c9SAnirudh Venkataramanan 
326680d144c9SAnirudh Venkataramanan 	list_add(&tmp->list_entry, vsi_list_head);
326780d144c9SAnirudh Venkataramanan 
326880d144c9SAnirudh Venkataramanan 	return 0;
3269d76a60baSAnirudh Venkataramanan }
3270d76a60baSAnirudh Venkataramanan 
3271d76a60baSAnirudh Venkataramanan /**
32729daf8208SAnirudh Venkataramanan  * ice_add_to_vsi_fltr_list - Add VSI filters to the list
32739daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
32745726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
32759daf8208SAnirudh Venkataramanan  * @lkup_list_head: pointer to the list that has certain lookup type filters
32765726ca0eSAnirudh Venkataramanan  * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle
327780d144c9SAnirudh Venkataramanan  *
327880d144c9SAnirudh Venkataramanan  * Locates all filters in lkup_list_head that are used by the given VSI,
327980d144c9SAnirudh Venkataramanan  * and adds COPIES of those entries to vsi_list_head (intended to be used
328080d144c9SAnirudh Venkataramanan  * to remove the listed filters).
328180d144c9SAnirudh Venkataramanan  * Note that this means all entries in vsi_list_head must be explicitly
328280d144c9SAnirudh Venkataramanan  * deallocated by the caller when done with list.
32839daf8208SAnirudh Venkataramanan  */
32845e24d598STony Nguyen static int
32855726ca0eSAnirudh Venkataramanan ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
32869daf8208SAnirudh Venkataramanan 			 struct list_head *lkup_list_head,
32879daf8208SAnirudh Venkataramanan 			 struct list_head *vsi_list_head)
32889daf8208SAnirudh Venkataramanan {
32899daf8208SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *fm_entry;
32905e24d598STony Nguyen 	int status = 0;
32919daf8208SAnirudh Venkataramanan 
3292f9867df6SAnirudh Venkataramanan 	/* check to make sure VSI ID is valid and within boundary */
32935726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
3294d54699e2STony Nguyen 		return -EINVAL;
32959daf8208SAnirudh Venkataramanan 
32969daf8208SAnirudh Venkataramanan 	list_for_each_entry(fm_entry, lkup_list_head, list_entry) {
32977a91d3f0SJacek Bułatek 		if (!ice_vsi_uses_fltr(fm_entry, vsi_handle))
329880d144c9SAnirudh Venkataramanan 			continue;
32999daf8208SAnirudh Venkataramanan 
33005726ca0eSAnirudh Venkataramanan 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
33017a91d3f0SJacek Bułatek 							vsi_list_head,
33027a91d3f0SJacek Bułatek 							&fm_entry->fltr_info);
330380d144c9SAnirudh Venkataramanan 		if (status)
330480d144c9SAnirudh Venkataramanan 			return status;
33059daf8208SAnirudh Venkataramanan 	}
330680d144c9SAnirudh Venkataramanan 	return status;
33079daf8208SAnirudh Venkataramanan }
33089daf8208SAnirudh Venkataramanan 
33099daf8208SAnirudh Venkataramanan /**
33105eda8afdSAkeem G Abodunrin  * ice_determine_promisc_mask
33115eda8afdSAkeem G Abodunrin  * @fi: filter info to parse
33125eda8afdSAkeem G Abodunrin  *
33135eda8afdSAkeem G Abodunrin  * Helper function to determine which ICE_PROMISC_ mask corresponds
33145eda8afdSAkeem G Abodunrin  * to given filter into.
33155eda8afdSAkeem G Abodunrin  */
33165eda8afdSAkeem G Abodunrin static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi)
33175eda8afdSAkeem G Abodunrin {
33185eda8afdSAkeem G Abodunrin 	u16 vid = fi->l_data.mac_vlan.vlan_id;
33195eda8afdSAkeem G Abodunrin 	u8 *macaddr = fi->l_data.mac.mac_addr;
33205eda8afdSAkeem G Abodunrin 	bool is_tx_fltr = false;
33215eda8afdSAkeem G Abodunrin 	u8 promisc_mask = 0;
33225eda8afdSAkeem G Abodunrin 
33235eda8afdSAkeem G Abodunrin 	if (fi->flag == ICE_FLTR_TX)
33245eda8afdSAkeem G Abodunrin 		is_tx_fltr = true;
33255eda8afdSAkeem G Abodunrin 
33265eda8afdSAkeem G Abodunrin 	if (is_broadcast_ether_addr(macaddr))
33275eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
33285eda8afdSAkeem G Abodunrin 			ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX;
33295eda8afdSAkeem G Abodunrin 	else if (is_multicast_ether_addr(macaddr))
33305eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
33315eda8afdSAkeem G Abodunrin 			ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX;
33325eda8afdSAkeem G Abodunrin 	else if (is_unicast_ether_addr(macaddr))
33335eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
33345eda8afdSAkeem G Abodunrin 			ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX;
33355eda8afdSAkeem G Abodunrin 	if (vid)
33365eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
33375eda8afdSAkeem G Abodunrin 			ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX;
33385eda8afdSAkeem G Abodunrin 
33395eda8afdSAkeem G Abodunrin 	return promisc_mask;
33405eda8afdSAkeem G Abodunrin }
33415eda8afdSAkeem G Abodunrin 
33425eda8afdSAkeem G Abodunrin /**
33435eda8afdSAkeem G Abodunrin  * ice_remove_promisc - Remove promisc based filter rules
33445eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
3345f9867df6SAnirudh Venkataramanan  * @recp_id: recipe ID for which the rule needs to removed
33465eda8afdSAkeem G Abodunrin  * @v_list: list of promisc entries
33475eda8afdSAkeem G Abodunrin  */
33485e24d598STony Nguyen static int
33495518ac2aSTony Nguyen ice_remove_promisc(struct ice_hw *hw, u8 recp_id, struct list_head *v_list)
33505eda8afdSAkeem G Abodunrin {
33515eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry *v_list_itr, *tmp;
33525eda8afdSAkeem G Abodunrin 
33535eda8afdSAkeem G Abodunrin 	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
33545eda8afdSAkeem G Abodunrin 		v_list_itr->status =
33555eda8afdSAkeem G Abodunrin 			ice_remove_rule_internal(hw, recp_id, v_list_itr);
33565eda8afdSAkeem G Abodunrin 		if (v_list_itr->status)
33575eda8afdSAkeem G Abodunrin 			return v_list_itr->status;
33585eda8afdSAkeem G Abodunrin 	}
33595eda8afdSAkeem G Abodunrin 	return 0;
33605eda8afdSAkeem G Abodunrin }
33615eda8afdSAkeem G Abodunrin 
33625eda8afdSAkeem G Abodunrin /**
33635eda8afdSAkeem G Abodunrin  * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI
33645eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
33655eda8afdSAkeem G Abodunrin  * @vsi_handle: VSI handle to clear mode
33665eda8afdSAkeem G Abodunrin  * @promisc_mask: mask of promiscuous config bits to clear
33675eda8afdSAkeem G Abodunrin  * @vid: VLAN ID to clear VLAN promiscuous
33685eda8afdSAkeem G Abodunrin  */
33695e24d598STony Nguyen int
33705eda8afdSAkeem G Abodunrin ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
33715eda8afdSAkeem G Abodunrin 		      u16 vid)
33725eda8afdSAkeem G Abodunrin {
33735eda8afdSAkeem G Abodunrin 	struct ice_switch_info *sw = hw->switch_info;
33745eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry *fm_entry, *tmp;
33755eda8afdSAkeem G Abodunrin 	struct list_head remove_list_head;
33765eda8afdSAkeem G Abodunrin 	struct ice_fltr_mgmt_list_entry *itr;
33775eda8afdSAkeem G Abodunrin 	struct list_head *rule_head;
33785eda8afdSAkeem G Abodunrin 	struct mutex *rule_lock;	/* Lock to protect filter rule list */
33795e24d598STony Nguyen 	int status = 0;
33805eda8afdSAkeem G Abodunrin 	u8 recipe_id;
33815eda8afdSAkeem G Abodunrin 
33825eda8afdSAkeem G Abodunrin 	if (!ice_is_vsi_valid(hw, vsi_handle))
3383d54699e2STony Nguyen 		return -EINVAL;
33845eda8afdSAkeem G Abodunrin 
33851bc7a4abSBrett Creeley 	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX))
33865eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
33875eda8afdSAkeem G Abodunrin 	else
33885eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC;
33895eda8afdSAkeem G Abodunrin 
33905eda8afdSAkeem G Abodunrin 	rule_head = &sw->recp_list[recipe_id].filt_rules;
33915eda8afdSAkeem G Abodunrin 	rule_lock = &sw->recp_list[recipe_id].filt_rule_lock;
33925eda8afdSAkeem G Abodunrin 
33935eda8afdSAkeem G Abodunrin 	INIT_LIST_HEAD(&remove_list_head);
33945eda8afdSAkeem G Abodunrin 
33955eda8afdSAkeem G Abodunrin 	mutex_lock(rule_lock);
33965eda8afdSAkeem G Abodunrin 	list_for_each_entry(itr, rule_head, list_entry) {
33971bc7a4abSBrett Creeley 		struct ice_fltr_info *fltr_info;
33985eda8afdSAkeem G Abodunrin 		u8 fltr_promisc_mask = 0;
33995eda8afdSAkeem G Abodunrin 
34005eda8afdSAkeem G Abodunrin 		if (!ice_vsi_uses_fltr(itr, vsi_handle))
34015eda8afdSAkeem G Abodunrin 			continue;
34021bc7a4abSBrett Creeley 		fltr_info = &itr->fltr_info;
34035eda8afdSAkeem G Abodunrin 
34041bc7a4abSBrett Creeley 		if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN &&
34051bc7a4abSBrett Creeley 		    vid != fltr_info->l_data.mac_vlan.vlan_id)
34061bc7a4abSBrett Creeley 			continue;
34071bc7a4abSBrett Creeley 
34081bc7a4abSBrett Creeley 		fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info);
34095eda8afdSAkeem G Abodunrin 
34105eda8afdSAkeem G Abodunrin 		/* Skip if filter is not completely specified by given mask */
34115eda8afdSAkeem G Abodunrin 		if (fltr_promisc_mask & ~promisc_mask)
34125eda8afdSAkeem G Abodunrin 			continue;
34135eda8afdSAkeem G Abodunrin 
34145eda8afdSAkeem G Abodunrin 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
34155eda8afdSAkeem G Abodunrin 							&remove_list_head,
34161bc7a4abSBrett Creeley 							fltr_info);
34175eda8afdSAkeem G Abodunrin 		if (status) {
34185eda8afdSAkeem G Abodunrin 			mutex_unlock(rule_lock);
34195eda8afdSAkeem G Abodunrin 			goto free_fltr_list;
34205eda8afdSAkeem G Abodunrin 		}
34215eda8afdSAkeem G Abodunrin 	}
34225eda8afdSAkeem G Abodunrin 	mutex_unlock(rule_lock);
34235eda8afdSAkeem G Abodunrin 
34245eda8afdSAkeem G Abodunrin 	status = ice_remove_promisc(hw, recipe_id, &remove_list_head);
34255eda8afdSAkeem G Abodunrin 
34265eda8afdSAkeem G Abodunrin free_fltr_list:
34275eda8afdSAkeem G Abodunrin 	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
34285eda8afdSAkeem G Abodunrin 		list_del(&fm_entry->list_entry);
34295eda8afdSAkeem G Abodunrin 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
34305eda8afdSAkeem G Abodunrin 	}
34315eda8afdSAkeem G Abodunrin 
34325eda8afdSAkeem G Abodunrin 	return status;
34335eda8afdSAkeem G Abodunrin }
34345eda8afdSAkeem G Abodunrin 
34355eda8afdSAkeem G Abodunrin /**
34365eda8afdSAkeem G Abodunrin  * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
34375eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
34385eda8afdSAkeem G Abodunrin  * @vsi_handle: VSI handle to configure
34395eda8afdSAkeem G Abodunrin  * @promisc_mask: mask of promiscuous config bits
34405eda8afdSAkeem G Abodunrin  * @vid: VLAN ID to set VLAN promiscuous
34415eda8afdSAkeem G Abodunrin  */
34425e24d598STony Nguyen int
34435eda8afdSAkeem G Abodunrin ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid)
34445eda8afdSAkeem G Abodunrin {
34455eda8afdSAkeem G Abodunrin 	enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };
34465eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry f_list_entry;
34475eda8afdSAkeem G Abodunrin 	struct ice_fltr_info new_fltr;
34485eda8afdSAkeem G Abodunrin 	bool is_tx_fltr;
34495518ac2aSTony Nguyen 	int status = 0;
34505eda8afdSAkeem G Abodunrin 	u16 hw_vsi_id;
34515eda8afdSAkeem G Abodunrin 	int pkt_type;
34525eda8afdSAkeem G Abodunrin 	u8 recipe_id;
34535eda8afdSAkeem G Abodunrin 
34545eda8afdSAkeem G Abodunrin 	if (!ice_is_vsi_valid(hw, vsi_handle))
3455d54699e2STony Nguyen 		return -EINVAL;
34565eda8afdSAkeem G Abodunrin 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
34575eda8afdSAkeem G Abodunrin 
34585eda8afdSAkeem G Abodunrin 	memset(&new_fltr, 0, sizeof(new_fltr));
34595eda8afdSAkeem G Abodunrin 
34605eda8afdSAkeem G Abodunrin 	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) {
34615eda8afdSAkeem G Abodunrin 		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;
34625eda8afdSAkeem G Abodunrin 		new_fltr.l_data.mac_vlan.vlan_id = vid;
34635eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
34645eda8afdSAkeem G Abodunrin 	} else {
34655eda8afdSAkeem G Abodunrin 		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC;
34665eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC;
34675eda8afdSAkeem G Abodunrin 	}
34685eda8afdSAkeem G Abodunrin 
34695eda8afdSAkeem G Abodunrin 	/* Separate filters must be set for each direction/packet type
34705eda8afdSAkeem G Abodunrin 	 * combination, so we will loop over the mask value, store the
34715eda8afdSAkeem G Abodunrin 	 * individual type, and clear it out in the input mask as it
34725eda8afdSAkeem G Abodunrin 	 * is found.
34735eda8afdSAkeem G Abodunrin 	 */
34745eda8afdSAkeem G Abodunrin 	while (promisc_mask) {
34755eda8afdSAkeem G Abodunrin 		u8 *mac_addr;
34765eda8afdSAkeem G Abodunrin 
34775eda8afdSAkeem G Abodunrin 		pkt_type = 0;
34785eda8afdSAkeem G Abodunrin 		is_tx_fltr = false;
34795eda8afdSAkeem G Abodunrin 
34805eda8afdSAkeem G Abodunrin 		if (promisc_mask & ICE_PROMISC_UCAST_RX) {
34815eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_UCAST_RX;
34825eda8afdSAkeem G Abodunrin 			pkt_type = UCAST_FLTR;
34835eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_UCAST_TX) {
34845eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_UCAST_TX;
34855eda8afdSAkeem G Abodunrin 			pkt_type = UCAST_FLTR;
34865eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
34875eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_MCAST_RX) {
34885eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_MCAST_RX;
34895eda8afdSAkeem G Abodunrin 			pkt_type = MCAST_FLTR;
34905eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_MCAST_TX) {
34915eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_MCAST_TX;
34925eda8afdSAkeem G Abodunrin 			pkt_type = MCAST_FLTR;
34935eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
34945eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_BCAST_RX) {
34955eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_BCAST_RX;
34965eda8afdSAkeem G Abodunrin 			pkt_type = BCAST_FLTR;
34975eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_BCAST_TX) {
34985eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_BCAST_TX;
34995eda8afdSAkeem G Abodunrin 			pkt_type = BCAST_FLTR;
35005eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
35015eda8afdSAkeem G Abodunrin 		}
35025eda8afdSAkeem G Abodunrin 
35035eda8afdSAkeem G Abodunrin 		/* Check for VLAN promiscuous flag */
35045eda8afdSAkeem G Abodunrin 		if (promisc_mask & ICE_PROMISC_VLAN_RX) {
35055eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_VLAN_RX;
35065eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_VLAN_TX) {
35075eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_VLAN_TX;
35085eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
35095eda8afdSAkeem G Abodunrin 		}
35105eda8afdSAkeem G Abodunrin 
35115eda8afdSAkeem G Abodunrin 		/* Set filter DA based on packet type */
35125eda8afdSAkeem G Abodunrin 		mac_addr = new_fltr.l_data.mac.mac_addr;
35135eda8afdSAkeem G Abodunrin 		if (pkt_type == BCAST_FLTR) {
35145eda8afdSAkeem G Abodunrin 			eth_broadcast_addr(mac_addr);
35155eda8afdSAkeem G Abodunrin 		} else if (pkt_type == MCAST_FLTR ||
35165eda8afdSAkeem G Abodunrin 			   pkt_type == UCAST_FLTR) {
35175eda8afdSAkeem G Abodunrin 			/* Use the dummy ether header DA */
35185eda8afdSAkeem G Abodunrin 			ether_addr_copy(mac_addr, dummy_eth_header);
35195eda8afdSAkeem G Abodunrin 			if (pkt_type == MCAST_FLTR)
35205eda8afdSAkeem G Abodunrin 				mac_addr[0] |= 0x1;	/* Set multicast bit */
35215eda8afdSAkeem G Abodunrin 		}
35225eda8afdSAkeem G Abodunrin 
35235eda8afdSAkeem G Abodunrin 		/* Need to reset this to zero for all iterations */
35245eda8afdSAkeem G Abodunrin 		new_fltr.flag = 0;
35255eda8afdSAkeem G Abodunrin 		if (is_tx_fltr) {
35265eda8afdSAkeem G Abodunrin 			new_fltr.flag |= ICE_FLTR_TX;
35275eda8afdSAkeem G Abodunrin 			new_fltr.src = hw_vsi_id;
35285eda8afdSAkeem G Abodunrin 		} else {
35295eda8afdSAkeem G Abodunrin 			new_fltr.flag |= ICE_FLTR_RX;
35305eda8afdSAkeem G Abodunrin 			new_fltr.src = hw->port_info->lport;
35315eda8afdSAkeem G Abodunrin 		}
35325eda8afdSAkeem G Abodunrin 
35335eda8afdSAkeem G Abodunrin 		new_fltr.fltr_act = ICE_FWD_TO_VSI;
35345eda8afdSAkeem G Abodunrin 		new_fltr.vsi_handle = vsi_handle;
35355eda8afdSAkeem G Abodunrin 		new_fltr.fwd_id.hw_vsi_id = hw_vsi_id;
35365eda8afdSAkeem G Abodunrin 		f_list_entry.fltr_info = new_fltr;
35375eda8afdSAkeem G Abodunrin 
35385eda8afdSAkeem G Abodunrin 		status = ice_add_rule_internal(hw, recipe_id, &f_list_entry);
35395eda8afdSAkeem G Abodunrin 		if (status)
35405eda8afdSAkeem G Abodunrin 			goto set_promisc_exit;
35415eda8afdSAkeem G Abodunrin 	}
35425eda8afdSAkeem G Abodunrin 
35435eda8afdSAkeem G Abodunrin set_promisc_exit:
35445eda8afdSAkeem G Abodunrin 	return status;
35455eda8afdSAkeem G Abodunrin }
35465eda8afdSAkeem G Abodunrin 
35475eda8afdSAkeem G Abodunrin /**
35485eda8afdSAkeem G Abodunrin  * ice_set_vlan_vsi_promisc
35495eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
35505eda8afdSAkeem G Abodunrin  * @vsi_handle: VSI handle to configure
35515eda8afdSAkeem G Abodunrin  * @promisc_mask: mask of promiscuous config bits
35525eda8afdSAkeem G Abodunrin  * @rm_vlan_promisc: Clear VLANs VSI promisc mode
35535eda8afdSAkeem G Abodunrin  *
35545eda8afdSAkeem G Abodunrin  * Configure VSI with all associated VLANs to given promiscuous mode(s)
35555eda8afdSAkeem G Abodunrin  */
35565e24d598STony Nguyen int
35575eda8afdSAkeem G Abodunrin ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
35585eda8afdSAkeem G Abodunrin 			 bool rm_vlan_promisc)
35595eda8afdSAkeem G Abodunrin {
35605eda8afdSAkeem G Abodunrin 	struct ice_switch_info *sw = hw->switch_info;
35615eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry *list_itr, *tmp;
35625eda8afdSAkeem G Abodunrin 	struct list_head vsi_list_head;
35635eda8afdSAkeem G Abodunrin 	struct list_head *vlan_head;
35645eda8afdSAkeem G Abodunrin 	struct mutex *vlan_lock; /* Lock to protect filter rule list */
35655eda8afdSAkeem G Abodunrin 	u16 vlan_id;
35665518ac2aSTony Nguyen 	int status;
35675eda8afdSAkeem G Abodunrin 
35685eda8afdSAkeem G Abodunrin 	INIT_LIST_HEAD(&vsi_list_head);
35695eda8afdSAkeem G Abodunrin 	vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
35705eda8afdSAkeem G Abodunrin 	vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
35715eda8afdSAkeem G Abodunrin 	mutex_lock(vlan_lock);
35725eda8afdSAkeem G Abodunrin 	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,
35735eda8afdSAkeem G Abodunrin 					  &vsi_list_head);
35745eda8afdSAkeem G Abodunrin 	mutex_unlock(vlan_lock);
35755eda8afdSAkeem G Abodunrin 	if (status)
35765eda8afdSAkeem G Abodunrin 		goto free_fltr_list;
35775eda8afdSAkeem G Abodunrin 
35785eda8afdSAkeem G Abodunrin 	list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
35795eda8afdSAkeem G Abodunrin 		vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
35805eda8afdSAkeem G Abodunrin 		if (rm_vlan_promisc)
35815eda8afdSAkeem G Abodunrin 			status = ice_clear_vsi_promisc(hw, vsi_handle,
35825eda8afdSAkeem G Abodunrin 						       promisc_mask, vlan_id);
35835eda8afdSAkeem G Abodunrin 		else
35845eda8afdSAkeem G Abodunrin 			status = ice_set_vsi_promisc(hw, vsi_handle,
35855eda8afdSAkeem G Abodunrin 						     promisc_mask, vlan_id);
35865eda8afdSAkeem G Abodunrin 		if (status)
35875eda8afdSAkeem G Abodunrin 			break;
35885eda8afdSAkeem G Abodunrin 	}
35895eda8afdSAkeem G Abodunrin 
35905eda8afdSAkeem G Abodunrin free_fltr_list:
35915eda8afdSAkeem G Abodunrin 	list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) {
35925eda8afdSAkeem G Abodunrin 		list_del(&list_itr->list_entry);
35935eda8afdSAkeem G Abodunrin 		devm_kfree(ice_hw_to_dev(hw), list_itr);
35945eda8afdSAkeem G Abodunrin 	}
35955eda8afdSAkeem G Abodunrin 	return status;
35965eda8afdSAkeem G Abodunrin }
35975eda8afdSAkeem G Abodunrin 
35985eda8afdSAkeem G Abodunrin /**
35999daf8208SAnirudh Venkataramanan  * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
36009daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
36015726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
36029daf8208SAnirudh Venkataramanan  * @lkup: switch rule filter lookup type
36039daf8208SAnirudh Venkataramanan  */
36049daf8208SAnirudh Venkataramanan static void
36055726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
36069daf8208SAnirudh Venkataramanan 			 enum ice_sw_lkup_type lkup)
36079daf8208SAnirudh Venkataramanan {
36089daf8208SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
36099daf8208SAnirudh Venkataramanan 	struct ice_fltr_list_entry *fm_entry;
36109daf8208SAnirudh Venkataramanan 	struct list_head remove_list_head;
361180d144c9SAnirudh Venkataramanan 	struct list_head *rule_head;
36129daf8208SAnirudh Venkataramanan 	struct ice_fltr_list_entry *tmp;
361380d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock;	/* Lock to protect filter rule list */
36145e24d598STony Nguyen 	int status;
36159daf8208SAnirudh Venkataramanan 
36169daf8208SAnirudh Venkataramanan 	INIT_LIST_HEAD(&remove_list_head);
361780d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[lkup].filt_rule_lock;
361880d144c9SAnirudh Venkataramanan 	rule_head = &sw->recp_list[lkup].filt_rules;
361980d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
36205726ca0eSAnirudh Venkataramanan 	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,
362180d144c9SAnirudh Venkataramanan 					  &remove_list_head);
362280d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
362380d144c9SAnirudh Venkataramanan 	if (status)
3624b7eeb527SRobert Malz 		goto free_fltr_list;
362580d144c9SAnirudh Venkataramanan 
36269daf8208SAnirudh Venkataramanan 	switch (lkup) {
36279daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC:
36289daf8208SAnirudh Venkataramanan 		ice_remove_mac(hw, &remove_list_head);
36299daf8208SAnirudh Venkataramanan 		break;
36309daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_VLAN:
3631d76a60baSAnirudh Venkataramanan 		ice_remove_vlan(hw, &remove_list_head);
3632d76a60baSAnirudh Venkataramanan 		break;
36335eda8afdSAkeem G Abodunrin 	case ICE_SW_LKUP_PROMISC:
36345eda8afdSAkeem G Abodunrin 	case ICE_SW_LKUP_PROMISC_VLAN:
36355eda8afdSAkeem G Abodunrin 		ice_remove_promisc(hw, lkup, &remove_list_head);
36365eda8afdSAkeem G Abodunrin 		break;
36379daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC_VLAN:
36389daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE:
36399daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE_MAC:
36409daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_DFLT:
364180d144c9SAnirudh Venkataramanan 	case ICE_SW_LKUP_LAST:
364280d144c9SAnirudh Venkataramanan 	default:
364380d144c9SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup);
36449daf8208SAnirudh Venkataramanan 		break;
36459daf8208SAnirudh Venkataramanan 	}
36469daf8208SAnirudh Venkataramanan 
3647b7eeb527SRobert Malz free_fltr_list:
36489daf8208SAnirudh Venkataramanan 	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
36499daf8208SAnirudh Venkataramanan 		list_del(&fm_entry->list_entry);
36509daf8208SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
36519daf8208SAnirudh Venkataramanan 	}
36529daf8208SAnirudh Venkataramanan }
36539daf8208SAnirudh Venkataramanan 
36549daf8208SAnirudh Venkataramanan /**
36559daf8208SAnirudh Venkataramanan  * ice_remove_vsi_fltr - Remove all filters for a VSI
36569daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
36575726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
36589daf8208SAnirudh Venkataramanan  */
36595726ca0eSAnirudh Venkataramanan void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)
36609daf8208SAnirudh Venkataramanan {
36615726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC);
36625726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN);
36635726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC);
36645726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN);
36655726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT);
36665726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE);
36675726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC);
36685726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);
36699daf8208SAnirudh Venkataramanan }
36700f9d5027SAnirudh Venkataramanan 
36710f9d5027SAnirudh Venkataramanan /**
3672148beb61SHenry Tieman  * ice_alloc_res_cntr - allocating resource counter
3673148beb61SHenry Tieman  * @hw: pointer to the hardware structure
3674148beb61SHenry Tieman  * @type: type of resource
3675148beb61SHenry Tieman  * @alloc_shared: if set it is shared else dedicated
3676148beb61SHenry Tieman  * @num_items: number of entries requested for FD resource type
3677148beb61SHenry Tieman  * @counter_id: counter index returned by AQ call
3678148beb61SHenry Tieman  */
36795e24d598STony Nguyen int
3680148beb61SHenry Tieman ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
3681148beb61SHenry Tieman 		   u16 *counter_id)
3682148beb61SHenry Tieman {
3683148beb61SHenry Tieman 	struct ice_aqc_alloc_free_res_elem *buf;
3684148beb61SHenry Tieman 	u16 buf_len;
36855518ac2aSTony Nguyen 	int status;
3686148beb61SHenry Tieman 
3687148beb61SHenry Tieman 	/* Allocate resource */
368866486d89SBruce Allan 	buf_len = struct_size(buf, elem, 1);
3689148beb61SHenry Tieman 	buf = kzalloc(buf_len, GFP_KERNEL);
3690148beb61SHenry Tieman 	if (!buf)
3691d54699e2STony Nguyen 		return -ENOMEM;
3692148beb61SHenry Tieman 
3693148beb61SHenry Tieman 	buf->num_elems = cpu_to_le16(num_items);
3694148beb61SHenry Tieman 	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
3695148beb61SHenry Tieman 				      ICE_AQC_RES_TYPE_M) | alloc_shared);
3696148beb61SHenry Tieman 
3697148beb61SHenry Tieman 	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
3698148beb61SHenry Tieman 				       ice_aqc_opc_alloc_res, NULL);
3699148beb61SHenry Tieman 	if (status)
3700148beb61SHenry Tieman 		goto exit;
3701148beb61SHenry Tieman 
3702148beb61SHenry Tieman 	*counter_id = le16_to_cpu(buf->elem[0].e.sw_resp);
3703148beb61SHenry Tieman 
3704148beb61SHenry Tieman exit:
3705148beb61SHenry Tieman 	kfree(buf);
3706148beb61SHenry Tieman 	return status;
3707148beb61SHenry Tieman }
3708148beb61SHenry Tieman 
3709148beb61SHenry Tieman /**
3710148beb61SHenry Tieman  * ice_free_res_cntr - free resource counter
3711148beb61SHenry Tieman  * @hw: pointer to the hardware structure
3712148beb61SHenry Tieman  * @type: type of resource
3713148beb61SHenry Tieman  * @alloc_shared: if set it is shared else dedicated
3714148beb61SHenry Tieman  * @num_items: number of entries to be freed for FD resource type
3715148beb61SHenry Tieman  * @counter_id: counter ID resource which needs to be freed
3716148beb61SHenry Tieman  */
37175e24d598STony Nguyen int
3718148beb61SHenry Tieman ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
3719148beb61SHenry Tieman 		  u16 counter_id)
3720148beb61SHenry Tieman {
3721148beb61SHenry Tieman 	struct ice_aqc_alloc_free_res_elem *buf;
3722148beb61SHenry Tieman 	u16 buf_len;
37235518ac2aSTony Nguyen 	int status;
3724148beb61SHenry Tieman 
3725148beb61SHenry Tieman 	/* Free resource */
372666486d89SBruce Allan 	buf_len = struct_size(buf, elem, 1);
3727148beb61SHenry Tieman 	buf = kzalloc(buf_len, GFP_KERNEL);
3728148beb61SHenry Tieman 	if (!buf)
3729d54699e2STony Nguyen 		return -ENOMEM;
3730148beb61SHenry Tieman 
3731148beb61SHenry Tieman 	buf->num_elems = cpu_to_le16(num_items);
3732148beb61SHenry Tieman 	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
3733148beb61SHenry Tieman 				      ICE_AQC_RES_TYPE_M) | alloc_shared);
3734148beb61SHenry Tieman 	buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
3735148beb61SHenry Tieman 
3736148beb61SHenry Tieman 	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
3737148beb61SHenry Tieman 				       ice_aqc_opc_free_res, NULL);
3738148beb61SHenry Tieman 	if (status)
37399228d8b2SJacob Keller 		ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n");
3740148beb61SHenry Tieman 
3741148beb61SHenry Tieman 	kfree(buf);
3742148beb61SHenry Tieman 	return status;
3743148beb61SHenry Tieman }
3744148beb61SHenry Tieman 
3745fd2a6b71SDan Nowlin /* This is mapping table entry that maps every word within a given protocol
3746fd2a6b71SDan Nowlin  * structure to the real byte offset as per the specification of that
3747fd2a6b71SDan Nowlin  * protocol header.
3748fd2a6b71SDan Nowlin  * for example dst address is 3 words in ethertype header and corresponding
3749fd2a6b71SDan Nowlin  * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8
3750fd2a6b71SDan Nowlin  * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a
3751fd2a6b71SDan Nowlin  * matching entry describing its field. This needs to be updated if new
3752fd2a6b71SDan Nowlin  * structure is added to that union.
3753fd2a6b71SDan Nowlin  */
3754fd2a6b71SDan Nowlin static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
3755fd2a6b71SDan Nowlin 	{ ICE_MAC_OFOS,		{ 0, 2, 4, 6, 8, 10, 12 } },
3756fd2a6b71SDan Nowlin 	{ ICE_MAC_IL,		{ 0, 2, 4, 6, 8, 10, 12 } },
3757fd2a6b71SDan Nowlin 	{ ICE_ETYPE_OL,		{ 0 } },
3758fd2a6b71SDan Nowlin 	{ ICE_VLAN_OFOS,	{ 2, 0 } },
3759fd2a6b71SDan Nowlin 	{ ICE_IPV4_OFOS,	{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
3760fd2a6b71SDan Nowlin 	{ ICE_IPV4_IL,		{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
3761fd2a6b71SDan Nowlin 	{ ICE_IPV6_OFOS,	{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
3762fd2a6b71SDan Nowlin 				 26, 28, 30, 32, 34, 36, 38 } },
3763fd2a6b71SDan Nowlin 	{ ICE_IPV6_IL,		{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
3764fd2a6b71SDan Nowlin 				 26, 28, 30, 32, 34, 36, 38 } },
3765fd2a6b71SDan Nowlin 	{ ICE_TCP_IL,		{ 0, 2 } },
3766fd2a6b71SDan Nowlin 	{ ICE_UDP_OF,		{ 0, 2 } },
3767fd2a6b71SDan Nowlin 	{ ICE_UDP_ILOS,		{ 0, 2 } },
37688b032a55SMichal Swiatkowski 	{ ICE_VXLAN,		{ 8, 10, 12, 14 } },
37698b032a55SMichal Swiatkowski 	{ ICE_GENEVE,		{ 8, 10, 12, 14 } },
3770f0a35040SMichal Swiatkowski 	{ ICE_NVGRE,            { 0, 2, 4, 6 } },
3771fd2a6b71SDan Nowlin };
3772fd2a6b71SDan Nowlin 
3773fd2a6b71SDan Nowlin static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
3774fd2a6b71SDan Nowlin 	{ ICE_MAC_OFOS,		ICE_MAC_OFOS_HW },
3775fd2a6b71SDan Nowlin 	{ ICE_MAC_IL,		ICE_MAC_IL_HW },
3776fd2a6b71SDan Nowlin 	{ ICE_ETYPE_OL,		ICE_ETYPE_OL_HW },
3777fd2a6b71SDan Nowlin 	{ ICE_VLAN_OFOS,	ICE_VLAN_OL_HW },
3778fd2a6b71SDan Nowlin 	{ ICE_IPV4_OFOS,	ICE_IPV4_OFOS_HW },
3779fd2a6b71SDan Nowlin 	{ ICE_IPV4_IL,		ICE_IPV4_IL_HW },
3780fd2a6b71SDan Nowlin 	{ ICE_IPV6_OFOS,	ICE_IPV6_OFOS_HW },
3781fd2a6b71SDan Nowlin 	{ ICE_IPV6_IL,		ICE_IPV6_IL_HW },
3782fd2a6b71SDan Nowlin 	{ ICE_TCP_IL,		ICE_TCP_IL_HW },
3783fd2a6b71SDan Nowlin 	{ ICE_UDP_OF,		ICE_UDP_OF_HW },
3784fd2a6b71SDan Nowlin 	{ ICE_UDP_ILOS,		ICE_UDP_ILOS_HW },
37858b032a55SMichal Swiatkowski 	{ ICE_VXLAN,		ICE_UDP_OF_HW },
37868b032a55SMichal Swiatkowski 	{ ICE_GENEVE,		ICE_UDP_OF_HW },
3787f0a35040SMichal Swiatkowski 	{ ICE_NVGRE,            ICE_GRE_OF_HW },
3788fd2a6b71SDan Nowlin };
3789fd2a6b71SDan Nowlin 
3790fd2a6b71SDan Nowlin /**
3791fd2a6b71SDan Nowlin  * ice_find_recp - find a recipe
3792fd2a6b71SDan Nowlin  * @hw: pointer to the hardware structure
3793fd2a6b71SDan Nowlin  * @lkup_exts: extension sequence to match
3794de6acd1cSMichal Swiatkowski  * @tun_type: type of recipe tunnel
3795fd2a6b71SDan Nowlin  *
3796fd2a6b71SDan Nowlin  * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
3797fd2a6b71SDan Nowlin  */
3798de6acd1cSMichal Swiatkowski static u16
3799de6acd1cSMichal Swiatkowski ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
3800de6acd1cSMichal Swiatkowski 	      enum ice_sw_tunnel_type tun_type)
3801fd2a6b71SDan Nowlin {
3802fd2a6b71SDan Nowlin 	bool refresh_required = true;
3803fd2a6b71SDan Nowlin 	struct ice_sw_recipe *recp;
3804fd2a6b71SDan Nowlin 	u8 i;
3805fd2a6b71SDan Nowlin 
3806fd2a6b71SDan Nowlin 	/* Walk through existing recipes to find a match */
3807fd2a6b71SDan Nowlin 	recp = hw->switch_info->recp_list;
3808fd2a6b71SDan Nowlin 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
3809fd2a6b71SDan Nowlin 		/* If recipe was not created for this ID, in SW bookkeeping,
3810fd2a6b71SDan Nowlin 		 * check if FW has an entry for this recipe. If the FW has an
3811fd2a6b71SDan Nowlin 		 * entry update it in our SW bookkeeping and continue with the
3812fd2a6b71SDan Nowlin 		 * matching.
3813fd2a6b71SDan Nowlin 		 */
3814fd2a6b71SDan Nowlin 		if (!recp[i].recp_created)
3815fd2a6b71SDan Nowlin 			if (ice_get_recp_frm_fw(hw,
3816fd2a6b71SDan Nowlin 						hw->switch_info->recp_list, i,
3817fd2a6b71SDan Nowlin 						&refresh_required))
3818fd2a6b71SDan Nowlin 				continue;
3819fd2a6b71SDan Nowlin 
3820fd2a6b71SDan Nowlin 		/* Skip inverse action recipes */
3821fd2a6b71SDan Nowlin 		if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl &
3822fd2a6b71SDan Nowlin 		    ICE_AQ_RECIPE_ACT_INV_ACT)
3823fd2a6b71SDan Nowlin 			continue;
3824fd2a6b71SDan Nowlin 
3825fd2a6b71SDan Nowlin 		/* if number of words we are looking for match */
3826fd2a6b71SDan Nowlin 		if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) {
3827fd2a6b71SDan Nowlin 			struct ice_fv_word *ar = recp[i].lkup_exts.fv_words;
3828fd2a6b71SDan Nowlin 			struct ice_fv_word *be = lkup_exts->fv_words;
3829fd2a6b71SDan Nowlin 			u16 *cr = recp[i].lkup_exts.field_mask;
3830fd2a6b71SDan Nowlin 			u16 *de = lkup_exts->field_mask;
3831fd2a6b71SDan Nowlin 			bool found = true;
3832fd2a6b71SDan Nowlin 			u8 pe, qr;
3833fd2a6b71SDan Nowlin 
3834fd2a6b71SDan Nowlin 			/* ar, cr, and qr are related to the recipe words, while
3835fd2a6b71SDan Nowlin 			 * be, de, and pe are related to the lookup words
3836fd2a6b71SDan Nowlin 			 */
3837fd2a6b71SDan Nowlin 			for (pe = 0; pe < lkup_exts->n_val_words; pe++) {
3838fd2a6b71SDan Nowlin 				for (qr = 0; qr < recp[i].lkup_exts.n_val_words;
3839fd2a6b71SDan Nowlin 				     qr++) {
3840fd2a6b71SDan Nowlin 					if (ar[qr].off == be[pe].off &&
3841fd2a6b71SDan Nowlin 					    ar[qr].prot_id == be[pe].prot_id &&
3842fd2a6b71SDan Nowlin 					    cr[qr] == de[pe])
3843fd2a6b71SDan Nowlin 						/* Found the "pe"th word in the
3844fd2a6b71SDan Nowlin 						 * given recipe
3845fd2a6b71SDan Nowlin 						 */
3846fd2a6b71SDan Nowlin 						break;
3847fd2a6b71SDan Nowlin 				}
3848fd2a6b71SDan Nowlin 				/* After walking through all the words in the
3849fd2a6b71SDan Nowlin 				 * "i"th recipe if "p"th word was not found then
3850fd2a6b71SDan Nowlin 				 * this recipe is not what we are looking for.
3851fd2a6b71SDan Nowlin 				 * So break out from this loop and try the next
3852fd2a6b71SDan Nowlin 				 * recipe
3853fd2a6b71SDan Nowlin 				 */
3854fd2a6b71SDan Nowlin 				if (qr >= recp[i].lkup_exts.n_val_words) {
3855fd2a6b71SDan Nowlin 					found = false;
3856fd2a6b71SDan Nowlin 					break;
3857fd2a6b71SDan Nowlin 				}
3858fd2a6b71SDan Nowlin 			}
3859fd2a6b71SDan Nowlin 			/* If for "i"th recipe the found was never set to false
3860fd2a6b71SDan Nowlin 			 * then it means we found our match
3861de6acd1cSMichal Swiatkowski 			 * Also tun type of recipe needs to be checked
3862fd2a6b71SDan Nowlin 			 */
3863de6acd1cSMichal Swiatkowski 			if (found && recp[i].tun_type == tun_type)
3864fd2a6b71SDan Nowlin 				return i; /* Return the recipe ID */
3865fd2a6b71SDan Nowlin 		}
3866fd2a6b71SDan Nowlin 	}
3867fd2a6b71SDan Nowlin 	return ICE_MAX_NUM_RECIPES;
3868fd2a6b71SDan Nowlin }
3869fd2a6b71SDan Nowlin 
3870fd2a6b71SDan Nowlin /**
3871fd2a6b71SDan Nowlin  * ice_prot_type_to_id - get protocol ID from protocol type
3872fd2a6b71SDan Nowlin  * @type: protocol type
3873fd2a6b71SDan Nowlin  * @id: pointer to variable that will receive the ID
3874fd2a6b71SDan Nowlin  *
3875fd2a6b71SDan Nowlin  * Returns true if found, false otherwise
3876fd2a6b71SDan Nowlin  */
3877fd2a6b71SDan Nowlin static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id)
3878fd2a6b71SDan Nowlin {
3879fd2a6b71SDan Nowlin 	u8 i;
3880fd2a6b71SDan Nowlin 
3881fd2a6b71SDan Nowlin 	for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++)
3882fd2a6b71SDan Nowlin 		if (ice_prot_id_tbl[i].type == type) {
3883fd2a6b71SDan Nowlin 			*id = ice_prot_id_tbl[i].protocol_id;
3884fd2a6b71SDan Nowlin 			return true;
3885fd2a6b71SDan Nowlin 		}
3886fd2a6b71SDan Nowlin 	return false;
3887fd2a6b71SDan Nowlin }
3888fd2a6b71SDan Nowlin 
3889fd2a6b71SDan Nowlin /**
3890fd2a6b71SDan Nowlin  * ice_fill_valid_words - count valid words
3891fd2a6b71SDan Nowlin  * @rule: advanced rule with lookup information
3892fd2a6b71SDan Nowlin  * @lkup_exts: byte offset extractions of the words that are valid
3893fd2a6b71SDan Nowlin  *
3894fd2a6b71SDan Nowlin  * calculate valid words in a lookup rule using mask value
3895fd2a6b71SDan Nowlin  */
3896fd2a6b71SDan Nowlin static u8
3897fd2a6b71SDan Nowlin ice_fill_valid_words(struct ice_adv_lkup_elem *rule,
3898fd2a6b71SDan Nowlin 		     struct ice_prot_lkup_ext *lkup_exts)
3899fd2a6b71SDan Nowlin {
3900fd2a6b71SDan Nowlin 	u8 j, word, prot_id, ret_val;
3901fd2a6b71SDan Nowlin 
3902fd2a6b71SDan Nowlin 	if (!ice_prot_type_to_id(rule->type, &prot_id))
3903fd2a6b71SDan Nowlin 		return 0;
3904fd2a6b71SDan Nowlin 
3905fd2a6b71SDan Nowlin 	word = lkup_exts->n_val_words;
3906fd2a6b71SDan Nowlin 
3907fd2a6b71SDan Nowlin 	for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++)
3908fd2a6b71SDan Nowlin 		if (((u16 *)&rule->m_u)[j] &&
3909fd2a6b71SDan Nowlin 		    rule->type < ARRAY_SIZE(ice_prot_ext)) {
3910fd2a6b71SDan Nowlin 			/* No more space to accommodate */
3911fd2a6b71SDan Nowlin 			if (word >= ICE_MAX_CHAIN_WORDS)
3912fd2a6b71SDan Nowlin 				return 0;
3913fd2a6b71SDan Nowlin 			lkup_exts->fv_words[word].off =
3914fd2a6b71SDan Nowlin 				ice_prot_ext[rule->type].offs[j];
3915fd2a6b71SDan Nowlin 			lkup_exts->fv_words[word].prot_id =
3916fd2a6b71SDan Nowlin 				ice_prot_id_tbl[rule->type].protocol_id;
3917fd2a6b71SDan Nowlin 			lkup_exts->field_mask[word] =
3918fd2a6b71SDan Nowlin 				be16_to_cpu(((__force __be16 *)&rule->m_u)[j]);
3919fd2a6b71SDan Nowlin 			word++;
3920fd2a6b71SDan Nowlin 		}
3921fd2a6b71SDan Nowlin 
3922fd2a6b71SDan Nowlin 	ret_val = word - lkup_exts->n_val_words;
3923fd2a6b71SDan Nowlin 	lkup_exts->n_val_words = word;
3924fd2a6b71SDan Nowlin 
3925fd2a6b71SDan Nowlin 	return ret_val;
3926fd2a6b71SDan Nowlin }
3927fd2a6b71SDan Nowlin 
3928fd2a6b71SDan Nowlin /**
3929fd2a6b71SDan Nowlin  * ice_create_first_fit_recp_def - Create a recipe grouping
3930fd2a6b71SDan Nowlin  * @hw: pointer to the hardware structure
3931fd2a6b71SDan Nowlin  * @lkup_exts: an array of protocol header extractions
3932fd2a6b71SDan Nowlin  * @rg_list: pointer to a list that stores new recipe groups
3933fd2a6b71SDan Nowlin  * @recp_cnt: pointer to a variable that stores returned number of recipe groups
3934fd2a6b71SDan Nowlin  *
3935fd2a6b71SDan Nowlin  * Using first fit algorithm, take all the words that are still not done
3936fd2a6b71SDan Nowlin  * and start grouping them in 4-word groups. Each group makes up one
3937fd2a6b71SDan Nowlin  * recipe.
3938fd2a6b71SDan Nowlin  */
39395e24d598STony Nguyen static int
3940fd2a6b71SDan Nowlin ice_create_first_fit_recp_def(struct ice_hw *hw,
3941fd2a6b71SDan Nowlin 			      struct ice_prot_lkup_ext *lkup_exts,
3942fd2a6b71SDan Nowlin 			      struct list_head *rg_list,
3943fd2a6b71SDan Nowlin 			      u8 *recp_cnt)
3944fd2a6b71SDan Nowlin {
3945fd2a6b71SDan Nowlin 	struct ice_pref_recipe_group *grp = NULL;
3946fd2a6b71SDan Nowlin 	u8 j;
3947fd2a6b71SDan Nowlin 
3948fd2a6b71SDan Nowlin 	*recp_cnt = 0;
3949fd2a6b71SDan Nowlin 
3950fd2a6b71SDan Nowlin 	/* Walk through every word in the rule to check if it is not done. If so
3951fd2a6b71SDan Nowlin 	 * then this word needs to be part of a new recipe.
3952fd2a6b71SDan Nowlin 	 */
3953fd2a6b71SDan Nowlin 	for (j = 0; j < lkup_exts->n_val_words; j++)
3954fd2a6b71SDan Nowlin 		if (!test_bit(j, lkup_exts->done)) {
3955fd2a6b71SDan Nowlin 			if (!grp ||
3956fd2a6b71SDan Nowlin 			    grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) {
3957fd2a6b71SDan Nowlin 				struct ice_recp_grp_entry *entry;
3958fd2a6b71SDan Nowlin 
3959fd2a6b71SDan Nowlin 				entry = devm_kzalloc(ice_hw_to_dev(hw),
3960fd2a6b71SDan Nowlin 						     sizeof(*entry),
3961fd2a6b71SDan Nowlin 						     GFP_KERNEL);
3962fd2a6b71SDan Nowlin 				if (!entry)
3963d54699e2STony Nguyen 					return -ENOMEM;
3964fd2a6b71SDan Nowlin 				list_add(&entry->l_entry, rg_list);
3965fd2a6b71SDan Nowlin 				grp = &entry->r_group;
3966fd2a6b71SDan Nowlin 				(*recp_cnt)++;
3967fd2a6b71SDan Nowlin 			}
3968fd2a6b71SDan Nowlin 
3969fd2a6b71SDan Nowlin 			grp->pairs[grp->n_val_pairs].prot_id =
3970fd2a6b71SDan Nowlin 				lkup_exts->fv_words[j].prot_id;
3971fd2a6b71SDan Nowlin 			grp->pairs[grp->n_val_pairs].off =
3972fd2a6b71SDan Nowlin 				lkup_exts->fv_words[j].off;
3973fd2a6b71SDan Nowlin 			grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j];
3974fd2a6b71SDan Nowlin 			grp->n_val_pairs++;
3975fd2a6b71SDan Nowlin 		}
3976fd2a6b71SDan Nowlin 
3977fd2a6b71SDan Nowlin 	return 0;
3978fd2a6b71SDan Nowlin }
3979fd2a6b71SDan Nowlin 
3980fd2a6b71SDan Nowlin /**
3981fd2a6b71SDan Nowlin  * ice_fill_fv_word_index - fill in the field vector indices for a recipe group
3982fd2a6b71SDan Nowlin  * @hw: pointer to the hardware structure
3983fd2a6b71SDan Nowlin  * @fv_list: field vector with the extraction sequence information
3984fd2a6b71SDan Nowlin  * @rg_list: recipe groupings with protocol-offset pairs
3985fd2a6b71SDan Nowlin  *
3986fd2a6b71SDan Nowlin  * Helper function to fill in the field vector indices for protocol-offset
3987fd2a6b71SDan Nowlin  * pairs. These indexes are then ultimately programmed into a recipe.
3988fd2a6b71SDan Nowlin  */
39895e24d598STony Nguyen static int
3990fd2a6b71SDan Nowlin ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list,
3991fd2a6b71SDan Nowlin 		       struct list_head *rg_list)
3992fd2a6b71SDan Nowlin {
3993fd2a6b71SDan Nowlin 	struct ice_sw_fv_list_entry *fv;
3994fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *rg;
3995fd2a6b71SDan Nowlin 	struct ice_fv_word *fv_ext;
3996fd2a6b71SDan Nowlin 
3997fd2a6b71SDan Nowlin 	if (list_empty(fv_list))
3998fd2a6b71SDan Nowlin 		return 0;
3999fd2a6b71SDan Nowlin 
4000fd2a6b71SDan Nowlin 	fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry,
4001fd2a6b71SDan Nowlin 			      list_entry);
4002fd2a6b71SDan Nowlin 	fv_ext = fv->fv_ptr->ew;
4003fd2a6b71SDan Nowlin 
4004fd2a6b71SDan Nowlin 	list_for_each_entry(rg, rg_list, l_entry) {
4005fd2a6b71SDan Nowlin 		u8 i;
4006fd2a6b71SDan Nowlin 
4007fd2a6b71SDan Nowlin 		for (i = 0; i < rg->r_group.n_val_pairs; i++) {
4008fd2a6b71SDan Nowlin 			struct ice_fv_word *pr;
4009fd2a6b71SDan Nowlin 			bool found = false;
4010fd2a6b71SDan Nowlin 			u16 mask;
4011fd2a6b71SDan Nowlin 			u8 j;
4012fd2a6b71SDan Nowlin 
4013fd2a6b71SDan Nowlin 			pr = &rg->r_group.pairs[i];
4014fd2a6b71SDan Nowlin 			mask = rg->r_group.mask[i];
4015fd2a6b71SDan Nowlin 
4016fd2a6b71SDan Nowlin 			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
4017fd2a6b71SDan Nowlin 				if (fv_ext[j].prot_id == pr->prot_id &&
4018fd2a6b71SDan Nowlin 				    fv_ext[j].off == pr->off) {
4019fd2a6b71SDan Nowlin 					found = true;
4020fd2a6b71SDan Nowlin 
4021fd2a6b71SDan Nowlin 					/* Store index of field vector */
4022fd2a6b71SDan Nowlin 					rg->fv_idx[i] = j;
4023fd2a6b71SDan Nowlin 					rg->fv_mask[i] = mask;
4024fd2a6b71SDan Nowlin 					break;
4025fd2a6b71SDan Nowlin 				}
4026fd2a6b71SDan Nowlin 
4027fd2a6b71SDan Nowlin 			/* Protocol/offset could not be found, caller gave an
4028fd2a6b71SDan Nowlin 			 * invalid pair
4029fd2a6b71SDan Nowlin 			 */
4030fd2a6b71SDan Nowlin 			if (!found)
4031d54699e2STony Nguyen 				return -EINVAL;
4032fd2a6b71SDan Nowlin 		}
4033fd2a6b71SDan Nowlin 	}
4034fd2a6b71SDan Nowlin 
4035fd2a6b71SDan Nowlin 	return 0;
4036fd2a6b71SDan Nowlin }
4037fd2a6b71SDan Nowlin 
4038fd2a6b71SDan Nowlin /**
4039fd2a6b71SDan Nowlin  * ice_find_free_recp_res_idx - find free result indexes for recipe
4040fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4041fd2a6b71SDan Nowlin  * @profiles: bitmap of profiles that will be associated with the new recipe
4042fd2a6b71SDan Nowlin  * @free_idx: pointer to variable to receive the free index bitmap
4043fd2a6b71SDan Nowlin  *
4044fd2a6b71SDan Nowlin  * The algorithm used here is:
4045fd2a6b71SDan Nowlin  *	1. When creating a new recipe, create a set P which contains all
4046fd2a6b71SDan Nowlin  *	   Profiles that will be associated with our new recipe
4047fd2a6b71SDan Nowlin  *
4048fd2a6b71SDan Nowlin  *	2. For each Profile p in set P:
4049fd2a6b71SDan Nowlin  *	    a. Add all recipes associated with Profile p into set R
4050fd2a6b71SDan Nowlin  *	    b. Optional : PossibleIndexes &= profile[p].possibleIndexes
4051fd2a6b71SDan Nowlin  *		[initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF]
4052fd2a6b71SDan Nowlin  *		i. Or just assume they all have the same possible indexes:
4053fd2a6b71SDan Nowlin  *			44, 45, 46, 47
4054fd2a6b71SDan Nowlin  *			i.e., PossibleIndexes = 0x0000F00000000000
4055fd2a6b71SDan Nowlin  *
4056fd2a6b71SDan Nowlin  *	3. For each Recipe r in set R:
4057fd2a6b71SDan Nowlin  *	    a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes
4058fd2a6b71SDan Nowlin  *	    b. FreeIndexes = UsedIndexes ^ PossibleIndexes
4059fd2a6b71SDan Nowlin  *
4060fd2a6b71SDan Nowlin  *	FreeIndexes will contain the bits indicating the indexes free for use,
4061fd2a6b71SDan Nowlin  *      then the code needs to update the recipe[r].used_result_idx_bits to
4062fd2a6b71SDan Nowlin  *      indicate which indexes were selected for use by this recipe.
4063fd2a6b71SDan Nowlin  */
4064fd2a6b71SDan Nowlin static u16
4065fd2a6b71SDan Nowlin ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
4066fd2a6b71SDan Nowlin 			   unsigned long *free_idx)
4067fd2a6b71SDan Nowlin {
4068fd2a6b71SDan Nowlin 	DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS);
4069fd2a6b71SDan Nowlin 	DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES);
4070fd2a6b71SDan Nowlin 	DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS);
4071fd2a6b71SDan Nowlin 	u16 bit;
4072fd2a6b71SDan Nowlin 
4073fd2a6b71SDan Nowlin 	bitmap_zero(recipes, ICE_MAX_NUM_RECIPES);
4074fd2a6b71SDan Nowlin 	bitmap_zero(used_idx, ICE_MAX_FV_WORDS);
4075fd2a6b71SDan Nowlin 
4076fd2a6b71SDan Nowlin 	bitmap_set(possible_idx, 0, ICE_MAX_FV_WORDS);
4077fd2a6b71SDan Nowlin 
4078fd2a6b71SDan Nowlin 	/* For each profile we are going to associate the recipe with, add the
4079fd2a6b71SDan Nowlin 	 * recipes that are associated with that profile. This will give us
4080fd2a6b71SDan Nowlin 	 * the set of recipes that our recipe may collide with. Also, determine
4081fd2a6b71SDan Nowlin 	 * what possible result indexes are usable given this set of profiles.
4082fd2a6b71SDan Nowlin 	 */
4083fd2a6b71SDan Nowlin 	for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) {
4084fd2a6b71SDan Nowlin 		bitmap_or(recipes, recipes, profile_to_recipe[bit],
4085fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_RECIPES);
4086fd2a6b71SDan Nowlin 		bitmap_and(possible_idx, possible_idx,
4087fd2a6b71SDan Nowlin 			   hw->switch_info->prof_res_bm[bit],
4088fd2a6b71SDan Nowlin 			   ICE_MAX_FV_WORDS);
4089fd2a6b71SDan Nowlin 	}
4090fd2a6b71SDan Nowlin 
4091fd2a6b71SDan Nowlin 	/* For each recipe that our new recipe may collide with, determine
4092fd2a6b71SDan Nowlin 	 * which indexes have been used.
4093fd2a6b71SDan Nowlin 	 */
4094fd2a6b71SDan Nowlin 	for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES)
4095fd2a6b71SDan Nowlin 		bitmap_or(used_idx, used_idx,
4096fd2a6b71SDan Nowlin 			  hw->switch_info->recp_list[bit].res_idxs,
4097fd2a6b71SDan Nowlin 			  ICE_MAX_FV_WORDS);
4098fd2a6b71SDan Nowlin 
4099fd2a6b71SDan Nowlin 	bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS);
4100fd2a6b71SDan Nowlin 
4101fd2a6b71SDan Nowlin 	/* return number of free indexes */
4102fd2a6b71SDan Nowlin 	return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS);
4103fd2a6b71SDan Nowlin }
4104fd2a6b71SDan Nowlin 
4105fd2a6b71SDan Nowlin /**
4106fd2a6b71SDan Nowlin  * ice_add_sw_recipe - function to call AQ calls to create switch recipe
4107fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4108fd2a6b71SDan Nowlin  * @rm: recipe management list entry
4109fd2a6b71SDan Nowlin  * @profiles: bitmap of profiles that will be associated.
4110fd2a6b71SDan Nowlin  */
41115e24d598STony Nguyen static int
4112fd2a6b71SDan Nowlin ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
41138b032a55SMichal Swiatkowski 		  unsigned long *profiles)
4114fd2a6b71SDan Nowlin {
4115fd2a6b71SDan Nowlin 	DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
4116fd2a6b71SDan Nowlin 	struct ice_aqc_recipe_data_elem *tmp;
4117fd2a6b71SDan Nowlin 	struct ice_aqc_recipe_data_elem *buf;
4118fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *entry;
4119fd2a6b71SDan Nowlin 	u16 free_res_idx;
4120fd2a6b71SDan Nowlin 	u16 recipe_count;
4121fd2a6b71SDan Nowlin 	u8 chain_idx;
4122fd2a6b71SDan Nowlin 	u8 recps = 0;
41235518ac2aSTony Nguyen 	int status;
4124fd2a6b71SDan Nowlin 
4125fd2a6b71SDan Nowlin 	/* When more than one recipe are required, another recipe is needed to
4126fd2a6b71SDan Nowlin 	 * chain them together. Matching a tunnel metadata ID takes up one of
4127fd2a6b71SDan Nowlin 	 * the match fields in the chaining recipe reducing the number of
4128fd2a6b71SDan Nowlin 	 * chained recipes by one.
4129fd2a6b71SDan Nowlin 	 */
4130fd2a6b71SDan Nowlin 	 /* check number of free result indices */
4131fd2a6b71SDan Nowlin 	bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS);
4132fd2a6b71SDan Nowlin 	free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm);
4133fd2a6b71SDan Nowlin 
4134fd2a6b71SDan Nowlin 	ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n",
4135fd2a6b71SDan Nowlin 		  free_res_idx, rm->n_grp_count);
4136fd2a6b71SDan Nowlin 
4137fd2a6b71SDan Nowlin 	if (rm->n_grp_count > 1) {
4138fd2a6b71SDan Nowlin 		if (rm->n_grp_count > free_res_idx)
4139d54699e2STony Nguyen 			return -ENOSPC;
4140fd2a6b71SDan Nowlin 
4141fd2a6b71SDan Nowlin 		rm->n_grp_count++;
4142fd2a6b71SDan Nowlin 	}
4143fd2a6b71SDan Nowlin 
4144fd2a6b71SDan Nowlin 	if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE)
4145d54699e2STony Nguyen 		return -ENOSPC;
4146fd2a6b71SDan Nowlin 
4147fd2a6b71SDan Nowlin 	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
4148fd2a6b71SDan Nowlin 	if (!tmp)
4149d54699e2STony Nguyen 		return -ENOMEM;
4150fd2a6b71SDan Nowlin 
4151fd2a6b71SDan Nowlin 	buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf),
4152fd2a6b71SDan Nowlin 			   GFP_KERNEL);
4153fd2a6b71SDan Nowlin 	if (!buf) {
4154d54699e2STony Nguyen 		status = -ENOMEM;
4155fd2a6b71SDan Nowlin 		goto err_mem;
4156fd2a6b71SDan Nowlin 	}
4157fd2a6b71SDan Nowlin 
4158fd2a6b71SDan Nowlin 	bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES);
4159fd2a6b71SDan Nowlin 	recipe_count = ICE_MAX_NUM_RECIPES;
4160fd2a6b71SDan Nowlin 	status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC,
4161fd2a6b71SDan Nowlin 				   NULL);
4162fd2a6b71SDan Nowlin 	if (status || recipe_count == 0)
4163fd2a6b71SDan Nowlin 		goto err_unroll;
4164fd2a6b71SDan Nowlin 
4165fd2a6b71SDan Nowlin 	/* Allocate the recipe resources, and configure them according to the
4166fd2a6b71SDan Nowlin 	 * match fields from protocol headers and extracted field vectors.
4167fd2a6b71SDan Nowlin 	 */
4168fd2a6b71SDan Nowlin 	chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS);
4169fd2a6b71SDan Nowlin 	list_for_each_entry(entry, &rm->rg_list, l_entry) {
4170fd2a6b71SDan Nowlin 		u8 i;
4171fd2a6b71SDan Nowlin 
4172fd2a6b71SDan Nowlin 		status = ice_alloc_recipe(hw, &entry->rid);
4173fd2a6b71SDan Nowlin 		if (status)
4174fd2a6b71SDan Nowlin 			goto err_unroll;
4175fd2a6b71SDan Nowlin 
4176fd2a6b71SDan Nowlin 		/* Clear the result index of the located recipe, as this will be
4177fd2a6b71SDan Nowlin 		 * updated, if needed, later in the recipe creation process.
4178fd2a6b71SDan Nowlin 		 */
4179fd2a6b71SDan Nowlin 		tmp[0].content.result_indx = 0;
4180fd2a6b71SDan Nowlin 
4181fd2a6b71SDan Nowlin 		buf[recps] = tmp[0];
4182fd2a6b71SDan Nowlin 		buf[recps].recipe_indx = (u8)entry->rid;
4183fd2a6b71SDan Nowlin 		/* if the recipe is a non-root recipe RID should be programmed
4184fd2a6b71SDan Nowlin 		 * as 0 for the rules to be applied correctly.
4185fd2a6b71SDan Nowlin 		 */
4186fd2a6b71SDan Nowlin 		buf[recps].content.rid = 0;
4187fd2a6b71SDan Nowlin 		memset(&buf[recps].content.lkup_indx, 0,
4188fd2a6b71SDan Nowlin 		       sizeof(buf[recps].content.lkup_indx));
4189fd2a6b71SDan Nowlin 
4190fd2a6b71SDan Nowlin 		/* All recipes use look-up index 0 to match switch ID. */
4191fd2a6b71SDan Nowlin 		buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
4192fd2a6b71SDan Nowlin 		buf[recps].content.mask[0] =
4193fd2a6b71SDan Nowlin 			cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
4194fd2a6b71SDan Nowlin 		/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
4195fd2a6b71SDan Nowlin 		 * to be 0
4196fd2a6b71SDan Nowlin 		 */
4197fd2a6b71SDan Nowlin 		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
4198fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] = 0x80;
4199fd2a6b71SDan Nowlin 			buf[recps].content.mask[i] = 0;
4200fd2a6b71SDan Nowlin 		}
4201fd2a6b71SDan Nowlin 
4202fd2a6b71SDan Nowlin 		for (i = 0; i < entry->r_group.n_val_pairs; i++) {
4203fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];
4204fd2a6b71SDan Nowlin 			buf[recps].content.mask[i + 1] =
4205fd2a6b71SDan Nowlin 				cpu_to_le16(entry->fv_mask[i]);
4206fd2a6b71SDan Nowlin 		}
4207fd2a6b71SDan Nowlin 
4208fd2a6b71SDan Nowlin 		if (rm->n_grp_count > 1) {
4209fd2a6b71SDan Nowlin 			/* Checks to see if there really is a valid result index
4210fd2a6b71SDan Nowlin 			 * that can be used.
4211fd2a6b71SDan Nowlin 			 */
4212fd2a6b71SDan Nowlin 			if (chain_idx >= ICE_MAX_FV_WORDS) {
4213fd2a6b71SDan Nowlin 				ice_debug(hw, ICE_DBG_SW, "No chain index available\n");
4214d54699e2STony Nguyen 				status = -ENOSPC;
4215fd2a6b71SDan Nowlin 				goto err_unroll;
4216fd2a6b71SDan Nowlin 			}
4217fd2a6b71SDan Nowlin 
4218fd2a6b71SDan Nowlin 			entry->chain_idx = chain_idx;
4219fd2a6b71SDan Nowlin 			buf[recps].content.result_indx =
4220fd2a6b71SDan Nowlin 				ICE_AQ_RECIPE_RESULT_EN |
4221fd2a6b71SDan Nowlin 				((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
4222fd2a6b71SDan Nowlin 				 ICE_AQ_RECIPE_RESULT_DATA_M);
4223fd2a6b71SDan Nowlin 			clear_bit(chain_idx, result_idx_bm);
4224fd2a6b71SDan Nowlin 			chain_idx = find_first_bit(result_idx_bm,
4225fd2a6b71SDan Nowlin 						   ICE_MAX_FV_WORDS);
4226fd2a6b71SDan Nowlin 		}
4227fd2a6b71SDan Nowlin 
4228fd2a6b71SDan Nowlin 		/* fill recipe dependencies */
4229fd2a6b71SDan Nowlin 		bitmap_zero((unsigned long *)buf[recps].recipe_bitmap,
4230fd2a6b71SDan Nowlin 			    ICE_MAX_NUM_RECIPES);
4231fd2a6b71SDan Nowlin 		set_bit(buf[recps].recipe_indx,
4232fd2a6b71SDan Nowlin 			(unsigned long *)buf[recps].recipe_bitmap);
4233fd2a6b71SDan Nowlin 		buf[recps].content.act_ctrl_fwd_priority = rm->priority;
4234fd2a6b71SDan Nowlin 		recps++;
4235fd2a6b71SDan Nowlin 	}
4236fd2a6b71SDan Nowlin 
4237fd2a6b71SDan Nowlin 	if (rm->n_grp_count == 1) {
4238fd2a6b71SDan Nowlin 		rm->root_rid = buf[0].recipe_indx;
4239fd2a6b71SDan Nowlin 		set_bit(buf[0].recipe_indx, rm->r_bitmap);
4240fd2a6b71SDan Nowlin 		buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT;
4241fd2a6b71SDan Nowlin 		if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) {
4242fd2a6b71SDan Nowlin 			memcpy(buf[0].recipe_bitmap, rm->r_bitmap,
4243fd2a6b71SDan Nowlin 			       sizeof(buf[0].recipe_bitmap));
4244fd2a6b71SDan Nowlin 		} else {
4245d54699e2STony Nguyen 			status = -EINVAL;
4246fd2a6b71SDan Nowlin 			goto err_unroll;
4247fd2a6b71SDan Nowlin 		}
4248fd2a6b71SDan Nowlin 		/* Applicable only for ROOT_RECIPE, set the fwd_priority for
4249fd2a6b71SDan Nowlin 		 * the recipe which is getting created if specified
4250fd2a6b71SDan Nowlin 		 * by user. Usually any advanced switch filter, which results
4251fd2a6b71SDan Nowlin 		 * into new extraction sequence, ended up creating a new recipe
4252fd2a6b71SDan Nowlin 		 * of type ROOT and usually recipes are associated with profiles
4253fd2a6b71SDan Nowlin 		 * Switch rule referreing newly created recipe, needs to have
4254fd2a6b71SDan Nowlin 		 * either/or 'fwd' or 'join' priority, otherwise switch rule
4255fd2a6b71SDan Nowlin 		 * evaluation will not happen correctly. In other words, if
4256fd2a6b71SDan Nowlin 		 * switch rule to be evaluated on priority basis, then recipe
4257fd2a6b71SDan Nowlin 		 * needs to have priority, otherwise it will be evaluated last.
4258fd2a6b71SDan Nowlin 		 */
4259fd2a6b71SDan Nowlin 		buf[0].content.act_ctrl_fwd_priority = rm->priority;
4260fd2a6b71SDan Nowlin 	} else {
4261fd2a6b71SDan Nowlin 		struct ice_recp_grp_entry *last_chain_entry;
4262fd2a6b71SDan Nowlin 		u16 rid, i;
4263fd2a6b71SDan Nowlin 
4264fd2a6b71SDan Nowlin 		/* Allocate the last recipe that will chain the outcomes of the
4265fd2a6b71SDan Nowlin 		 * other recipes together
4266fd2a6b71SDan Nowlin 		 */
4267fd2a6b71SDan Nowlin 		status = ice_alloc_recipe(hw, &rid);
4268fd2a6b71SDan Nowlin 		if (status)
4269fd2a6b71SDan Nowlin 			goto err_unroll;
4270fd2a6b71SDan Nowlin 
4271fd2a6b71SDan Nowlin 		buf[recps].recipe_indx = (u8)rid;
4272fd2a6b71SDan Nowlin 		buf[recps].content.rid = (u8)rid;
4273fd2a6b71SDan Nowlin 		buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
4274fd2a6b71SDan Nowlin 		/* the new entry created should also be part of rg_list to
4275fd2a6b71SDan Nowlin 		 * make sure we have complete recipe
4276fd2a6b71SDan Nowlin 		 */
4277fd2a6b71SDan Nowlin 		last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw),
4278fd2a6b71SDan Nowlin 						sizeof(*last_chain_entry),
4279fd2a6b71SDan Nowlin 						GFP_KERNEL);
4280fd2a6b71SDan Nowlin 		if (!last_chain_entry) {
4281d54699e2STony Nguyen 			status = -ENOMEM;
4282fd2a6b71SDan Nowlin 			goto err_unroll;
4283fd2a6b71SDan Nowlin 		}
4284fd2a6b71SDan Nowlin 		last_chain_entry->rid = rid;
4285fd2a6b71SDan Nowlin 		memset(&buf[recps].content.lkup_indx, 0,
4286fd2a6b71SDan Nowlin 		       sizeof(buf[recps].content.lkup_indx));
4287fd2a6b71SDan Nowlin 		/* All recipes use look-up index 0 to match switch ID. */
4288fd2a6b71SDan Nowlin 		buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
4289fd2a6b71SDan Nowlin 		buf[recps].content.mask[0] =
4290fd2a6b71SDan Nowlin 			cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
4291fd2a6b71SDan Nowlin 		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
4292fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] =
4293fd2a6b71SDan Nowlin 				ICE_AQ_RECIPE_LKUP_IGNORE;
4294fd2a6b71SDan Nowlin 			buf[recps].content.mask[i] = 0;
4295fd2a6b71SDan Nowlin 		}
4296fd2a6b71SDan Nowlin 
4297fd2a6b71SDan Nowlin 		i = 1;
4298fd2a6b71SDan Nowlin 		/* update r_bitmap with the recp that is used for chaining */
4299fd2a6b71SDan Nowlin 		set_bit(rid, rm->r_bitmap);
4300fd2a6b71SDan Nowlin 		/* this is the recipe that chains all the other recipes so it
4301fd2a6b71SDan Nowlin 		 * should not have a chaining ID to indicate the same
4302fd2a6b71SDan Nowlin 		 */
4303fd2a6b71SDan Nowlin 		last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
4304fd2a6b71SDan Nowlin 		list_for_each_entry(entry, &rm->rg_list, l_entry) {
4305fd2a6b71SDan Nowlin 			last_chain_entry->fv_idx[i] = entry->chain_idx;
4306fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] = entry->chain_idx;
4307fd2a6b71SDan Nowlin 			buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF);
4308fd2a6b71SDan Nowlin 			set_bit(entry->rid, rm->r_bitmap);
4309fd2a6b71SDan Nowlin 		}
4310fd2a6b71SDan Nowlin 		list_add(&last_chain_entry->l_entry, &rm->rg_list);
4311fd2a6b71SDan Nowlin 		if (sizeof(buf[recps].recipe_bitmap) >=
4312fd2a6b71SDan Nowlin 		    sizeof(rm->r_bitmap)) {
4313fd2a6b71SDan Nowlin 			memcpy(buf[recps].recipe_bitmap, rm->r_bitmap,
4314fd2a6b71SDan Nowlin 			       sizeof(buf[recps].recipe_bitmap));
4315fd2a6b71SDan Nowlin 		} else {
4316d54699e2STony Nguyen 			status = -EINVAL;
4317fd2a6b71SDan Nowlin 			goto err_unroll;
4318fd2a6b71SDan Nowlin 		}
4319fd2a6b71SDan Nowlin 		buf[recps].content.act_ctrl_fwd_priority = rm->priority;
4320fd2a6b71SDan Nowlin 
4321fd2a6b71SDan Nowlin 		recps++;
4322fd2a6b71SDan Nowlin 		rm->root_rid = (u8)rid;
4323fd2a6b71SDan Nowlin 	}
4324fd2a6b71SDan Nowlin 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
4325fd2a6b71SDan Nowlin 	if (status)
4326fd2a6b71SDan Nowlin 		goto err_unroll;
4327fd2a6b71SDan Nowlin 
4328fd2a6b71SDan Nowlin 	status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL);
4329fd2a6b71SDan Nowlin 	ice_release_change_lock(hw);
4330fd2a6b71SDan Nowlin 	if (status)
4331fd2a6b71SDan Nowlin 		goto err_unroll;
4332fd2a6b71SDan Nowlin 
4333fd2a6b71SDan Nowlin 	/* Every recipe that just got created add it to the recipe
4334fd2a6b71SDan Nowlin 	 * book keeping list
4335fd2a6b71SDan Nowlin 	 */
4336fd2a6b71SDan Nowlin 	list_for_each_entry(entry, &rm->rg_list, l_entry) {
4337fd2a6b71SDan Nowlin 		struct ice_switch_info *sw = hw->switch_info;
4338fd2a6b71SDan Nowlin 		bool is_root, idx_found = false;
4339fd2a6b71SDan Nowlin 		struct ice_sw_recipe *recp;
4340fd2a6b71SDan Nowlin 		u16 idx, buf_idx = 0;
4341fd2a6b71SDan Nowlin 
4342fd2a6b71SDan Nowlin 		/* find buffer index for copying some data */
4343fd2a6b71SDan Nowlin 		for (idx = 0; idx < rm->n_grp_count; idx++)
4344fd2a6b71SDan Nowlin 			if (buf[idx].recipe_indx == entry->rid) {
4345fd2a6b71SDan Nowlin 				buf_idx = idx;
4346fd2a6b71SDan Nowlin 				idx_found = true;
4347fd2a6b71SDan Nowlin 			}
4348fd2a6b71SDan Nowlin 
4349fd2a6b71SDan Nowlin 		if (!idx_found) {
4350d54699e2STony Nguyen 			status = -EIO;
4351fd2a6b71SDan Nowlin 			goto err_unroll;
4352fd2a6b71SDan Nowlin 		}
4353fd2a6b71SDan Nowlin 
4354fd2a6b71SDan Nowlin 		recp = &sw->recp_list[entry->rid];
4355fd2a6b71SDan Nowlin 		is_root = (rm->root_rid == entry->rid);
4356fd2a6b71SDan Nowlin 		recp->is_root = is_root;
4357fd2a6b71SDan Nowlin 
4358fd2a6b71SDan Nowlin 		recp->root_rid = entry->rid;
4359fd2a6b71SDan Nowlin 		recp->big_recp = (is_root && rm->n_grp_count > 1);
4360fd2a6b71SDan Nowlin 
4361fd2a6b71SDan Nowlin 		memcpy(&recp->ext_words, entry->r_group.pairs,
4362fd2a6b71SDan Nowlin 		       entry->r_group.n_val_pairs * sizeof(struct ice_fv_word));
4363fd2a6b71SDan Nowlin 
4364fd2a6b71SDan Nowlin 		memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap,
4365fd2a6b71SDan Nowlin 		       sizeof(recp->r_bitmap));
4366fd2a6b71SDan Nowlin 
4367fd2a6b71SDan Nowlin 		/* Copy non-result fv index values and masks to recipe. This
4368fd2a6b71SDan Nowlin 		 * call will also update the result recipe bitmask.
4369fd2a6b71SDan Nowlin 		 */
4370fd2a6b71SDan Nowlin 		ice_collect_result_idx(&buf[buf_idx], recp);
4371fd2a6b71SDan Nowlin 
4372fd2a6b71SDan Nowlin 		/* for non-root recipes, also copy to the root, this allows
4373fd2a6b71SDan Nowlin 		 * easier matching of a complete chained recipe
4374fd2a6b71SDan Nowlin 		 */
4375fd2a6b71SDan Nowlin 		if (!is_root)
4376fd2a6b71SDan Nowlin 			ice_collect_result_idx(&buf[buf_idx],
4377fd2a6b71SDan Nowlin 					       &sw->recp_list[rm->root_rid]);
4378fd2a6b71SDan Nowlin 
4379fd2a6b71SDan Nowlin 		recp->n_ext_words = entry->r_group.n_val_pairs;
4380fd2a6b71SDan Nowlin 		recp->chain_idx = entry->chain_idx;
4381fd2a6b71SDan Nowlin 		recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
4382fd2a6b71SDan Nowlin 		recp->n_grp_count = rm->n_grp_count;
43838b032a55SMichal Swiatkowski 		recp->tun_type = rm->tun_type;
4384fd2a6b71SDan Nowlin 		recp->recp_created = true;
4385fd2a6b71SDan Nowlin 	}
4386fd2a6b71SDan Nowlin 	rm->root_buf = buf;
4387fd2a6b71SDan Nowlin 	kfree(tmp);
4388fd2a6b71SDan Nowlin 	return status;
4389fd2a6b71SDan Nowlin 
4390fd2a6b71SDan Nowlin err_unroll:
4391fd2a6b71SDan Nowlin err_mem:
4392fd2a6b71SDan Nowlin 	kfree(tmp);
4393fd2a6b71SDan Nowlin 	devm_kfree(ice_hw_to_dev(hw), buf);
4394fd2a6b71SDan Nowlin 	return status;
4395fd2a6b71SDan Nowlin }
4396fd2a6b71SDan Nowlin 
4397fd2a6b71SDan Nowlin /**
4398fd2a6b71SDan Nowlin  * ice_create_recipe_group - creates recipe group
4399fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4400fd2a6b71SDan Nowlin  * @rm: recipe management list entry
4401fd2a6b71SDan Nowlin  * @lkup_exts: lookup elements
4402fd2a6b71SDan Nowlin  */
44035e24d598STony Nguyen static int
4404fd2a6b71SDan Nowlin ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm,
4405fd2a6b71SDan Nowlin 			struct ice_prot_lkup_ext *lkup_exts)
4406fd2a6b71SDan Nowlin {
4407fd2a6b71SDan Nowlin 	u8 recp_count = 0;
44085518ac2aSTony Nguyen 	int status;
4409fd2a6b71SDan Nowlin 
4410fd2a6b71SDan Nowlin 	rm->n_grp_count = 0;
4411fd2a6b71SDan Nowlin 
4412fd2a6b71SDan Nowlin 	/* Create recipes for words that are marked not done by packing them
4413fd2a6b71SDan Nowlin 	 * as best fit.
4414fd2a6b71SDan Nowlin 	 */
4415fd2a6b71SDan Nowlin 	status = ice_create_first_fit_recp_def(hw, lkup_exts,
4416fd2a6b71SDan Nowlin 					       &rm->rg_list, &recp_count);
4417fd2a6b71SDan Nowlin 	if (!status) {
4418fd2a6b71SDan Nowlin 		rm->n_grp_count += recp_count;
4419fd2a6b71SDan Nowlin 		rm->n_ext_words = lkup_exts->n_val_words;
4420fd2a6b71SDan Nowlin 		memcpy(&rm->ext_words, lkup_exts->fv_words,
4421fd2a6b71SDan Nowlin 		       sizeof(rm->ext_words));
4422fd2a6b71SDan Nowlin 		memcpy(rm->word_masks, lkup_exts->field_mask,
4423fd2a6b71SDan Nowlin 		       sizeof(rm->word_masks));
4424fd2a6b71SDan Nowlin 	}
4425fd2a6b71SDan Nowlin 
4426fd2a6b71SDan Nowlin 	return status;
4427fd2a6b71SDan Nowlin }
4428fd2a6b71SDan Nowlin 
4429fd2a6b71SDan Nowlin /**
4430fd2a6b71SDan Nowlin  * ice_get_fv - get field vectors/extraction sequences for spec. lookup types
4431fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4432fd2a6b71SDan Nowlin  * @lkups: lookup elements or match criteria for the advanced recipe, one
4433fd2a6b71SDan Nowlin  *	   structure per protocol header
4434fd2a6b71SDan Nowlin  * @lkups_cnt: number of protocols
4435fd2a6b71SDan Nowlin  * @bm: bitmap of field vectors to consider
4436fd2a6b71SDan Nowlin  * @fv_list: pointer to a list that holds the returned field vectors
4437fd2a6b71SDan Nowlin  */
44385e24d598STony Nguyen static int
4439fd2a6b71SDan Nowlin ice_get_fv(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
4440fd2a6b71SDan Nowlin 	   unsigned long *bm, struct list_head *fv_list)
4441fd2a6b71SDan Nowlin {
4442fd2a6b71SDan Nowlin 	u8 *prot_ids;
44435518ac2aSTony Nguyen 	int status;
4444fd2a6b71SDan Nowlin 	u16 i;
4445fd2a6b71SDan Nowlin 
4446fd2a6b71SDan Nowlin 	prot_ids = kcalloc(lkups_cnt, sizeof(*prot_ids), GFP_KERNEL);
4447fd2a6b71SDan Nowlin 	if (!prot_ids)
4448d54699e2STony Nguyen 		return -ENOMEM;
4449fd2a6b71SDan Nowlin 
4450fd2a6b71SDan Nowlin 	for (i = 0; i < lkups_cnt; i++)
4451fd2a6b71SDan Nowlin 		if (!ice_prot_type_to_id(lkups[i].type, &prot_ids[i])) {
4452d54699e2STony Nguyen 			status = -EIO;
4453fd2a6b71SDan Nowlin 			goto free_mem;
4454fd2a6b71SDan Nowlin 		}
4455fd2a6b71SDan Nowlin 
4456fd2a6b71SDan Nowlin 	/* Find field vectors that include all specified protocol types */
4457fd2a6b71SDan Nowlin 	status = ice_get_sw_fv_list(hw, prot_ids, lkups_cnt, bm, fv_list);
4458fd2a6b71SDan Nowlin 
4459fd2a6b71SDan Nowlin free_mem:
4460fd2a6b71SDan Nowlin 	kfree(prot_ids);
4461fd2a6b71SDan Nowlin 	return status;
4462fd2a6b71SDan Nowlin }
4463fd2a6b71SDan Nowlin 
44648b032a55SMichal Swiatkowski /**
44658b032a55SMichal Swiatkowski  * ice_tun_type_match_word - determine if tun type needs a match mask
44668b032a55SMichal Swiatkowski  * @tun_type: tunnel type
44678b032a55SMichal Swiatkowski  * @mask: mask to be used for the tunnel
44688b032a55SMichal Swiatkowski  */
44698b032a55SMichal Swiatkowski static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask)
44708b032a55SMichal Swiatkowski {
44718b032a55SMichal Swiatkowski 	switch (tun_type) {
44728b032a55SMichal Swiatkowski 	case ICE_SW_TUN_GENEVE:
44738b032a55SMichal Swiatkowski 	case ICE_SW_TUN_VXLAN:
4474f0a35040SMichal Swiatkowski 	case ICE_SW_TUN_NVGRE:
44758b032a55SMichal Swiatkowski 		*mask = ICE_TUN_FLAG_MASK;
44768b032a55SMichal Swiatkowski 		return true;
44778b032a55SMichal Swiatkowski 
44788b032a55SMichal Swiatkowski 	default:
44798b032a55SMichal Swiatkowski 		*mask = 0;
44808b032a55SMichal Swiatkowski 		return false;
44818b032a55SMichal Swiatkowski 	}
44828b032a55SMichal Swiatkowski }
44838b032a55SMichal Swiatkowski 
44848b032a55SMichal Swiatkowski /**
44858b032a55SMichal Swiatkowski  * ice_add_special_words - Add words that are not protocols, such as metadata
44868b032a55SMichal Swiatkowski  * @rinfo: other information regarding the rule e.g. priority and action info
44878b032a55SMichal Swiatkowski  * @lkup_exts: lookup word structure
44888b032a55SMichal Swiatkowski  */
4489d54699e2STony Nguyen static int
44908b032a55SMichal Swiatkowski ice_add_special_words(struct ice_adv_rule_info *rinfo,
44918b032a55SMichal Swiatkowski 		      struct ice_prot_lkup_ext *lkup_exts)
44928b032a55SMichal Swiatkowski {
44938b032a55SMichal Swiatkowski 	u16 mask;
44948b032a55SMichal Swiatkowski 
44958b032a55SMichal Swiatkowski 	/* If this is a tunneled packet, then add recipe index to match the
44968b032a55SMichal Swiatkowski 	 * tunnel bit in the packet metadata flags.
44978b032a55SMichal Swiatkowski 	 */
44988b032a55SMichal Swiatkowski 	if (ice_tun_type_match_word(rinfo->tun_type, &mask)) {
44998b032a55SMichal Swiatkowski 		if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) {
45008b032a55SMichal Swiatkowski 			u8 word = lkup_exts->n_val_words++;
45018b032a55SMichal Swiatkowski 
45028b032a55SMichal Swiatkowski 			lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW;
45038b032a55SMichal Swiatkowski 			lkup_exts->fv_words[word].off = ICE_TUN_FLAG_MDID_OFF;
45048b032a55SMichal Swiatkowski 			lkup_exts->field_mask[word] = mask;
45058b032a55SMichal Swiatkowski 		} else {
4506d54699e2STony Nguyen 			return -ENOSPC;
45078b032a55SMichal Swiatkowski 		}
45088b032a55SMichal Swiatkowski 	}
45098b032a55SMichal Swiatkowski 
45108b032a55SMichal Swiatkowski 	return 0;
45118b032a55SMichal Swiatkowski }
45128b032a55SMichal Swiatkowski 
4513fd2a6b71SDan Nowlin /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule
4514fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4515fd2a6b71SDan Nowlin  * @rinfo: other information regarding the rule e.g. priority and action info
4516fd2a6b71SDan Nowlin  * @bm: pointer to memory for returning the bitmap of field vectors
4517fd2a6b71SDan Nowlin  */
4518fd2a6b71SDan Nowlin static void
4519fd2a6b71SDan Nowlin ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
4520fd2a6b71SDan Nowlin 			 unsigned long *bm)
4521fd2a6b71SDan Nowlin {
45228b032a55SMichal Swiatkowski 	enum ice_prof_type prof_type;
45238b032a55SMichal Swiatkowski 
4524fd2a6b71SDan Nowlin 	bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
4525fd2a6b71SDan Nowlin 
45268b032a55SMichal Swiatkowski 	switch (rinfo->tun_type) {
45278b032a55SMichal Swiatkowski 	case ICE_NON_TUN:
45288b032a55SMichal Swiatkowski 		prof_type = ICE_PROF_NON_TUN;
45298b032a55SMichal Swiatkowski 		break;
45308b032a55SMichal Swiatkowski 	case ICE_ALL_TUNNELS:
45318b032a55SMichal Swiatkowski 		prof_type = ICE_PROF_TUN_ALL;
45328b032a55SMichal Swiatkowski 		break;
45338b032a55SMichal Swiatkowski 	case ICE_SW_TUN_GENEVE:
45348b032a55SMichal Swiatkowski 	case ICE_SW_TUN_VXLAN:
45358b032a55SMichal Swiatkowski 		prof_type = ICE_PROF_TUN_UDP;
45368b032a55SMichal Swiatkowski 		break;
4537f0a35040SMichal Swiatkowski 	case ICE_SW_TUN_NVGRE:
4538f0a35040SMichal Swiatkowski 		prof_type = ICE_PROF_TUN_GRE;
4539f0a35040SMichal Swiatkowski 		break;
4540*b70bc066SWojciech Drewek 	case ICE_SW_TUN_AND_NON_TUN:
45418b032a55SMichal Swiatkowski 	default:
45428b032a55SMichal Swiatkowski 		prof_type = ICE_PROF_ALL;
45438b032a55SMichal Swiatkowski 		break;
45448b032a55SMichal Swiatkowski 	}
45458b032a55SMichal Swiatkowski 
45468b032a55SMichal Swiatkowski 	ice_get_sw_fv_bitmap(hw, prof_type, bm);
4547fd2a6b71SDan Nowlin }
4548fd2a6b71SDan Nowlin 
4549fd2a6b71SDan Nowlin /**
4550fd2a6b71SDan Nowlin  * ice_add_adv_recipe - Add an advanced recipe that is not part of the default
4551fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4552fd2a6b71SDan Nowlin  * @lkups: lookup elements or match criteria for the advanced recipe, one
4553fd2a6b71SDan Nowlin  *  structure per protocol header
4554fd2a6b71SDan Nowlin  * @lkups_cnt: number of protocols
4555fd2a6b71SDan Nowlin  * @rinfo: other information regarding the rule e.g. priority and action info
4556fd2a6b71SDan Nowlin  * @rid: return the recipe ID of the recipe created
4557fd2a6b71SDan Nowlin  */
45585e24d598STony Nguyen static int
4559fd2a6b71SDan Nowlin ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
4560fd2a6b71SDan Nowlin 		   u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid)
4561fd2a6b71SDan Nowlin {
4562fd2a6b71SDan Nowlin 	DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES);
4563fd2a6b71SDan Nowlin 	DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES);
4564fd2a6b71SDan Nowlin 	struct ice_prot_lkup_ext *lkup_exts;
4565fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *r_entry;
4566fd2a6b71SDan Nowlin 	struct ice_sw_fv_list_entry *fvit;
4567fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *r_tmp;
4568fd2a6b71SDan Nowlin 	struct ice_sw_fv_list_entry *tmp;
4569fd2a6b71SDan Nowlin 	struct ice_sw_recipe *rm;
45705518ac2aSTony Nguyen 	int status = 0;
4571fd2a6b71SDan Nowlin 	u8 i;
4572fd2a6b71SDan Nowlin 
4573fd2a6b71SDan Nowlin 	if (!lkups_cnt)
4574d54699e2STony Nguyen 		return -EINVAL;
4575fd2a6b71SDan Nowlin 
4576fd2a6b71SDan Nowlin 	lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL);
4577fd2a6b71SDan Nowlin 	if (!lkup_exts)
4578d54699e2STony Nguyen 		return -ENOMEM;
4579fd2a6b71SDan Nowlin 
4580fd2a6b71SDan Nowlin 	/* Determine the number of words to be matched and if it exceeds a
4581fd2a6b71SDan Nowlin 	 * recipe's restrictions
4582fd2a6b71SDan Nowlin 	 */
4583fd2a6b71SDan Nowlin 	for (i = 0; i < lkups_cnt; i++) {
4584fd2a6b71SDan Nowlin 		u16 count;
4585fd2a6b71SDan Nowlin 
4586fd2a6b71SDan Nowlin 		if (lkups[i].type >= ICE_PROTOCOL_LAST) {
4587d54699e2STony Nguyen 			status = -EIO;
4588fd2a6b71SDan Nowlin 			goto err_free_lkup_exts;
4589fd2a6b71SDan Nowlin 		}
4590fd2a6b71SDan Nowlin 
4591fd2a6b71SDan Nowlin 		count = ice_fill_valid_words(&lkups[i], lkup_exts);
4592fd2a6b71SDan Nowlin 		if (!count) {
4593d54699e2STony Nguyen 			status = -EIO;
4594fd2a6b71SDan Nowlin 			goto err_free_lkup_exts;
4595fd2a6b71SDan Nowlin 		}
4596fd2a6b71SDan Nowlin 	}
4597fd2a6b71SDan Nowlin 
4598fd2a6b71SDan Nowlin 	rm = kzalloc(sizeof(*rm), GFP_KERNEL);
4599fd2a6b71SDan Nowlin 	if (!rm) {
4600d54699e2STony Nguyen 		status = -ENOMEM;
4601fd2a6b71SDan Nowlin 		goto err_free_lkup_exts;
4602fd2a6b71SDan Nowlin 	}
4603fd2a6b71SDan Nowlin 
4604fd2a6b71SDan Nowlin 	/* Get field vectors that contain fields extracted from all the protocol
4605fd2a6b71SDan Nowlin 	 * headers being programmed.
4606fd2a6b71SDan Nowlin 	 */
4607fd2a6b71SDan Nowlin 	INIT_LIST_HEAD(&rm->fv_list);
4608fd2a6b71SDan Nowlin 	INIT_LIST_HEAD(&rm->rg_list);
4609fd2a6b71SDan Nowlin 
4610fd2a6b71SDan Nowlin 	/* Get bitmap of field vectors (profiles) that are compatible with the
4611fd2a6b71SDan Nowlin 	 * rule request; only these will be searched in the subsequent call to
4612fd2a6b71SDan Nowlin 	 * ice_get_fv.
4613fd2a6b71SDan Nowlin 	 */
4614fd2a6b71SDan Nowlin 	ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap);
4615fd2a6b71SDan Nowlin 
4616fd2a6b71SDan Nowlin 	status = ice_get_fv(hw, lkups, lkups_cnt, fv_bitmap, &rm->fv_list);
4617fd2a6b71SDan Nowlin 	if (status)
4618fd2a6b71SDan Nowlin 		goto err_unroll;
4619fd2a6b71SDan Nowlin 
46208b032a55SMichal Swiatkowski 	/* Create any special protocol/offset pairs, such as looking at tunnel
46218b032a55SMichal Swiatkowski 	 * bits by extracting metadata
46228b032a55SMichal Swiatkowski 	 */
46238b032a55SMichal Swiatkowski 	status = ice_add_special_words(rinfo, lkup_exts);
46248b032a55SMichal Swiatkowski 	if (status)
46258b032a55SMichal Swiatkowski 		goto err_free_lkup_exts;
46268b032a55SMichal Swiatkowski 
4627fd2a6b71SDan Nowlin 	/* Group match words into recipes using preferred recipe grouping
4628fd2a6b71SDan Nowlin 	 * criteria.
4629fd2a6b71SDan Nowlin 	 */
4630fd2a6b71SDan Nowlin 	status = ice_create_recipe_group(hw, rm, lkup_exts);
4631fd2a6b71SDan Nowlin 	if (status)
4632fd2a6b71SDan Nowlin 		goto err_unroll;
4633fd2a6b71SDan Nowlin 
4634fd2a6b71SDan Nowlin 	/* set the recipe priority if specified */
4635fd2a6b71SDan Nowlin 	rm->priority = (u8)rinfo->priority;
4636fd2a6b71SDan Nowlin 
4637fd2a6b71SDan Nowlin 	/* Find offsets from the field vector. Pick the first one for all the
4638fd2a6b71SDan Nowlin 	 * recipes.
4639fd2a6b71SDan Nowlin 	 */
4640fd2a6b71SDan Nowlin 	status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list);
4641fd2a6b71SDan Nowlin 	if (status)
4642fd2a6b71SDan Nowlin 		goto err_unroll;
4643fd2a6b71SDan Nowlin 
4644fd2a6b71SDan Nowlin 	/* get bitmap of all profiles the recipe will be associated with */
4645fd2a6b71SDan Nowlin 	bitmap_zero(profiles, ICE_MAX_NUM_PROFILES);
4646fd2a6b71SDan Nowlin 	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
4647fd2a6b71SDan Nowlin 		ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id);
4648fd2a6b71SDan Nowlin 		set_bit((u16)fvit->profile_id, profiles);
4649fd2a6b71SDan Nowlin 	}
4650fd2a6b71SDan Nowlin 
4651fd2a6b71SDan Nowlin 	/* Look for a recipe which matches our requested fv / mask list */
4652de6acd1cSMichal Swiatkowski 	*rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type);
4653fd2a6b71SDan Nowlin 	if (*rid < ICE_MAX_NUM_RECIPES)
4654fd2a6b71SDan Nowlin 		/* Success if found a recipe that match the existing criteria */
4655fd2a6b71SDan Nowlin 		goto err_unroll;
4656fd2a6b71SDan Nowlin 
4657de6acd1cSMichal Swiatkowski 	rm->tun_type = rinfo->tun_type;
4658fd2a6b71SDan Nowlin 	/* Recipe we need does not exist, add a recipe */
46598b032a55SMichal Swiatkowski 	status = ice_add_sw_recipe(hw, rm, profiles);
4660fd2a6b71SDan Nowlin 	if (status)
4661fd2a6b71SDan Nowlin 		goto err_unroll;
4662fd2a6b71SDan Nowlin 
4663fd2a6b71SDan Nowlin 	/* Associate all the recipes created with all the profiles in the
4664fd2a6b71SDan Nowlin 	 * common field vector.
4665fd2a6b71SDan Nowlin 	 */
4666fd2a6b71SDan Nowlin 	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
4667fd2a6b71SDan Nowlin 		DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
4668fd2a6b71SDan Nowlin 		u16 j;
4669fd2a6b71SDan Nowlin 
4670fd2a6b71SDan Nowlin 		status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id,
4671fd2a6b71SDan Nowlin 						      (u8 *)r_bitmap, NULL);
4672fd2a6b71SDan Nowlin 		if (status)
4673fd2a6b71SDan Nowlin 			goto err_unroll;
4674fd2a6b71SDan Nowlin 
4675fd2a6b71SDan Nowlin 		bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap,
4676fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_RECIPES);
4677fd2a6b71SDan Nowlin 		status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
4678fd2a6b71SDan Nowlin 		if (status)
4679fd2a6b71SDan Nowlin 			goto err_unroll;
4680fd2a6b71SDan Nowlin 
4681fd2a6b71SDan Nowlin 		status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,
4682fd2a6b71SDan Nowlin 						      (u8 *)r_bitmap,
4683fd2a6b71SDan Nowlin 						      NULL);
4684fd2a6b71SDan Nowlin 		ice_release_change_lock(hw);
4685fd2a6b71SDan Nowlin 
4686fd2a6b71SDan Nowlin 		if (status)
4687fd2a6b71SDan Nowlin 			goto err_unroll;
4688fd2a6b71SDan Nowlin 
4689fd2a6b71SDan Nowlin 		/* Update profile to recipe bitmap array */
4690fd2a6b71SDan Nowlin 		bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap,
4691fd2a6b71SDan Nowlin 			    ICE_MAX_NUM_RECIPES);
4692fd2a6b71SDan Nowlin 
4693fd2a6b71SDan Nowlin 		/* Update recipe to profile bitmap array */
4694fd2a6b71SDan Nowlin 		for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES)
4695fd2a6b71SDan Nowlin 			set_bit((u16)fvit->profile_id, recipe_to_profile[j]);
4696fd2a6b71SDan Nowlin 	}
4697fd2a6b71SDan Nowlin 
4698fd2a6b71SDan Nowlin 	*rid = rm->root_rid;
4699fd2a6b71SDan Nowlin 	memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts,
4700fd2a6b71SDan Nowlin 	       sizeof(*lkup_exts));
4701fd2a6b71SDan Nowlin err_unroll:
4702fd2a6b71SDan Nowlin 	list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) {
4703fd2a6b71SDan Nowlin 		list_del(&r_entry->l_entry);
4704fd2a6b71SDan Nowlin 		devm_kfree(ice_hw_to_dev(hw), r_entry);
4705fd2a6b71SDan Nowlin 	}
4706fd2a6b71SDan Nowlin 
4707fd2a6b71SDan Nowlin 	list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) {
4708fd2a6b71SDan Nowlin 		list_del(&fvit->list_entry);
4709fd2a6b71SDan Nowlin 		devm_kfree(ice_hw_to_dev(hw), fvit);
4710fd2a6b71SDan Nowlin 	}
4711fd2a6b71SDan Nowlin 
4712fd2a6b71SDan Nowlin 	if (rm->root_buf)
4713fd2a6b71SDan Nowlin 		devm_kfree(ice_hw_to_dev(hw), rm->root_buf);
4714fd2a6b71SDan Nowlin 
4715fd2a6b71SDan Nowlin 	kfree(rm);
4716fd2a6b71SDan Nowlin 
4717fd2a6b71SDan Nowlin err_free_lkup_exts:
4718fd2a6b71SDan Nowlin 	kfree(lkup_exts);
4719fd2a6b71SDan Nowlin 
4720fd2a6b71SDan Nowlin 	return status;
4721fd2a6b71SDan Nowlin }
4722fd2a6b71SDan Nowlin 
4723148beb61SHenry Tieman /**
47240f94570dSGrishma Kotecha  * ice_find_dummy_packet - find dummy packet
47250f94570dSGrishma Kotecha  *
47260f94570dSGrishma Kotecha  * @lkups: lookup elements or match criteria for the advanced recipe, one
47270f94570dSGrishma Kotecha  *	   structure per protocol header
47280f94570dSGrishma Kotecha  * @lkups_cnt: number of protocols
47298b032a55SMichal Swiatkowski  * @tun_type: tunnel type
47300f94570dSGrishma Kotecha  * @pkt: dummy packet to fill according to filter match criteria
47310f94570dSGrishma Kotecha  * @pkt_len: packet length of dummy packet
47320f94570dSGrishma Kotecha  * @offsets: pointer to receive the pointer to the offsets for the packet
47330f94570dSGrishma Kotecha  */
47340f94570dSGrishma Kotecha static void
47350f94570dSGrishma Kotecha ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
47368b032a55SMichal Swiatkowski 		      enum ice_sw_tunnel_type tun_type,
47370f94570dSGrishma Kotecha 		      const u8 **pkt, u16 *pkt_len,
47380f94570dSGrishma Kotecha 		      const struct ice_dummy_pkt_offsets **offsets)
47390f94570dSGrishma Kotecha {
47400f94570dSGrishma Kotecha 	bool tcp = false, udp = false, ipv6 = false, vlan = false;
47410f94570dSGrishma Kotecha 	u16 i;
47420f94570dSGrishma Kotecha 
47430f94570dSGrishma Kotecha 	for (i = 0; i < lkups_cnt; i++) {
47440f94570dSGrishma Kotecha 		if (lkups[i].type == ICE_UDP_ILOS)
47450f94570dSGrishma Kotecha 			udp = true;
47460f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_TCP_IL)
47470f94570dSGrishma Kotecha 			tcp = true;
47480f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_IPV6_OFOS)
47490f94570dSGrishma Kotecha 			ipv6 = true;
47500f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_VLAN_OFOS)
47510f94570dSGrishma Kotecha 			vlan = true;
47520f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_ETYPE_OL &&
47530f94570dSGrishma Kotecha 			 lkups[i].h_u.ethertype.ethtype_id ==
47540f94570dSGrishma Kotecha 				cpu_to_be16(ICE_IPV6_ETHER_ID) &&
47550f94570dSGrishma Kotecha 			 lkups[i].m_u.ethertype.ethtype_id ==
47560f94570dSGrishma Kotecha 					cpu_to_be16(0xFFFF))
47570f94570dSGrishma Kotecha 			ipv6 = true;
47580f94570dSGrishma Kotecha 	}
47590f94570dSGrishma Kotecha 
4760f0a35040SMichal Swiatkowski 	if (tun_type == ICE_SW_TUN_NVGRE) {
4761f0a35040SMichal Swiatkowski 		if (tcp) {
4762f0a35040SMichal Swiatkowski 			*pkt = dummy_gre_tcp_packet;
4763f0a35040SMichal Swiatkowski 			*pkt_len = sizeof(dummy_gre_tcp_packet);
4764f0a35040SMichal Swiatkowski 			*offsets = dummy_gre_tcp_packet_offsets;
4765f0a35040SMichal Swiatkowski 			return;
4766f0a35040SMichal Swiatkowski 		}
4767f0a35040SMichal Swiatkowski 
4768f0a35040SMichal Swiatkowski 		*pkt = dummy_gre_udp_packet;
4769f0a35040SMichal Swiatkowski 		*pkt_len = sizeof(dummy_gre_udp_packet);
4770f0a35040SMichal Swiatkowski 		*offsets = dummy_gre_udp_packet_offsets;
4771f0a35040SMichal Swiatkowski 		return;
4772f0a35040SMichal Swiatkowski 	}
4773f0a35040SMichal Swiatkowski 
47748b032a55SMichal Swiatkowski 	if (tun_type == ICE_SW_TUN_VXLAN ||
47758b032a55SMichal Swiatkowski 	    tun_type == ICE_SW_TUN_GENEVE) {
47768b032a55SMichal Swiatkowski 		if (tcp) {
47778b032a55SMichal Swiatkowski 			*pkt = dummy_udp_tun_tcp_packet;
47788b032a55SMichal Swiatkowski 			*pkt_len = sizeof(dummy_udp_tun_tcp_packet);
47798b032a55SMichal Swiatkowski 			*offsets = dummy_udp_tun_tcp_packet_offsets;
47808b032a55SMichal Swiatkowski 			return;
47818b032a55SMichal Swiatkowski 		}
47828b032a55SMichal Swiatkowski 
47838b032a55SMichal Swiatkowski 		*pkt = dummy_udp_tun_udp_packet;
47848b032a55SMichal Swiatkowski 		*pkt_len = sizeof(dummy_udp_tun_udp_packet);
47858b032a55SMichal Swiatkowski 		*offsets = dummy_udp_tun_udp_packet_offsets;
47868b032a55SMichal Swiatkowski 		return;
47878b032a55SMichal Swiatkowski 	}
47888b032a55SMichal Swiatkowski 
47890f94570dSGrishma Kotecha 	if (udp && !ipv6) {
47900f94570dSGrishma Kotecha 		if (vlan) {
47910f94570dSGrishma Kotecha 			*pkt = dummy_vlan_udp_packet;
47920f94570dSGrishma Kotecha 			*pkt_len = sizeof(dummy_vlan_udp_packet);
47930f94570dSGrishma Kotecha 			*offsets = dummy_vlan_udp_packet_offsets;
47940f94570dSGrishma Kotecha 			return;
47950f94570dSGrishma Kotecha 		}
47960f94570dSGrishma Kotecha 		*pkt = dummy_udp_packet;
47970f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_udp_packet);
47980f94570dSGrishma Kotecha 		*offsets = dummy_udp_packet_offsets;
47990f94570dSGrishma Kotecha 		return;
48000f94570dSGrishma Kotecha 	} else if (udp && ipv6) {
48010f94570dSGrishma Kotecha 		if (vlan) {
48020f94570dSGrishma Kotecha 			*pkt = dummy_vlan_udp_ipv6_packet;
48030f94570dSGrishma Kotecha 			*pkt_len = sizeof(dummy_vlan_udp_ipv6_packet);
48040f94570dSGrishma Kotecha 			*offsets = dummy_vlan_udp_ipv6_packet_offsets;
48050f94570dSGrishma Kotecha 			return;
48060f94570dSGrishma Kotecha 		}
48070f94570dSGrishma Kotecha 		*pkt = dummy_udp_ipv6_packet;
48080f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_udp_ipv6_packet);
48090f94570dSGrishma Kotecha 		*offsets = dummy_udp_ipv6_packet_offsets;
48100f94570dSGrishma Kotecha 		return;
48110f94570dSGrishma Kotecha 	} else if ((tcp && ipv6) || ipv6) {
48120f94570dSGrishma Kotecha 		if (vlan) {
48130f94570dSGrishma Kotecha 			*pkt = dummy_vlan_tcp_ipv6_packet;
48140f94570dSGrishma Kotecha 			*pkt_len = sizeof(dummy_vlan_tcp_ipv6_packet);
48150f94570dSGrishma Kotecha 			*offsets = dummy_vlan_tcp_ipv6_packet_offsets;
48160f94570dSGrishma Kotecha 			return;
48170f94570dSGrishma Kotecha 		}
48180f94570dSGrishma Kotecha 		*pkt = dummy_tcp_ipv6_packet;
48190f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_tcp_ipv6_packet);
48200f94570dSGrishma Kotecha 		*offsets = dummy_tcp_ipv6_packet_offsets;
48210f94570dSGrishma Kotecha 		return;
48220f94570dSGrishma Kotecha 	}
48230f94570dSGrishma Kotecha 
48240f94570dSGrishma Kotecha 	if (vlan) {
48250f94570dSGrishma Kotecha 		*pkt = dummy_vlan_tcp_packet;
48260f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_vlan_tcp_packet);
48270f94570dSGrishma Kotecha 		*offsets = dummy_vlan_tcp_packet_offsets;
48280f94570dSGrishma Kotecha 	} else {
48290f94570dSGrishma Kotecha 		*pkt = dummy_tcp_packet;
48300f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_tcp_packet);
48310f94570dSGrishma Kotecha 		*offsets = dummy_tcp_packet_offsets;
48320f94570dSGrishma Kotecha 	}
48330f94570dSGrishma Kotecha }
48340f94570dSGrishma Kotecha 
48350f94570dSGrishma Kotecha /**
48360f94570dSGrishma Kotecha  * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria
48370f94570dSGrishma Kotecha  *
48380f94570dSGrishma Kotecha  * @lkups: lookup elements or match criteria for the advanced recipe, one
48390f94570dSGrishma Kotecha  *	   structure per protocol header
48400f94570dSGrishma Kotecha  * @lkups_cnt: number of protocols
48410f94570dSGrishma Kotecha  * @s_rule: stores rule information from the match criteria
48420f94570dSGrishma Kotecha  * @dummy_pkt: dummy packet to fill according to filter match criteria
48430f94570dSGrishma Kotecha  * @pkt_len: packet length of dummy packet
48440f94570dSGrishma Kotecha  * @offsets: offset info for the dummy packet
48450f94570dSGrishma Kotecha  */
48465e24d598STony Nguyen static int
48470f94570dSGrishma Kotecha ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
48480f94570dSGrishma Kotecha 			  struct ice_aqc_sw_rules_elem *s_rule,
48490f94570dSGrishma Kotecha 			  const u8 *dummy_pkt, u16 pkt_len,
48500f94570dSGrishma Kotecha 			  const struct ice_dummy_pkt_offsets *offsets)
48510f94570dSGrishma Kotecha {
48520f94570dSGrishma Kotecha 	u8 *pkt;
48530f94570dSGrishma Kotecha 	u16 i;
48540f94570dSGrishma Kotecha 
48550f94570dSGrishma Kotecha 	/* Start with a packet with a pre-defined/dummy content. Then, fill
48560f94570dSGrishma Kotecha 	 * in the header values to be looked up or matched.
48570f94570dSGrishma Kotecha 	 */
48580f94570dSGrishma Kotecha 	pkt = s_rule->pdata.lkup_tx_rx.hdr;
48590f94570dSGrishma Kotecha 
48600f94570dSGrishma Kotecha 	memcpy(pkt, dummy_pkt, pkt_len);
48610f94570dSGrishma Kotecha 
48620f94570dSGrishma Kotecha 	for (i = 0; i < lkups_cnt; i++) {
48630f94570dSGrishma Kotecha 		enum ice_protocol_type type;
48640f94570dSGrishma Kotecha 		u16 offset = 0, len = 0, j;
48650f94570dSGrishma Kotecha 		bool found = false;
48660f94570dSGrishma Kotecha 
48670f94570dSGrishma Kotecha 		/* find the start of this layer; it should be found since this
48680f94570dSGrishma Kotecha 		 * was already checked when search for the dummy packet
48690f94570dSGrishma Kotecha 		 */
48700f94570dSGrishma Kotecha 		type = lkups[i].type;
48710f94570dSGrishma Kotecha 		for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) {
48720f94570dSGrishma Kotecha 			if (type == offsets[j].type) {
48730f94570dSGrishma Kotecha 				offset = offsets[j].offset;
48740f94570dSGrishma Kotecha 				found = true;
48750f94570dSGrishma Kotecha 				break;
48760f94570dSGrishma Kotecha 			}
48770f94570dSGrishma Kotecha 		}
48780f94570dSGrishma Kotecha 		/* this should never happen in a correct calling sequence */
48790f94570dSGrishma Kotecha 		if (!found)
4880d54699e2STony Nguyen 			return -EINVAL;
48810f94570dSGrishma Kotecha 
48820f94570dSGrishma Kotecha 		switch (lkups[i].type) {
48830f94570dSGrishma Kotecha 		case ICE_MAC_OFOS:
48840f94570dSGrishma Kotecha 		case ICE_MAC_IL:
48850f94570dSGrishma Kotecha 			len = sizeof(struct ice_ether_hdr);
48860f94570dSGrishma Kotecha 			break;
48870f94570dSGrishma Kotecha 		case ICE_ETYPE_OL:
48880f94570dSGrishma Kotecha 			len = sizeof(struct ice_ethtype_hdr);
48890f94570dSGrishma Kotecha 			break;
48900f94570dSGrishma Kotecha 		case ICE_VLAN_OFOS:
48910f94570dSGrishma Kotecha 			len = sizeof(struct ice_vlan_hdr);
48920f94570dSGrishma Kotecha 			break;
48930f94570dSGrishma Kotecha 		case ICE_IPV4_OFOS:
48940f94570dSGrishma Kotecha 		case ICE_IPV4_IL:
48950f94570dSGrishma Kotecha 			len = sizeof(struct ice_ipv4_hdr);
48960f94570dSGrishma Kotecha 			break;
48970f94570dSGrishma Kotecha 		case ICE_IPV6_OFOS:
48980f94570dSGrishma Kotecha 		case ICE_IPV6_IL:
48990f94570dSGrishma Kotecha 			len = sizeof(struct ice_ipv6_hdr);
49000f94570dSGrishma Kotecha 			break;
49010f94570dSGrishma Kotecha 		case ICE_TCP_IL:
49020f94570dSGrishma Kotecha 		case ICE_UDP_OF:
49030f94570dSGrishma Kotecha 		case ICE_UDP_ILOS:
49040f94570dSGrishma Kotecha 			len = sizeof(struct ice_l4_hdr);
49050f94570dSGrishma Kotecha 			break;
49060f94570dSGrishma Kotecha 		case ICE_SCTP_IL:
49070f94570dSGrishma Kotecha 			len = sizeof(struct ice_sctp_hdr);
49080f94570dSGrishma Kotecha 			break;
4909f0a35040SMichal Swiatkowski 		case ICE_NVGRE:
4910f0a35040SMichal Swiatkowski 			len = sizeof(struct ice_nvgre_hdr);
4911f0a35040SMichal Swiatkowski 			break;
49128b032a55SMichal Swiatkowski 		case ICE_VXLAN:
49138b032a55SMichal Swiatkowski 		case ICE_GENEVE:
49148b032a55SMichal Swiatkowski 			len = sizeof(struct ice_udp_tnl_hdr);
49158b032a55SMichal Swiatkowski 			break;
49160f94570dSGrishma Kotecha 		default:
4917d54699e2STony Nguyen 			return -EINVAL;
49180f94570dSGrishma Kotecha 		}
49190f94570dSGrishma Kotecha 
49200f94570dSGrishma Kotecha 		/* the length should be a word multiple */
49210f94570dSGrishma Kotecha 		if (len % ICE_BYTES_PER_WORD)
4922d54699e2STony Nguyen 			return -EIO;
49230f94570dSGrishma Kotecha 
49240f94570dSGrishma Kotecha 		/* We have the offset to the header start, the length, the
49250f94570dSGrishma Kotecha 		 * caller's header values and mask. Use this information to
49260f94570dSGrishma Kotecha 		 * copy the data into the dummy packet appropriately based on
49270f94570dSGrishma Kotecha 		 * the mask. Note that we need to only write the bits as
49280f94570dSGrishma Kotecha 		 * indicated by the mask to make sure we don't improperly write
49290f94570dSGrishma Kotecha 		 * over any significant packet data.
49300f94570dSGrishma Kotecha 		 */
49310f94570dSGrishma Kotecha 		for (j = 0; j < len / sizeof(u16); j++)
49320f94570dSGrishma Kotecha 			if (((u16 *)&lkups[i].m_u)[j])
49330f94570dSGrishma Kotecha 				((u16 *)(pkt + offset))[j] =
49340f94570dSGrishma Kotecha 					(((u16 *)(pkt + offset))[j] &
49350f94570dSGrishma Kotecha 					 ~((u16 *)&lkups[i].m_u)[j]) |
49360f94570dSGrishma Kotecha 					(((u16 *)&lkups[i].h_u)[j] &
49370f94570dSGrishma Kotecha 					 ((u16 *)&lkups[i].m_u)[j]);
49380f94570dSGrishma Kotecha 	}
49390f94570dSGrishma Kotecha 
49400f94570dSGrishma Kotecha 	s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(pkt_len);
49410f94570dSGrishma Kotecha 
49420f94570dSGrishma Kotecha 	return 0;
49430f94570dSGrishma Kotecha }
49440f94570dSGrishma Kotecha 
49450f94570dSGrishma Kotecha /**
49468b032a55SMichal Swiatkowski  * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port
49478b032a55SMichal Swiatkowski  * @hw: pointer to the hardware structure
49488b032a55SMichal Swiatkowski  * @tun_type: tunnel type
49498b032a55SMichal Swiatkowski  * @pkt: dummy packet to fill in
49508b032a55SMichal Swiatkowski  * @offsets: offset info for the dummy packet
49518b032a55SMichal Swiatkowski  */
4952d54699e2STony Nguyen static int
49538b032a55SMichal Swiatkowski ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type,
49548b032a55SMichal Swiatkowski 			u8 *pkt, const struct ice_dummy_pkt_offsets *offsets)
49558b032a55SMichal Swiatkowski {
49568b032a55SMichal Swiatkowski 	u16 open_port, i;
49578b032a55SMichal Swiatkowski 
49588b032a55SMichal Swiatkowski 	switch (tun_type) {
49598b032a55SMichal Swiatkowski 	case ICE_SW_TUN_VXLAN:
4960de6acd1cSMichal Swiatkowski 		if (!ice_get_open_tunnel_port(hw, &open_port, TNL_VXLAN))
4961d54699e2STony Nguyen 			return -EIO;
49628b032a55SMichal Swiatkowski 		break;
4963de6acd1cSMichal Swiatkowski 	case ICE_SW_TUN_GENEVE:
4964de6acd1cSMichal Swiatkowski 		if (!ice_get_open_tunnel_port(hw, &open_port, TNL_GENEVE))
4965d54699e2STony Nguyen 			return -EIO;
4966de6acd1cSMichal Swiatkowski 		break;
49678b032a55SMichal Swiatkowski 	default:
49688b032a55SMichal Swiatkowski 		/* Nothing needs to be done for this tunnel type */
49698b032a55SMichal Swiatkowski 		return 0;
49708b032a55SMichal Swiatkowski 	}
49718b032a55SMichal Swiatkowski 
49728b032a55SMichal Swiatkowski 	/* Find the outer UDP protocol header and insert the port number */
49738b032a55SMichal Swiatkowski 	for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) {
49748b032a55SMichal Swiatkowski 		if (offsets[i].type == ICE_UDP_OF) {
49758b032a55SMichal Swiatkowski 			struct ice_l4_hdr *hdr;
49768b032a55SMichal Swiatkowski 			u16 offset;
49778b032a55SMichal Swiatkowski 
49788b032a55SMichal Swiatkowski 			offset = offsets[i].offset;
49798b032a55SMichal Swiatkowski 			hdr = (struct ice_l4_hdr *)&pkt[offset];
49808b032a55SMichal Swiatkowski 			hdr->dst_port = cpu_to_be16(open_port);
49818b032a55SMichal Swiatkowski 
49828b032a55SMichal Swiatkowski 			return 0;
49838b032a55SMichal Swiatkowski 		}
49848b032a55SMichal Swiatkowski 	}
49858b032a55SMichal Swiatkowski 
4986d54699e2STony Nguyen 	return -EIO;
49878b032a55SMichal Swiatkowski }
49888b032a55SMichal Swiatkowski 
49898b032a55SMichal Swiatkowski /**
49900f94570dSGrishma Kotecha  * ice_find_adv_rule_entry - Search a rule entry
49910f94570dSGrishma Kotecha  * @hw: pointer to the hardware structure
49920f94570dSGrishma Kotecha  * @lkups: lookup elements or match criteria for the advanced recipe, one
49930f94570dSGrishma Kotecha  *	   structure per protocol header
49940f94570dSGrishma Kotecha  * @lkups_cnt: number of protocols
49950f94570dSGrishma Kotecha  * @recp_id: recipe ID for which we are finding the rule
49960f94570dSGrishma Kotecha  * @rinfo: other information regarding the rule e.g. priority and action info
49970f94570dSGrishma Kotecha  *
49980f94570dSGrishma Kotecha  * Helper function to search for a given advance rule entry
49990f94570dSGrishma Kotecha  * Returns pointer to entry storing the rule if found
50000f94570dSGrishma Kotecha  */
50010f94570dSGrishma Kotecha static struct ice_adv_fltr_mgmt_list_entry *
50020f94570dSGrishma Kotecha ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
50030f94570dSGrishma Kotecha 			u16 lkups_cnt, u16 recp_id,
50040f94570dSGrishma Kotecha 			struct ice_adv_rule_info *rinfo)
50050f94570dSGrishma Kotecha {
50060f94570dSGrishma Kotecha 	struct ice_adv_fltr_mgmt_list_entry *list_itr;
50070f94570dSGrishma Kotecha 	struct ice_switch_info *sw = hw->switch_info;
50080f94570dSGrishma Kotecha 	int i;
50090f94570dSGrishma Kotecha 
50100f94570dSGrishma Kotecha 	list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules,
50110f94570dSGrishma Kotecha 			    list_entry) {
50120f94570dSGrishma Kotecha 		bool lkups_matched = true;
50130f94570dSGrishma Kotecha 
50140f94570dSGrishma Kotecha 		if (lkups_cnt != list_itr->lkups_cnt)
50150f94570dSGrishma Kotecha 			continue;
50160f94570dSGrishma Kotecha 		for (i = 0; i < list_itr->lkups_cnt; i++)
50170f94570dSGrishma Kotecha 			if (memcmp(&list_itr->lkups[i], &lkups[i],
50180f94570dSGrishma Kotecha 				   sizeof(*lkups))) {
50190f94570dSGrishma Kotecha 				lkups_matched = false;
50200f94570dSGrishma Kotecha 				break;
50210f94570dSGrishma Kotecha 			}
50220f94570dSGrishma Kotecha 		if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag &&
50238b032a55SMichal Swiatkowski 		    rinfo->tun_type == list_itr->rule_info.tun_type &&
50240f94570dSGrishma Kotecha 		    lkups_matched)
50250f94570dSGrishma Kotecha 			return list_itr;
50260f94570dSGrishma Kotecha 	}
50270f94570dSGrishma Kotecha 	return NULL;
50280f94570dSGrishma Kotecha }
50290f94570dSGrishma Kotecha 
50300f94570dSGrishma Kotecha /**
50310f94570dSGrishma Kotecha  * ice_adv_add_update_vsi_list
50320f94570dSGrishma Kotecha  * @hw: pointer to the hardware structure
50330f94570dSGrishma Kotecha  * @m_entry: pointer to current adv filter management list entry
50340f94570dSGrishma Kotecha  * @cur_fltr: filter information from the book keeping entry
50350f94570dSGrishma Kotecha  * @new_fltr: filter information with the new VSI to be added
50360f94570dSGrishma Kotecha  *
50370f94570dSGrishma Kotecha  * Call AQ command to add or update previously created VSI list with new VSI.
50380f94570dSGrishma Kotecha  *
50390f94570dSGrishma Kotecha  * Helper function to do book keeping associated with adding filter information
50400f94570dSGrishma Kotecha  * The algorithm to do the booking keeping is described below :
50410f94570dSGrishma Kotecha  * When a VSI needs to subscribe to a given advanced filter
50420f94570dSGrishma Kotecha  *	if only one VSI has been added till now
50430f94570dSGrishma Kotecha  *		Allocate a new VSI list and add two VSIs
50440f94570dSGrishma Kotecha  *		to this list using switch rule command
50450f94570dSGrishma Kotecha  *		Update the previously created switch rule with the
50460f94570dSGrishma Kotecha  *		newly created VSI list ID
50470f94570dSGrishma Kotecha  *	if a VSI list was previously created
50480f94570dSGrishma Kotecha  *		Add the new VSI to the previously created VSI list set
50490f94570dSGrishma Kotecha  *		using the update switch rule command
50500f94570dSGrishma Kotecha  */
50515e24d598STony Nguyen static int
50520f94570dSGrishma Kotecha ice_adv_add_update_vsi_list(struct ice_hw *hw,
50530f94570dSGrishma Kotecha 			    struct ice_adv_fltr_mgmt_list_entry *m_entry,
50540f94570dSGrishma Kotecha 			    struct ice_adv_rule_info *cur_fltr,
50550f94570dSGrishma Kotecha 			    struct ice_adv_rule_info *new_fltr)
50560f94570dSGrishma Kotecha {
50570f94570dSGrishma Kotecha 	u16 vsi_list_id = 0;
50585518ac2aSTony Nguyen 	int status;
50590f94570dSGrishma Kotecha 
50600f94570dSGrishma Kotecha 	if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||
50610f94570dSGrishma Kotecha 	    cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
50620f94570dSGrishma Kotecha 	    cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET)
5063d54699e2STony Nguyen 		return -EOPNOTSUPP;
50640f94570dSGrishma Kotecha 
50650f94570dSGrishma Kotecha 	if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||
50660f94570dSGrishma Kotecha 	     new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) &&
50670f94570dSGrishma Kotecha 	    (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI ||
50680f94570dSGrishma Kotecha 	     cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST))
5069d54699e2STony Nguyen 		return -EOPNOTSUPP;
50700f94570dSGrishma Kotecha 
50710f94570dSGrishma Kotecha 	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
50720f94570dSGrishma Kotecha 		 /* Only one entry existed in the mapping and it was not already
50730f94570dSGrishma Kotecha 		  * a part of a VSI list. So, create a VSI list with the old and
50740f94570dSGrishma Kotecha 		  * new VSIs.
50750f94570dSGrishma Kotecha 		  */
50760f94570dSGrishma Kotecha 		struct ice_fltr_info tmp_fltr;
50770f94570dSGrishma Kotecha 		u16 vsi_handle_arr[2];
50780f94570dSGrishma Kotecha 
50790f94570dSGrishma Kotecha 		/* A rule already exists with the new VSI being added */
50800f94570dSGrishma Kotecha 		if (cur_fltr->sw_act.fwd_id.hw_vsi_id ==
50810f94570dSGrishma Kotecha 		    new_fltr->sw_act.fwd_id.hw_vsi_id)
5082d54699e2STony Nguyen 			return -EEXIST;
50830f94570dSGrishma Kotecha 
50840f94570dSGrishma Kotecha 		vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle;
50850f94570dSGrishma Kotecha 		vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle;
50860f94570dSGrishma Kotecha 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
50870f94570dSGrishma Kotecha 						  &vsi_list_id,
50880f94570dSGrishma Kotecha 						  ICE_SW_LKUP_LAST);
50890f94570dSGrishma Kotecha 		if (status)
50900f94570dSGrishma Kotecha 			return status;
50910f94570dSGrishma Kotecha 
50920f94570dSGrishma Kotecha 		memset(&tmp_fltr, 0, sizeof(tmp_fltr));
50930f94570dSGrishma Kotecha 		tmp_fltr.flag = m_entry->rule_info.sw_act.flag;
50940f94570dSGrishma Kotecha 		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
50950f94570dSGrishma Kotecha 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
50960f94570dSGrishma Kotecha 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
50970f94570dSGrishma Kotecha 		tmp_fltr.lkup_type = ICE_SW_LKUP_LAST;
50980f94570dSGrishma Kotecha 
50990f94570dSGrishma Kotecha 		/* Update the previous switch rule of "forward to VSI" to
51000f94570dSGrishma Kotecha 		 * "fwd to VSI list"
51010f94570dSGrishma Kotecha 		 */
51020f94570dSGrishma Kotecha 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
51030f94570dSGrishma Kotecha 		if (status)
51040f94570dSGrishma Kotecha 			return status;
51050f94570dSGrishma Kotecha 
51060f94570dSGrishma Kotecha 		cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id;
51070f94570dSGrishma Kotecha 		cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST;
51080f94570dSGrishma Kotecha 		m_entry->vsi_list_info =
51090f94570dSGrishma Kotecha 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
51100f94570dSGrishma Kotecha 						vsi_list_id);
51110f94570dSGrishma Kotecha 	} else {
51120f94570dSGrishma Kotecha 		u16 vsi_handle = new_fltr->sw_act.vsi_handle;
51130f94570dSGrishma Kotecha 
51140f94570dSGrishma Kotecha 		if (!m_entry->vsi_list_info)
5115d54699e2STony Nguyen 			return -EIO;
51160f94570dSGrishma Kotecha 
51170f94570dSGrishma Kotecha 		/* A rule already exists with the new VSI being added */
51180f94570dSGrishma Kotecha 		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
51190f94570dSGrishma Kotecha 			return 0;
51200f94570dSGrishma Kotecha 
51210f94570dSGrishma Kotecha 		/* Update the previously created VSI list set with
51220f94570dSGrishma Kotecha 		 * the new VSI ID passed in
51230f94570dSGrishma Kotecha 		 */
51240f94570dSGrishma Kotecha 		vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id;
51250f94570dSGrishma Kotecha 
51260f94570dSGrishma Kotecha 		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
51270f94570dSGrishma Kotecha 						  vsi_list_id, false,
51280f94570dSGrishma Kotecha 						  ice_aqc_opc_update_sw_rules,
51290f94570dSGrishma Kotecha 						  ICE_SW_LKUP_LAST);
51300f94570dSGrishma Kotecha 		/* update VSI list mapping info with new VSI ID */
51310f94570dSGrishma Kotecha 		if (!status)
51320f94570dSGrishma Kotecha 			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
51330f94570dSGrishma Kotecha 	}
51340f94570dSGrishma Kotecha 	if (!status)
51350f94570dSGrishma Kotecha 		m_entry->vsi_count++;
51360f94570dSGrishma Kotecha 	return status;
51370f94570dSGrishma Kotecha }
51380f94570dSGrishma Kotecha 
51390f94570dSGrishma Kotecha /**
51400f94570dSGrishma Kotecha  * ice_add_adv_rule - helper function to create an advanced switch rule
51410f94570dSGrishma Kotecha  * @hw: pointer to the hardware structure
51420f94570dSGrishma Kotecha  * @lkups: information on the words that needs to be looked up. All words
51430f94570dSGrishma Kotecha  * together makes one recipe
51440f94570dSGrishma Kotecha  * @lkups_cnt: num of entries in the lkups array
51450f94570dSGrishma Kotecha  * @rinfo: other information related to the rule that needs to be programmed
51460f94570dSGrishma Kotecha  * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be
51470f94570dSGrishma Kotecha  *               ignored is case of error.
51480f94570dSGrishma Kotecha  *
51490f94570dSGrishma Kotecha  * This function can program only 1 rule at a time. The lkups is used to
51500f94570dSGrishma Kotecha  * describe the all the words that forms the "lookup" portion of the recipe.
51510f94570dSGrishma Kotecha  * These words can span multiple protocols. Callers to this function need to
51520f94570dSGrishma Kotecha  * pass in a list of protocol headers with lookup information along and mask
51530f94570dSGrishma Kotecha  * that determines which words are valid from the given protocol header.
51540f94570dSGrishma Kotecha  * rinfo describes other information related to this rule such as forwarding
51550f94570dSGrishma Kotecha  * IDs, priority of this rule, etc.
51560f94570dSGrishma Kotecha  */
51575e24d598STony Nguyen int
51580f94570dSGrishma Kotecha ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
51590f94570dSGrishma Kotecha 		 u16 lkups_cnt, struct ice_adv_rule_info *rinfo,
51600f94570dSGrishma Kotecha 		 struct ice_rule_query_data *added_entry)
51610f94570dSGrishma Kotecha {
51620f94570dSGrishma Kotecha 	struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL;
51630f94570dSGrishma Kotecha 	u16 rid = 0, i, pkt_len, rule_buf_sz, vsi_handle;
51640f94570dSGrishma Kotecha 	const struct ice_dummy_pkt_offsets *pkt_offsets;
51650f94570dSGrishma Kotecha 	struct ice_aqc_sw_rules_elem *s_rule = NULL;
51660f94570dSGrishma Kotecha 	struct list_head *rule_head;
51670f94570dSGrishma Kotecha 	struct ice_switch_info *sw;
51680f94570dSGrishma Kotecha 	const u8 *pkt = NULL;
51690f94570dSGrishma Kotecha 	u16 word_cnt;
51700f94570dSGrishma Kotecha 	u32 act = 0;
51715518ac2aSTony Nguyen 	int status;
51720f94570dSGrishma Kotecha 	u8 q_rgn;
51730f94570dSGrishma Kotecha 
51740f94570dSGrishma Kotecha 	/* Initialize profile to result index bitmap */
51750f94570dSGrishma Kotecha 	if (!hw->switch_info->prof_res_bm_init) {
51760f94570dSGrishma Kotecha 		hw->switch_info->prof_res_bm_init = 1;
51770f94570dSGrishma Kotecha 		ice_init_prof_result_bm(hw);
51780f94570dSGrishma Kotecha 	}
51790f94570dSGrishma Kotecha 
51800f94570dSGrishma Kotecha 	if (!lkups_cnt)
5181d54699e2STony Nguyen 		return -EINVAL;
51820f94570dSGrishma Kotecha 
51830f94570dSGrishma Kotecha 	/* get # of words we need to match */
51840f94570dSGrishma Kotecha 	word_cnt = 0;
51850f94570dSGrishma Kotecha 	for (i = 0; i < lkups_cnt; i++) {
51860f94570dSGrishma Kotecha 		u16 j, *ptr;
51870f94570dSGrishma Kotecha 
51880f94570dSGrishma Kotecha 		ptr = (u16 *)&lkups[i].m_u;
51890f94570dSGrishma Kotecha 		for (j = 0; j < sizeof(lkups->m_u) / sizeof(u16); j++)
51900f94570dSGrishma Kotecha 			if (ptr[j] != 0)
51910f94570dSGrishma Kotecha 				word_cnt++;
51920f94570dSGrishma Kotecha 	}
51930f94570dSGrishma Kotecha 
51940f94570dSGrishma Kotecha 	if (!word_cnt || word_cnt > ICE_MAX_CHAIN_WORDS)
5195d54699e2STony Nguyen 		return -EINVAL;
51960f94570dSGrishma Kotecha 
51970f94570dSGrishma Kotecha 	/* make sure that we can locate a dummy packet */
51988b032a55SMichal Swiatkowski 	ice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type, &pkt, &pkt_len,
51990f94570dSGrishma Kotecha 			      &pkt_offsets);
52000f94570dSGrishma Kotecha 	if (!pkt) {
5201d54699e2STony Nguyen 		status = -EINVAL;
52020f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
52030f94570dSGrishma Kotecha 	}
52040f94570dSGrishma Kotecha 
52050f94570dSGrishma Kotecha 	if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
52060f94570dSGrishma Kotecha 	      rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
52070f94570dSGrishma Kotecha 	      rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
52080f94570dSGrishma Kotecha 	      rinfo->sw_act.fltr_act == ICE_DROP_PACKET))
5209d54699e2STony Nguyen 		return -EIO;
52100f94570dSGrishma Kotecha 
52110f94570dSGrishma Kotecha 	vsi_handle = rinfo->sw_act.vsi_handle;
52120f94570dSGrishma Kotecha 	if (!ice_is_vsi_valid(hw, vsi_handle))
5213d54699e2STony Nguyen 		return -EINVAL;
52140f94570dSGrishma Kotecha 
52150f94570dSGrishma Kotecha 	if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
52160f94570dSGrishma Kotecha 		rinfo->sw_act.fwd_id.hw_vsi_id =
52170f94570dSGrishma Kotecha 			ice_get_hw_vsi_num(hw, vsi_handle);
52180f94570dSGrishma Kotecha 	if (rinfo->sw_act.flag & ICE_FLTR_TX)
52190f94570dSGrishma Kotecha 		rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle);
52200f94570dSGrishma Kotecha 
52210f94570dSGrishma Kotecha 	status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid);
52220f94570dSGrishma Kotecha 	if (status)
52230f94570dSGrishma Kotecha 		return status;
52240f94570dSGrishma Kotecha 	m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
52250f94570dSGrishma Kotecha 	if (m_entry) {
52260f94570dSGrishma Kotecha 		/* we have to add VSI to VSI_LIST and increment vsi_count.
52270f94570dSGrishma Kotecha 		 * Also Update VSI list so that we can change forwarding rule
52280f94570dSGrishma Kotecha 		 * if the rule already exists, we will check if it exists with
52290f94570dSGrishma Kotecha 		 * same vsi_id, if not then add it to the VSI list if it already
52300f94570dSGrishma Kotecha 		 * exists if not then create a VSI list and add the existing VSI
52310f94570dSGrishma Kotecha 		 * ID and the new VSI ID to the list
52320f94570dSGrishma Kotecha 		 * We will add that VSI to the list
52330f94570dSGrishma Kotecha 		 */
52340f94570dSGrishma Kotecha 		status = ice_adv_add_update_vsi_list(hw, m_entry,
52350f94570dSGrishma Kotecha 						     &m_entry->rule_info,
52360f94570dSGrishma Kotecha 						     rinfo);
52370f94570dSGrishma Kotecha 		if (added_entry) {
52380f94570dSGrishma Kotecha 			added_entry->rid = rid;
52390f94570dSGrishma Kotecha 			added_entry->rule_id = m_entry->rule_info.fltr_rule_id;
52400f94570dSGrishma Kotecha 			added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
52410f94570dSGrishma Kotecha 		}
52420f94570dSGrishma Kotecha 		return status;
52430f94570dSGrishma Kotecha 	}
52440f94570dSGrishma Kotecha 	rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE + pkt_len;
52450f94570dSGrishma Kotecha 	s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
52460f94570dSGrishma Kotecha 	if (!s_rule)
5247d54699e2STony Nguyen 		return -ENOMEM;
524873b483b7SWojciech Drewek 	if (!rinfo->flags_info.act_valid) {
524973b483b7SWojciech Drewek 		act |= ICE_SINGLE_ACT_LAN_ENABLE;
525073b483b7SWojciech Drewek 		act |= ICE_SINGLE_ACT_LB_ENABLE;
525173b483b7SWojciech Drewek 	} else {
525273b483b7SWojciech Drewek 		act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
525373b483b7SWojciech Drewek 						ICE_SINGLE_ACT_LB_ENABLE);
525473b483b7SWojciech Drewek 	}
525573b483b7SWojciech Drewek 
52560f94570dSGrishma Kotecha 	switch (rinfo->sw_act.fltr_act) {
52570f94570dSGrishma Kotecha 	case ICE_FWD_TO_VSI:
52580f94570dSGrishma Kotecha 		act |= (rinfo->sw_act.fwd_id.hw_vsi_id <<
52590f94570dSGrishma Kotecha 			ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M;
52600f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;
52610f94570dSGrishma Kotecha 		break;
52620f94570dSGrishma Kotecha 	case ICE_FWD_TO_Q:
52630f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_TO_Q;
52640f94570dSGrishma Kotecha 		act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
52650f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_Q_INDEX_M;
52660f94570dSGrishma Kotecha 		break;
52670f94570dSGrishma Kotecha 	case ICE_FWD_TO_QGRP:
52680f94570dSGrishma Kotecha 		q_rgn = rinfo->sw_act.qgrp_size > 0 ?
52690f94570dSGrishma Kotecha 			(u8)ilog2(rinfo->sw_act.qgrp_size) : 0;
52700f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_TO_Q;
52710f94570dSGrishma Kotecha 		act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
52720f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_Q_INDEX_M;
52730f94570dSGrishma Kotecha 		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
52740f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_Q_REGION_M;
52750f94570dSGrishma Kotecha 		break;
52760f94570dSGrishma Kotecha 	case ICE_DROP_PACKET:
52770f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
52780f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_VALID_BIT;
52790f94570dSGrishma Kotecha 		break;
52800f94570dSGrishma Kotecha 	default:
5281d54699e2STony Nguyen 		status = -EIO;
52820f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
52830f94570dSGrishma Kotecha 	}
52840f94570dSGrishma Kotecha 
52850f94570dSGrishma Kotecha 	/* set the rule LOOKUP type based on caller specified 'Rx'
52860f94570dSGrishma Kotecha 	 * instead of hardcoding it to be either LOOKUP_TX/RX
52870f94570dSGrishma Kotecha 	 *
52880f94570dSGrishma Kotecha 	 * for 'Rx' set the source to be the port number
52890f94570dSGrishma Kotecha 	 * for 'Tx' set the source to be the source HW VSI number (determined
52900f94570dSGrishma Kotecha 	 * by caller)
52910f94570dSGrishma Kotecha 	 */
52920f94570dSGrishma Kotecha 	if (rinfo->rx) {
52930f94570dSGrishma Kotecha 		s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
52940f94570dSGrishma Kotecha 		s_rule->pdata.lkup_tx_rx.src =
52950f94570dSGrishma Kotecha 			cpu_to_le16(hw->port_info->lport);
52960f94570dSGrishma Kotecha 	} else {
52970f94570dSGrishma Kotecha 		s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
52980f94570dSGrishma Kotecha 		s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(rinfo->sw_act.src);
52990f94570dSGrishma Kotecha 	}
53000f94570dSGrishma Kotecha 
53010f94570dSGrishma Kotecha 	s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(rid);
53020f94570dSGrishma Kotecha 	s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act);
53030f94570dSGrishma Kotecha 
53040f94570dSGrishma Kotecha 	status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, pkt,
53050f94570dSGrishma Kotecha 					   pkt_len, pkt_offsets);
53060f94570dSGrishma Kotecha 	if (status)
53070f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
53080f94570dSGrishma Kotecha 
5309*b70bc066SWojciech Drewek 	if (rinfo->tun_type != ICE_NON_TUN &&
5310*b70bc066SWojciech Drewek 	    rinfo->tun_type != ICE_SW_TUN_AND_NON_TUN) {
53118b032a55SMichal Swiatkowski 		status = ice_fill_adv_packet_tun(hw, rinfo->tun_type,
53128b032a55SMichal Swiatkowski 						 s_rule->pdata.lkup_tx_rx.hdr,
53138b032a55SMichal Swiatkowski 						 pkt_offsets);
53148b032a55SMichal Swiatkowski 		if (status)
53158b032a55SMichal Swiatkowski 			goto err_ice_add_adv_rule;
53168b032a55SMichal Swiatkowski 	}
53178b032a55SMichal Swiatkowski 
53180f94570dSGrishma Kotecha 	status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
53190f94570dSGrishma Kotecha 				 rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,
53200f94570dSGrishma Kotecha 				 NULL);
53210f94570dSGrishma Kotecha 	if (status)
53220f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
53230f94570dSGrishma Kotecha 	adv_fltr = devm_kzalloc(ice_hw_to_dev(hw),
53240f94570dSGrishma Kotecha 				sizeof(struct ice_adv_fltr_mgmt_list_entry),
53250f94570dSGrishma Kotecha 				GFP_KERNEL);
53260f94570dSGrishma Kotecha 	if (!adv_fltr) {
5327d54699e2STony Nguyen 		status = -ENOMEM;
53280f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
53290f94570dSGrishma Kotecha 	}
53300f94570dSGrishma Kotecha 
53310f94570dSGrishma Kotecha 	adv_fltr->lkups = devm_kmemdup(ice_hw_to_dev(hw), lkups,
53320f94570dSGrishma Kotecha 				       lkups_cnt * sizeof(*lkups), GFP_KERNEL);
53330f94570dSGrishma Kotecha 	if (!adv_fltr->lkups) {
5334d54699e2STony Nguyen 		status = -ENOMEM;
53350f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
53360f94570dSGrishma Kotecha 	}
53370f94570dSGrishma Kotecha 
53380f94570dSGrishma Kotecha 	adv_fltr->lkups_cnt = lkups_cnt;
53390f94570dSGrishma Kotecha 	adv_fltr->rule_info = *rinfo;
53400f94570dSGrishma Kotecha 	adv_fltr->rule_info.fltr_rule_id =
53410f94570dSGrishma Kotecha 		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
53420f94570dSGrishma Kotecha 	sw = hw->switch_info;
53430f94570dSGrishma Kotecha 	sw->recp_list[rid].adv_rule = true;
53440f94570dSGrishma Kotecha 	rule_head = &sw->recp_list[rid].filt_rules;
53450f94570dSGrishma Kotecha 
53460f94570dSGrishma Kotecha 	if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
53470f94570dSGrishma Kotecha 		adv_fltr->vsi_count = 1;
53480f94570dSGrishma Kotecha 
53490f94570dSGrishma Kotecha 	/* Add rule entry to book keeping list */
53500f94570dSGrishma Kotecha 	list_add(&adv_fltr->list_entry, rule_head);
53510f94570dSGrishma Kotecha 	if (added_entry) {
53520f94570dSGrishma Kotecha 		added_entry->rid = rid;
53530f94570dSGrishma Kotecha 		added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id;
53540f94570dSGrishma Kotecha 		added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
53550f94570dSGrishma Kotecha 	}
53560f94570dSGrishma Kotecha err_ice_add_adv_rule:
53570f94570dSGrishma Kotecha 	if (status && adv_fltr) {
53580f94570dSGrishma Kotecha 		devm_kfree(ice_hw_to_dev(hw), adv_fltr->lkups);
53590f94570dSGrishma Kotecha 		devm_kfree(ice_hw_to_dev(hw), adv_fltr);
53600f94570dSGrishma Kotecha 	}
53610f94570dSGrishma Kotecha 
53620f94570dSGrishma Kotecha 	kfree(s_rule);
53630f94570dSGrishma Kotecha 
53640f94570dSGrishma Kotecha 	return status;
53650f94570dSGrishma Kotecha }
53660f94570dSGrishma Kotecha 
53670f94570dSGrishma Kotecha /**
5368334cb062SAnirudh Venkataramanan  * ice_replay_vsi_fltr - Replay filters for requested VSI
53690f9d5027SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
5370334cb062SAnirudh Venkataramanan  * @vsi_handle: driver VSI handle
5371f9867df6SAnirudh Venkataramanan  * @recp_id: Recipe ID for which rules need to be replayed
5372334cb062SAnirudh Venkataramanan  * @list_head: list for which filters need to be replayed
5373334cb062SAnirudh Venkataramanan  *
5374334cb062SAnirudh Venkataramanan  * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.
5375334cb062SAnirudh Venkataramanan  * It is required to pass valid VSI handle.
53760f9d5027SAnirudh Venkataramanan  */
53775e24d598STony Nguyen static int
5378334cb062SAnirudh Venkataramanan ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id,
5379334cb062SAnirudh Venkataramanan 		    struct list_head *list_head)
53800f9d5027SAnirudh Venkataramanan {
53810f9d5027SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *itr;
53825e24d598STony Nguyen 	int status = 0;
5383334cb062SAnirudh Venkataramanan 	u16 hw_vsi_id;
53840f9d5027SAnirudh Venkataramanan 
53850f9d5027SAnirudh Venkataramanan 	if (list_empty(list_head))
53860f9d5027SAnirudh Venkataramanan 		return status;
5387334cb062SAnirudh Venkataramanan 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
53880f9d5027SAnirudh Venkataramanan 
5389334cb062SAnirudh Venkataramanan 	list_for_each_entry(itr, list_head, list_entry) {
53900f9d5027SAnirudh Venkataramanan 		struct ice_fltr_list_entry f_entry;
53910f9d5027SAnirudh Venkataramanan 
53920f9d5027SAnirudh Venkataramanan 		f_entry.fltr_info = itr->fltr_info;
5393334cb062SAnirudh Venkataramanan 		if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&
5394334cb062SAnirudh Venkataramanan 		    itr->fltr_info.vsi_handle == vsi_handle) {
5395f9867df6SAnirudh Venkataramanan 			/* update the src in case it is VSI num */
5396334cb062SAnirudh Venkataramanan 			if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
5397334cb062SAnirudh Venkataramanan 				f_entry.fltr_info.src = hw_vsi_id;
53980f9d5027SAnirudh Venkataramanan 			status = ice_add_rule_internal(hw, recp_id, &f_entry);
53990f9d5027SAnirudh Venkataramanan 			if (status)
54000f9d5027SAnirudh Venkataramanan 				goto end;
54010f9d5027SAnirudh Venkataramanan 			continue;
54020f9d5027SAnirudh Venkataramanan 		}
5403072f0c3dSDave Ertman 		if (!itr->vsi_list_info ||
5404072f0c3dSDave Ertman 		    !test_bit(vsi_handle, itr->vsi_list_info->vsi_map))
5405334cb062SAnirudh Venkataramanan 			continue;
5406334cb062SAnirudh Venkataramanan 		/* Clearing it so that the logic can add it back */
5407334cb062SAnirudh Venkataramanan 		clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);
5408334cb062SAnirudh Venkataramanan 		f_entry.fltr_info.vsi_handle = vsi_handle;
54090f9d5027SAnirudh Venkataramanan 		f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
5410f9867df6SAnirudh Venkataramanan 		/* update the src in case it is VSI num */
5411334cb062SAnirudh Venkataramanan 		if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
5412334cb062SAnirudh Venkataramanan 			f_entry.fltr_info.src = hw_vsi_id;
54130f9d5027SAnirudh Venkataramanan 		if (recp_id == ICE_SW_LKUP_VLAN)
54140f9d5027SAnirudh Venkataramanan 			status = ice_add_vlan_internal(hw, &f_entry);
54150f9d5027SAnirudh Venkataramanan 		else
5416334cb062SAnirudh Venkataramanan 			status = ice_add_rule_internal(hw, recp_id, &f_entry);
54170f9d5027SAnirudh Venkataramanan 		if (status)
54180f9d5027SAnirudh Venkataramanan 			goto end;
54190f9d5027SAnirudh Venkataramanan 	}
54200f9d5027SAnirudh Venkataramanan end:
54210f9d5027SAnirudh Venkataramanan 	return status;
54220f9d5027SAnirudh Venkataramanan }
54230f9d5027SAnirudh Venkataramanan 
54240f9d5027SAnirudh Venkataramanan /**
54258bb98f33SShivanshu Shukla  * ice_adv_rem_update_vsi_list
54268bb98f33SShivanshu Shukla  * @hw: pointer to the hardware structure
54278bb98f33SShivanshu Shukla  * @vsi_handle: VSI handle of the VSI to remove
54288bb98f33SShivanshu Shukla  * @fm_list: filter management entry for which the VSI list management needs to
54298bb98f33SShivanshu Shukla  *	     be done
54308bb98f33SShivanshu Shukla  */
54315e24d598STony Nguyen static int
54328bb98f33SShivanshu Shukla ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
54338bb98f33SShivanshu Shukla 			    struct ice_adv_fltr_mgmt_list_entry *fm_list)
54348bb98f33SShivanshu Shukla {
54358bb98f33SShivanshu Shukla 	struct ice_vsi_list_map_info *vsi_list_info;
54368bb98f33SShivanshu Shukla 	enum ice_sw_lkup_type lkup_type;
54378bb98f33SShivanshu Shukla 	u16 vsi_list_id;
54385518ac2aSTony Nguyen 	int status;
54398bb98f33SShivanshu Shukla 
54408bb98f33SShivanshu Shukla 	if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST ||
54418bb98f33SShivanshu Shukla 	    fm_list->vsi_count == 0)
5442d54699e2STony Nguyen 		return -EINVAL;
54438bb98f33SShivanshu Shukla 
54448bb98f33SShivanshu Shukla 	/* A rule with the VSI being removed does not exist */
54458bb98f33SShivanshu Shukla 	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
5446d54699e2STony Nguyen 		return -ENOENT;
54478bb98f33SShivanshu Shukla 
54488bb98f33SShivanshu Shukla 	lkup_type = ICE_SW_LKUP_LAST;
54498bb98f33SShivanshu Shukla 	vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id;
54508bb98f33SShivanshu Shukla 	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
54518bb98f33SShivanshu Shukla 					  ice_aqc_opc_update_sw_rules,
54528bb98f33SShivanshu Shukla 					  lkup_type);
54538bb98f33SShivanshu Shukla 	if (status)
54548bb98f33SShivanshu Shukla 		return status;
54558bb98f33SShivanshu Shukla 
54568bb98f33SShivanshu Shukla 	fm_list->vsi_count--;
54578bb98f33SShivanshu Shukla 	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
54588bb98f33SShivanshu Shukla 	vsi_list_info = fm_list->vsi_list_info;
54598bb98f33SShivanshu Shukla 	if (fm_list->vsi_count == 1) {
54608bb98f33SShivanshu Shukla 		struct ice_fltr_info tmp_fltr;
54618bb98f33SShivanshu Shukla 		u16 rem_vsi_handle;
54628bb98f33SShivanshu Shukla 
54638bb98f33SShivanshu Shukla 		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
54648bb98f33SShivanshu Shukla 						ICE_MAX_VSI);
54658bb98f33SShivanshu Shukla 		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
5466d54699e2STony Nguyen 			return -EIO;
54678bb98f33SShivanshu Shukla 
54688bb98f33SShivanshu Shukla 		/* Make sure VSI list is empty before removing it below */
54698bb98f33SShivanshu Shukla 		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
54708bb98f33SShivanshu Shukla 						  vsi_list_id, true,
54718bb98f33SShivanshu Shukla 						  ice_aqc_opc_update_sw_rules,
54728bb98f33SShivanshu Shukla 						  lkup_type);
54738bb98f33SShivanshu Shukla 		if (status)
54748bb98f33SShivanshu Shukla 			return status;
54758bb98f33SShivanshu Shukla 
54768bb98f33SShivanshu Shukla 		memset(&tmp_fltr, 0, sizeof(tmp_fltr));
54778bb98f33SShivanshu Shukla 		tmp_fltr.flag = fm_list->rule_info.sw_act.flag;
54788bb98f33SShivanshu Shukla 		tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id;
54798bb98f33SShivanshu Shukla 		fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI;
54808bb98f33SShivanshu Shukla 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI;
54818bb98f33SShivanshu Shukla 		tmp_fltr.fwd_id.hw_vsi_id =
54828bb98f33SShivanshu Shukla 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
54838bb98f33SShivanshu Shukla 		fm_list->rule_info.sw_act.fwd_id.hw_vsi_id =
54848bb98f33SShivanshu Shukla 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
54858bb98f33SShivanshu Shukla 		fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle;
54868bb98f33SShivanshu Shukla 
54878bb98f33SShivanshu Shukla 		/* Update the previous switch rule of "MAC forward to VSI" to
54888bb98f33SShivanshu Shukla 		 * "MAC fwd to VSI list"
54898bb98f33SShivanshu Shukla 		 */
54908bb98f33SShivanshu Shukla 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
54918bb98f33SShivanshu Shukla 		if (status) {
54928bb98f33SShivanshu Shukla 			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
54938bb98f33SShivanshu Shukla 				  tmp_fltr.fwd_id.hw_vsi_id, status);
54948bb98f33SShivanshu Shukla 			return status;
54958bb98f33SShivanshu Shukla 		}
54968bb98f33SShivanshu Shukla 		fm_list->vsi_list_info->ref_cnt--;
54978bb98f33SShivanshu Shukla 
54988bb98f33SShivanshu Shukla 		/* Remove the VSI list since it is no longer used */
54998bb98f33SShivanshu Shukla 		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
55008bb98f33SShivanshu Shukla 		if (status) {
55018bb98f33SShivanshu Shukla 			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
55028bb98f33SShivanshu Shukla 				  vsi_list_id, status);
55038bb98f33SShivanshu Shukla 			return status;
55048bb98f33SShivanshu Shukla 		}
55058bb98f33SShivanshu Shukla 
55068bb98f33SShivanshu Shukla 		list_del(&vsi_list_info->list_entry);
55078bb98f33SShivanshu Shukla 		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
55088bb98f33SShivanshu Shukla 		fm_list->vsi_list_info = NULL;
55098bb98f33SShivanshu Shukla 	}
55108bb98f33SShivanshu Shukla 
55118bb98f33SShivanshu Shukla 	return status;
55128bb98f33SShivanshu Shukla }
55138bb98f33SShivanshu Shukla 
55148bb98f33SShivanshu Shukla /**
55158bb98f33SShivanshu Shukla  * ice_rem_adv_rule - removes existing advanced switch rule
55168bb98f33SShivanshu Shukla  * @hw: pointer to the hardware structure
55178bb98f33SShivanshu Shukla  * @lkups: information on the words that needs to be looked up. All words
55188bb98f33SShivanshu Shukla  *         together makes one recipe
55198bb98f33SShivanshu Shukla  * @lkups_cnt: num of entries in the lkups array
55208bb98f33SShivanshu Shukla  * @rinfo: Its the pointer to the rule information for the rule
55218bb98f33SShivanshu Shukla  *
55228bb98f33SShivanshu Shukla  * This function can be used to remove 1 rule at a time. The lkups is
55238bb98f33SShivanshu Shukla  * used to describe all the words that forms the "lookup" portion of the
55248bb98f33SShivanshu Shukla  * rule. These words can span multiple protocols. Callers to this function
55258bb98f33SShivanshu Shukla  * need to pass in a list of protocol headers with lookup information along
55268bb98f33SShivanshu Shukla  * and mask that determines which words are valid from the given protocol
55278bb98f33SShivanshu Shukla  * header. rinfo describes other information related to this rule such as
55288bb98f33SShivanshu Shukla  * forwarding IDs, priority of this rule, etc.
55298bb98f33SShivanshu Shukla  */
55305e24d598STony Nguyen static int
55318bb98f33SShivanshu Shukla ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
55328bb98f33SShivanshu Shukla 		 u16 lkups_cnt, struct ice_adv_rule_info *rinfo)
55338bb98f33SShivanshu Shukla {
55348bb98f33SShivanshu Shukla 	struct ice_adv_fltr_mgmt_list_entry *list_elem;
55358bb98f33SShivanshu Shukla 	struct ice_prot_lkup_ext lkup_exts;
55368bb98f33SShivanshu Shukla 	bool remove_rule = false;
55378bb98f33SShivanshu Shukla 	struct mutex *rule_lock; /* Lock to protect filter rule list */
55388bb98f33SShivanshu Shukla 	u16 i, rid, vsi_handle;
55395518ac2aSTony Nguyen 	int status = 0;
55408bb98f33SShivanshu Shukla 
55418bb98f33SShivanshu Shukla 	memset(&lkup_exts, 0, sizeof(lkup_exts));
55428bb98f33SShivanshu Shukla 	for (i = 0; i < lkups_cnt; i++) {
55438bb98f33SShivanshu Shukla 		u16 count;
55448bb98f33SShivanshu Shukla 
55458bb98f33SShivanshu Shukla 		if (lkups[i].type >= ICE_PROTOCOL_LAST)
5546d54699e2STony Nguyen 			return -EIO;
55478bb98f33SShivanshu Shukla 
55488bb98f33SShivanshu Shukla 		count = ice_fill_valid_words(&lkups[i], &lkup_exts);
55498bb98f33SShivanshu Shukla 		if (!count)
5550d54699e2STony Nguyen 			return -EIO;
55518bb98f33SShivanshu Shukla 	}
55528bb98f33SShivanshu Shukla 
55538b032a55SMichal Swiatkowski 	/* Create any special protocol/offset pairs, such as looking at tunnel
55548b032a55SMichal Swiatkowski 	 * bits by extracting metadata
55558b032a55SMichal Swiatkowski 	 */
55568b032a55SMichal Swiatkowski 	status = ice_add_special_words(rinfo, &lkup_exts);
55578b032a55SMichal Swiatkowski 	if (status)
55588b032a55SMichal Swiatkowski 		return status;
55598b032a55SMichal Swiatkowski 
5560de6acd1cSMichal Swiatkowski 	rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type);
55618bb98f33SShivanshu Shukla 	/* If did not find a recipe that match the existing criteria */
55628bb98f33SShivanshu Shukla 	if (rid == ICE_MAX_NUM_RECIPES)
5563d54699e2STony Nguyen 		return -EINVAL;
55648bb98f33SShivanshu Shukla 
55658bb98f33SShivanshu Shukla 	rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock;
55668bb98f33SShivanshu Shukla 	list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
55678bb98f33SShivanshu Shukla 	/* the rule is already removed */
55688bb98f33SShivanshu Shukla 	if (!list_elem)
55698bb98f33SShivanshu Shukla 		return 0;
55708bb98f33SShivanshu Shukla 	mutex_lock(rule_lock);
55718bb98f33SShivanshu Shukla 	if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) {
55728bb98f33SShivanshu Shukla 		remove_rule = true;
55738bb98f33SShivanshu Shukla 	} else if (list_elem->vsi_count > 1) {
55748bb98f33SShivanshu Shukla 		remove_rule = false;
55758bb98f33SShivanshu Shukla 		vsi_handle = rinfo->sw_act.vsi_handle;
55768bb98f33SShivanshu Shukla 		status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem);
55778bb98f33SShivanshu Shukla 	} else {
55788bb98f33SShivanshu Shukla 		vsi_handle = rinfo->sw_act.vsi_handle;
55798bb98f33SShivanshu Shukla 		status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem);
55808bb98f33SShivanshu Shukla 		if (status) {
55818bb98f33SShivanshu Shukla 			mutex_unlock(rule_lock);
55828bb98f33SShivanshu Shukla 			return status;
55838bb98f33SShivanshu Shukla 		}
55848bb98f33SShivanshu Shukla 		if (list_elem->vsi_count == 0)
55858bb98f33SShivanshu Shukla 			remove_rule = true;
55868bb98f33SShivanshu Shukla 	}
55878bb98f33SShivanshu Shukla 	mutex_unlock(rule_lock);
55888bb98f33SShivanshu Shukla 	if (remove_rule) {
55898bb98f33SShivanshu Shukla 		struct ice_aqc_sw_rules_elem *s_rule;
55908bb98f33SShivanshu Shukla 		u16 rule_buf_sz;
55918bb98f33SShivanshu Shukla 
55928bb98f33SShivanshu Shukla 		rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
55938bb98f33SShivanshu Shukla 		s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
55948bb98f33SShivanshu Shukla 		if (!s_rule)
5595d54699e2STony Nguyen 			return -ENOMEM;
55968bb98f33SShivanshu Shukla 		s_rule->pdata.lkup_tx_rx.act = 0;
55978bb98f33SShivanshu Shukla 		s_rule->pdata.lkup_tx_rx.index =
55988bb98f33SShivanshu Shukla 			cpu_to_le16(list_elem->rule_info.fltr_rule_id);
55998bb98f33SShivanshu Shukla 		s_rule->pdata.lkup_tx_rx.hdr_len = 0;
56008bb98f33SShivanshu Shukla 		status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
56018bb98f33SShivanshu Shukla 					 rule_buf_sz, 1,
56028bb98f33SShivanshu Shukla 					 ice_aqc_opc_remove_sw_rules, NULL);
5603d54699e2STony Nguyen 		if (!status || status == -ENOENT) {
56048bb98f33SShivanshu Shukla 			struct ice_switch_info *sw = hw->switch_info;
56058bb98f33SShivanshu Shukla 
56068bb98f33SShivanshu Shukla 			mutex_lock(rule_lock);
56078bb98f33SShivanshu Shukla 			list_del(&list_elem->list_entry);
56088bb98f33SShivanshu Shukla 			devm_kfree(ice_hw_to_dev(hw), list_elem->lkups);
56098bb98f33SShivanshu Shukla 			devm_kfree(ice_hw_to_dev(hw), list_elem);
56108bb98f33SShivanshu Shukla 			mutex_unlock(rule_lock);
56118bb98f33SShivanshu Shukla 			if (list_empty(&sw->recp_list[rid].filt_rules))
56128bb98f33SShivanshu Shukla 				sw->recp_list[rid].adv_rule = false;
56138bb98f33SShivanshu Shukla 		}
56148bb98f33SShivanshu Shukla 		kfree(s_rule);
56158bb98f33SShivanshu Shukla 	}
56168bb98f33SShivanshu Shukla 	return status;
56178bb98f33SShivanshu Shukla }
56188bb98f33SShivanshu Shukla 
56198bb98f33SShivanshu Shukla /**
56208bb98f33SShivanshu Shukla  * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID
56218bb98f33SShivanshu Shukla  * @hw: pointer to the hardware structure
56228bb98f33SShivanshu Shukla  * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID
56238bb98f33SShivanshu Shukla  *
56248bb98f33SShivanshu Shukla  * This function is used to remove 1 rule at a time. The removal is based on
56258bb98f33SShivanshu Shukla  * the remove_entry parameter. This function will remove rule for a given
56268bb98f33SShivanshu Shukla  * vsi_handle with a given rule_id which is passed as parameter in remove_entry
56278bb98f33SShivanshu Shukla  */
56285e24d598STony Nguyen int
56298bb98f33SShivanshu Shukla ice_rem_adv_rule_by_id(struct ice_hw *hw,
56308bb98f33SShivanshu Shukla 		       struct ice_rule_query_data *remove_entry)
56318bb98f33SShivanshu Shukla {
56328bb98f33SShivanshu Shukla 	struct ice_adv_fltr_mgmt_list_entry *list_itr;
56338bb98f33SShivanshu Shukla 	struct list_head *list_head;
56348bb98f33SShivanshu Shukla 	struct ice_adv_rule_info rinfo;
56358bb98f33SShivanshu Shukla 	struct ice_switch_info *sw;
56368bb98f33SShivanshu Shukla 
56378bb98f33SShivanshu Shukla 	sw = hw->switch_info;
56388bb98f33SShivanshu Shukla 	if (!sw->recp_list[remove_entry->rid].recp_created)
5639d54699e2STony Nguyen 		return -EINVAL;
56408bb98f33SShivanshu Shukla 	list_head = &sw->recp_list[remove_entry->rid].filt_rules;
56418bb98f33SShivanshu Shukla 	list_for_each_entry(list_itr, list_head, list_entry) {
56428bb98f33SShivanshu Shukla 		if (list_itr->rule_info.fltr_rule_id ==
56438bb98f33SShivanshu Shukla 		    remove_entry->rule_id) {
56448bb98f33SShivanshu Shukla 			rinfo = list_itr->rule_info;
56458bb98f33SShivanshu Shukla 			rinfo.sw_act.vsi_handle = remove_entry->vsi_handle;
56468bb98f33SShivanshu Shukla 			return ice_rem_adv_rule(hw, list_itr->lkups,
56478bb98f33SShivanshu Shukla 						list_itr->lkups_cnt, &rinfo);
56488bb98f33SShivanshu Shukla 		}
56498bb98f33SShivanshu Shukla 	}
56508bb98f33SShivanshu Shukla 	/* either list is empty or unable to find rule */
5651d54699e2STony Nguyen 	return -ENOENT;
56528bb98f33SShivanshu Shukla }
56538bb98f33SShivanshu Shukla 
56548bb98f33SShivanshu Shukla /**
5655c1e5da5dSWojciech Drewek  * ice_rem_adv_rule_for_vsi - removes existing advanced switch rules for a
5656c1e5da5dSWojciech Drewek  *                            given VSI handle
5657c1e5da5dSWojciech Drewek  * @hw: pointer to the hardware structure
5658c1e5da5dSWojciech Drewek  * @vsi_handle: VSI handle for which we are supposed to remove all the rules.
5659c1e5da5dSWojciech Drewek  *
5660c1e5da5dSWojciech Drewek  * This function is used to remove all the rules for a given VSI and as soon
5661c1e5da5dSWojciech Drewek  * as removing a rule fails, it will return immediately with the error code,
5662c1e5da5dSWojciech Drewek  * else it will return success.
5663c1e5da5dSWojciech Drewek  */
5664c1e5da5dSWojciech Drewek int ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle)
5665c1e5da5dSWojciech Drewek {
5666c1e5da5dSWojciech Drewek 	struct ice_adv_fltr_mgmt_list_entry *list_itr, *tmp_entry;
5667c1e5da5dSWojciech Drewek 	struct ice_vsi_list_map_info *map_info;
5668c1e5da5dSWojciech Drewek 	struct ice_adv_rule_info rinfo;
5669c1e5da5dSWojciech Drewek 	struct list_head *list_head;
5670c1e5da5dSWojciech Drewek 	struct ice_switch_info *sw;
5671c1e5da5dSWojciech Drewek 	int status;
5672c1e5da5dSWojciech Drewek 	u8 rid;
5673c1e5da5dSWojciech Drewek 
5674c1e5da5dSWojciech Drewek 	sw = hw->switch_info;
5675c1e5da5dSWojciech Drewek 	for (rid = 0; rid < ICE_MAX_NUM_RECIPES; rid++) {
5676c1e5da5dSWojciech Drewek 		if (!sw->recp_list[rid].recp_created)
5677c1e5da5dSWojciech Drewek 			continue;
5678c1e5da5dSWojciech Drewek 		if (!sw->recp_list[rid].adv_rule)
5679c1e5da5dSWojciech Drewek 			continue;
5680c1e5da5dSWojciech Drewek 
5681c1e5da5dSWojciech Drewek 		list_head = &sw->recp_list[rid].filt_rules;
5682c1e5da5dSWojciech Drewek 		list_for_each_entry_safe(list_itr, tmp_entry, list_head,
5683c1e5da5dSWojciech Drewek 					 list_entry) {
5684c1e5da5dSWojciech Drewek 			rinfo = list_itr->rule_info;
5685c1e5da5dSWojciech Drewek 
5686c1e5da5dSWojciech Drewek 			if (rinfo.sw_act.fltr_act == ICE_FWD_TO_VSI_LIST) {
5687c1e5da5dSWojciech Drewek 				map_info = list_itr->vsi_list_info;
5688c1e5da5dSWojciech Drewek 				if (!map_info)
5689c1e5da5dSWojciech Drewek 					continue;
5690c1e5da5dSWojciech Drewek 
5691c1e5da5dSWojciech Drewek 				if (!test_bit(vsi_handle, map_info->vsi_map))
5692c1e5da5dSWojciech Drewek 					continue;
5693c1e5da5dSWojciech Drewek 			} else if (rinfo.sw_act.vsi_handle != vsi_handle) {
5694c1e5da5dSWojciech Drewek 				continue;
5695c1e5da5dSWojciech Drewek 			}
5696c1e5da5dSWojciech Drewek 
5697c1e5da5dSWojciech Drewek 			rinfo.sw_act.vsi_handle = vsi_handle;
5698c1e5da5dSWojciech Drewek 			status = ice_rem_adv_rule(hw, list_itr->lkups,
5699c1e5da5dSWojciech Drewek 						  list_itr->lkups_cnt, &rinfo);
5700c1e5da5dSWojciech Drewek 			if (status)
5701c1e5da5dSWojciech Drewek 				return status;
5702c1e5da5dSWojciech Drewek 		}
5703c1e5da5dSWojciech Drewek 	}
5704c1e5da5dSWojciech Drewek 	return 0;
5705c1e5da5dSWojciech Drewek }
5706c1e5da5dSWojciech Drewek 
5707c1e5da5dSWojciech Drewek /**
5708c36a2b97SVictor Raj  * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI
5709c36a2b97SVictor Raj  * @hw: pointer to the hardware structure
5710c36a2b97SVictor Raj  * @vsi_handle: driver VSI handle
5711c36a2b97SVictor Raj  * @list_head: list for which filters need to be replayed
5712c36a2b97SVictor Raj  *
5713c36a2b97SVictor Raj  * Replay the advanced rule for the given VSI.
5714c36a2b97SVictor Raj  */
5715c36a2b97SVictor Raj static int
5716c36a2b97SVictor Raj ice_replay_vsi_adv_rule(struct ice_hw *hw, u16 vsi_handle,
5717c36a2b97SVictor Raj 			struct list_head *list_head)
5718c36a2b97SVictor Raj {
5719c36a2b97SVictor Raj 	struct ice_rule_query_data added_entry = { 0 };
5720c36a2b97SVictor Raj 	struct ice_adv_fltr_mgmt_list_entry *adv_fltr;
5721c36a2b97SVictor Raj 	int status = 0;
5722c36a2b97SVictor Raj 
5723c36a2b97SVictor Raj 	if (list_empty(list_head))
5724c36a2b97SVictor Raj 		return status;
5725c36a2b97SVictor Raj 	list_for_each_entry(adv_fltr, list_head, list_entry) {
5726c36a2b97SVictor Raj 		struct ice_adv_rule_info *rinfo = &adv_fltr->rule_info;
5727c36a2b97SVictor Raj 		u16 lk_cnt = adv_fltr->lkups_cnt;
5728c36a2b97SVictor Raj 
5729c36a2b97SVictor Raj 		if (vsi_handle != rinfo->sw_act.vsi_handle)
5730c36a2b97SVictor Raj 			continue;
5731c36a2b97SVictor Raj 		status = ice_add_adv_rule(hw, adv_fltr->lkups, lk_cnt, rinfo,
5732c36a2b97SVictor Raj 					  &added_entry);
5733c36a2b97SVictor Raj 		if (status)
5734c36a2b97SVictor Raj 			break;
5735c36a2b97SVictor Raj 	}
5736c36a2b97SVictor Raj 	return status;
5737c36a2b97SVictor Raj }
5738c36a2b97SVictor Raj 
5739c36a2b97SVictor Raj /**
5740334cb062SAnirudh Venkataramanan  * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists
57410f9d5027SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
5742334cb062SAnirudh Venkataramanan  * @vsi_handle: driver VSI handle
57430f9d5027SAnirudh Venkataramanan  *
5744334cb062SAnirudh Venkataramanan  * Replays filters for requested VSI via vsi_handle.
57450f9d5027SAnirudh Venkataramanan  */
57465e24d598STony Nguyen int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle)
57470f9d5027SAnirudh Venkataramanan {
57480f9d5027SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
5749c36a2b97SVictor Raj 	int status;
57500f9d5027SAnirudh Venkataramanan 	u8 i;
57510f9d5027SAnirudh Venkataramanan 
5752c36a2b97SVictor Raj 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
5753334cb062SAnirudh Venkataramanan 		struct list_head *head;
57540f9d5027SAnirudh Venkataramanan 
5755334cb062SAnirudh Venkataramanan 		head = &sw->recp_list[i].filt_replay_rules;
5756c36a2b97SVictor Raj 		if (!sw->recp_list[i].adv_rule)
5757334cb062SAnirudh Venkataramanan 			status = ice_replay_vsi_fltr(hw, vsi_handle, i, head);
5758c36a2b97SVictor Raj 		else
5759c36a2b97SVictor Raj 			status = ice_replay_vsi_adv_rule(hw, vsi_handle, head);
57600f9d5027SAnirudh Venkataramanan 		if (status)
57610f9d5027SAnirudh Venkataramanan 			return status;
57620f9d5027SAnirudh Venkataramanan 	}
57630f9d5027SAnirudh Venkataramanan 	return status;
57640f9d5027SAnirudh Venkataramanan }
5765334cb062SAnirudh Venkataramanan 
5766334cb062SAnirudh Venkataramanan /**
5767334cb062SAnirudh Venkataramanan  * ice_rm_all_sw_replay_rule_info - deletes filter replay rules
5768f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5769334cb062SAnirudh Venkataramanan  *
5770334cb062SAnirudh Venkataramanan  * Deletes the filter replay rules.
5771334cb062SAnirudh Venkataramanan  */
5772334cb062SAnirudh Venkataramanan void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)
5773334cb062SAnirudh Venkataramanan {
5774334cb062SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
5775334cb062SAnirudh Venkataramanan 	u8 i;
5776334cb062SAnirudh Venkataramanan 
5777334cb062SAnirudh Venkataramanan 	if (!sw)
5778334cb062SAnirudh Venkataramanan 		return;
5779334cb062SAnirudh Venkataramanan 
57808b8ef05bSVictor Raj 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
5781334cb062SAnirudh Venkataramanan 		if (!list_empty(&sw->recp_list[i].filt_replay_rules)) {
5782334cb062SAnirudh Venkataramanan 			struct list_head *l_head;
5783334cb062SAnirudh Venkataramanan 
5784334cb062SAnirudh Venkataramanan 			l_head = &sw->recp_list[i].filt_replay_rules;
57858b8ef05bSVictor Raj 			if (!sw->recp_list[i].adv_rule)
5786334cb062SAnirudh Venkataramanan 				ice_rem_sw_rule_info(hw, l_head);
57878b8ef05bSVictor Raj 			else
57888b8ef05bSVictor Raj 				ice_rem_adv_rule_info(hw, l_head);
5789334cb062SAnirudh Venkataramanan 		}
5790334cb062SAnirudh Venkataramanan 	}
5791334cb062SAnirudh Venkataramanan }
5792