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 
380f94570dSGrishma Kotecha /* offset info for MAC + IPv4 + UDP dummy packet */
390f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_udp_packet_offsets[] = {
400f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
410f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
420f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	14 },
430f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		34 },
440f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
450f94570dSGrishma Kotecha };
460f94570dSGrishma Kotecha 
470f94570dSGrishma Kotecha /* Dummy packet for MAC + IPv4 + UDP */
480f94570dSGrishma Kotecha static const u8 dummy_udp_packet[] = {
490f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
500f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
510f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
520f94570dSGrishma Kotecha 
530f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
540f94570dSGrishma Kotecha 
550f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 14 */
560f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
570f94570dSGrishma Kotecha 	0x00, 0x11, 0x00, 0x00,
580f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
590f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
600f94570dSGrishma Kotecha 
610f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 34 */
620f94570dSGrishma Kotecha 	0x00, 0x08, 0x00, 0x00,
630f94570dSGrishma Kotecha 
640f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
650f94570dSGrishma Kotecha };
660f94570dSGrishma Kotecha 
670f94570dSGrishma Kotecha /* offset info for MAC + VLAN + IPv4 + UDP dummy packet */
680f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_vlan_udp_packet_offsets[] = {
690f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
700f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
710f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
720f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	18 },
730f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		38 },
740f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
750f94570dSGrishma Kotecha };
760f94570dSGrishma Kotecha 
770f94570dSGrishma Kotecha /* C-tag (801.1Q), IPv4:UDP dummy packet */
780f94570dSGrishma Kotecha static const u8 dummy_vlan_udp_packet[] = {
790f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
800f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
810f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
820f94570dSGrishma Kotecha 
830f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
840f94570dSGrishma Kotecha 
850f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 16 */
860f94570dSGrishma Kotecha 
870f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 18 */
880f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
890f94570dSGrishma Kotecha 	0x00, 0x11, 0x00, 0x00,
900f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
910f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
920f94570dSGrishma Kotecha 
930f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 38 */
940f94570dSGrishma Kotecha 	0x00, 0x08, 0x00, 0x00,
950f94570dSGrishma Kotecha 
960f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
970f94570dSGrishma Kotecha };
980f94570dSGrishma Kotecha 
990f94570dSGrishma Kotecha /* offset info for MAC + IPv4 + TCP dummy packet */
1000f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_tcp_packet_offsets[] = {
1010f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
1020f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
1030f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	14 },
1040f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		34 },
1050f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
1060f94570dSGrishma Kotecha };
1070f94570dSGrishma Kotecha 
1080f94570dSGrishma Kotecha /* Dummy packet for MAC + IPv4 + TCP */
1090f94570dSGrishma Kotecha static const u8 dummy_tcp_packet[] = {
1100f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
1110f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1120f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1130f94570dSGrishma Kotecha 
1140f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 12 */
1150f94570dSGrishma Kotecha 
1160f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 14 */
1170f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
1180f94570dSGrishma Kotecha 	0x00, 0x06, 0x00, 0x00,
1190f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1200f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1210f94570dSGrishma Kotecha 
1220f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 34 */
1230f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1240f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1250f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
1260f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1270f94570dSGrishma Kotecha 
1280f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
1290f94570dSGrishma Kotecha };
1300f94570dSGrishma Kotecha 
1310f94570dSGrishma Kotecha /* offset info for MAC + VLAN (C-tag, 802.1Q) + IPv4 + TCP dummy packet */
1320f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_vlan_tcp_packet_offsets[] = {
1330f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
1340f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
1350f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
1360f94570dSGrishma Kotecha 	{ ICE_IPV4_OFOS,	18 },
1370f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		38 },
1380f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
1390f94570dSGrishma Kotecha };
1400f94570dSGrishma Kotecha 
1410f94570dSGrishma Kotecha /* C-tag (801.1Q), IPv4:TCP dummy packet */
1420f94570dSGrishma Kotecha static const u8 dummy_vlan_tcp_packet[] = {
1430f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
1440f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1450f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1460f94570dSGrishma Kotecha 
1470f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00,	/* ICE_VLAN_OFOS 12 */
1480f94570dSGrishma Kotecha 
1490f94570dSGrishma Kotecha 	0x08, 0x00,		/* ICE_ETYPE_OL 16 */
1500f94570dSGrishma Kotecha 
1510f94570dSGrishma Kotecha 	0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 18 */
1520f94570dSGrishma Kotecha 	0x00, 0x01, 0x00, 0x00,
1530f94570dSGrishma Kotecha 	0x00, 0x06, 0x00, 0x00,
1540f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1550f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1560f94570dSGrishma Kotecha 
1570f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 38 */
1580f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1590f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1600f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
1610f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1620f94570dSGrishma Kotecha 
1630f94570dSGrishma Kotecha 	0x00, 0x00,	/* 2 bytes for 4 byte alignment */
1640f94570dSGrishma Kotecha };
1650f94570dSGrishma Kotecha 
1660f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_tcp_ipv6_packet_offsets[] = {
1670f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
1680f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
1690f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	14 },
1700f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		54 },
1710f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
1720f94570dSGrishma Kotecha };
1730f94570dSGrishma Kotecha 
1740f94570dSGrishma Kotecha static const u8 dummy_tcp_ipv6_packet[] = {
1750f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
1760f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1770f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1780f94570dSGrishma Kotecha 
1790f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
1800f94570dSGrishma Kotecha 
1810f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */
1820f94570dSGrishma Kotecha 	0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
1830f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1840f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1850f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1860f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1870f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1880f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1890f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1900f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1910f94570dSGrishma Kotecha 
1920f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 54 */
1930f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1940f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1950f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
1960f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
1970f94570dSGrishma Kotecha 
1980f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
1990f94570dSGrishma Kotecha };
2000f94570dSGrishma Kotecha 
2010f94570dSGrishma Kotecha /* C-tag (802.1Q): IPv6 + TCP */
2020f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets
2030f94570dSGrishma Kotecha dummy_vlan_tcp_ipv6_packet_offsets[] = {
2040f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
2050f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
2060f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
2070f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	18 },
2080f94570dSGrishma Kotecha 	{ ICE_TCP_IL,		58 },
2090f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
2100f94570dSGrishma Kotecha };
2110f94570dSGrishma Kotecha 
2120f94570dSGrishma Kotecha /* C-tag (802.1Q), IPv6 + TCP dummy packet */
2130f94570dSGrishma Kotecha static const u8 dummy_vlan_tcp_ipv6_packet[] = {
2140f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
2150f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2160f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2170f94570dSGrishma Kotecha 
2180f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00,	/* ICE_VLAN_OFOS 12 */
2190f94570dSGrishma Kotecha 
2200f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 16 */
2210f94570dSGrishma Kotecha 
2220f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */
2230f94570dSGrishma Kotecha 	0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
2240f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2250f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2260f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2270f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2280f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2290f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2300f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2310f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2320f94570dSGrishma Kotecha 
2330f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 58 */
2340f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2350f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2360f94570dSGrishma Kotecha 	0x50, 0x00, 0x00, 0x00,
2370f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2380f94570dSGrishma Kotecha 
2390f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
2400f94570dSGrishma Kotecha };
2410f94570dSGrishma Kotecha 
2420f94570dSGrishma Kotecha /* IPv6 + UDP */
2430f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_udp_ipv6_packet_offsets[] = {
2440f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
2450f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		12 },
2460f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	14 },
2470f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		54 },
2480f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
2490f94570dSGrishma Kotecha };
2500f94570dSGrishma Kotecha 
2510f94570dSGrishma Kotecha /* IPv6 + UDP dummy packet */
2520f94570dSGrishma Kotecha static const u8 dummy_udp_ipv6_packet[] = {
2530f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
2540f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2550f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2560f94570dSGrishma Kotecha 
2570f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 12 */
2580f94570dSGrishma Kotecha 
2590f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */
2600f94570dSGrishma Kotecha 	0x00, 0x10, 0x11, 0x00, /* Next header UDP */
2610f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2620f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2630f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2640f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2650f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2660f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2670f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2680f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2690f94570dSGrishma Kotecha 
2700f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 54 */
2710f94570dSGrishma Kotecha 	0x00, 0x10, 0x00, 0x00,
2720f94570dSGrishma Kotecha 
2730f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* needed for ESP packets */
2740f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2750f94570dSGrishma Kotecha 
2760f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
2770f94570dSGrishma Kotecha };
2780f94570dSGrishma Kotecha 
2790f94570dSGrishma Kotecha /* C-tag (802.1Q): IPv6 + UDP */
2800f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets
2810f94570dSGrishma Kotecha dummy_vlan_udp_ipv6_packet_offsets[] = {
2820f94570dSGrishma Kotecha 	{ ICE_MAC_OFOS,		0 },
2830f94570dSGrishma Kotecha 	{ ICE_VLAN_OFOS,	12 },
2840f94570dSGrishma Kotecha 	{ ICE_ETYPE_OL,		16 },
2850f94570dSGrishma Kotecha 	{ ICE_IPV6_OFOS,	18 },
2860f94570dSGrishma Kotecha 	{ ICE_UDP_ILOS,		58 },
2870f94570dSGrishma Kotecha 	{ ICE_PROTOCOL_LAST,	0 },
2880f94570dSGrishma Kotecha };
2890f94570dSGrishma Kotecha 
2900f94570dSGrishma Kotecha /* C-tag (802.1Q), IPv6 + UDP dummy packet */
2910f94570dSGrishma Kotecha static const u8 dummy_vlan_udp_ipv6_packet[] = {
2920f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
2930f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2940f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
2950f94570dSGrishma Kotecha 
2960f94570dSGrishma Kotecha 	0x81, 0x00, 0x00, 0x00,/* ICE_VLAN_OFOS 12 */
2970f94570dSGrishma Kotecha 
2980f94570dSGrishma Kotecha 	0x86, 0xDD,		/* ICE_ETYPE_OL 16 */
2990f94570dSGrishma Kotecha 
3000f94570dSGrishma Kotecha 	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */
3010f94570dSGrishma Kotecha 	0x00, 0x08, 0x11, 0x00, /* Next header UDP */
3020f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3030f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3040f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3050f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3060f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3070f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3080f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3090f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00,
3100f94570dSGrishma Kotecha 
3110f94570dSGrishma Kotecha 	0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 58 */
3120f94570dSGrishma Kotecha 	0x00, 0x08, 0x00, 0x00,
3130f94570dSGrishma Kotecha 
3140f94570dSGrishma Kotecha 	0x00, 0x00, /* 2 bytes for 4 byte alignment */
3150f94570dSGrishma Kotecha };
3160f94570dSGrishma Kotecha 
3179daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE \
31866486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr) + \
31966486d89SBruce Allan 	 (DUMMY_ETH_HDR_LEN * \
32066486d89SBruce Allan 	  sizeof(((struct ice_sw_rule_lkup_rx_tx *)0)->hdr[0])))
3219daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_RX_TX_NO_HDR_SIZE \
32266486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr))
3239daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_LG_ACT_SIZE(n) \
32466486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lg_act.act) + \
32566486d89SBruce Allan 	 ((n) * sizeof(((struct ice_sw_rule_lg_act *)0)->act[0])))
3269daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_VSI_LIST_SIZE(n) \
32766486d89SBruce Allan 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.vsi_list.vsi) + \
32866486d89SBruce Allan 	 ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi[0])))
3299daf8208SAnirudh Venkataramanan 
330fd2a6b71SDan Nowlin /* this is a recipe to profile association bitmap */
331fd2a6b71SDan Nowlin static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES],
332fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_PROFILES);
333fd2a6b71SDan Nowlin 
334fd2a6b71SDan Nowlin /* this is a profile to recipe association bitmap */
335fd2a6b71SDan Nowlin static DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES],
336fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_RECIPES);
337fd2a6b71SDan Nowlin 
3389daf8208SAnirudh Venkataramanan /**
33980d144c9SAnirudh Venkataramanan  * ice_init_def_sw_recp - initialize the recipe book keeping tables
340f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
34180d144c9SAnirudh Venkataramanan  *
34280d144c9SAnirudh Venkataramanan  * Allocate memory for the entire recipe table and initialize the structures/
34380d144c9SAnirudh Venkataramanan  * entries corresponding to basic recipes.
34480d144c9SAnirudh Venkataramanan  */
3452c5492deSBruce Allan enum ice_status ice_init_def_sw_recp(struct ice_hw *hw)
34680d144c9SAnirudh Venkataramanan {
34780d144c9SAnirudh Venkataramanan 	struct ice_sw_recipe *recps;
34880d144c9SAnirudh Venkataramanan 	u8 i;
34980d144c9SAnirudh Venkataramanan 
35080d144c9SAnirudh Venkataramanan 	recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES,
351c6dfd690SBruce Allan 			     sizeof(*recps), GFP_KERNEL);
35280d144c9SAnirudh Venkataramanan 	if (!recps)
35380d144c9SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
35480d144c9SAnirudh Venkataramanan 
355450052a4SDan Nowlin 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
35680d144c9SAnirudh Venkataramanan 		recps[i].root_rid = i;
35780d144c9SAnirudh Venkataramanan 		INIT_LIST_HEAD(&recps[i].filt_rules);
358334cb062SAnirudh Venkataramanan 		INIT_LIST_HEAD(&recps[i].filt_replay_rules);
359450052a4SDan Nowlin 		INIT_LIST_HEAD(&recps[i].rg_list);
36080d144c9SAnirudh Venkataramanan 		mutex_init(&recps[i].filt_rule_lock);
36180d144c9SAnirudh Venkataramanan 	}
36280d144c9SAnirudh Venkataramanan 
36380d144c9SAnirudh Venkataramanan 	hw->switch_info->recp_list = recps;
36480d144c9SAnirudh Venkataramanan 
36580d144c9SAnirudh Venkataramanan 	return 0;
36680d144c9SAnirudh Venkataramanan }
36780d144c9SAnirudh Venkataramanan 
36880d144c9SAnirudh Venkataramanan /**
3699c20346bSAnirudh Venkataramanan  * ice_aq_get_sw_cfg - get switch configuration
3709c20346bSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
3719c20346bSAnirudh Venkataramanan  * @buf: pointer to the result buffer
3729c20346bSAnirudh Venkataramanan  * @buf_size: length of the buffer available for response
3739c20346bSAnirudh Venkataramanan  * @req_desc: pointer to requested descriptor
3749c20346bSAnirudh Venkataramanan  * @num_elems: pointer to number of elements
3759c20346bSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
3769c20346bSAnirudh Venkataramanan  *
377b3c38904SBruce Allan  * Get switch configuration (0x0200) to be placed in buf.
3789c20346bSAnirudh Venkataramanan  * This admin command returns information such as initial VSI/port number
3799c20346bSAnirudh Venkataramanan  * and switch ID it belongs to.
3809c20346bSAnirudh Venkataramanan  *
3819c20346bSAnirudh Venkataramanan  * NOTE: *req_desc is both an input/output parameter.
3829c20346bSAnirudh Venkataramanan  * The caller of this function first calls this function with *request_desc set
3839c20346bSAnirudh Venkataramanan  * to 0. If the response from f/w has *req_desc set to 0, all the switch
3849c20346bSAnirudh Venkataramanan  * configuration information has been returned; if non-zero (meaning not all
3859c20346bSAnirudh Venkataramanan  * the information was returned), the caller should call this function again
3869c20346bSAnirudh Venkataramanan  * with *req_desc set to the previous value returned by f/w to get the
3879c20346bSAnirudh Venkataramanan  * next block of switch configuration information.
3889c20346bSAnirudh Venkataramanan  *
3899c20346bSAnirudh Venkataramanan  * *num_elems is output only parameter. This reflects the number of elements
3909c20346bSAnirudh Venkataramanan  * in response buffer. The caller of this function to use *num_elems while
3919c20346bSAnirudh Venkataramanan  * parsing the response buffer.
3929c20346bSAnirudh Venkataramanan  */
3939c20346bSAnirudh Venkataramanan static enum ice_status
394b3c38904SBruce Allan ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf,
3959c20346bSAnirudh Venkataramanan 		  u16 buf_size, u16 *req_desc, u16 *num_elems,
3969c20346bSAnirudh Venkataramanan 		  struct ice_sq_cd *cd)
3979c20346bSAnirudh Venkataramanan {
3989c20346bSAnirudh Venkataramanan 	struct ice_aqc_get_sw_cfg *cmd;
3999c20346bSAnirudh Venkataramanan 	struct ice_aq_desc desc;
400b3c38904SBruce Allan 	enum ice_status status;
4019c20346bSAnirudh Venkataramanan 
4029c20346bSAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);
4039c20346bSAnirudh Venkataramanan 	cmd = &desc.params.get_sw_conf;
4049c20346bSAnirudh Venkataramanan 	cmd->element = cpu_to_le16(*req_desc);
4059c20346bSAnirudh Venkataramanan 
4069c20346bSAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
4079c20346bSAnirudh Venkataramanan 	if (!status) {
4089c20346bSAnirudh Venkataramanan 		*req_desc = le16_to_cpu(cmd->element);
4099c20346bSAnirudh Venkataramanan 		*num_elems = le16_to_cpu(cmd->num_elems);
4109c20346bSAnirudh Venkataramanan 	}
4119c20346bSAnirudh Venkataramanan 
4129c20346bSAnirudh Venkataramanan 	return status;
4139c20346bSAnirudh Venkataramanan }
4149c20346bSAnirudh Venkataramanan 
4153a858ba3SAnirudh Venkataramanan /**
4163a858ba3SAnirudh Venkataramanan  * ice_aq_add_vsi
417f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4183a858ba3SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
4193a858ba3SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4203a858ba3SAnirudh Venkataramanan  *
4213a858ba3SAnirudh Venkataramanan  * Add a VSI context to the hardware (0x0210)
4223a858ba3SAnirudh Venkataramanan  */
4230f9d5027SAnirudh Venkataramanan static enum ice_status
4243a858ba3SAnirudh Venkataramanan ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
4253a858ba3SAnirudh Venkataramanan 	       struct ice_sq_cd *cd)
4263a858ba3SAnirudh Venkataramanan {
4273a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_update_free_vsi_resp *res;
4283a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_get_update_free_vsi *cmd;
4293a858ba3SAnirudh Venkataramanan 	struct ice_aq_desc desc;
4300f9d5027SAnirudh Venkataramanan 	enum ice_status status;
4313a858ba3SAnirudh Venkataramanan 
4323a858ba3SAnirudh Venkataramanan 	cmd = &desc.params.vsi_cmd;
4330f9d5027SAnirudh Venkataramanan 	res = &desc.params.add_update_free_vsi_res;
4343a858ba3SAnirudh Venkataramanan 
4353a858ba3SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);
4363a858ba3SAnirudh Venkataramanan 
4373a858ba3SAnirudh Venkataramanan 	if (!vsi_ctx->alloc_from_pool)
4383a858ba3SAnirudh Venkataramanan 		cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num |
4393a858ba3SAnirudh Venkataramanan 					   ICE_AQ_VSI_IS_VALID);
4401071a835SAnirudh Venkataramanan 	cmd->vf_id = vsi_ctx->vf_num;
4413a858ba3SAnirudh Venkataramanan 
4423a858ba3SAnirudh Venkataramanan 	cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags);
4433a858ba3SAnirudh Venkataramanan 
4443a858ba3SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
4453a858ba3SAnirudh Venkataramanan 
4463a858ba3SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
4473a858ba3SAnirudh Venkataramanan 				 sizeof(vsi_ctx->info), cd);
4483a858ba3SAnirudh Venkataramanan 
4493a858ba3SAnirudh Venkataramanan 	if (!status) {
4503a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M;
4513a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used);
4523a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free);
4533a858ba3SAnirudh Venkataramanan 	}
4543a858ba3SAnirudh Venkataramanan 
4553a858ba3SAnirudh Venkataramanan 	return status;
4563a858ba3SAnirudh Venkataramanan }
4573a858ba3SAnirudh Venkataramanan 
4583a858ba3SAnirudh Venkataramanan /**
4590f9d5027SAnirudh Venkataramanan  * ice_aq_free_vsi
460f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4610f9d5027SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
4620f9d5027SAnirudh Venkataramanan  * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
4630f9d5027SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4640f9d5027SAnirudh Venkataramanan  *
4650f9d5027SAnirudh Venkataramanan  * Free VSI context info from hardware (0x0213)
4660f9d5027SAnirudh Venkataramanan  */
4670f9d5027SAnirudh Venkataramanan static enum ice_status
4680f9d5027SAnirudh Venkataramanan ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
4690f9d5027SAnirudh Venkataramanan 		bool keep_vsi_alloc, struct ice_sq_cd *cd)
4700f9d5027SAnirudh Venkataramanan {
4710f9d5027SAnirudh Venkataramanan 	struct ice_aqc_add_update_free_vsi_resp *resp;
4720f9d5027SAnirudh Venkataramanan 	struct ice_aqc_add_get_update_free_vsi *cmd;
4730f9d5027SAnirudh Venkataramanan 	struct ice_aq_desc desc;
4740f9d5027SAnirudh Venkataramanan 	enum ice_status status;
4750f9d5027SAnirudh Venkataramanan 
4760f9d5027SAnirudh Venkataramanan 	cmd = &desc.params.vsi_cmd;
4770f9d5027SAnirudh Venkataramanan 	resp = &desc.params.add_update_free_vsi_res;
4780f9d5027SAnirudh Venkataramanan 
4790f9d5027SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
4800f9d5027SAnirudh Venkataramanan 
4810f9d5027SAnirudh Venkataramanan 	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
4820f9d5027SAnirudh Venkataramanan 	if (keep_vsi_alloc)
4830f9d5027SAnirudh Venkataramanan 		cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);
4840f9d5027SAnirudh Venkataramanan 
4850f9d5027SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
4860f9d5027SAnirudh Venkataramanan 	if (!status) {
4870f9d5027SAnirudh Venkataramanan 		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
4880f9d5027SAnirudh Venkataramanan 		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
4890f9d5027SAnirudh Venkataramanan 	}
4900f9d5027SAnirudh Venkataramanan 
4910f9d5027SAnirudh Venkataramanan 	return status;
4920f9d5027SAnirudh Venkataramanan }
4930f9d5027SAnirudh Venkataramanan 
4940f9d5027SAnirudh Venkataramanan /**
4953a858ba3SAnirudh Venkataramanan  * ice_aq_update_vsi
496f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4973a858ba3SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
4983a858ba3SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4993a858ba3SAnirudh Venkataramanan  *
5003a858ba3SAnirudh Venkataramanan  * Update VSI context in the hardware (0x0211)
5013a858ba3SAnirudh Venkataramanan  */
5025726ca0eSAnirudh Venkataramanan static enum ice_status
5033a858ba3SAnirudh Venkataramanan ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
5043a858ba3SAnirudh Venkataramanan 		  struct ice_sq_cd *cd)
5053a858ba3SAnirudh Venkataramanan {
5063a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_update_free_vsi_resp *resp;
5073a858ba3SAnirudh Venkataramanan 	struct ice_aqc_add_get_update_free_vsi *cmd;
5083a858ba3SAnirudh Venkataramanan 	struct ice_aq_desc desc;
5093a858ba3SAnirudh Venkataramanan 	enum ice_status status;
5103a858ba3SAnirudh Venkataramanan 
5113a858ba3SAnirudh Venkataramanan 	cmd = &desc.params.vsi_cmd;
5120f9d5027SAnirudh Venkataramanan 	resp = &desc.params.add_update_free_vsi_res;
5133a858ba3SAnirudh Venkataramanan 
5143a858ba3SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);
5153a858ba3SAnirudh Venkataramanan 
5163a858ba3SAnirudh Venkataramanan 	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
5173a858ba3SAnirudh Venkataramanan 
5183a858ba3SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
5193a858ba3SAnirudh Venkataramanan 
5203a858ba3SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
5213a858ba3SAnirudh Venkataramanan 				 sizeof(vsi_ctx->info), cd);
5223a858ba3SAnirudh Venkataramanan 
5233a858ba3SAnirudh Venkataramanan 	if (!status) {
5243a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
5253a858ba3SAnirudh Venkataramanan 		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
5263a858ba3SAnirudh Venkataramanan 	}
5273a858ba3SAnirudh Venkataramanan 
5283a858ba3SAnirudh Venkataramanan 	return status;
5293a858ba3SAnirudh Venkataramanan }
5303a858ba3SAnirudh Venkataramanan 
5313a858ba3SAnirudh Venkataramanan /**
5320f9d5027SAnirudh Venkataramanan  * ice_is_vsi_valid - check whether the VSI is valid or not
533f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5340f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
5350f9d5027SAnirudh Venkataramanan  *
5360f9d5027SAnirudh Venkataramanan  * check whether the VSI is valid or not
5370f9d5027SAnirudh Venkataramanan  */
5384fb33f31SAnirudh Venkataramanan bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)
5390f9d5027SAnirudh Venkataramanan {
5400f9d5027SAnirudh Venkataramanan 	return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];
5410f9d5027SAnirudh Venkataramanan }
5420f9d5027SAnirudh Venkataramanan 
5430f9d5027SAnirudh Venkataramanan /**
544f9867df6SAnirudh Venkataramanan  * ice_get_hw_vsi_num - return the HW VSI number
545f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5460f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
5470f9d5027SAnirudh Venkataramanan  *
548f9867df6SAnirudh Venkataramanan  * return the HW VSI number
5490f9d5027SAnirudh Venkataramanan  * Caution: call this function only if VSI is valid (ice_is_vsi_valid)
5500f9d5027SAnirudh Venkataramanan  */
5514fb33f31SAnirudh Venkataramanan u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)
5520f9d5027SAnirudh Venkataramanan {
5530f9d5027SAnirudh Venkataramanan 	return hw->vsi_ctx[vsi_handle]->vsi_num;
5540f9d5027SAnirudh Venkataramanan }
5550f9d5027SAnirudh Venkataramanan 
5560f9d5027SAnirudh Venkataramanan /**
5570f9d5027SAnirudh Venkataramanan  * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle
558f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5590f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
5600f9d5027SAnirudh Venkataramanan  *
5610f9d5027SAnirudh Venkataramanan  * return the VSI context entry for a given VSI handle
5620f9d5027SAnirudh Venkataramanan  */
5634fb33f31SAnirudh Venkataramanan struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
5640f9d5027SAnirudh Venkataramanan {
5650f9d5027SAnirudh Venkataramanan 	return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];
5660f9d5027SAnirudh Venkataramanan }
5670f9d5027SAnirudh Venkataramanan 
5680f9d5027SAnirudh Venkataramanan /**
5690f9d5027SAnirudh Venkataramanan  * ice_save_vsi_ctx - save the VSI context for a given VSI handle
570f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5710f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
5720f9d5027SAnirudh Venkataramanan  * @vsi: VSI context pointer
5730f9d5027SAnirudh Venkataramanan  *
5740f9d5027SAnirudh Venkataramanan  * save the VSI context entry for a given VSI handle
5750f9d5027SAnirudh Venkataramanan  */
576c8b7abddSBruce Allan static void
577c8b7abddSBruce Allan ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)
5780f9d5027SAnirudh Venkataramanan {
5790f9d5027SAnirudh Venkataramanan 	hw->vsi_ctx[vsi_handle] = vsi;
5800f9d5027SAnirudh Venkataramanan }
5810f9d5027SAnirudh Venkataramanan 
5820f9d5027SAnirudh Venkataramanan /**
583bb87ee0eSAnirudh Venkataramanan  * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs
584bb87ee0eSAnirudh Venkataramanan  * @hw: pointer to the HW struct
585bb87ee0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle
586bb87ee0eSAnirudh Venkataramanan  */
587bb87ee0eSAnirudh Venkataramanan static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
588bb87ee0eSAnirudh Venkataramanan {
589bb87ee0eSAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi;
590bb87ee0eSAnirudh Venkataramanan 	u8 i;
591bb87ee0eSAnirudh Venkataramanan 
592bb87ee0eSAnirudh Venkataramanan 	vsi = ice_get_vsi_ctx(hw, vsi_handle);
593bb87ee0eSAnirudh Venkataramanan 	if (!vsi)
594bb87ee0eSAnirudh Venkataramanan 		return;
595bb87ee0eSAnirudh Venkataramanan 	ice_for_each_traffic_class(i) {
596bb87ee0eSAnirudh Venkataramanan 		if (vsi->lan_q_ctx[i]) {
597bb87ee0eSAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
598bb87ee0eSAnirudh Venkataramanan 			vsi->lan_q_ctx[i] = NULL;
599bb87ee0eSAnirudh Venkataramanan 		}
600348048e7SDave Ertman 		if (vsi->rdma_q_ctx[i]) {
601348048e7SDave Ertman 			devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]);
602348048e7SDave Ertman 			vsi->rdma_q_ctx[i] = NULL;
603348048e7SDave Ertman 		}
604bb87ee0eSAnirudh Venkataramanan 	}
605bb87ee0eSAnirudh Venkataramanan }
606bb87ee0eSAnirudh Venkataramanan 
607bb87ee0eSAnirudh Venkataramanan /**
6080f9d5027SAnirudh Venkataramanan  * ice_clear_vsi_ctx - clear the VSI context entry
609f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
6100f9d5027SAnirudh Venkataramanan  * @vsi_handle: VSI handle
6110f9d5027SAnirudh Venkataramanan  *
6120f9d5027SAnirudh Venkataramanan  * clear the VSI context entry
6130f9d5027SAnirudh Venkataramanan  */
6140f9d5027SAnirudh Venkataramanan static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
6150f9d5027SAnirudh Venkataramanan {
6160f9d5027SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi;
6170f9d5027SAnirudh Venkataramanan 
6180f9d5027SAnirudh Venkataramanan 	vsi = ice_get_vsi_ctx(hw, vsi_handle);
6190f9d5027SAnirudh Venkataramanan 	if (vsi) {
620bb87ee0eSAnirudh Venkataramanan 		ice_clear_vsi_q_ctx(hw, vsi_handle);
6210f9d5027SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), vsi);
6220f9d5027SAnirudh Venkataramanan 		hw->vsi_ctx[vsi_handle] = NULL;
6230f9d5027SAnirudh Venkataramanan 	}
6240f9d5027SAnirudh Venkataramanan }
6250f9d5027SAnirudh Venkataramanan 
6260f9d5027SAnirudh Venkataramanan /**
62733e055fcSVictor Raj  * ice_clear_all_vsi_ctx - clear all the VSI context entries
628f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
62933e055fcSVictor Raj  */
63033e055fcSVictor Raj void ice_clear_all_vsi_ctx(struct ice_hw *hw)
63133e055fcSVictor Raj {
63233e055fcSVictor Raj 	u16 i;
63333e055fcSVictor Raj 
63433e055fcSVictor Raj 	for (i = 0; i < ICE_MAX_VSI; i++)
63533e055fcSVictor Raj 		ice_clear_vsi_ctx(hw, i);
63633e055fcSVictor Raj }
63733e055fcSVictor Raj 
63833e055fcSVictor Raj /**
6390f9d5027SAnirudh Venkataramanan  * ice_add_vsi - add VSI context to the hardware and VSI handle list
640f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
6410f9d5027SAnirudh Venkataramanan  * @vsi_handle: unique VSI handle provided by drivers
6420f9d5027SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
6430f9d5027SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
6440f9d5027SAnirudh Venkataramanan  *
6450f9d5027SAnirudh Venkataramanan  * Add a VSI context to the hardware also add it into the VSI handle list.
6460f9d5027SAnirudh Venkataramanan  * If this function gets called after reset for existing VSIs then update
6470f9d5027SAnirudh Venkataramanan  * with the new HW VSI number in the corresponding VSI handle list entry.
6480f9d5027SAnirudh Venkataramanan  */
6490f9d5027SAnirudh Venkataramanan enum ice_status
6500f9d5027SAnirudh Venkataramanan ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
6510f9d5027SAnirudh Venkataramanan 	    struct ice_sq_cd *cd)
6520f9d5027SAnirudh Venkataramanan {
6530f9d5027SAnirudh Venkataramanan 	struct ice_vsi_ctx *tmp_vsi_ctx;
6540f9d5027SAnirudh Venkataramanan 	enum ice_status status;
6550f9d5027SAnirudh Venkataramanan 
6560f9d5027SAnirudh Venkataramanan 	if (vsi_handle >= ICE_MAX_VSI)
6570f9d5027SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
6580f9d5027SAnirudh Venkataramanan 	status = ice_aq_add_vsi(hw, vsi_ctx, cd);
6590f9d5027SAnirudh Venkataramanan 	if (status)
6600f9d5027SAnirudh Venkataramanan 		return status;
6610f9d5027SAnirudh Venkataramanan 	tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
6620f9d5027SAnirudh Venkataramanan 	if (!tmp_vsi_ctx) {
663f9867df6SAnirudh Venkataramanan 		/* Create a new VSI context */
6640f9d5027SAnirudh Venkataramanan 		tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw),
6650f9d5027SAnirudh Venkataramanan 					   sizeof(*tmp_vsi_ctx), GFP_KERNEL);
6660f9d5027SAnirudh Venkataramanan 		if (!tmp_vsi_ctx) {
6670f9d5027SAnirudh Venkataramanan 			ice_aq_free_vsi(hw, vsi_ctx, false, cd);
6680f9d5027SAnirudh Venkataramanan 			return ICE_ERR_NO_MEMORY;
6690f9d5027SAnirudh Venkataramanan 		}
6700f9d5027SAnirudh Venkataramanan 		*tmp_vsi_ctx = *vsi_ctx;
6710f9d5027SAnirudh Venkataramanan 		ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);
6720f9d5027SAnirudh Venkataramanan 	} else {
6730f9d5027SAnirudh Venkataramanan 		/* update with new HW VSI num */
6740f9d5027SAnirudh Venkataramanan 		tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;
6750f9d5027SAnirudh Venkataramanan 	}
6760f9d5027SAnirudh Venkataramanan 
6771b5c19c7SBruce Allan 	return 0;
6780f9d5027SAnirudh Venkataramanan }
6790f9d5027SAnirudh Venkataramanan 
6800f9d5027SAnirudh Venkataramanan /**
6810f9d5027SAnirudh Venkataramanan  * ice_free_vsi- free VSI context from hardware and VSI handle list
682f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
6830f9d5027SAnirudh Venkataramanan  * @vsi_handle: unique VSI handle
6843a858ba3SAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
6853a858ba3SAnirudh Venkataramanan  * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
6863a858ba3SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
6873a858ba3SAnirudh Venkataramanan  *
6880f9d5027SAnirudh Venkataramanan  * Free VSI context info from hardware as well as from VSI handle list
6893a858ba3SAnirudh Venkataramanan  */
6903a858ba3SAnirudh Venkataramanan enum ice_status
6910f9d5027SAnirudh Venkataramanan ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
6923a858ba3SAnirudh Venkataramanan 	     bool keep_vsi_alloc, struct ice_sq_cd *cd)
6933a858ba3SAnirudh Venkataramanan {
6943a858ba3SAnirudh Venkataramanan 	enum ice_status status;
6953a858ba3SAnirudh Venkataramanan 
6960f9d5027SAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
6970f9d5027SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
6980f9d5027SAnirudh Venkataramanan 	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
6990f9d5027SAnirudh Venkataramanan 	status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);
7000f9d5027SAnirudh Venkataramanan 	if (!status)
7010f9d5027SAnirudh Venkataramanan 		ice_clear_vsi_ctx(hw, vsi_handle);
7023a858ba3SAnirudh Venkataramanan 	return status;
7033a858ba3SAnirudh Venkataramanan }
7043a858ba3SAnirudh Venkataramanan 
7059daf8208SAnirudh Venkataramanan /**
7065726ca0eSAnirudh Venkataramanan  * ice_update_vsi
707f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
7085726ca0eSAnirudh Venkataramanan  * @vsi_handle: unique VSI handle
7095726ca0eSAnirudh Venkataramanan  * @vsi_ctx: pointer to a VSI context struct
7105726ca0eSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
7115726ca0eSAnirudh Venkataramanan  *
7125726ca0eSAnirudh Venkataramanan  * Update VSI context in the hardware
7135726ca0eSAnirudh Venkataramanan  */
7145726ca0eSAnirudh Venkataramanan enum ice_status
7155726ca0eSAnirudh Venkataramanan ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
7165726ca0eSAnirudh Venkataramanan 	       struct ice_sq_cd *cd)
7175726ca0eSAnirudh Venkataramanan {
7185726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
7195726ca0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
7205726ca0eSAnirudh Venkataramanan 	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
7215726ca0eSAnirudh Venkataramanan 	return ice_aq_update_vsi(hw, vsi_ctx, cd);
7225726ca0eSAnirudh Venkataramanan }
7235726ca0eSAnirudh Venkataramanan 
7245726ca0eSAnirudh Venkataramanan /**
725348048e7SDave Ertman  * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI
726348048e7SDave Ertman  * @hw: pointer to HW struct
727348048e7SDave Ertman  * @vsi_handle: VSI SW index
728348048e7SDave Ertman  * @enable: boolean for enable/disable
729348048e7SDave Ertman  */
730348048e7SDave Ertman int
731348048e7SDave Ertman ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
732348048e7SDave Ertman {
733348048e7SDave Ertman 	struct ice_vsi_ctx *ctx;
734348048e7SDave Ertman 
735348048e7SDave Ertman 	ctx = ice_get_vsi_ctx(hw, vsi_handle);
736348048e7SDave Ertman 	if (!ctx)
737348048e7SDave Ertman 		return -EIO;
738348048e7SDave Ertman 
739348048e7SDave Ertman 	if (enable)
740348048e7SDave Ertman 		ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
741348048e7SDave Ertman 	else
742348048e7SDave Ertman 		ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
743348048e7SDave Ertman 
744348048e7SDave Ertman 	return ice_status_to_errno(ice_update_vsi(hw, vsi_handle, ctx, NULL));
745348048e7SDave Ertman }
746348048e7SDave Ertman 
747348048e7SDave Ertman /**
7489daf8208SAnirudh Venkataramanan  * ice_aq_alloc_free_vsi_list
749f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
750f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID returned or used for lookup
7519daf8208SAnirudh Venkataramanan  * @lkup_type: switch rule filter lookup type
7529daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
7539daf8208SAnirudh Venkataramanan  *
7549daf8208SAnirudh Venkataramanan  * allocates or free a VSI list resource
7559daf8208SAnirudh Venkataramanan  */
7569daf8208SAnirudh Venkataramanan static enum ice_status
7579daf8208SAnirudh Venkataramanan ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
7589daf8208SAnirudh Venkataramanan 			   enum ice_sw_lkup_type lkup_type,
7599daf8208SAnirudh Venkataramanan 			   enum ice_adminq_opc opc)
7609daf8208SAnirudh Venkataramanan {
7619daf8208SAnirudh Venkataramanan 	struct ice_aqc_alloc_free_res_elem *sw_buf;
7629daf8208SAnirudh Venkataramanan 	struct ice_aqc_res_elem *vsi_ele;
7639daf8208SAnirudh Venkataramanan 	enum ice_status status;
7649daf8208SAnirudh Venkataramanan 	u16 buf_len;
7659daf8208SAnirudh Venkataramanan 
76666486d89SBruce Allan 	buf_len = struct_size(sw_buf, elem, 1);
7679daf8208SAnirudh Venkataramanan 	sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL);
7689daf8208SAnirudh Venkataramanan 	if (!sw_buf)
7699daf8208SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
7709daf8208SAnirudh Venkataramanan 	sw_buf->num_elems = cpu_to_le16(1);
7719daf8208SAnirudh Venkataramanan 
7729daf8208SAnirudh Venkataramanan 	if (lkup_type == ICE_SW_LKUP_MAC ||
7739daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
7749daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
7759daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
7769daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC ||
7779daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN) {
7789daf8208SAnirudh Venkataramanan 		sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
7799daf8208SAnirudh Venkataramanan 	} else if (lkup_type == ICE_SW_LKUP_VLAN) {
7809daf8208SAnirudh Venkataramanan 		sw_buf->res_type =
7819daf8208SAnirudh Venkataramanan 			cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
7829daf8208SAnirudh Venkataramanan 	} else {
7839daf8208SAnirudh Venkataramanan 		status = ICE_ERR_PARAM;
7849daf8208SAnirudh Venkataramanan 		goto ice_aq_alloc_free_vsi_list_exit;
7859daf8208SAnirudh Venkataramanan 	}
7869daf8208SAnirudh Venkataramanan 
7879daf8208SAnirudh Venkataramanan 	if (opc == ice_aqc_opc_free_res)
7889daf8208SAnirudh Venkataramanan 		sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id);
7899daf8208SAnirudh Venkataramanan 
7909daf8208SAnirudh Venkataramanan 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);
7919daf8208SAnirudh Venkataramanan 	if (status)
7929daf8208SAnirudh Venkataramanan 		goto ice_aq_alloc_free_vsi_list_exit;
7939daf8208SAnirudh Venkataramanan 
7949daf8208SAnirudh Venkataramanan 	if (opc == ice_aqc_opc_alloc_res) {
7959daf8208SAnirudh Venkataramanan 		vsi_ele = &sw_buf->elem[0];
7969daf8208SAnirudh Venkataramanan 		*vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp);
7979daf8208SAnirudh Venkataramanan 	}
7989daf8208SAnirudh Venkataramanan 
7999daf8208SAnirudh Venkataramanan ice_aq_alloc_free_vsi_list_exit:
8009daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), sw_buf);
8019daf8208SAnirudh Venkataramanan 	return status;
8029daf8208SAnirudh Venkataramanan }
8039daf8208SAnirudh Venkataramanan 
8049daf8208SAnirudh Venkataramanan /**
8059daf8208SAnirudh Venkataramanan  * ice_aq_sw_rules - add/update/remove switch rules
806f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
8079daf8208SAnirudh Venkataramanan  * @rule_list: pointer to switch rule population list
8089daf8208SAnirudh Venkataramanan  * @rule_list_sz: total size of the rule list in bytes
8099daf8208SAnirudh Venkataramanan  * @num_rules: number of switch rules in the rule_list
8109daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
8119daf8208SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
8129daf8208SAnirudh Venkataramanan  *
8139daf8208SAnirudh Venkataramanan  * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware
8149daf8208SAnirudh Venkataramanan  */
815bd676b29SMichal Swiatkowski enum ice_status
8169daf8208SAnirudh Venkataramanan ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
8179daf8208SAnirudh Venkataramanan 		u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd)
8189daf8208SAnirudh Venkataramanan {
8199daf8208SAnirudh Venkataramanan 	struct ice_aq_desc desc;
820ca1fdb88SKiran Patil 	enum ice_status status;
8219daf8208SAnirudh Venkataramanan 
8229daf8208SAnirudh Venkataramanan 	if (opc != ice_aqc_opc_add_sw_rules &&
8239daf8208SAnirudh Venkataramanan 	    opc != ice_aqc_opc_update_sw_rules &&
8249daf8208SAnirudh Venkataramanan 	    opc != ice_aqc_opc_remove_sw_rules)
8259daf8208SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
8269daf8208SAnirudh Venkataramanan 
8279daf8208SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, opc);
8289daf8208SAnirudh Venkataramanan 
8299daf8208SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
8309daf8208SAnirudh Venkataramanan 	desc.params.sw_rules.num_rules_fltr_entry_index =
8319daf8208SAnirudh Venkataramanan 		cpu_to_le16(num_rules);
832ca1fdb88SKiran Patil 	status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd);
833ca1fdb88SKiran Patil 	if (opc != ice_aqc_opc_add_sw_rules &&
834ca1fdb88SKiran Patil 	    hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
835ca1fdb88SKiran Patil 		status = ICE_ERR_DOES_NOT_EXIST;
836ca1fdb88SKiran Patil 
837ca1fdb88SKiran Patil 	return status;
8389daf8208SAnirudh Venkataramanan }
8399daf8208SAnirudh Venkataramanan 
8407715ec32SGrishma Kotecha /**
8417715ec32SGrishma Kotecha  * ice_aq_add_recipe - add switch recipe
8427715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
8437715ec32SGrishma Kotecha  * @s_recipe_list: pointer to switch rule population list
8447715ec32SGrishma Kotecha  * @num_recipes: number of switch recipes in the list
8457715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
8467715ec32SGrishma Kotecha  *
8477715ec32SGrishma Kotecha  * Add(0x0290)
8487715ec32SGrishma Kotecha  */
849fd2a6b71SDan Nowlin static enum ice_status
8507715ec32SGrishma Kotecha ice_aq_add_recipe(struct ice_hw *hw,
8517715ec32SGrishma Kotecha 		  struct ice_aqc_recipe_data_elem *s_recipe_list,
8527715ec32SGrishma Kotecha 		  u16 num_recipes, struct ice_sq_cd *cd)
8537715ec32SGrishma Kotecha {
8547715ec32SGrishma Kotecha 	struct ice_aqc_add_get_recipe *cmd;
8557715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
8567715ec32SGrishma Kotecha 	u16 buf_size;
8577715ec32SGrishma Kotecha 
8587715ec32SGrishma Kotecha 	cmd = &desc.params.add_get_recipe;
8597715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_recipe);
8607715ec32SGrishma Kotecha 
8617715ec32SGrishma Kotecha 	cmd->num_sub_recipes = cpu_to_le16(num_recipes);
8627715ec32SGrishma Kotecha 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
8637715ec32SGrishma Kotecha 
8647715ec32SGrishma Kotecha 	buf_size = num_recipes * sizeof(*s_recipe_list);
8657715ec32SGrishma Kotecha 
8667715ec32SGrishma Kotecha 	return ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd);
8677715ec32SGrishma Kotecha }
8687715ec32SGrishma Kotecha 
8697715ec32SGrishma Kotecha /**
8707715ec32SGrishma Kotecha  * ice_aq_get_recipe - get switch recipe
8717715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
8727715ec32SGrishma Kotecha  * @s_recipe_list: pointer to switch rule population list
8737715ec32SGrishma Kotecha  * @num_recipes: pointer to the number of recipes (input and output)
8747715ec32SGrishma Kotecha  * @recipe_root: root recipe number of recipe(s) to retrieve
8757715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
8767715ec32SGrishma Kotecha  *
8777715ec32SGrishma Kotecha  * Get(0x0292)
8787715ec32SGrishma Kotecha  *
8797715ec32SGrishma Kotecha  * On input, *num_recipes should equal the number of entries in s_recipe_list.
8807715ec32SGrishma Kotecha  * On output, *num_recipes will equal the number of entries returned in
8817715ec32SGrishma Kotecha  * s_recipe_list.
8827715ec32SGrishma Kotecha  *
8837715ec32SGrishma Kotecha  * The caller must supply enough space in s_recipe_list to hold all possible
8847715ec32SGrishma Kotecha  * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES.
8857715ec32SGrishma Kotecha  */
886fd2a6b71SDan Nowlin static enum ice_status
8877715ec32SGrishma Kotecha ice_aq_get_recipe(struct ice_hw *hw,
8887715ec32SGrishma Kotecha 		  struct ice_aqc_recipe_data_elem *s_recipe_list,
8897715ec32SGrishma Kotecha 		  u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd)
8907715ec32SGrishma Kotecha {
8917715ec32SGrishma Kotecha 	struct ice_aqc_add_get_recipe *cmd;
8927715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
8937715ec32SGrishma Kotecha 	enum ice_status status;
8947715ec32SGrishma Kotecha 	u16 buf_size;
8957715ec32SGrishma Kotecha 
8967715ec32SGrishma Kotecha 	if (*num_recipes != ICE_MAX_NUM_RECIPES)
8977715ec32SGrishma Kotecha 		return ICE_ERR_PARAM;
8987715ec32SGrishma Kotecha 
8997715ec32SGrishma Kotecha 	cmd = &desc.params.add_get_recipe;
9007715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe);
9017715ec32SGrishma Kotecha 
9027715ec32SGrishma Kotecha 	cmd->return_index = cpu_to_le16(recipe_root);
9037715ec32SGrishma Kotecha 	cmd->num_sub_recipes = 0;
9047715ec32SGrishma Kotecha 
9057715ec32SGrishma Kotecha 	buf_size = *num_recipes * sizeof(*s_recipe_list);
9067715ec32SGrishma Kotecha 
9077715ec32SGrishma Kotecha 	status = ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd);
9087715ec32SGrishma Kotecha 	*num_recipes = le16_to_cpu(cmd->num_sub_recipes);
9097715ec32SGrishma Kotecha 
9107715ec32SGrishma Kotecha 	return status;
9117715ec32SGrishma Kotecha }
9127715ec32SGrishma Kotecha 
9137715ec32SGrishma Kotecha /**
9147715ec32SGrishma Kotecha  * ice_aq_map_recipe_to_profile - Map recipe to packet profile
9157715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
9167715ec32SGrishma Kotecha  * @profile_id: package profile ID to associate the recipe with
9177715ec32SGrishma Kotecha  * @r_bitmap: Recipe bitmap filled in and need to be returned as response
9187715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
9197715ec32SGrishma Kotecha  * Recipe to profile association (0x0291)
9207715ec32SGrishma Kotecha  */
921fd2a6b71SDan Nowlin static enum ice_status
9227715ec32SGrishma Kotecha ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
9237715ec32SGrishma Kotecha 			     struct ice_sq_cd *cd)
9247715ec32SGrishma Kotecha {
9257715ec32SGrishma Kotecha 	struct ice_aqc_recipe_to_profile *cmd;
9267715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
9277715ec32SGrishma Kotecha 
9287715ec32SGrishma Kotecha 	cmd = &desc.params.recipe_to_profile;
9297715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_recipe_to_profile);
9307715ec32SGrishma Kotecha 	cmd->profile_id = cpu_to_le16(profile_id);
9317715ec32SGrishma Kotecha 	/* Set the recipe ID bit in the bitmask to let the device know which
9327715ec32SGrishma Kotecha 	 * profile we are associating the recipe to
9337715ec32SGrishma Kotecha 	 */
9347715ec32SGrishma Kotecha 	memcpy(cmd->recipe_assoc, r_bitmap, sizeof(cmd->recipe_assoc));
9357715ec32SGrishma Kotecha 
9367715ec32SGrishma Kotecha 	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
9377715ec32SGrishma Kotecha }
9387715ec32SGrishma Kotecha 
9397715ec32SGrishma Kotecha /**
9407715ec32SGrishma Kotecha  * ice_aq_get_recipe_to_profile - Map recipe to packet profile
9417715ec32SGrishma Kotecha  * @hw: pointer to the HW struct
9427715ec32SGrishma Kotecha  * @profile_id: package profile ID to associate the recipe with
9437715ec32SGrishma Kotecha  * @r_bitmap: Recipe bitmap filled in and need to be returned as response
9447715ec32SGrishma Kotecha  * @cd: pointer to command details structure or NULL
9457715ec32SGrishma Kotecha  * Associate profile ID with given recipe (0x0293)
9467715ec32SGrishma Kotecha  */
947fd2a6b71SDan Nowlin static enum ice_status
9487715ec32SGrishma Kotecha ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
9497715ec32SGrishma Kotecha 			     struct ice_sq_cd *cd)
9507715ec32SGrishma Kotecha {
9517715ec32SGrishma Kotecha 	struct ice_aqc_recipe_to_profile *cmd;
9527715ec32SGrishma Kotecha 	struct ice_aq_desc desc;
9537715ec32SGrishma Kotecha 	enum ice_status status;
9547715ec32SGrishma Kotecha 
9557715ec32SGrishma Kotecha 	cmd = &desc.params.recipe_to_profile;
9567715ec32SGrishma Kotecha 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile);
9577715ec32SGrishma Kotecha 	cmd->profile_id = cpu_to_le16(profile_id);
9587715ec32SGrishma Kotecha 
9597715ec32SGrishma Kotecha 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
9607715ec32SGrishma Kotecha 	if (!status)
9617715ec32SGrishma Kotecha 		memcpy(r_bitmap, cmd->recipe_assoc, sizeof(cmd->recipe_assoc));
9627715ec32SGrishma Kotecha 
9637715ec32SGrishma Kotecha 	return status;
9647715ec32SGrishma Kotecha }
9657715ec32SGrishma Kotecha 
9667715ec32SGrishma Kotecha /**
9677715ec32SGrishma Kotecha  * ice_alloc_recipe - add recipe resource
9687715ec32SGrishma Kotecha  * @hw: pointer to the hardware structure
9697715ec32SGrishma Kotecha  * @rid: recipe ID returned as response to AQ call
9707715ec32SGrishma Kotecha  */
971fd2a6b71SDan Nowlin static enum ice_status ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
9727715ec32SGrishma Kotecha {
9737715ec32SGrishma Kotecha 	struct ice_aqc_alloc_free_res_elem *sw_buf;
9747715ec32SGrishma Kotecha 	enum ice_status status;
9757715ec32SGrishma Kotecha 	u16 buf_len;
9767715ec32SGrishma Kotecha 
9777715ec32SGrishma Kotecha 	buf_len = struct_size(sw_buf, elem, 1);
9787715ec32SGrishma Kotecha 	sw_buf = kzalloc(buf_len, GFP_KERNEL);
9797715ec32SGrishma Kotecha 	if (!sw_buf)
9807715ec32SGrishma Kotecha 		return ICE_ERR_NO_MEMORY;
9817715ec32SGrishma Kotecha 
9827715ec32SGrishma Kotecha 	sw_buf->num_elems = cpu_to_le16(1);
9837715ec32SGrishma Kotecha 	sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
9847715ec32SGrishma Kotecha 					ICE_AQC_RES_TYPE_S) |
9857715ec32SGrishma Kotecha 					ICE_AQC_RES_TYPE_FLAG_SHARED);
9867715ec32SGrishma Kotecha 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
9877715ec32SGrishma Kotecha 				       ice_aqc_opc_alloc_res, NULL);
9887715ec32SGrishma Kotecha 	if (!status)
9897715ec32SGrishma Kotecha 		*rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp);
9907715ec32SGrishma Kotecha 	kfree(sw_buf);
9917715ec32SGrishma Kotecha 
9927715ec32SGrishma Kotecha 	return status;
9937715ec32SGrishma Kotecha }
9947715ec32SGrishma Kotecha 
995fd2a6b71SDan Nowlin /**
996fd2a6b71SDan Nowlin  * ice_get_recp_to_prof_map - updates recipe to profile mapping
997fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
998fd2a6b71SDan Nowlin  *
999fd2a6b71SDan Nowlin  * This function is used to populate recipe_to_profile matrix where index to
1000fd2a6b71SDan Nowlin  * this array is the recipe ID and the element is the mapping of which profiles
1001fd2a6b71SDan Nowlin  * is this recipe mapped to.
1002fd2a6b71SDan Nowlin  */
1003fd2a6b71SDan Nowlin static void ice_get_recp_to_prof_map(struct ice_hw *hw)
1004fd2a6b71SDan Nowlin {
1005fd2a6b71SDan Nowlin 	DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
1006fd2a6b71SDan Nowlin 	u16 i;
1007fd2a6b71SDan Nowlin 
1008fd2a6b71SDan Nowlin 	for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) {
1009fd2a6b71SDan Nowlin 		u16 j;
1010fd2a6b71SDan Nowlin 
1011fd2a6b71SDan Nowlin 		bitmap_zero(profile_to_recipe[i], ICE_MAX_NUM_RECIPES);
1012fd2a6b71SDan Nowlin 		bitmap_zero(r_bitmap, ICE_MAX_NUM_RECIPES);
1013fd2a6b71SDan Nowlin 		if (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL))
1014fd2a6b71SDan Nowlin 			continue;
1015fd2a6b71SDan Nowlin 		bitmap_copy(profile_to_recipe[i], r_bitmap,
1016fd2a6b71SDan Nowlin 			    ICE_MAX_NUM_RECIPES);
1017fd2a6b71SDan Nowlin 		for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES)
1018fd2a6b71SDan Nowlin 			set_bit(i, recipe_to_profile[j]);
1019fd2a6b71SDan Nowlin 	}
1020fd2a6b71SDan Nowlin }
1021fd2a6b71SDan Nowlin 
1022fd2a6b71SDan Nowlin /**
1023fd2a6b71SDan Nowlin  * ice_collect_result_idx - copy result index values
1024fd2a6b71SDan Nowlin  * @buf: buffer that contains the result index
1025fd2a6b71SDan Nowlin  * @recp: the recipe struct to copy data into
1026fd2a6b71SDan Nowlin  */
1027fd2a6b71SDan Nowlin static void
1028fd2a6b71SDan Nowlin ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
1029fd2a6b71SDan Nowlin 		       struct ice_sw_recipe *recp)
1030fd2a6b71SDan Nowlin {
1031fd2a6b71SDan Nowlin 	if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
1032fd2a6b71SDan Nowlin 		set_bit(buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
1033fd2a6b71SDan Nowlin 			recp->res_idxs);
1034fd2a6b71SDan Nowlin }
1035fd2a6b71SDan Nowlin 
1036fd2a6b71SDan Nowlin /**
1037fd2a6b71SDan Nowlin  * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries
1038fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
1039fd2a6b71SDan Nowlin  * @recps: struct that we need to populate
1040fd2a6b71SDan Nowlin  * @rid: recipe ID that we are populating
1041fd2a6b71SDan Nowlin  * @refresh_required: true if we should get recipe to profile mapping from FW
1042fd2a6b71SDan Nowlin  *
1043fd2a6b71SDan Nowlin  * This function is used to populate all the necessary entries into our
1044fd2a6b71SDan Nowlin  * bookkeeping so that we have a current list of all the recipes that are
1045fd2a6b71SDan Nowlin  * programmed in the firmware.
1046fd2a6b71SDan Nowlin  */
1047fd2a6b71SDan Nowlin static enum ice_status
1048fd2a6b71SDan Nowlin ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
1049fd2a6b71SDan Nowlin 		    bool *refresh_required)
1050fd2a6b71SDan Nowlin {
1051fd2a6b71SDan Nowlin 	DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS);
1052fd2a6b71SDan Nowlin 	struct ice_aqc_recipe_data_elem *tmp;
1053fd2a6b71SDan Nowlin 	u16 num_recps = ICE_MAX_NUM_RECIPES;
1054fd2a6b71SDan Nowlin 	struct ice_prot_lkup_ext *lkup_exts;
1055fd2a6b71SDan Nowlin 	enum ice_status status;
1056fd2a6b71SDan Nowlin 	u8 fv_word_idx = 0;
1057fd2a6b71SDan Nowlin 	u16 sub_recps;
1058fd2a6b71SDan Nowlin 
1059fd2a6b71SDan Nowlin 	bitmap_zero(result_bm, ICE_MAX_FV_WORDS);
1060fd2a6b71SDan Nowlin 
1061fd2a6b71SDan Nowlin 	/* we need a buffer big enough to accommodate all the recipes */
1062fd2a6b71SDan Nowlin 	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
1063fd2a6b71SDan Nowlin 	if (!tmp)
1064fd2a6b71SDan Nowlin 		return ICE_ERR_NO_MEMORY;
1065fd2a6b71SDan Nowlin 
1066fd2a6b71SDan Nowlin 	tmp[0].recipe_indx = rid;
1067fd2a6b71SDan Nowlin 	status = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL);
1068fd2a6b71SDan Nowlin 	/* non-zero status meaning recipe doesn't exist */
1069fd2a6b71SDan Nowlin 	if (status)
1070fd2a6b71SDan Nowlin 		goto err_unroll;
1071fd2a6b71SDan Nowlin 
1072fd2a6b71SDan Nowlin 	/* Get recipe to profile map so that we can get the fv from lkups that
1073fd2a6b71SDan Nowlin 	 * we read for a recipe from FW. Since we want to minimize the number of
1074fd2a6b71SDan Nowlin 	 * times we make this FW call, just make one call and cache the copy
1075fd2a6b71SDan Nowlin 	 * until a new recipe is added. This operation is only required the
1076fd2a6b71SDan Nowlin 	 * first time to get the changes from FW. Then to search existing
1077fd2a6b71SDan Nowlin 	 * entries we don't need to update the cache again until another recipe
1078fd2a6b71SDan Nowlin 	 * gets added.
1079fd2a6b71SDan Nowlin 	 */
1080fd2a6b71SDan Nowlin 	if (*refresh_required) {
1081fd2a6b71SDan Nowlin 		ice_get_recp_to_prof_map(hw);
1082fd2a6b71SDan Nowlin 		*refresh_required = false;
1083fd2a6b71SDan Nowlin 	}
1084fd2a6b71SDan Nowlin 
1085fd2a6b71SDan Nowlin 	/* Start populating all the entries for recps[rid] based on lkups from
1086fd2a6b71SDan Nowlin 	 * firmware. Note that we are only creating the root recipe in our
1087fd2a6b71SDan Nowlin 	 * database.
1088fd2a6b71SDan Nowlin 	 */
1089fd2a6b71SDan Nowlin 	lkup_exts = &recps[rid].lkup_exts;
1090fd2a6b71SDan Nowlin 
1091fd2a6b71SDan Nowlin 	for (sub_recps = 0; sub_recps < num_recps; sub_recps++) {
1092fd2a6b71SDan Nowlin 		struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps];
1093fd2a6b71SDan Nowlin 		struct ice_recp_grp_entry *rg_entry;
1094fd2a6b71SDan Nowlin 		u8 i, prof, idx, prot = 0;
1095fd2a6b71SDan Nowlin 		bool is_root;
1096fd2a6b71SDan Nowlin 		u16 off = 0;
1097fd2a6b71SDan Nowlin 
1098fd2a6b71SDan Nowlin 		rg_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rg_entry),
1099fd2a6b71SDan Nowlin 					GFP_KERNEL);
1100fd2a6b71SDan Nowlin 		if (!rg_entry) {
1101fd2a6b71SDan Nowlin 			status = ICE_ERR_NO_MEMORY;
1102fd2a6b71SDan Nowlin 			goto err_unroll;
1103fd2a6b71SDan Nowlin 		}
1104fd2a6b71SDan Nowlin 
1105fd2a6b71SDan Nowlin 		idx = root_bufs.recipe_indx;
1106fd2a6b71SDan Nowlin 		is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT;
1107fd2a6b71SDan Nowlin 
1108fd2a6b71SDan Nowlin 		/* Mark all result indices in this chain */
1109fd2a6b71SDan Nowlin 		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
1110fd2a6b71SDan Nowlin 			set_bit(root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
1111fd2a6b71SDan Nowlin 				result_bm);
1112fd2a6b71SDan Nowlin 
1113fd2a6b71SDan Nowlin 		/* get the first profile that is associated with rid */
1114fd2a6b71SDan Nowlin 		prof = find_first_bit(recipe_to_profile[idx],
1115fd2a6b71SDan Nowlin 				      ICE_MAX_NUM_PROFILES);
1116fd2a6b71SDan Nowlin 		for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) {
1117fd2a6b71SDan Nowlin 			u8 lkup_indx = root_bufs.content.lkup_indx[i + 1];
1118fd2a6b71SDan Nowlin 
1119fd2a6b71SDan Nowlin 			rg_entry->fv_idx[i] = lkup_indx;
1120fd2a6b71SDan Nowlin 			rg_entry->fv_mask[i] =
1121fd2a6b71SDan Nowlin 				le16_to_cpu(root_bufs.content.mask[i + 1]);
1122fd2a6b71SDan Nowlin 
1123fd2a6b71SDan Nowlin 			/* If the recipe is a chained recipe then all its
1124fd2a6b71SDan Nowlin 			 * child recipe's result will have a result index.
1125fd2a6b71SDan Nowlin 			 * To fill fv_words we should not use those result
1126fd2a6b71SDan Nowlin 			 * index, we only need the protocol ids and offsets.
1127fd2a6b71SDan Nowlin 			 * We will skip all the fv_idx which stores result
1128fd2a6b71SDan Nowlin 			 * index in them. We also need to skip any fv_idx which
1129fd2a6b71SDan Nowlin 			 * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a
1130fd2a6b71SDan Nowlin 			 * valid offset value.
1131fd2a6b71SDan Nowlin 			 */
1132fd2a6b71SDan Nowlin 			if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) ||
1133fd2a6b71SDan Nowlin 			    rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE ||
1134fd2a6b71SDan Nowlin 			    rg_entry->fv_idx[i] == 0)
1135fd2a6b71SDan Nowlin 				continue;
1136fd2a6b71SDan Nowlin 
1137fd2a6b71SDan Nowlin 			ice_find_prot_off(hw, ICE_BLK_SW, prof,
1138fd2a6b71SDan Nowlin 					  rg_entry->fv_idx[i], &prot, &off);
1139fd2a6b71SDan Nowlin 			lkup_exts->fv_words[fv_word_idx].prot_id = prot;
1140fd2a6b71SDan Nowlin 			lkup_exts->fv_words[fv_word_idx].off = off;
1141fd2a6b71SDan Nowlin 			lkup_exts->field_mask[fv_word_idx] =
1142fd2a6b71SDan Nowlin 				rg_entry->fv_mask[i];
1143fd2a6b71SDan Nowlin 			fv_word_idx++;
1144fd2a6b71SDan Nowlin 		}
1145fd2a6b71SDan Nowlin 		/* populate rg_list with the data from the child entry of this
1146fd2a6b71SDan Nowlin 		 * recipe
1147fd2a6b71SDan Nowlin 		 */
1148fd2a6b71SDan Nowlin 		list_add(&rg_entry->l_entry, &recps[rid].rg_list);
1149fd2a6b71SDan Nowlin 
1150fd2a6b71SDan Nowlin 		/* Propagate some data to the recipe database */
1151fd2a6b71SDan Nowlin 		recps[idx].is_root = !!is_root;
1152fd2a6b71SDan Nowlin 		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
1153fd2a6b71SDan Nowlin 		bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
1154fd2a6b71SDan Nowlin 		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
1155fd2a6b71SDan Nowlin 			recps[idx].chain_idx = root_bufs.content.result_indx &
1156fd2a6b71SDan Nowlin 				~ICE_AQ_RECIPE_RESULT_EN;
1157fd2a6b71SDan Nowlin 			set_bit(recps[idx].chain_idx, recps[idx].res_idxs);
1158fd2a6b71SDan Nowlin 		} else {
1159fd2a6b71SDan Nowlin 			recps[idx].chain_idx = ICE_INVAL_CHAIN_IND;
1160fd2a6b71SDan Nowlin 		}
1161fd2a6b71SDan Nowlin 
1162fd2a6b71SDan Nowlin 		if (!is_root)
1163fd2a6b71SDan Nowlin 			continue;
1164fd2a6b71SDan Nowlin 
1165fd2a6b71SDan Nowlin 		/* Only do the following for root recipes entries */
1166fd2a6b71SDan Nowlin 		memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap,
1167fd2a6b71SDan Nowlin 		       sizeof(recps[idx].r_bitmap));
1168fd2a6b71SDan Nowlin 		recps[idx].root_rid = root_bufs.content.rid &
1169fd2a6b71SDan Nowlin 			~ICE_AQ_RECIPE_ID_IS_ROOT;
1170fd2a6b71SDan Nowlin 		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
1171fd2a6b71SDan Nowlin 	}
1172fd2a6b71SDan Nowlin 
1173fd2a6b71SDan Nowlin 	/* Complete initialization of the root recipe entry */
1174fd2a6b71SDan Nowlin 	lkup_exts->n_val_words = fv_word_idx;
1175fd2a6b71SDan Nowlin 	recps[rid].big_recp = (num_recps > 1);
1176fd2a6b71SDan Nowlin 	recps[rid].n_grp_count = (u8)num_recps;
1177fd2a6b71SDan Nowlin 	recps[rid].root_buf = devm_kmemdup(ice_hw_to_dev(hw), tmp,
1178fd2a6b71SDan Nowlin 					   recps[rid].n_grp_count * sizeof(*recps[rid].root_buf),
1179fd2a6b71SDan Nowlin 					   GFP_KERNEL);
1180fd2a6b71SDan Nowlin 	if (!recps[rid].root_buf)
1181fd2a6b71SDan Nowlin 		goto err_unroll;
1182fd2a6b71SDan Nowlin 
1183fd2a6b71SDan Nowlin 	/* Copy result indexes */
1184fd2a6b71SDan Nowlin 	bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS);
1185fd2a6b71SDan Nowlin 	recps[rid].recp_created = true;
1186fd2a6b71SDan Nowlin 
1187fd2a6b71SDan Nowlin err_unroll:
1188fd2a6b71SDan Nowlin 	kfree(tmp);
1189fd2a6b71SDan Nowlin 	return status;
1190fd2a6b71SDan Nowlin }
1191fd2a6b71SDan Nowlin 
11929c20346bSAnirudh Venkataramanan /* ice_init_port_info - Initialize port_info with switch configuration data
11939c20346bSAnirudh Venkataramanan  * @pi: pointer to port_info
11949c20346bSAnirudh Venkataramanan  * @vsi_port_num: VSI number or port number
11959c20346bSAnirudh Venkataramanan  * @type: Type of switch element (port or VSI)
11969c20346bSAnirudh Venkataramanan  * @swid: switch ID of the switch the element is attached to
11979c20346bSAnirudh Venkataramanan  * @pf_vf_num: PF or VF number
11989c20346bSAnirudh Venkataramanan  * @is_vf: true if the element is a VF, false otherwise
11999c20346bSAnirudh Venkataramanan  */
12009c20346bSAnirudh Venkataramanan static void
12019c20346bSAnirudh Venkataramanan ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,
12029c20346bSAnirudh Venkataramanan 		   u16 swid, u16 pf_vf_num, bool is_vf)
12039c20346bSAnirudh Venkataramanan {
12049c20346bSAnirudh Venkataramanan 	switch (type) {
12059c20346bSAnirudh Venkataramanan 	case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
12069c20346bSAnirudh Venkataramanan 		pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);
12079c20346bSAnirudh Venkataramanan 		pi->sw_id = swid;
12089c20346bSAnirudh Venkataramanan 		pi->pf_vf_num = pf_vf_num;
12099c20346bSAnirudh Venkataramanan 		pi->is_vf = is_vf;
12109c20346bSAnirudh Venkataramanan 		pi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
12119c20346bSAnirudh Venkataramanan 		pi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
12129c20346bSAnirudh Venkataramanan 		break;
12139c20346bSAnirudh Venkataramanan 	default:
12149228d8b2SJacob Keller 		ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n");
12159c20346bSAnirudh Venkataramanan 		break;
12169c20346bSAnirudh Venkataramanan 	}
12179c20346bSAnirudh Venkataramanan }
12189c20346bSAnirudh Venkataramanan 
12199c20346bSAnirudh Venkataramanan /* ice_get_initial_sw_cfg - Get initial port and default VSI data
12209c20346bSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
12219c20346bSAnirudh Venkataramanan  */
12229c20346bSAnirudh Venkataramanan enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw)
12239c20346bSAnirudh Venkataramanan {
1224b3c38904SBruce Allan 	struct ice_aqc_get_sw_cfg_resp_elem *rbuf;
12259c20346bSAnirudh Venkataramanan 	enum ice_status status;
12269c20346bSAnirudh Venkataramanan 	u16 req_desc = 0;
12279c20346bSAnirudh Venkataramanan 	u16 num_elems;
12289c20346bSAnirudh Venkataramanan 	u16 i;
12299c20346bSAnirudh Venkataramanan 
12309c20346bSAnirudh Venkataramanan 	rbuf = devm_kzalloc(ice_hw_to_dev(hw), ICE_SW_CFG_MAX_BUF_LEN,
12319c20346bSAnirudh Venkataramanan 			    GFP_KERNEL);
12329c20346bSAnirudh Venkataramanan 
12339c20346bSAnirudh Venkataramanan 	if (!rbuf)
12349c20346bSAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
12359c20346bSAnirudh Venkataramanan 
12369c20346bSAnirudh Venkataramanan 	/* Multiple calls to ice_aq_get_sw_cfg may be required
12379c20346bSAnirudh Venkataramanan 	 * to get all the switch configuration information. The need
12389c20346bSAnirudh Venkataramanan 	 * for additional calls is indicated by ice_aq_get_sw_cfg
12399c20346bSAnirudh Venkataramanan 	 * writing a non-zero value in req_desc
12409c20346bSAnirudh Venkataramanan 	 */
12419c20346bSAnirudh Venkataramanan 	do {
1242b3c38904SBruce Allan 		struct ice_aqc_get_sw_cfg_resp_elem *ele;
1243b3c38904SBruce Allan 
12449c20346bSAnirudh Venkataramanan 		status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,
12459c20346bSAnirudh Venkataramanan 					   &req_desc, &num_elems, NULL);
12469c20346bSAnirudh Venkataramanan 
12479c20346bSAnirudh Venkataramanan 		if (status)
12489c20346bSAnirudh Venkataramanan 			break;
12499c20346bSAnirudh Venkataramanan 
1250b3c38904SBruce Allan 		for (i = 0, ele = rbuf; i < num_elems; i++, ele++) {
12519c20346bSAnirudh Venkataramanan 			u16 pf_vf_num, swid, vsi_port_num;
12529c20346bSAnirudh Venkataramanan 			bool is_vf = false;
12536dae8aa0SBruce Allan 			u8 res_type;
12549c20346bSAnirudh Venkataramanan 
12559c20346bSAnirudh Venkataramanan 			vsi_port_num = le16_to_cpu(ele->vsi_port_num) &
12569c20346bSAnirudh Venkataramanan 				ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;
12579c20346bSAnirudh Venkataramanan 
12589c20346bSAnirudh Venkataramanan 			pf_vf_num = le16_to_cpu(ele->pf_vf_num) &
12599c20346bSAnirudh Venkataramanan 				ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;
12609c20346bSAnirudh Venkataramanan 
12619c20346bSAnirudh Venkataramanan 			swid = le16_to_cpu(ele->swid);
12629c20346bSAnirudh Venkataramanan 
12639c20346bSAnirudh Venkataramanan 			if (le16_to_cpu(ele->pf_vf_num) &
12649c20346bSAnirudh Venkataramanan 			    ICE_AQC_GET_SW_CONF_RESP_IS_VF)
12659c20346bSAnirudh Venkataramanan 				is_vf = true;
12669c20346bSAnirudh Venkataramanan 
126788865fc4SKarol Kolacinski 			res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >>
126888865fc4SKarol Kolacinski 					ICE_AQC_GET_SW_CONF_RESP_TYPE_S);
12699c20346bSAnirudh Venkataramanan 
12706dae8aa0SBruce Allan 			if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) {
12719c20346bSAnirudh Venkataramanan 				/* FW VSI is not needed. Just continue. */
12729c20346bSAnirudh Venkataramanan 				continue;
12739c20346bSAnirudh Venkataramanan 			}
12749c20346bSAnirudh Venkataramanan 
12759c20346bSAnirudh Venkataramanan 			ice_init_port_info(hw->port_info, vsi_port_num,
12766dae8aa0SBruce Allan 					   res_type, swid, pf_vf_num, is_vf);
12779c20346bSAnirudh Venkataramanan 		}
12789c20346bSAnirudh Venkataramanan 	} while (req_desc && !status);
12799c20346bSAnirudh Venkataramanan 
12807a63dae0SBruce Allan 	devm_kfree(ice_hw_to_dev(hw), rbuf);
12819c20346bSAnirudh Venkataramanan 	return status;
12829c20346bSAnirudh Venkataramanan }
12839daf8208SAnirudh Venkataramanan 
12849daf8208SAnirudh Venkataramanan /**
12859daf8208SAnirudh Venkataramanan  * ice_fill_sw_info - Helper function to populate lb_en and lan_en
12869daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
12876a7e6993SYashaswini Raghuram Prathivadi Bhayankaram  * @fi: filter info structure to fill/update
12889daf8208SAnirudh Venkataramanan  *
12899daf8208SAnirudh Venkataramanan  * This helper function populates the lb_en and lan_en elements of the provided
12909daf8208SAnirudh Venkataramanan  * ice_fltr_info struct using the switch's type and characteristics of the
12919daf8208SAnirudh Venkataramanan  * switch rule being configured.
12929daf8208SAnirudh Venkataramanan  */
12936a7e6993SYashaswini Raghuram Prathivadi Bhayankaram static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
12949daf8208SAnirudh Venkataramanan {
12956a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	fi->lb_en = false;
12966a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	fi->lan_en = false;
12976a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	if ((fi->flag & ICE_FLTR_TX) &&
12986a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	    (fi->fltr_act == ICE_FWD_TO_VSI ||
12996a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
13006a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	     fi->fltr_act == ICE_FWD_TO_Q ||
13016a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 	     fi->fltr_act == ICE_FWD_TO_QGRP)) {
1302b58dafbcSChristopher N Bednarz 		/* Setting LB for prune actions will result in replicated
1303b58dafbcSChristopher N Bednarz 		 * packets to the internal switch that will be dropped.
1304b58dafbcSChristopher N Bednarz 		 */
1305b58dafbcSChristopher N Bednarz 		if (fi->lkup_type != ICE_SW_LKUP_VLAN)
13066a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 			fi->lb_en = true;
1307b58dafbcSChristopher N Bednarz 
1308277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		/* Set lan_en to TRUE if
13096a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 * 1. The switch is a VEB AND
13106a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2
131126069b44SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.1 The lookup is a directional lookup like ethertype,
1312f9867df6SAnirudh Venkataramanan 		 * promiscuous, ethertype-MAC, promiscuous-VLAN
131326069b44SYashaswini Raghuram Prathivadi Bhayankaram 		 * and default-port OR
131426069b44SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.2 The lookup is VLAN, OR
1315277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR
1316277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC.
13176a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 *
1318277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * OR
1319277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 *
1320277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * The switch is a VEPA.
1321277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 *
1322277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		 * In all other cases, the LAN enable has to be set to false.
13236a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 		 */
1324277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		if (hw->evb_veb) {
132526069b44SYashaswini Raghuram Prathivadi Bhayankaram 			if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE ||
132626069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_PROMISC ||
132726069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
132826069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
1329277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_DFLT ||
133026069b44SYashaswini Raghuram Prathivadi Bhayankaram 			    fi->lkup_type == ICE_SW_LKUP_VLAN ||
1331277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			    (fi->lkup_type == ICE_SW_LKUP_MAC &&
1332277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)) ||
13336a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 			    (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&
1334277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)))
13356a7e6993SYashaswini Raghuram Prathivadi Bhayankaram 				fi->lan_en = true;
1336277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		} else {
1337277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 			fi->lan_en = true;
1338277b3a45SYashaswini Raghuram Prathivadi Bhayankaram 		}
13399daf8208SAnirudh Venkataramanan 	}
13409daf8208SAnirudh Venkataramanan }
13419daf8208SAnirudh Venkataramanan 
13429daf8208SAnirudh Venkataramanan /**
13439daf8208SAnirudh Venkataramanan  * ice_fill_sw_rule - Helper function to fill switch rule structure
13449daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
13459daf8208SAnirudh Venkataramanan  * @f_info: entry containing packet forwarding information
13469daf8208SAnirudh Venkataramanan  * @s_rule: switch rule structure to be filled in based on mac_entry
13479daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
13489daf8208SAnirudh Venkataramanan  */
13499daf8208SAnirudh Venkataramanan static void
13509daf8208SAnirudh Venkataramanan ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
13519daf8208SAnirudh Venkataramanan 		 struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc)
13529daf8208SAnirudh Venkataramanan {
13539daf8208SAnirudh Venkataramanan 	u16 vlan_id = ICE_MAX_VLAN_ID + 1;
13549daf8208SAnirudh Venkataramanan 	void *daddr = NULL;
135574118f7aSZhenning Xiao 	u16 eth_hdr_sz;
135674118f7aSZhenning Xiao 	u8 *eth_hdr;
13579daf8208SAnirudh Venkataramanan 	u32 act = 0;
13589daf8208SAnirudh Venkataramanan 	__be16 *off;
1359be8ff000SAnirudh Venkataramanan 	u8 q_rgn;
13609daf8208SAnirudh Venkataramanan 
13619daf8208SAnirudh Venkataramanan 	if (opc == ice_aqc_opc_remove_sw_rules) {
13629daf8208SAnirudh Venkataramanan 		s_rule->pdata.lkup_tx_rx.act = 0;
13639daf8208SAnirudh Venkataramanan 		s_rule->pdata.lkup_tx_rx.index =
13649daf8208SAnirudh Venkataramanan 			cpu_to_le16(f_info->fltr_rule_id);
13659daf8208SAnirudh Venkataramanan 		s_rule->pdata.lkup_tx_rx.hdr_len = 0;
13669daf8208SAnirudh Venkataramanan 		return;
13679daf8208SAnirudh Venkataramanan 	}
13689daf8208SAnirudh Venkataramanan 
136974118f7aSZhenning Xiao 	eth_hdr_sz = sizeof(dummy_eth_header);
137074118f7aSZhenning Xiao 	eth_hdr = s_rule->pdata.lkup_tx_rx.hdr;
137174118f7aSZhenning Xiao 
13729daf8208SAnirudh Venkataramanan 	/* initialize the ether header with a dummy header */
137374118f7aSZhenning Xiao 	memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);
13749daf8208SAnirudh Venkataramanan 	ice_fill_sw_info(hw, f_info);
13759daf8208SAnirudh Venkataramanan 
13769daf8208SAnirudh Venkataramanan 	switch (f_info->fltr_act) {
13779daf8208SAnirudh Venkataramanan 	case ICE_FWD_TO_VSI:
13785726ca0eSAnirudh Venkataramanan 		act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
13799daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VSI_ID_M;
13809daf8208SAnirudh Venkataramanan 		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
13819daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
13829daf8208SAnirudh Venkataramanan 				ICE_SINGLE_ACT_VALID_BIT;
13839daf8208SAnirudh Venkataramanan 		break;
13849daf8208SAnirudh Venkataramanan 	case ICE_FWD_TO_VSI_LIST:
13859daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_VSI_LIST;
13869daf8208SAnirudh Venkataramanan 		act |= (f_info->fwd_id.vsi_list_id <<
13879daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VSI_LIST_ID_S) &
13889daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VSI_LIST_ID_M;
13899daf8208SAnirudh Venkataramanan 		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
13909daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
13919daf8208SAnirudh Venkataramanan 				ICE_SINGLE_ACT_VALID_BIT;
13929daf8208SAnirudh Venkataramanan 		break;
13939daf8208SAnirudh Venkataramanan 	case ICE_FWD_TO_Q:
13949daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_TO_Q;
13959daf8208SAnirudh Venkataramanan 		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
13969daf8208SAnirudh Venkataramanan 			ICE_SINGLE_ACT_Q_INDEX_M;
13979daf8208SAnirudh Venkataramanan 		break;
13989daf8208SAnirudh Venkataramanan 	case ICE_DROP_PACKET:
1399be8ff000SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
1400be8ff000SAnirudh Venkataramanan 			ICE_SINGLE_ACT_VALID_BIT;
1401be8ff000SAnirudh Venkataramanan 		break;
1402be8ff000SAnirudh Venkataramanan 	case ICE_FWD_TO_QGRP:
1403be8ff000SAnirudh Venkataramanan 		q_rgn = f_info->qgrp_size > 0 ?
1404be8ff000SAnirudh Venkataramanan 			(u8)ilog2(f_info->qgrp_size) : 0;
1405be8ff000SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_TO_Q;
1406be8ff000SAnirudh Venkataramanan 		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
1407be8ff000SAnirudh Venkataramanan 			ICE_SINGLE_ACT_Q_INDEX_M;
1408be8ff000SAnirudh Venkataramanan 		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
1409be8ff000SAnirudh Venkataramanan 			ICE_SINGLE_ACT_Q_REGION_M;
14109daf8208SAnirudh Venkataramanan 		break;
14119daf8208SAnirudh Venkataramanan 	default:
14129daf8208SAnirudh Venkataramanan 		return;
14139daf8208SAnirudh Venkataramanan 	}
14149daf8208SAnirudh Venkataramanan 
14159daf8208SAnirudh Venkataramanan 	if (f_info->lb_en)
14169daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_LB_ENABLE;
14179daf8208SAnirudh Venkataramanan 	if (f_info->lan_en)
14189daf8208SAnirudh Venkataramanan 		act |= ICE_SINGLE_ACT_LAN_ENABLE;
14199daf8208SAnirudh Venkataramanan 
14209daf8208SAnirudh Venkataramanan 	switch (f_info->lkup_type) {
14219daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC:
14229daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.mac.mac_addr;
14239daf8208SAnirudh Venkataramanan 		break;
14249daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_VLAN:
14259daf8208SAnirudh Venkataramanan 		vlan_id = f_info->l_data.vlan.vlan_id;
14269daf8208SAnirudh Venkataramanan 		if (f_info->fltr_act == ICE_FWD_TO_VSI ||
14279daf8208SAnirudh Venkataramanan 		    f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
14289daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_PRUNE;
14299daf8208SAnirudh Venkataramanan 			act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS;
14309daf8208SAnirudh Venkataramanan 		}
14319daf8208SAnirudh Venkataramanan 		break;
14329daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE_MAC:
14339daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.ethertype_mac.mac_addr;
14344e83fc93SBruce Allan 		fallthrough;
14359daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE:
1436feee3cb3SBruce Allan 		off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
14379daf8208SAnirudh Venkataramanan 		*off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype);
14389daf8208SAnirudh Venkataramanan 		break;
14399daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC_VLAN:
14409daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.mac_vlan.mac_addr;
14419daf8208SAnirudh Venkataramanan 		vlan_id = f_info->l_data.mac_vlan.vlan_id;
14429daf8208SAnirudh Venkataramanan 		break;
14439daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_PROMISC_VLAN:
14449daf8208SAnirudh Venkataramanan 		vlan_id = f_info->l_data.mac_vlan.vlan_id;
14454e83fc93SBruce Allan 		fallthrough;
14469daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_PROMISC:
14479daf8208SAnirudh Venkataramanan 		daddr = f_info->l_data.mac_vlan.mac_addr;
14489daf8208SAnirudh Venkataramanan 		break;
14499daf8208SAnirudh Venkataramanan 	default:
14509daf8208SAnirudh Venkataramanan 		break;
14519daf8208SAnirudh Venkataramanan 	}
14529daf8208SAnirudh Venkataramanan 
14539daf8208SAnirudh Venkataramanan 	s_rule->type = (f_info->flag & ICE_FLTR_RX) ?
14549daf8208SAnirudh Venkataramanan 		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) :
14559daf8208SAnirudh Venkataramanan 		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
14569daf8208SAnirudh Venkataramanan 
14579daf8208SAnirudh Venkataramanan 	/* Recipe set depending on lookup type */
14589daf8208SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(f_info->lkup_type);
14599daf8208SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(f_info->src);
14609daf8208SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act);
14619daf8208SAnirudh Venkataramanan 
14629daf8208SAnirudh Venkataramanan 	if (daddr)
146374118f7aSZhenning Xiao 		ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr);
14649daf8208SAnirudh Venkataramanan 
14659daf8208SAnirudh Venkataramanan 	if (!(vlan_id > ICE_MAX_VLAN_ID)) {
1466feee3cb3SBruce Allan 		off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
14679daf8208SAnirudh Venkataramanan 		*off = cpu_to_be16(vlan_id);
14689daf8208SAnirudh Venkataramanan 	}
14699daf8208SAnirudh Venkataramanan 
14709daf8208SAnirudh Venkataramanan 	/* Create the switch rule with the final dummy Ethernet header */
14719daf8208SAnirudh Venkataramanan 	if (opc != ice_aqc_opc_update_sw_rules)
147274118f7aSZhenning Xiao 		s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(eth_hdr_sz);
14739daf8208SAnirudh Venkataramanan }
14749daf8208SAnirudh Venkataramanan 
14759daf8208SAnirudh Venkataramanan /**
14769daf8208SAnirudh Venkataramanan  * ice_add_marker_act
14779daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
14789daf8208SAnirudh Venkataramanan  * @m_ent: the management entry for which sw marker needs to be added
14799daf8208SAnirudh Venkataramanan  * @sw_marker: sw marker to tag the Rx descriptor with
1480f9867df6SAnirudh Venkataramanan  * @l_id: large action resource ID
14819daf8208SAnirudh Venkataramanan  *
14829daf8208SAnirudh Venkataramanan  * Create a large action to hold software marker and update the switch rule
14839daf8208SAnirudh Venkataramanan  * entry pointed by m_ent with newly created large action
14849daf8208SAnirudh Venkataramanan  */
14859daf8208SAnirudh Venkataramanan static enum ice_status
14869daf8208SAnirudh Venkataramanan ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
14879daf8208SAnirudh Venkataramanan 		   u16 sw_marker, u16 l_id)
14889daf8208SAnirudh Venkataramanan {
14899daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *lg_act, *rx_tx;
14909daf8208SAnirudh Venkataramanan 	/* For software marker we need 3 large actions
14919daf8208SAnirudh Venkataramanan 	 * 1. FWD action: FWD TO VSI or VSI LIST
1492f9867df6SAnirudh Venkataramanan 	 * 2. GENERIC VALUE action to hold the profile ID
1493f9867df6SAnirudh Venkataramanan 	 * 3. GENERIC VALUE action to hold the software marker ID
14949daf8208SAnirudh Venkataramanan 	 */
14959daf8208SAnirudh Venkataramanan 	const u16 num_lg_acts = 3;
14969daf8208SAnirudh Venkataramanan 	enum ice_status status;
14979daf8208SAnirudh Venkataramanan 	u16 lg_act_size;
14989daf8208SAnirudh Venkataramanan 	u16 rules_size;
14999daf8208SAnirudh Venkataramanan 	u32 act;
15005726ca0eSAnirudh Venkataramanan 	u16 id;
15019daf8208SAnirudh Venkataramanan 
15029daf8208SAnirudh Venkataramanan 	if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
15039daf8208SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
15049daf8208SAnirudh Venkataramanan 
15059daf8208SAnirudh Venkataramanan 	/* Create two back-to-back switch rules and submit them to the HW using
15069daf8208SAnirudh Venkataramanan 	 * one memory buffer:
15079daf8208SAnirudh Venkataramanan 	 *    1. Large Action
1508d337f2afSAnirudh Venkataramanan 	 *    2. Look up Tx Rx
15099daf8208SAnirudh Venkataramanan 	 */
15109daf8208SAnirudh Venkataramanan 	lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(num_lg_acts);
15119daf8208SAnirudh Venkataramanan 	rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
15129daf8208SAnirudh Venkataramanan 	lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL);
15139daf8208SAnirudh Venkataramanan 	if (!lg_act)
15149daf8208SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
15159daf8208SAnirudh Venkataramanan 
15169daf8208SAnirudh Venkataramanan 	rx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size);
15179daf8208SAnirudh Venkataramanan 
15189daf8208SAnirudh Venkataramanan 	/* Fill in the first switch rule i.e. large action */
15199daf8208SAnirudh Venkataramanan 	lg_act->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT);
15209daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.index = cpu_to_le16(l_id);
15219daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.size = cpu_to_le16(num_lg_acts);
15229daf8208SAnirudh Venkataramanan 
15239daf8208SAnirudh Venkataramanan 	/* First action VSI forwarding or VSI list forwarding depending on how
15249daf8208SAnirudh Venkataramanan 	 * many VSIs
15259daf8208SAnirudh Venkataramanan 	 */
15265726ca0eSAnirudh Venkataramanan 	id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :
15275726ca0eSAnirudh Venkataramanan 		m_ent->fltr_info.fwd_id.hw_vsi_id;
15289daf8208SAnirudh Venkataramanan 
15299daf8208SAnirudh Venkataramanan 	act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
153066486d89SBruce Allan 	act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
15319daf8208SAnirudh Venkataramanan 	if (m_ent->vsi_count > 1)
15329daf8208SAnirudh Venkataramanan 		act |= ICE_LG_ACT_VSI_LIST;
15339daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.act[0] = cpu_to_le32(act);
15349daf8208SAnirudh Venkataramanan 
15359daf8208SAnirudh Venkataramanan 	/* Second action descriptor type */
15369daf8208SAnirudh Venkataramanan 	act = ICE_LG_ACT_GENERIC;
15379daf8208SAnirudh Venkataramanan 
15389daf8208SAnirudh Venkataramanan 	act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
15399daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.act[1] = cpu_to_le32(act);
15409daf8208SAnirudh Venkataramanan 
15414381147dSAnirudh Venkataramanan 	act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
15424381147dSAnirudh Venkataramanan 	       ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
15439daf8208SAnirudh Venkataramanan 
15449daf8208SAnirudh Venkataramanan 	/* Third action Marker value */
15459daf8208SAnirudh Venkataramanan 	act |= ICE_LG_ACT_GENERIC;
15469daf8208SAnirudh Venkataramanan 	act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
15479daf8208SAnirudh Venkataramanan 		ICE_LG_ACT_GENERIC_VALUE_M;
15489daf8208SAnirudh Venkataramanan 
15499daf8208SAnirudh Venkataramanan 	lg_act->pdata.lg_act.act[2] = cpu_to_le32(act);
15509daf8208SAnirudh Venkataramanan 
1551d337f2afSAnirudh Venkataramanan 	/* call the fill switch rule to fill the lookup Tx Rx structure */
15529daf8208SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,
15539daf8208SAnirudh Venkataramanan 			 ice_aqc_opc_update_sw_rules);
15549daf8208SAnirudh Venkataramanan 
1555f9867df6SAnirudh Venkataramanan 	/* Update the action to point to the large action ID */
15569daf8208SAnirudh Venkataramanan 	rx_tx->pdata.lkup_tx_rx.act =
15579daf8208SAnirudh Venkataramanan 		cpu_to_le32(ICE_SINGLE_ACT_PTR |
15589daf8208SAnirudh Venkataramanan 			    ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
15599daf8208SAnirudh Venkataramanan 			     ICE_SINGLE_ACT_PTR_VAL_M));
15609daf8208SAnirudh Venkataramanan 
1561f9867df6SAnirudh Venkataramanan 	/* Use the filter rule ID of the previously created rule with single
15629daf8208SAnirudh Venkataramanan 	 * act. Once the update happens, hardware will treat this as large
15639daf8208SAnirudh Venkataramanan 	 * action
15649daf8208SAnirudh Venkataramanan 	 */
15659daf8208SAnirudh Venkataramanan 	rx_tx->pdata.lkup_tx_rx.index =
15669daf8208SAnirudh Venkataramanan 		cpu_to_le16(m_ent->fltr_info.fltr_rule_id);
15679daf8208SAnirudh Venkataramanan 
15689daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, lg_act, rules_size, 2,
15699daf8208SAnirudh Venkataramanan 				 ice_aqc_opc_update_sw_rules, NULL);
15709daf8208SAnirudh Venkataramanan 	if (!status) {
15719daf8208SAnirudh Venkataramanan 		m_ent->lg_act_idx = l_id;
15729daf8208SAnirudh Venkataramanan 		m_ent->sw_marker_id = sw_marker;
15739daf8208SAnirudh Venkataramanan 	}
15749daf8208SAnirudh Venkataramanan 
15759daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), lg_act);
15769daf8208SAnirudh Venkataramanan 	return status;
15779daf8208SAnirudh Venkataramanan }
15789daf8208SAnirudh Venkataramanan 
15799daf8208SAnirudh Venkataramanan /**
15809daf8208SAnirudh Venkataramanan  * ice_create_vsi_list_map
15819daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
15825726ca0eSAnirudh Venkataramanan  * @vsi_handle_arr: array of VSI handles to set in the VSI mapping
15835726ca0eSAnirudh Venkataramanan  * @num_vsi: number of VSI handles in the array
1584f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID generated as part of allocate resource
15859daf8208SAnirudh Venkataramanan  *
1586f9867df6SAnirudh Venkataramanan  * Helper function to create a new entry of VSI list ID to VSI mapping
1587f9867df6SAnirudh Venkataramanan  * using the given VSI list ID
15889daf8208SAnirudh Venkataramanan  */
15899daf8208SAnirudh Venkataramanan static struct ice_vsi_list_map_info *
15905726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
15919daf8208SAnirudh Venkataramanan 			u16 vsi_list_id)
15929daf8208SAnirudh Venkataramanan {
15939daf8208SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
15949daf8208SAnirudh Venkataramanan 	struct ice_vsi_list_map_info *v_map;
15959daf8208SAnirudh Venkataramanan 	int i;
15969daf8208SAnirudh Venkataramanan 
159736ac7911SBruce Allan 	v_map = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*v_map), GFP_KERNEL);
15989daf8208SAnirudh Venkataramanan 	if (!v_map)
15999daf8208SAnirudh Venkataramanan 		return NULL;
16009daf8208SAnirudh Venkataramanan 
16019daf8208SAnirudh Venkataramanan 	v_map->vsi_list_id = vsi_list_id;
16025726ca0eSAnirudh Venkataramanan 	v_map->ref_cnt = 1;
16039daf8208SAnirudh Venkataramanan 	for (i = 0; i < num_vsi; i++)
16045726ca0eSAnirudh Venkataramanan 		set_bit(vsi_handle_arr[i], v_map->vsi_map);
16059daf8208SAnirudh Venkataramanan 
16069daf8208SAnirudh Venkataramanan 	list_add(&v_map->list_entry, &sw->vsi_list_map_head);
16079daf8208SAnirudh Venkataramanan 	return v_map;
16089daf8208SAnirudh Venkataramanan }
16099daf8208SAnirudh Venkataramanan 
16109daf8208SAnirudh Venkataramanan /**
16119daf8208SAnirudh Venkataramanan  * ice_update_vsi_list_rule
16129daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
16135726ca0eSAnirudh Venkataramanan  * @vsi_handle_arr: array of VSI handles to form a VSI list
16145726ca0eSAnirudh Venkataramanan  * @num_vsi: number of VSI handles in the array
1615f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID generated as part of allocate resource
16169daf8208SAnirudh Venkataramanan  * @remove: Boolean value to indicate if this is a remove action
16179daf8208SAnirudh Venkataramanan  * @opc: switch rules population command type - pass in the command opcode
16189daf8208SAnirudh Venkataramanan  * @lkup_type: lookup type of the filter
16199daf8208SAnirudh Venkataramanan  *
16209daf8208SAnirudh Venkataramanan  * Call AQ command to add a new switch rule or update existing switch rule
1621f9867df6SAnirudh Venkataramanan  * using the given VSI list ID
16229daf8208SAnirudh Venkataramanan  */
16239daf8208SAnirudh Venkataramanan static enum ice_status
16245726ca0eSAnirudh Venkataramanan ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
16259daf8208SAnirudh Venkataramanan 			 u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,
16269daf8208SAnirudh Venkataramanan 			 enum ice_sw_lkup_type lkup_type)
16279daf8208SAnirudh Venkataramanan {
16289daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
16299daf8208SAnirudh Venkataramanan 	enum ice_status status;
16309daf8208SAnirudh Venkataramanan 	u16 s_rule_size;
16316dae8aa0SBruce Allan 	u16 rule_type;
16329daf8208SAnirudh Venkataramanan 	int i;
16339daf8208SAnirudh Venkataramanan 
16349daf8208SAnirudh Venkataramanan 	if (!num_vsi)
16359daf8208SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
16369daf8208SAnirudh Venkataramanan 
16379daf8208SAnirudh Venkataramanan 	if (lkup_type == ICE_SW_LKUP_MAC ||
16389daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
16399daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
16409daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
16419daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC ||
16429daf8208SAnirudh Venkataramanan 	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN)
16436dae8aa0SBruce Allan 		rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR :
16449daf8208SAnirudh Venkataramanan 			ICE_AQC_SW_RULES_T_VSI_LIST_SET;
16459daf8208SAnirudh Venkataramanan 	else if (lkup_type == ICE_SW_LKUP_VLAN)
16466dae8aa0SBruce Allan 		rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR :
16479daf8208SAnirudh Venkataramanan 			ICE_AQC_SW_RULES_T_PRUNE_LIST_SET;
16489daf8208SAnirudh Venkataramanan 	else
16499daf8208SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
16509daf8208SAnirudh Venkataramanan 
16519daf8208SAnirudh Venkataramanan 	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(num_vsi);
16529daf8208SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
16539daf8208SAnirudh Venkataramanan 	if (!s_rule)
16549daf8208SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
16555726ca0eSAnirudh Venkataramanan 	for (i = 0; i < num_vsi; i++) {
16565726ca0eSAnirudh Venkataramanan 		if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {
16575726ca0eSAnirudh Venkataramanan 			status = ICE_ERR_PARAM;
16585726ca0eSAnirudh Venkataramanan 			goto exit;
16595726ca0eSAnirudh Venkataramanan 		}
16605726ca0eSAnirudh Venkataramanan 		/* AQ call requires hw_vsi_id(s) */
16615726ca0eSAnirudh Venkataramanan 		s_rule->pdata.vsi_list.vsi[i] =
16625726ca0eSAnirudh Venkataramanan 			cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));
16635726ca0eSAnirudh Venkataramanan 	}
16649daf8208SAnirudh Venkataramanan 
16656dae8aa0SBruce Allan 	s_rule->type = cpu_to_le16(rule_type);
16669daf8208SAnirudh Venkataramanan 	s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi);
16679daf8208SAnirudh Venkataramanan 	s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
16689daf8208SAnirudh Venkataramanan 
16699daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);
16709daf8208SAnirudh Venkataramanan 
16715726ca0eSAnirudh Venkataramanan exit:
16729daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
16739daf8208SAnirudh Venkataramanan 	return status;
16749daf8208SAnirudh Venkataramanan }
16759daf8208SAnirudh Venkataramanan 
16769daf8208SAnirudh Venkataramanan /**
16779daf8208SAnirudh Venkataramanan  * ice_create_vsi_list_rule - Creates and populates a VSI list rule
1678f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
16795726ca0eSAnirudh Venkataramanan  * @vsi_handle_arr: array of VSI handles to form a VSI list
16805726ca0eSAnirudh Venkataramanan  * @num_vsi: number of VSI handles in the array
16819daf8208SAnirudh Venkataramanan  * @vsi_list_id: stores the ID of the VSI list to be created
16829daf8208SAnirudh Venkataramanan  * @lkup_type: switch rule filter's lookup type
16839daf8208SAnirudh Venkataramanan  */
16849daf8208SAnirudh Venkataramanan static enum ice_status
16855726ca0eSAnirudh Venkataramanan ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
16869daf8208SAnirudh Venkataramanan 			 u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)
16879daf8208SAnirudh Venkataramanan {
16889daf8208SAnirudh Venkataramanan 	enum ice_status status;
16899daf8208SAnirudh Venkataramanan 
16909daf8208SAnirudh Venkataramanan 	status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,
16919daf8208SAnirudh Venkataramanan 					    ice_aqc_opc_alloc_res);
16929daf8208SAnirudh Venkataramanan 	if (status)
16939daf8208SAnirudh Venkataramanan 		return status;
16949daf8208SAnirudh Venkataramanan 
16959daf8208SAnirudh Venkataramanan 	/* Update the newly created VSI list to include the specified VSIs */
16965726ca0eSAnirudh Venkataramanan 	return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,
16975726ca0eSAnirudh Venkataramanan 					*vsi_list_id, false,
16985726ca0eSAnirudh Venkataramanan 					ice_aqc_opc_add_sw_rules, lkup_type);
16999daf8208SAnirudh Venkataramanan }
17009daf8208SAnirudh Venkataramanan 
17019daf8208SAnirudh Venkataramanan /**
17029daf8208SAnirudh Venkataramanan  * ice_create_pkt_fwd_rule
17039daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
17049daf8208SAnirudh Venkataramanan  * @f_entry: entry containing packet forwarding information
17059daf8208SAnirudh Venkataramanan  *
17069daf8208SAnirudh Venkataramanan  * Create switch rule with given filter information and add an entry
17079daf8208SAnirudh Venkataramanan  * to the corresponding filter management list to track this switch rule
17089daf8208SAnirudh Venkataramanan  * and VSI mapping
17099daf8208SAnirudh Venkataramanan  */
17109daf8208SAnirudh Venkataramanan static enum ice_status
17119daf8208SAnirudh Venkataramanan ice_create_pkt_fwd_rule(struct ice_hw *hw,
17129daf8208SAnirudh Venkataramanan 			struct ice_fltr_list_entry *f_entry)
17139daf8208SAnirudh Venkataramanan {
17149daf8208SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *fm_entry;
17159daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
17169daf8208SAnirudh Venkataramanan 	enum ice_sw_lkup_type l_type;
171780d144c9SAnirudh Venkataramanan 	struct ice_sw_recipe *recp;
17189daf8208SAnirudh Venkataramanan 	enum ice_status status;
17199daf8208SAnirudh Venkataramanan 
17209daf8208SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
17219daf8208SAnirudh Venkataramanan 			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);
17229daf8208SAnirudh Venkataramanan 	if (!s_rule)
17239daf8208SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
17249daf8208SAnirudh Venkataramanan 	fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry),
17259daf8208SAnirudh Venkataramanan 				GFP_KERNEL);
17269daf8208SAnirudh Venkataramanan 	if (!fm_entry) {
17279daf8208SAnirudh Venkataramanan 		status = ICE_ERR_NO_MEMORY;
17289daf8208SAnirudh Venkataramanan 		goto ice_create_pkt_fwd_rule_exit;
17299daf8208SAnirudh Venkataramanan 	}
17309daf8208SAnirudh Venkataramanan 
17319daf8208SAnirudh Venkataramanan 	fm_entry->fltr_info = f_entry->fltr_info;
17329daf8208SAnirudh Venkataramanan 
17339daf8208SAnirudh Venkataramanan 	/* Initialize all the fields for the management entry */
17349daf8208SAnirudh Venkataramanan 	fm_entry->vsi_count = 1;
17359daf8208SAnirudh Venkataramanan 	fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX;
17369daf8208SAnirudh Venkataramanan 	fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID;
17379daf8208SAnirudh Venkataramanan 	fm_entry->counter_index = ICE_INVAL_COUNTER_ID;
17389daf8208SAnirudh Venkataramanan 
17399daf8208SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule,
17409daf8208SAnirudh Venkataramanan 			 ice_aqc_opc_add_sw_rules);
17419daf8208SAnirudh Venkataramanan 
17429daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
17439daf8208SAnirudh Venkataramanan 				 ice_aqc_opc_add_sw_rules, NULL);
17449daf8208SAnirudh Venkataramanan 	if (status) {
17459daf8208SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
17469daf8208SAnirudh Venkataramanan 		goto ice_create_pkt_fwd_rule_exit;
17479daf8208SAnirudh Venkataramanan 	}
17489daf8208SAnirudh Venkataramanan 
17499daf8208SAnirudh Venkataramanan 	f_entry->fltr_info.fltr_rule_id =
17509daf8208SAnirudh Venkataramanan 		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
17519daf8208SAnirudh Venkataramanan 	fm_entry->fltr_info.fltr_rule_id =
17529daf8208SAnirudh Venkataramanan 		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
17539daf8208SAnirudh Venkataramanan 
17549daf8208SAnirudh Venkataramanan 	/* The book keeping entries will get removed when base driver
17559daf8208SAnirudh Venkataramanan 	 * calls remove filter AQ command
17569daf8208SAnirudh Venkataramanan 	 */
17579daf8208SAnirudh Venkataramanan 	l_type = fm_entry->fltr_info.lkup_type;
175880d144c9SAnirudh Venkataramanan 	recp = &hw->switch_info->recp_list[l_type];
175980d144c9SAnirudh Venkataramanan 	list_add(&fm_entry->list_entry, &recp->filt_rules);
176080d144c9SAnirudh Venkataramanan 
17619daf8208SAnirudh Venkataramanan ice_create_pkt_fwd_rule_exit:
17629daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
17639daf8208SAnirudh Venkataramanan 	return status;
17649daf8208SAnirudh Venkataramanan }
17659daf8208SAnirudh Venkataramanan 
17669daf8208SAnirudh Venkataramanan /**
17679daf8208SAnirudh Venkataramanan  * ice_update_pkt_fwd_rule
17689daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
176980d144c9SAnirudh Venkataramanan  * @f_info: filter information for switch rule
17709daf8208SAnirudh Venkataramanan  *
17719daf8208SAnirudh Venkataramanan  * Call AQ command to update a previously created switch rule with a
1772f9867df6SAnirudh Venkataramanan  * VSI list ID
17739daf8208SAnirudh Venkataramanan  */
17749daf8208SAnirudh Venkataramanan static enum ice_status
177580d144c9SAnirudh Venkataramanan ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
17769daf8208SAnirudh Venkataramanan {
17779daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
17789daf8208SAnirudh Venkataramanan 	enum ice_status status;
17799daf8208SAnirudh Venkataramanan 
17809daf8208SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
17819daf8208SAnirudh Venkataramanan 			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);
17829daf8208SAnirudh Venkataramanan 	if (!s_rule)
17839daf8208SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
17849daf8208SAnirudh Venkataramanan 
178580d144c9SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);
17869daf8208SAnirudh Venkataramanan 
178780d144c9SAnirudh Venkataramanan 	s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(f_info->fltr_rule_id);
17889daf8208SAnirudh Venkataramanan 
17899daf8208SAnirudh Venkataramanan 	/* Update switch rule with new rule set to forward VSI list */
17909daf8208SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
17919daf8208SAnirudh Venkataramanan 				 ice_aqc_opc_update_sw_rules, NULL);
17929daf8208SAnirudh Venkataramanan 
17939daf8208SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
17949daf8208SAnirudh Venkataramanan 	return status;
17959daf8208SAnirudh Venkataramanan }
17969daf8208SAnirudh Venkataramanan 
17979daf8208SAnirudh Venkataramanan /**
1798b1edc14aSMd Fahad Iqbal Polash  * ice_update_sw_rule_bridge_mode
1799f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
1800b1edc14aSMd Fahad Iqbal Polash  *
1801b1edc14aSMd Fahad Iqbal Polash  * Updates unicast switch filter rules based on VEB/VEPA mode
1802b1edc14aSMd Fahad Iqbal Polash  */
1803b1edc14aSMd Fahad Iqbal Polash enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
1804b1edc14aSMd Fahad Iqbal Polash {
1805b1edc14aSMd Fahad Iqbal Polash 	struct ice_switch_info *sw = hw->switch_info;
1806b1edc14aSMd Fahad Iqbal Polash 	struct ice_fltr_mgmt_list_entry *fm_entry;
1807b1edc14aSMd Fahad Iqbal Polash 	enum ice_status status = 0;
1808b1edc14aSMd Fahad Iqbal Polash 	struct list_head *rule_head;
1809b1edc14aSMd Fahad Iqbal Polash 	struct mutex *rule_lock; /* Lock to protect filter rule list */
1810b1edc14aSMd Fahad Iqbal Polash 
1811b1edc14aSMd Fahad Iqbal Polash 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
1812b1edc14aSMd Fahad Iqbal Polash 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
1813b1edc14aSMd Fahad Iqbal Polash 
1814b1edc14aSMd Fahad Iqbal Polash 	mutex_lock(rule_lock);
1815b1edc14aSMd Fahad Iqbal Polash 	list_for_each_entry(fm_entry, rule_head, list_entry) {
1816b1edc14aSMd Fahad Iqbal Polash 		struct ice_fltr_info *fi = &fm_entry->fltr_info;
1817b1edc14aSMd Fahad Iqbal Polash 		u8 *addr = fi->l_data.mac.mac_addr;
1818b1edc14aSMd Fahad Iqbal Polash 
1819b1edc14aSMd Fahad Iqbal Polash 		/* Update unicast Tx rules to reflect the selected
1820b1edc14aSMd Fahad Iqbal Polash 		 * VEB/VEPA mode
1821b1edc14aSMd Fahad Iqbal Polash 		 */
1822b1edc14aSMd Fahad Iqbal Polash 		if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) &&
1823b1edc14aSMd Fahad Iqbal Polash 		    (fi->fltr_act == ICE_FWD_TO_VSI ||
1824b1edc14aSMd Fahad Iqbal Polash 		     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
1825b1edc14aSMd Fahad Iqbal Polash 		     fi->fltr_act == ICE_FWD_TO_Q ||
1826b1edc14aSMd Fahad Iqbal Polash 		     fi->fltr_act == ICE_FWD_TO_QGRP)) {
1827b1edc14aSMd Fahad Iqbal Polash 			status = ice_update_pkt_fwd_rule(hw, fi);
1828b1edc14aSMd Fahad Iqbal Polash 			if (status)
1829b1edc14aSMd Fahad Iqbal Polash 				break;
1830b1edc14aSMd Fahad Iqbal Polash 		}
1831b1edc14aSMd Fahad Iqbal Polash 	}
1832b1edc14aSMd Fahad Iqbal Polash 
1833b1edc14aSMd Fahad Iqbal Polash 	mutex_unlock(rule_lock);
1834b1edc14aSMd Fahad Iqbal Polash 
1835b1edc14aSMd Fahad Iqbal Polash 	return status;
1836b1edc14aSMd Fahad Iqbal Polash }
1837b1edc14aSMd Fahad Iqbal Polash 
1838b1edc14aSMd Fahad Iqbal Polash /**
183980d144c9SAnirudh Venkataramanan  * ice_add_update_vsi_list
18409daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
18419daf8208SAnirudh Venkataramanan  * @m_entry: pointer to current filter management list entry
18429daf8208SAnirudh Venkataramanan  * @cur_fltr: filter information from the book keeping entry
18439daf8208SAnirudh Venkataramanan  * @new_fltr: filter information with the new VSI to be added
18449daf8208SAnirudh Venkataramanan  *
18459daf8208SAnirudh Venkataramanan  * Call AQ command to add or update previously created VSI list with new VSI.
18469daf8208SAnirudh Venkataramanan  *
18479daf8208SAnirudh Venkataramanan  * Helper function to do book keeping associated with adding filter information
1848d337f2afSAnirudh Venkataramanan  * The algorithm to do the book keeping is described below :
18499daf8208SAnirudh Venkataramanan  * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.)
18509daf8208SAnirudh Venkataramanan  *	if only one VSI has been added till now
18519daf8208SAnirudh Venkataramanan  *		Allocate a new VSI list and add two VSIs
18529daf8208SAnirudh Venkataramanan  *		to this list using switch rule command
18539daf8208SAnirudh Venkataramanan  *		Update the previously created switch rule with the
1854f9867df6SAnirudh Venkataramanan  *		newly created VSI list ID
18559daf8208SAnirudh Venkataramanan  *	if a VSI list was previously created
18569daf8208SAnirudh Venkataramanan  *		Add the new VSI to the previously created VSI list set
18579daf8208SAnirudh Venkataramanan  *		using the update switch rule command
18589daf8208SAnirudh Venkataramanan  */
18599daf8208SAnirudh Venkataramanan static enum ice_status
186080d144c9SAnirudh Venkataramanan ice_add_update_vsi_list(struct ice_hw *hw,
18619daf8208SAnirudh Venkataramanan 			struct ice_fltr_mgmt_list_entry *m_entry,
18629daf8208SAnirudh Venkataramanan 			struct ice_fltr_info *cur_fltr,
18639daf8208SAnirudh Venkataramanan 			struct ice_fltr_info *new_fltr)
18649daf8208SAnirudh Venkataramanan {
18659daf8208SAnirudh Venkataramanan 	enum ice_status status = 0;
18669daf8208SAnirudh Venkataramanan 	u16 vsi_list_id = 0;
18679daf8208SAnirudh Venkataramanan 
18689daf8208SAnirudh Venkataramanan 	if ((cur_fltr->fltr_act == ICE_FWD_TO_Q ||
18699daf8208SAnirudh Venkataramanan 	     cur_fltr->fltr_act == ICE_FWD_TO_QGRP))
18709daf8208SAnirudh Venkataramanan 		return ICE_ERR_NOT_IMPL;
18719daf8208SAnirudh Venkataramanan 
18729daf8208SAnirudh Venkataramanan 	if ((new_fltr->fltr_act == ICE_FWD_TO_Q ||
18739daf8208SAnirudh Venkataramanan 	     new_fltr->fltr_act == ICE_FWD_TO_QGRP) &&
18749daf8208SAnirudh Venkataramanan 	    (cur_fltr->fltr_act == ICE_FWD_TO_VSI ||
18759daf8208SAnirudh Venkataramanan 	     cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST))
18769daf8208SAnirudh Venkataramanan 		return ICE_ERR_NOT_IMPL;
18779daf8208SAnirudh Venkataramanan 
18789daf8208SAnirudh Venkataramanan 	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
18799daf8208SAnirudh Venkataramanan 		/* Only one entry existed in the mapping and it was not already
18809daf8208SAnirudh Venkataramanan 		 * a part of a VSI list. So, create a VSI list with the old and
18819daf8208SAnirudh Venkataramanan 		 * new VSIs.
18829daf8208SAnirudh Venkataramanan 		 */
188380d144c9SAnirudh Venkataramanan 		struct ice_fltr_info tmp_fltr;
18845726ca0eSAnirudh Venkataramanan 		u16 vsi_handle_arr[2];
18859daf8208SAnirudh Venkataramanan 
18869daf8208SAnirudh Venkataramanan 		/* A rule already exists with the new VSI being added */
18875726ca0eSAnirudh Venkataramanan 		if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id)
18889daf8208SAnirudh Venkataramanan 			return ICE_ERR_ALREADY_EXISTS;
18899daf8208SAnirudh Venkataramanan 
18905726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[0] = cur_fltr->vsi_handle;
18915726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[1] = new_fltr->vsi_handle;
18925726ca0eSAnirudh Venkataramanan 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
18939daf8208SAnirudh Venkataramanan 						  &vsi_list_id,
18949daf8208SAnirudh Venkataramanan 						  new_fltr->lkup_type);
18959daf8208SAnirudh Venkataramanan 		if (status)
18969daf8208SAnirudh Venkataramanan 			return status;
18979daf8208SAnirudh Venkataramanan 
189880d144c9SAnirudh Venkataramanan 		tmp_fltr = *new_fltr;
189980d144c9SAnirudh Venkataramanan 		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
190080d144c9SAnirudh Venkataramanan 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
190180d144c9SAnirudh Venkataramanan 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
19029daf8208SAnirudh Venkataramanan 		/* Update the previous switch rule of "MAC forward to VSI" to
19039daf8208SAnirudh Venkataramanan 		 * "MAC fwd to VSI list"
19049daf8208SAnirudh Venkataramanan 		 */
190580d144c9SAnirudh Venkataramanan 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
19069daf8208SAnirudh Venkataramanan 		if (status)
19079daf8208SAnirudh Venkataramanan 			return status;
19089daf8208SAnirudh Venkataramanan 
19099daf8208SAnirudh Venkataramanan 		cur_fltr->fwd_id.vsi_list_id = vsi_list_id;
19109daf8208SAnirudh Venkataramanan 		cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
19119daf8208SAnirudh Venkataramanan 		m_entry->vsi_list_info =
19125726ca0eSAnirudh Venkataramanan 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
19139daf8208SAnirudh Venkataramanan 						vsi_list_id);
19149daf8208SAnirudh Venkataramanan 
19157a91d3f0SJacek Bułatek 		if (!m_entry->vsi_list_info)
19167a91d3f0SJacek Bułatek 			return ICE_ERR_NO_MEMORY;
19177a91d3f0SJacek Bułatek 
19189daf8208SAnirudh Venkataramanan 		/* If this entry was large action then the large action needs
19199daf8208SAnirudh Venkataramanan 		 * to be updated to point to FWD to VSI list
19209daf8208SAnirudh Venkataramanan 		 */
19219daf8208SAnirudh Venkataramanan 		if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID)
19229daf8208SAnirudh Venkataramanan 			status =
19239daf8208SAnirudh Venkataramanan 			    ice_add_marker_act(hw, m_entry,
19249daf8208SAnirudh Venkataramanan 					       m_entry->sw_marker_id,
19259daf8208SAnirudh Venkataramanan 					       m_entry->lg_act_idx);
19269daf8208SAnirudh Venkataramanan 	} else {
19275726ca0eSAnirudh Venkataramanan 		u16 vsi_handle = new_fltr->vsi_handle;
19289daf8208SAnirudh Venkataramanan 		enum ice_adminq_opc opcode;
19299daf8208SAnirudh Venkataramanan 
1930f25dad19SBruce Allan 		if (!m_entry->vsi_list_info)
1931f25dad19SBruce Allan 			return ICE_ERR_CFG;
1932f25dad19SBruce Allan 
19339daf8208SAnirudh Venkataramanan 		/* A rule already exists with the new VSI being added */
19345726ca0eSAnirudh Venkataramanan 		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
19359daf8208SAnirudh Venkataramanan 			return 0;
19369daf8208SAnirudh Venkataramanan 
19379daf8208SAnirudh Venkataramanan 		/* Update the previously created VSI list set with
1938f9867df6SAnirudh Venkataramanan 		 * the new VSI ID passed in
19399daf8208SAnirudh Venkataramanan 		 */
19409daf8208SAnirudh Venkataramanan 		vsi_list_id = cur_fltr->fwd_id.vsi_list_id;
19419daf8208SAnirudh Venkataramanan 		opcode = ice_aqc_opc_update_sw_rules;
19429daf8208SAnirudh Venkataramanan 
19435726ca0eSAnirudh Venkataramanan 		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
19445726ca0eSAnirudh Venkataramanan 						  vsi_list_id, false, opcode,
19459daf8208SAnirudh Venkataramanan 						  new_fltr->lkup_type);
1946f9867df6SAnirudh Venkataramanan 		/* update VSI list mapping info with new VSI ID */
19479daf8208SAnirudh Venkataramanan 		if (!status)
19485726ca0eSAnirudh Venkataramanan 			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
19499daf8208SAnirudh Venkataramanan 	}
19509daf8208SAnirudh Venkataramanan 	if (!status)
19519daf8208SAnirudh Venkataramanan 		m_entry->vsi_count++;
19529daf8208SAnirudh Venkataramanan 	return status;
19539daf8208SAnirudh Venkataramanan }
19549daf8208SAnirudh Venkataramanan 
19559daf8208SAnirudh Venkataramanan /**
195680d144c9SAnirudh Venkataramanan  * ice_find_rule_entry - Search a rule entry
19579daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
195880d144c9SAnirudh Venkataramanan  * @recp_id: lookup type for which the specified rule needs to be searched
195980d144c9SAnirudh Venkataramanan  * @f_info: rule information
19609daf8208SAnirudh Venkataramanan  *
196180d144c9SAnirudh Venkataramanan  * Helper function to search for a given rule entry
196280d144c9SAnirudh Venkataramanan  * Returns pointer to entry storing the rule if found
19639daf8208SAnirudh Venkataramanan  */
19649daf8208SAnirudh Venkataramanan static struct ice_fltr_mgmt_list_entry *
196580d144c9SAnirudh Venkataramanan ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
19669daf8208SAnirudh Venkataramanan {
196780d144c9SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;
19689daf8208SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
196980d144c9SAnirudh Venkataramanan 	struct list_head *list_head;
19709daf8208SAnirudh Venkataramanan 
197180d144c9SAnirudh Venkataramanan 	list_head = &sw->recp_list[recp_id].filt_rules;
197280d144c9SAnirudh Venkataramanan 	list_for_each_entry(list_itr, list_head, list_entry) {
197380d144c9SAnirudh Venkataramanan 		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
197480d144c9SAnirudh Venkataramanan 			    sizeof(f_info->l_data)) &&
197580d144c9SAnirudh Venkataramanan 		    f_info->flag == list_itr->fltr_info.flag) {
197680d144c9SAnirudh Venkataramanan 			ret = list_itr;
19779daf8208SAnirudh Venkataramanan 			break;
19789daf8208SAnirudh Venkataramanan 		}
19799daf8208SAnirudh Venkataramanan 	}
198080d144c9SAnirudh Venkataramanan 	return ret;
19819daf8208SAnirudh Venkataramanan }
19829daf8208SAnirudh Venkataramanan 
19839daf8208SAnirudh Venkataramanan /**
19845726ca0eSAnirudh Venkataramanan  * ice_find_vsi_list_entry - Search VSI list map with VSI count 1
19855726ca0eSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
19865726ca0eSAnirudh Venkataramanan  * @recp_id: lookup type for which VSI lists needs to be searched
19875726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to be found in VSI list
1988f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID found containing vsi_handle
19895726ca0eSAnirudh Venkataramanan  *
19905726ca0eSAnirudh Venkataramanan  * Helper function to search a VSI list with single entry containing given VSI
19915726ca0eSAnirudh Venkataramanan  * handle element. This can be extended further to search VSI list with more
19925726ca0eSAnirudh Venkataramanan  * than 1 vsi_count. Returns pointer to VSI list entry if found.
19935726ca0eSAnirudh Venkataramanan  */
19945726ca0eSAnirudh Venkataramanan static struct ice_vsi_list_map_info *
19955726ca0eSAnirudh Venkataramanan ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
19965726ca0eSAnirudh Venkataramanan 			u16 *vsi_list_id)
19975726ca0eSAnirudh Venkataramanan {
19985726ca0eSAnirudh Venkataramanan 	struct ice_vsi_list_map_info *map_info = NULL;
19995726ca0eSAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
20005726ca0eSAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *list_itr;
20015726ca0eSAnirudh Venkataramanan 	struct list_head *list_head;
20025726ca0eSAnirudh Venkataramanan 
20035726ca0eSAnirudh Venkataramanan 	list_head = &sw->recp_list[recp_id].filt_rules;
20045726ca0eSAnirudh Venkataramanan 	list_for_each_entry(list_itr, list_head, list_entry) {
20055726ca0eSAnirudh Venkataramanan 		if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {
20065726ca0eSAnirudh Venkataramanan 			map_info = list_itr->vsi_list_info;
20075726ca0eSAnirudh Venkataramanan 			if (test_bit(vsi_handle, map_info->vsi_map)) {
20085726ca0eSAnirudh Venkataramanan 				*vsi_list_id = map_info->vsi_list_id;
20095726ca0eSAnirudh Venkataramanan 				return map_info;
20105726ca0eSAnirudh Venkataramanan 			}
20115726ca0eSAnirudh Venkataramanan 		}
20125726ca0eSAnirudh Venkataramanan 	}
20135726ca0eSAnirudh Venkataramanan 	return NULL;
20145726ca0eSAnirudh Venkataramanan }
20155726ca0eSAnirudh Venkataramanan 
20165726ca0eSAnirudh Venkataramanan /**
201780d144c9SAnirudh Venkataramanan  * ice_add_rule_internal - add rule for a given lookup type
20189daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2019f9867df6SAnirudh Venkataramanan  * @recp_id: lookup type (recipe ID) for which rule has to be added
20209daf8208SAnirudh Venkataramanan  * @f_entry: structure containing MAC forwarding information
20219daf8208SAnirudh Venkataramanan  *
202280d144c9SAnirudh Venkataramanan  * Adds or updates the rule lists for a given recipe
20239daf8208SAnirudh Venkataramanan  */
20249daf8208SAnirudh Venkataramanan static enum ice_status
202580d144c9SAnirudh Venkataramanan ice_add_rule_internal(struct ice_hw *hw, u8 recp_id,
202680d144c9SAnirudh Venkataramanan 		      struct ice_fltr_list_entry *f_entry)
20279daf8208SAnirudh Venkataramanan {
202880d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
20299daf8208SAnirudh Venkataramanan 	struct ice_fltr_info *new_fltr, *cur_fltr;
20309daf8208SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *m_entry;
203180d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
203280d144c9SAnirudh Venkataramanan 	enum ice_status status = 0;
20339daf8208SAnirudh Venkataramanan 
20345726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
20355726ca0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
20365726ca0eSAnirudh Venkataramanan 	f_entry->fltr_info.fwd_id.hw_vsi_id =
20375726ca0eSAnirudh Venkataramanan 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
20385726ca0eSAnirudh Venkataramanan 
203980d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
204080d144c9SAnirudh Venkataramanan 
204180d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
20429daf8208SAnirudh Venkataramanan 	new_fltr = &f_entry->fltr_info;
204380d144c9SAnirudh Venkataramanan 	if (new_fltr->flag & ICE_FLTR_RX)
204480d144c9SAnirudh Venkataramanan 		new_fltr->src = hw->port_info->lport;
204580d144c9SAnirudh Venkataramanan 	else if (new_fltr->flag & ICE_FLTR_TX)
20465726ca0eSAnirudh Venkataramanan 		new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id;
20479daf8208SAnirudh Venkataramanan 
204880d144c9SAnirudh Venkataramanan 	m_entry = ice_find_rule_entry(hw, recp_id, new_fltr);
204980d144c9SAnirudh Venkataramanan 	if (!m_entry) {
205080d144c9SAnirudh Venkataramanan 		mutex_unlock(rule_lock);
20519daf8208SAnirudh Venkataramanan 		return ice_create_pkt_fwd_rule(hw, f_entry);
205280d144c9SAnirudh Venkataramanan 	}
20539daf8208SAnirudh Venkataramanan 
20549daf8208SAnirudh Venkataramanan 	cur_fltr = &m_entry->fltr_info;
205580d144c9SAnirudh Venkataramanan 	status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);
205680d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
20579daf8208SAnirudh Venkataramanan 
205880d144c9SAnirudh Venkataramanan 	return status;
205980d144c9SAnirudh Venkataramanan }
206080d144c9SAnirudh Venkataramanan 
206180d144c9SAnirudh Venkataramanan /**
206280d144c9SAnirudh Venkataramanan  * ice_remove_vsi_list_rule
206380d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2064f9867df6SAnirudh Venkataramanan  * @vsi_list_id: VSI list ID generated as part of allocate resource
206580d144c9SAnirudh Venkataramanan  * @lkup_type: switch rule filter lookup type
206680d144c9SAnirudh Venkataramanan  *
206780d144c9SAnirudh Venkataramanan  * The VSI list should be emptied before this function is called to remove the
206880d144c9SAnirudh Venkataramanan  * VSI list.
206980d144c9SAnirudh Venkataramanan  */
207080d144c9SAnirudh Venkataramanan static enum ice_status
207180d144c9SAnirudh Venkataramanan ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
207280d144c9SAnirudh Venkataramanan 			 enum ice_sw_lkup_type lkup_type)
207380d144c9SAnirudh Venkataramanan {
207480d144c9SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
207580d144c9SAnirudh Venkataramanan 	enum ice_status status;
207680d144c9SAnirudh Venkataramanan 	u16 s_rule_size;
207780d144c9SAnirudh Venkataramanan 
207880d144c9SAnirudh Venkataramanan 	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0);
207980d144c9SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
208080d144c9SAnirudh Venkataramanan 	if (!s_rule)
208180d144c9SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
208280d144c9SAnirudh Venkataramanan 
208380d144c9SAnirudh Venkataramanan 	s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);
208480d144c9SAnirudh Venkataramanan 	s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
208580d144c9SAnirudh Venkataramanan 
208680d144c9SAnirudh Venkataramanan 	/* Free the vsi_list resource that we allocated. It is assumed that the
208780d144c9SAnirudh Venkataramanan 	 * list is empty at this point.
208880d144c9SAnirudh Venkataramanan 	 */
208980d144c9SAnirudh Venkataramanan 	status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
209080d144c9SAnirudh Venkataramanan 					    ice_aqc_opc_free_res);
209180d144c9SAnirudh Venkataramanan 
209280d144c9SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
209380d144c9SAnirudh Venkataramanan 	return status;
209480d144c9SAnirudh Venkataramanan }
209580d144c9SAnirudh Venkataramanan 
209680d144c9SAnirudh Venkataramanan /**
209780d144c9SAnirudh Venkataramanan  * ice_rem_update_vsi_list
209880d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
20995726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle of the VSI to remove
210080d144c9SAnirudh Venkataramanan  * @fm_list: filter management entry for which the VSI list management needs to
210180d144c9SAnirudh Venkataramanan  *           be done
210280d144c9SAnirudh Venkataramanan  */
210380d144c9SAnirudh Venkataramanan static enum ice_status
21045726ca0eSAnirudh Venkataramanan ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
210580d144c9SAnirudh Venkataramanan 			struct ice_fltr_mgmt_list_entry *fm_list)
210680d144c9SAnirudh Venkataramanan {
210780d144c9SAnirudh Venkataramanan 	enum ice_sw_lkup_type lkup_type;
210880d144c9SAnirudh Venkataramanan 	enum ice_status status = 0;
210980d144c9SAnirudh Venkataramanan 	u16 vsi_list_id;
211080d144c9SAnirudh Venkataramanan 
211180d144c9SAnirudh Venkataramanan 	if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||
211280d144c9SAnirudh Venkataramanan 	    fm_list->vsi_count == 0)
211380d144c9SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
211480d144c9SAnirudh Venkataramanan 
211580d144c9SAnirudh Venkataramanan 	/* A rule with the VSI being removed does not exist */
21165726ca0eSAnirudh Venkataramanan 	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
211780d144c9SAnirudh Venkataramanan 		return ICE_ERR_DOES_NOT_EXIST;
211880d144c9SAnirudh Venkataramanan 
211980d144c9SAnirudh Venkataramanan 	lkup_type = fm_list->fltr_info.lkup_type;
212080d144c9SAnirudh Venkataramanan 	vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;
21215726ca0eSAnirudh Venkataramanan 	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
212280d144c9SAnirudh Venkataramanan 					  ice_aqc_opc_update_sw_rules,
212380d144c9SAnirudh Venkataramanan 					  lkup_type);
212480d144c9SAnirudh Venkataramanan 	if (status)
212580d144c9SAnirudh Venkataramanan 		return status;
212680d144c9SAnirudh Venkataramanan 
212780d144c9SAnirudh Venkataramanan 	fm_list->vsi_count--;
21285726ca0eSAnirudh Venkataramanan 	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
212980d144c9SAnirudh Venkataramanan 
2130c60cdb13SBrett Creeley 	if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {
2131c60cdb13SBrett Creeley 		struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;
213280d144c9SAnirudh Venkataramanan 		struct ice_vsi_list_map_info *vsi_list_info =
213380d144c9SAnirudh Venkataramanan 			fm_list->vsi_list_info;
21345726ca0eSAnirudh Venkataramanan 		u16 rem_vsi_handle;
213580d144c9SAnirudh Venkataramanan 
21365726ca0eSAnirudh Venkataramanan 		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
213780d144c9SAnirudh Venkataramanan 						ICE_MAX_VSI);
21385726ca0eSAnirudh Venkataramanan 		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
213980d144c9SAnirudh Venkataramanan 			return ICE_ERR_OUT_OF_RANGE;
2140c60cdb13SBrett Creeley 
2141c60cdb13SBrett Creeley 		/* Make sure VSI list is empty before removing it below */
21425726ca0eSAnirudh Venkataramanan 		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
214380d144c9SAnirudh Venkataramanan 						  vsi_list_id, true,
214480d144c9SAnirudh Venkataramanan 						  ice_aqc_opc_update_sw_rules,
214580d144c9SAnirudh Venkataramanan 						  lkup_type);
214680d144c9SAnirudh Venkataramanan 		if (status)
214780d144c9SAnirudh Venkataramanan 			return status;
214880d144c9SAnirudh Venkataramanan 
2149c60cdb13SBrett Creeley 		tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;
2150c60cdb13SBrett Creeley 		tmp_fltr_info.fwd_id.hw_vsi_id =
2151c60cdb13SBrett Creeley 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
2152c60cdb13SBrett Creeley 		tmp_fltr_info.vsi_handle = rem_vsi_handle;
2153c60cdb13SBrett Creeley 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);
2154c60cdb13SBrett Creeley 		if (status) {
21559228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
2156c60cdb13SBrett Creeley 				  tmp_fltr_info.fwd_id.hw_vsi_id, status);
2157c60cdb13SBrett Creeley 			return status;
2158c60cdb13SBrett Creeley 		}
2159c60cdb13SBrett Creeley 
2160c60cdb13SBrett Creeley 		fm_list->fltr_info = tmp_fltr_info;
2161c60cdb13SBrett Creeley 	}
2162c60cdb13SBrett Creeley 
2163c60cdb13SBrett Creeley 	if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||
2164c60cdb13SBrett Creeley 	    (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {
2165c60cdb13SBrett Creeley 		struct ice_vsi_list_map_info *vsi_list_info =
2166c60cdb13SBrett Creeley 			fm_list->vsi_list_info;
2167c60cdb13SBrett Creeley 
216880d144c9SAnirudh Venkataramanan 		/* Remove the VSI list since it is no longer used */
216980d144c9SAnirudh Venkataramanan 		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
2170c60cdb13SBrett Creeley 		if (status) {
21719228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
2172c60cdb13SBrett Creeley 				  vsi_list_id, status);
217380d144c9SAnirudh Venkataramanan 			return status;
2174c60cdb13SBrett Creeley 		}
217580d144c9SAnirudh Venkataramanan 
217680d144c9SAnirudh Venkataramanan 		list_del(&vsi_list_info->list_entry);
217780d144c9SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
217880d144c9SAnirudh Venkataramanan 		fm_list->vsi_list_info = NULL;
217980d144c9SAnirudh Venkataramanan 	}
218080d144c9SAnirudh Venkataramanan 
218180d144c9SAnirudh Venkataramanan 	return status;
218280d144c9SAnirudh Venkataramanan }
218380d144c9SAnirudh Venkataramanan 
218480d144c9SAnirudh Venkataramanan /**
218580d144c9SAnirudh Venkataramanan  * ice_remove_rule_internal - Remove a filter rule of a given type
218680d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2187f9867df6SAnirudh Venkataramanan  * @recp_id: recipe ID for which the rule needs to removed
218880d144c9SAnirudh Venkataramanan  * @f_entry: rule entry containing filter information
218980d144c9SAnirudh Venkataramanan  */
219080d144c9SAnirudh Venkataramanan static enum ice_status
219180d144c9SAnirudh Venkataramanan ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id,
219280d144c9SAnirudh Venkataramanan 			 struct ice_fltr_list_entry *f_entry)
219380d144c9SAnirudh Venkataramanan {
219480d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
219580d144c9SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *list_elem;
219680d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
219780d144c9SAnirudh Venkataramanan 	enum ice_status status = 0;
219880d144c9SAnirudh Venkataramanan 	bool remove_rule = false;
21995726ca0eSAnirudh Venkataramanan 	u16 vsi_handle;
22005726ca0eSAnirudh Venkataramanan 
22015726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
22025726ca0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
22035726ca0eSAnirudh Venkataramanan 	f_entry->fltr_info.fwd_id.hw_vsi_id =
22045726ca0eSAnirudh Venkataramanan 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
220580d144c9SAnirudh Venkataramanan 
220680d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
220780d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
220880d144c9SAnirudh Venkataramanan 	list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info);
220980d144c9SAnirudh Venkataramanan 	if (!list_elem) {
221080d144c9SAnirudh Venkataramanan 		status = ICE_ERR_DOES_NOT_EXIST;
221180d144c9SAnirudh Venkataramanan 		goto exit;
221280d144c9SAnirudh Venkataramanan 	}
221380d144c9SAnirudh Venkataramanan 
221480d144c9SAnirudh Venkataramanan 	if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
221580d144c9SAnirudh Venkataramanan 		remove_rule = true;
22165726ca0eSAnirudh Venkataramanan 	} else if (!list_elem->vsi_list_info) {
22175726ca0eSAnirudh Venkataramanan 		status = ICE_ERR_DOES_NOT_EXIST;
22185726ca0eSAnirudh Venkataramanan 		goto exit;
2219f9264dd6SJacob Keller 	} else if (list_elem->vsi_list_info->ref_cnt > 1) {
2220f9264dd6SJacob Keller 		/* a ref_cnt > 1 indicates that the vsi_list is being
2221f9264dd6SJacob Keller 		 * shared by multiple rules. Decrement the ref_cnt and
2222f9264dd6SJacob Keller 		 * remove this rule, but do not modify the list, as it
2223f9264dd6SJacob Keller 		 * is in-use by other rules.
2224f9264dd6SJacob Keller 		 */
22255726ca0eSAnirudh Venkataramanan 		list_elem->vsi_list_info->ref_cnt--;
2226f9264dd6SJacob Keller 		remove_rule = true;
2227f9264dd6SJacob Keller 	} else {
2228f9264dd6SJacob Keller 		/* a ref_cnt of 1 indicates the vsi_list is only used
2229f9264dd6SJacob Keller 		 * by one rule. However, the original removal request is only
2230f9264dd6SJacob Keller 		 * for a single VSI. Update the vsi_list first, and only
2231f9264dd6SJacob Keller 		 * remove the rule if there are no further VSIs in this list.
2232f9264dd6SJacob Keller 		 */
22335726ca0eSAnirudh Venkataramanan 		vsi_handle = f_entry->fltr_info.vsi_handle;
22345726ca0eSAnirudh Venkataramanan 		status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);
223580d144c9SAnirudh Venkataramanan 		if (status)
223680d144c9SAnirudh Venkataramanan 			goto exit;
2237f9867df6SAnirudh Venkataramanan 		/* if VSI count goes to zero after updating the VSI list */
223880d144c9SAnirudh Venkataramanan 		if (list_elem->vsi_count == 0)
223980d144c9SAnirudh Venkataramanan 			remove_rule = true;
224080d144c9SAnirudh Venkataramanan 	}
224180d144c9SAnirudh Venkataramanan 
224280d144c9SAnirudh Venkataramanan 	if (remove_rule) {
224380d144c9SAnirudh Venkataramanan 		/* Remove the lookup rule */
224480d144c9SAnirudh Venkataramanan 		struct ice_aqc_sw_rules_elem *s_rule;
224580d144c9SAnirudh Venkataramanan 
224680d144c9SAnirudh Venkataramanan 		s_rule = devm_kzalloc(ice_hw_to_dev(hw),
224780d144c9SAnirudh Venkataramanan 				      ICE_SW_RULE_RX_TX_NO_HDR_SIZE,
224880d144c9SAnirudh Venkataramanan 				      GFP_KERNEL);
224980d144c9SAnirudh Venkataramanan 		if (!s_rule) {
225080d144c9SAnirudh Venkataramanan 			status = ICE_ERR_NO_MEMORY;
225180d144c9SAnirudh Venkataramanan 			goto exit;
225280d144c9SAnirudh Venkataramanan 		}
225380d144c9SAnirudh Venkataramanan 
225480d144c9SAnirudh Venkataramanan 		ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,
225580d144c9SAnirudh Venkataramanan 				 ice_aqc_opc_remove_sw_rules);
225680d144c9SAnirudh Venkataramanan 
225780d144c9SAnirudh Venkataramanan 		status = ice_aq_sw_rules(hw, s_rule,
225880d144c9SAnirudh Venkataramanan 					 ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1,
225980d144c9SAnirudh Venkataramanan 					 ice_aqc_opc_remove_sw_rules, NULL);
226080d144c9SAnirudh Venkataramanan 
226180d144c9SAnirudh Venkataramanan 		/* Remove a book keeping from the list */
226280d144c9SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), s_rule);
226380d144c9SAnirudh Venkataramanan 
22648132e17dSJeb Cramer 		if (status)
22658132e17dSJeb Cramer 			goto exit;
22668132e17dSJeb Cramer 
226780d144c9SAnirudh Venkataramanan 		list_del(&list_elem->list_entry);
226880d144c9SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), list_elem);
226980d144c9SAnirudh Venkataramanan 	}
227080d144c9SAnirudh Venkataramanan exit:
227180d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
227280d144c9SAnirudh Venkataramanan 	return status;
22739daf8208SAnirudh Venkataramanan }
22749daf8208SAnirudh Venkataramanan 
22759daf8208SAnirudh Venkataramanan /**
2276*9fea7498SKiran Patil  * ice_mac_fltr_exist - does this MAC filter exist for given VSI
2277*9fea7498SKiran Patil  * @hw: pointer to the hardware structure
2278*9fea7498SKiran Patil  * @mac: MAC address to be checked (for MAC filter)
2279*9fea7498SKiran Patil  * @vsi_handle: check MAC filter for this VSI
2280*9fea7498SKiran Patil  */
2281*9fea7498SKiran Patil bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle)
2282*9fea7498SKiran Patil {
2283*9fea7498SKiran Patil 	struct ice_fltr_mgmt_list_entry *entry;
2284*9fea7498SKiran Patil 	struct list_head *rule_head;
2285*9fea7498SKiran Patil 	struct ice_switch_info *sw;
2286*9fea7498SKiran Patil 	struct mutex *rule_lock; /* Lock to protect filter rule list */
2287*9fea7498SKiran Patil 	u16 hw_vsi_id;
2288*9fea7498SKiran Patil 
2289*9fea7498SKiran Patil 	if (!ice_is_vsi_valid(hw, vsi_handle))
2290*9fea7498SKiran Patil 		return false;
2291*9fea7498SKiran Patil 
2292*9fea7498SKiran Patil 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
2293*9fea7498SKiran Patil 	sw = hw->switch_info;
2294*9fea7498SKiran Patil 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
2295*9fea7498SKiran Patil 	if (!rule_head)
2296*9fea7498SKiran Patil 		return false;
2297*9fea7498SKiran Patil 
2298*9fea7498SKiran Patil 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
2299*9fea7498SKiran Patil 	mutex_lock(rule_lock);
2300*9fea7498SKiran Patil 	list_for_each_entry(entry, rule_head, list_entry) {
2301*9fea7498SKiran Patil 		struct ice_fltr_info *f_info = &entry->fltr_info;
2302*9fea7498SKiran Patil 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
2303*9fea7498SKiran Patil 
2304*9fea7498SKiran Patil 		if (is_zero_ether_addr(mac_addr))
2305*9fea7498SKiran Patil 			continue;
2306*9fea7498SKiran Patil 
2307*9fea7498SKiran Patil 		if (f_info->flag != ICE_FLTR_TX ||
2308*9fea7498SKiran Patil 		    f_info->src_id != ICE_SRC_ID_VSI ||
2309*9fea7498SKiran Patil 		    f_info->lkup_type != ICE_SW_LKUP_MAC ||
2310*9fea7498SKiran Patil 		    f_info->fltr_act != ICE_FWD_TO_VSI ||
2311*9fea7498SKiran Patil 		    hw_vsi_id != f_info->fwd_id.hw_vsi_id)
2312*9fea7498SKiran Patil 			continue;
2313*9fea7498SKiran Patil 
2314*9fea7498SKiran Patil 		if (ether_addr_equal(mac, mac_addr)) {
2315*9fea7498SKiran Patil 			mutex_unlock(rule_lock);
2316*9fea7498SKiran Patil 			return true;
2317*9fea7498SKiran Patil 		}
2318*9fea7498SKiran Patil 	}
2319*9fea7498SKiran Patil 	mutex_unlock(rule_lock);
2320*9fea7498SKiran Patil 	return false;
2321*9fea7498SKiran Patil }
2322*9fea7498SKiran Patil 
2323*9fea7498SKiran Patil /**
2324*9fea7498SKiran Patil  * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI
2325*9fea7498SKiran Patil  * @hw: pointer to the hardware structure
2326*9fea7498SKiran Patil  * @vlan_id: VLAN ID
2327*9fea7498SKiran Patil  * @vsi_handle: check MAC filter for this VSI
2328*9fea7498SKiran Patil  */
2329*9fea7498SKiran Patil bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle)
2330*9fea7498SKiran Patil {
2331*9fea7498SKiran Patil 	struct ice_fltr_mgmt_list_entry *entry;
2332*9fea7498SKiran Patil 	struct list_head *rule_head;
2333*9fea7498SKiran Patil 	struct ice_switch_info *sw;
2334*9fea7498SKiran Patil 	struct mutex *rule_lock; /* Lock to protect filter rule list */
2335*9fea7498SKiran Patil 	u16 hw_vsi_id;
2336*9fea7498SKiran Patil 
2337*9fea7498SKiran Patil 	if (vlan_id > ICE_MAX_VLAN_ID)
2338*9fea7498SKiran Patil 		return false;
2339*9fea7498SKiran Patil 
2340*9fea7498SKiran Patil 	if (!ice_is_vsi_valid(hw, vsi_handle))
2341*9fea7498SKiran Patil 		return false;
2342*9fea7498SKiran Patil 
2343*9fea7498SKiran Patil 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
2344*9fea7498SKiran Patil 	sw = hw->switch_info;
2345*9fea7498SKiran Patil 	rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
2346*9fea7498SKiran Patil 	if (!rule_head)
2347*9fea7498SKiran Patil 		return false;
2348*9fea7498SKiran Patil 
2349*9fea7498SKiran Patil 	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
2350*9fea7498SKiran Patil 	mutex_lock(rule_lock);
2351*9fea7498SKiran Patil 	list_for_each_entry(entry, rule_head, list_entry) {
2352*9fea7498SKiran Patil 		struct ice_fltr_info *f_info = &entry->fltr_info;
2353*9fea7498SKiran Patil 		u16 entry_vlan_id = f_info->l_data.vlan.vlan_id;
2354*9fea7498SKiran Patil 		struct ice_vsi_list_map_info *map_info;
2355*9fea7498SKiran Patil 
2356*9fea7498SKiran Patil 		if (entry_vlan_id > ICE_MAX_VLAN_ID)
2357*9fea7498SKiran Patil 			continue;
2358*9fea7498SKiran Patil 
2359*9fea7498SKiran Patil 		if (f_info->flag != ICE_FLTR_TX ||
2360*9fea7498SKiran Patil 		    f_info->src_id != ICE_SRC_ID_VSI ||
2361*9fea7498SKiran Patil 		    f_info->lkup_type != ICE_SW_LKUP_VLAN)
2362*9fea7498SKiran Patil 			continue;
2363*9fea7498SKiran Patil 
2364*9fea7498SKiran Patil 		/* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */
2365*9fea7498SKiran Patil 		if (f_info->fltr_act != ICE_FWD_TO_VSI &&
2366*9fea7498SKiran Patil 		    f_info->fltr_act != ICE_FWD_TO_VSI_LIST)
2367*9fea7498SKiran Patil 			continue;
2368*9fea7498SKiran Patil 
2369*9fea7498SKiran Patil 		if (f_info->fltr_act == ICE_FWD_TO_VSI) {
2370*9fea7498SKiran Patil 			if (hw_vsi_id != f_info->fwd_id.hw_vsi_id)
2371*9fea7498SKiran Patil 				continue;
2372*9fea7498SKiran Patil 		} else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
2373*9fea7498SKiran Patil 			/* If filter_action is FWD_TO_VSI_LIST, make sure
2374*9fea7498SKiran Patil 			 * that VSI being checked is part of VSI list
2375*9fea7498SKiran Patil 			 */
2376*9fea7498SKiran Patil 			if (entry->vsi_count == 1 &&
2377*9fea7498SKiran Patil 			    entry->vsi_list_info) {
2378*9fea7498SKiran Patil 				map_info = entry->vsi_list_info;
2379*9fea7498SKiran Patil 				if (!test_bit(vsi_handle, map_info->vsi_map))
2380*9fea7498SKiran Patil 					continue;
2381*9fea7498SKiran Patil 			}
2382*9fea7498SKiran Patil 		}
2383*9fea7498SKiran Patil 
2384*9fea7498SKiran Patil 		if (vlan_id == entry_vlan_id) {
2385*9fea7498SKiran Patil 			mutex_unlock(rule_lock);
2386*9fea7498SKiran Patil 			return true;
2387*9fea7498SKiran Patil 		}
2388*9fea7498SKiran Patil 	}
2389*9fea7498SKiran Patil 	mutex_unlock(rule_lock);
2390*9fea7498SKiran Patil 
2391*9fea7498SKiran Patil 	return false;
2392*9fea7498SKiran Patil }
2393*9fea7498SKiran Patil 
2394*9fea7498SKiran Patil /**
23959daf8208SAnirudh Venkataramanan  * ice_add_mac - Add a MAC address based filter rule
23969daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
23979daf8208SAnirudh Venkataramanan  * @m_list: list of MAC addresses and forwarding information
23989daf8208SAnirudh Venkataramanan  *
23999daf8208SAnirudh Venkataramanan  * IMPORTANT: When the ucast_shared flag is set to false and m_list has
24009daf8208SAnirudh Venkataramanan  * multiple unicast addresses, the function assumes that all the
24019daf8208SAnirudh Venkataramanan  * addresses are unique in a given add_mac call. It doesn't
24029daf8208SAnirudh Venkataramanan  * check for duplicates in this case, removing duplicates from a given
24039daf8208SAnirudh Venkataramanan  * list should be taken care of in the caller of this function.
24049daf8208SAnirudh Venkataramanan  */
2405ebb462dcSBruce Allan enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
24069daf8208SAnirudh Venkataramanan {
24079daf8208SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule, *r_iter;
24089daf8208SAnirudh Venkataramanan 	struct ice_fltr_list_entry *m_list_itr;
240980d144c9SAnirudh Venkataramanan 	struct list_head *rule_head;
241088865fc4SKarol Kolacinski 	u16 total_elem_left, s_rule_size;
241180d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw;
241280d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
24139daf8208SAnirudh Venkataramanan 	enum ice_status status = 0;
24149daf8208SAnirudh Venkataramanan 	u16 num_unicast = 0;
241588865fc4SKarol Kolacinski 	u8 elem_sent;
24169daf8208SAnirudh Venkataramanan 
24179daf8208SAnirudh Venkataramanan 	if (!m_list || !hw)
24189daf8208SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
24199daf8208SAnirudh Venkataramanan 
242080d144c9SAnirudh Venkataramanan 	s_rule = NULL;
242180d144c9SAnirudh Venkataramanan 	sw = hw->switch_info;
242280d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
24239daf8208SAnirudh Venkataramanan 	list_for_each_entry(m_list_itr, m_list, list_entry) {
24249daf8208SAnirudh Venkataramanan 		u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
24255726ca0eSAnirudh Venkataramanan 		u16 vsi_handle;
24265726ca0eSAnirudh Venkataramanan 		u16 hw_vsi_id;
24279daf8208SAnirudh Venkataramanan 
242880d144c9SAnirudh Venkataramanan 		m_list_itr->fltr_info.flag = ICE_FLTR_TX;
24295726ca0eSAnirudh Venkataramanan 		vsi_handle = m_list_itr->fltr_info.vsi_handle;
24305726ca0eSAnirudh Venkataramanan 		if (!ice_is_vsi_valid(hw, vsi_handle))
24315726ca0eSAnirudh Venkataramanan 			return ICE_ERR_PARAM;
24325726ca0eSAnirudh Venkataramanan 		hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
24335726ca0eSAnirudh Venkataramanan 		m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;
2434f9867df6SAnirudh Venkataramanan 		/* update the src in case it is VSI num */
24355726ca0eSAnirudh Venkataramanan 		if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)
24365726ca0eSAnirudh Venkataramanan 			return ICE_ERR_PARAM;
24375726ca0eSAnirudh Venkataramanan 		m_list_itr->fltr_info.src = hw_vsi_id;
243880d144c9SAnirudh Venkataramanan 		if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
243980d144c9SAnirudh Venkataramanan 		    is_zero_ether_addr(add))
24409daf8208SAnirudh Venkataramanan 			return ICE_ERR_PARAM;
24419daf8208SAnirudh Venkataramanan 		if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
24429daf8208SAnirudh Venkataramanan 			/* Don't overwrite the unicast address */
244380d144c9SAnirudh Venkataramanan 			mutex_lock(rule_lock);
244480d144c9SAnirudh Venkataramanan 			if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC,
244580d144c9SAnirudh Venkataramanan 						&m_list_itr->fltr_info)) {
244680d144c9SAnirudh Venkataramanan 				mutex_unlock(rule_lock);
24479daf8208SAnirudh Venkataramanan 				return ICE_ERR_ALREADY_EXISTS;
244880d144c9SAnirudh Venkataramanan 			}
244980d144c9SAnirudh Venkataramanan 			mutex_unlock(rule_lock);
24509daf8208SAnirudh Venkataramanan 			num_unicast++;
24519daf8208SAnirudh Venkataramanan 		} else if (is_multicast_ether_addr(add) ||
24529daf8208SAnirudh Venkataramanan 			   (is_unicast_ether_addr(add) && hw->ucast_shared)) {
245380d144c9SAnirudh Venkataramanan 			m_list_itr->status =
245480d144c9SAnirudh Venkataramanan 				ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
245580d144c9SAnirudh Venkataramanan 						      m_list_itr);
245680d144c9SAnirudh Venkataramanan 			if (m_list_itr->status)
245780d144c9SAnirudh Venkataramanan 				return m_list_itr->status;
24589daf8208SAnirudh Venkataramanan 		}
24599daf8208SAnirudh Venkataramanan 	}
24609daf8208SAnirudh Venkataramanan 
246180d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
24629daf8208SAnirudh Venkataramanan 	/* Exit if no suitable entries were found for adding bulk switch rule */
246380d144c9SAnirudh Venkataramanan 	if (!num_unicast) {
246480d144c9SAnirudh Venkataramanan 		status = 0;
246580d144c9SAnirudh Venkataramanan 		goto ice_add_mac_exit;
246680d144c9SAnirudh Venkataramanan 	}
246780d144c9SAnirudh Venkataramanan 
246880d144c9SAnirudh Venkataramanan 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
24699daf8208SAnirudh Venkataramanan 
24709daf8208SAnirudh Venkataramanan 	/* Allocate switch rule buffer for the bulk update for unicast */
24719daf8208SAnirudh Venkataramanan 	s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
24729daf8208SAnirudh Venkataramanan 	s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,
24739daf8208SAnirudh Venkataramanan 			      GFP_KERNEL);
247480d144c9SAnirudh Venkataramanan 	if (!s_rule) {
247580d144c9SAnirudh Venkataramanan 		status = ICE_ERR_NO_MEMORY;
247680d144c9SAnirudh Venkataramanan 		goto ice_add_mac_exit;
247780d144c9SAnirudh Venkataramanan 	}
24789daf8208SAnirudh Venkataramanan 
24799daf8208SAnirudh Venkataramanan 	r_iter = s_rule;
24809daf8208SAnirudh Venkataramanan 	list_for_each_entry(m_list_itr, m_list, list_entry) {
24819daf8208SAnirudh Venkataramanan 		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
248280d144c9SAnirudh Venkataramanan 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
24839daf8208SAnirudh Venkataramanan 
248480d144c9SAnirudh Venkataramanan 		if (is_unicast_ether_addr(mac_addr)) {
248580d144c9SAnirudh Venkataramanan 			ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,
248680d144c9SAnirudh Venkataramanan 					 ice_aqc_opc_add_sw_rules);
24879daf8208SAnirudh Venkataramanan 			r_iter = (struct ice_aqc_sw_rules_elem *)
24889daf8208SAnirudh Venkataramanan 				((u8 *)r_iter + s_rule_size);
24899daf8208SAnirudh Venkataramanan 		}
24909daf8208SAnirudh Venkataramanan 	}
24919daf8208SAnirudh Venkataramanan 
24929daf8208SAnirudh Venkataramanan 	/* Call AQ bulk switch rule update for all unicast addresses */
24939daf8208SAnirudh Venkataramanan 	r_iter = s_rule;
24949daf8208SAnirudh Venkataramanan 	/* Call AQ switch rule in AQ_MAX chunk */
24959daf8208SAnirudh Venkataramanan 	for (total_elem_left = num_unicast; total_elem_left > 0;
24969daf8208SAnirudh Venkataramanan 	     total_elem_left -= elem_sent) {
24979daf8208SAnirudh Venkataramanan 		struct ice_aqc_sw_rules_elem *entry = r_iter;
24989daf8208SAnirudh Venkataramanan 
249988865fc4SKarol Kolacinski 		elem_sent = min_t(u8, total_elem_left,
250088865fc4SKarol Kolacinski 				  (ICE_AQ_MAX_BUF_LEN / s_rule_size));
25019daf8208SAnirudh Venkataramanan 		status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,
25029daf8208SAnirudh Venkataramanan 					 elem_sent, ice_aqc_opc_add_sw_rules,
25039daf8208SAnirudh Venkataramanan 					 NULL);
25049daf8208SAnirudh Venkataramanan 		if (status)
25059daf8208SAnirudh Venkataramanan 			goto ice_add_mac_exit;
25069daf8208SAnirudh Venkataramanan 		r_iter = (struct ice_aqc_sw_rules_elem *)
25079daf8208SAnirudh Venkataramanan 			((u8 *)r_iter + (elem_sent * s_rule_size));
25089daf8208SAnirudh Venkataramanan 	}
25099daf8208SAnirudh Venkataramanan 
2510f9867df6SAnirudh Venkataramanan 	/* Fill up rule ID based on the value returned from FW */
25119daf8208SAnirudh Venkataramanan 	r_iter = s_rule;
25129daf8208SAnirudh Venkataramanan 	list_for_each_entry(m_list_itr, m_list, list_entry) {
25139daf8208SAnirudh Venkataramanan 		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
251480d144c9SAnirudh Venkataramanan 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
25159daf8208SAnirudh Venkataramanan 		struct ice_fltr_mgmt_list_entry *fm_entry;
25169daf8208SAnirudh Venkataramanan 
251780d144c9SAnirudh Venkataramanan 		if (is_unicast_ether_addr(mac_addr)) {
25189daf8208SAnirudh Venkataramanan 			f_info->fltr_rule_id =
25199daf8208SAnirudh Venkataramanan 				le16_to_cpu(r_iter->pdata.lkup_tx_rx.index);
25209daf8208SAnirudh Venkataramanan 			f_info->fltr_act = ICE_FWD_TO_VSI;
25219daf8208SAnirudh Venkataramanan 			/* Create an entry to track this MAC address */
25229daf8208SAnirudh Venkataramanan 			fm_entry = devm_kzalloc(ice_hw_to_dev(hw),
25239daf8208SAnirudh Venkataramanan 						sizeof(*fm_entry), GFP_KERNEL);
25249daf8208SAnirudh Venkataramanan 			if (!fm_entry) {
25259daf8208SAnirudh Venkataramanan 				status = ICE_ERR_NO_MEMORY;
25269daf8208SAnirudh Venkataramanan 				goto ice_add_mac_exit;
25279daf8208SAnirudh Venkataramanan 			}
25289daf8208SAnirudh Venkataramanan 			fm_entry->fltr_info = *f_info;
25299daf8208SAnirudh Venkataramanan 			fm_entry->vsi_count = 1;
25309daf8208SAnirudh Venkataramanan 			/* The book keeping entries will get removed when
25319daf8208SAnirudh Venkataramanan 			 * base driver calls remove filter AQ command
25329daf8208SAnirudh Venkataramanan 			 */
25339daf8208SAnirudh Venkataramanan 
253480d144c9SAnirudh Venkataramanan 			list_add(&fm_entry->list_entry, rule_head);
25359daf8208SAnirudh Venkataramanan 			r_iter = (struct ice_aqc_sw_rules_elem *)
25369daf8208SAnirudh Venkataramanan 				((u8 *)r_iter + s_rule_size);
25379daf8208SAnirudh Venkataramanan 		}
25389daf8208SAnirudh Venkataramanan 	}
25399daf8208SAnirudh Venkataramanan 
25409daf8208SAnirudh Venkataramanan ice_add_mac_exit:
254180d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
254280d144c9SAnirudh Venkataramanan 	if (s_rule)
25439daf8208SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), s_rule);
25449daf8208SAnirudh Venkataramanan 	return status;
25459daf8208SAnirudh Venkataramanan }
25469daf8208SAnirudh Venkataramanan 
25479daf8208SAnirudh Venkataramanan /**
2548d76a60baSAnirudh Venkataramanan  * ice_add_vlan_internal - Add one VLAN based filter rule
2549d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2550d76a60baSAnirudh Venkataramanan  * @f_entry: filter entry containing one VLAN information
2551d76a60baSAnirudh Venkataramanan  */
2552d76a60baSAnirudh Venkataramanan static enum ice_status
2553d76a60baSAnirudh Venkataramanan ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
2554d76a60baSAnirudh Venkataramanan {
255580d144c9SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
2556d76a60baSAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *v_list_itr;
25575726ca0eSAnirudh Venkataramanan 	struct ice_fltr_info *new_fltr, *cur_fltr;
25585726ca0eSAnirudh Venkataramanan 	enum ice_sw_lkup_type lkup_type;
25595726ca0eSAnirudh Venkataramanan 	u16 vsi_list_id = 0, vsi_handle;
256080d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock; /* Lock to protect filter rule list */
256180d144c9SAnirudh Venkataramanan 	enum ice_status status = 0;
2562d76a60baSAnirudh Venkataramanan 
25635726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
25645726ca0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
25655726ca0eSAnirudh Venkataramanan 
25665726ca0eSAnirudh Venkataramanan 	f_entry->fltr_info.fwd_id.hw_vsi_id =
25675726ca0eSAnirudh Venkataramanan 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
2568d76a60baSAnirudh Venkataramanan 	new_fltr = &f_entry->fltr_info;
25695726ca0eSAnirudh Venkataramanan 
2570f9867df6SAnirudh Venkataramanan 	/* VLAN ID should only be 12 bits */
2571d76a60baSAnirudh Venkataramanan 	if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
2572d76a60baSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
2573d76a60baSAnirudh Venkataramanan 
25745726ca0eSAnirudh Venkataramanan 	if (new_fltr->src_id != ICE_SRC_ID_VSI)
25755726ca0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
25765726ca0eSAnirudh Venkataramanan 
25775726ca0eSAnirudh Venkataramanan 	new_fltr->src = new_fltr->fwd_id.hw_vsi_id;
25785726ca0eSAnirudh Venkataramanan 	lkup_type = new_fltr->lkup_type;
25795726ca0eSAnirudh Venkataramanan 	vsi_handle = new_fltr->vsi_handle;
258080d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
258180d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
258280d144c9SAnirudh Venkataramanan 	v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr);
2583d76a60baSAnirudh Venkataramanan 	if (!v_list_itr) {
25845726ca0eSAnirudh Venkataramanan 		struct ice_vsi_list_map_info *map_info = NULL;
2585d76a60baSAnirudh Venkataramanan 
2586d76a60baSAnirudh Venkataramanan 		if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
25875726ca0eSAnirudh Venkataramanan 			/* All VLAN pruning rules use a VSI list. Check if
25885726ca0eSAnirudh Venkataramanan 			 * there is already a VSI list containing VSI that we
25895726ca0eSAnirudh Venkataramanan 			 * want to add. If found, use the same vsi_list_id for
25905726ca0eSAnirudh Venkataramanan 			 * this new VLAN rule or else create a new list.
2591d76a60baSAnirudh Venkataramanan 			 */
25925726ca0eSAnirudh Venkataramanan 			map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN,
25935726ca0eSAnirudh Venkataramanan 							   vsi_handle,
25945726ca0eSAnirudh Venkataramanan 							   &vsi_list_id);
25955726ca0eSAnirudh Venkataramanan 			if (!map_info) {
25965726ca0eSAnirudh Venkataramanan 				status = ice_create_vsi_list_rule(hw,
25975726ca0eSAnirudh Venkataramanan 								  &vsi_handle,
25985726ca0eSAnirudh Venkataramanan 								  1,
2599d76a60baSAnirudh Venkataramanan 								  &vsi_list_id,
2600d76a60baSAnirudh Venkataramanan 								  lkup_type);
2601d76a60baSAnirudh Venkataramanan 				if (status)
260280d144c9SAnirudh Venkataramanan 					goto exit;
26035726ca0eSAnirudh Venkataramanan 			}
26045726ca0eSAnirudh Venkataramanan 			/* Convert the action to forwarding to a VSI list. */
2605d76a60baSAnirudh Venkataramanan 			new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
2606d76a60baSAnirudh Venkataramanan 			new_fltr->fwd_id.vsi_list_id = vsi_list_id;
2607d76a60baSAnirudh Venkataramanan 		}
2608d76a60baSAnirudh Venkataramanan 
2609d76a60baSAnirudh Venkataramanan 		status = ice_create_pkt_fwd_rule(hw, f_entry);
26105726ca0eSAnirudh Venkataramanan 		if (!status) {
261180d144c9SAnirudh Venkataramanan 			v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN,
261280d144c9SAnirudh Venkataramanan 							 new_fltr);
261380d144c9SAnirudh Venkataramanan 			if (!v_list_itr) {
261480d144c9SAnirudh Venkataramanan 				status = ICE_ERR_DOES_NOT_EXIST;
261580d144c9SAnirudh Venkataramanan 				goto exit;
261680d144c9SAnirudh Venkataramanan 			}
26175726ca0eSAnirudh Venkataramanan 			/* reuse VSI list for new rule and increment ref_cnt */
26185726ca0eSAnirudh Venkataramanan 			if (map_info) {
26195726ca0eSAnirudh Venkataramanan 				v_list_itr->vsi_list_info = map_info;
26205726ca0eSAnirudh Venkataramanan 				map_info->ref_cnt++;
26215726ca0eSAnirudh Venkataramanan 			} else {
2622d76a60baSAnirudh Venkataramanan 				v_list_itr->vsi_list_info =
26235726ca0eSAnirudh Venkataramanan 					ice_create_vsi_list_map(hw, &vsi_handle,
26245726ca0eSAnirudh Venkataramanan 								1, vsi_list_id);
2625d76a60baSAnirudh Venkataramanan 			}
26265726ca0eSAnirudh Venkataramanan 		}
26275726ca0eSAnirudh Venkataramanan 	} else if (v_list_itr->vsi_list_info->ref_cnt == 1) {
2628f9867df6SAnirudh Venkataramanan 		/* Update existing VSI list to add new VSI ID only if it used
26295726ca0eSAnirudh Venkataramanan 		 * by one VLAN rule.
26305726ca0eSAnirudh Venkataramanan 		 */
26315726ca0eSAnirudh Venkataramanan 		cur_fltr = &v_list_itr->fltr_info;
26325726ca0eSAnirudh Venkataramanan 		status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,
26335726ca0eSAnirudh Venkataramanan 						 new_fltr);
26345726ca0eSAnirudh Venkataramanan 	} else {
26355726ca0eSAnirudh Venkataramanan 		/* If VLAN rule exists and VSI list being used by this rule is
26365726ca0eSAnirudh Venkataramanan 		 * referenced by more than 1 VLAN rule. Then create a new VSI
26375726ca0eSAnirudh Venkataramanan 		 * list appending previous VSI with new VSI and update existing
2638f9867df6SAnirudh Venkataramanan 		 * VLAN rule to point to new VSI list ID
26395726ca0eSAnirudh Venkataramanan 		 */
26405726ca0eSAnirudh Venkataramanan 		struct ice_fltr_info tmp_fltr;
26415726ca0eSAnirudh Venkataramanan 		u16 vsi_handle_arr[2];
26425726ca0eSAnirudh Venkataramanan 		u16 cur_handle;
2643d76a60baSAnirudh Venkataramanan 
26445726ca0eSAnirudh Venkataramanan 		/* Current implementation only supports reusing VSI list with
26455726ca0eSAnirudh Venkataramanan 		 * one VSI count. We should never hit below condition
26465726ca0eSAnirudh Venkataramanan 		 */
26475726ca0eSAnirudh Venkataramanan 		if (v_list_itr->vsi_count > 1 &&
26485726ca0eSAnirudh Venkataramanan 		    v_list_itr->vsi_list_info->ref_cnt > 1) {
26499228d8b2SJacob 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");
26505726ca0eSAnirudh Venkataramanan 			status = ICE_ERR_CFG;
265180d144c9SAnirudh Venkataramanan 			goto exit;
2652d76a60baSAnirudh Venkataramanan 		}
2653d76a60baSAnirudh Venkataramanan 
26545726ca0eSAnirudh Venkataramanan 		cur_handle =
26555726ca0eSAnirudh Venkataramanan 			find_first_bit(v_list_itr->vsi_list_info->vsi_map,
26565726ca0eSAnirudh Venkataramanan 				       ICE_MAX_VSI);
26575726ca0eSAnirudh Venkataramanan 
26585726ca0eSAnirudh Venkataramanan 		/* A rule already exists with the new VSI being added */
26595726ca0eSAnirudh Venkataramanan 		if (cur_handle == vsi_handle) {
26605726ca0eSAnirudh Venkataramanan 			status = ICE_ERR_ALREADY_EXISTS;
26615726ca0eSAnirudh Venkataramanan 			goto exit;
26625726ca0eSAnirudh Venkataramanan 		}
26635726ca0eSAnirudh Venkataramanan 
26645726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[0] = cur_handle;
26655726ca0eSAnirudh Venkataramanan 		vsi_handle_arr[1] = vsi_handle;
26665726ca0eSAnirudh Venkataramanan 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
26675726ca0eSAnirudh Venkataramanan 						  &vsi_list_id, lkup_type);
26685726ca0eSAnirudh Venkataramanan 		if (status)
26695726ca0eSAnirudh Venkataramanan 			goto exit;
26705726ca0eSAnirudh Venkataramanan 
26715726ca0eSAnirudh Venkataramanan 		tmp_fltr = v_list_itr->fltr_info;
26725726ca0eSAnirudh Venkataramanan 		tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;
26735726ca0eSAnirudh Venkataramanan 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
26745726ca0eSAnirudh Venkataramanan 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
26755726ca0eSAnirudh Venkataramanan 		/* Update the previous switch rule to a new VSI list which
2676df17b7e0SAnirudh Venkataramanan 		 * includes current VSI that is requested
26775726ca0eSAnirudh Venkataramanan 		 */
26785726ca0eSAnirudh Venkataramanan 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
26795726ca0eSAnirudh Venkataramanan 		if (status)
26805726ca0eSAnirudh Venkataramanan 			goto exit;
26815726ca0eSAnirudh Venkataramanan 
26825726ca0eSAnirudh Venkataramanan 		/* before overriding VSI list map info. decrement ref_cnt of
26835726ca0eSAnirudh Venkataramanan 		 * previous VSI list
26845726ca0eSAnirudh Venkataramanan 		 */
26855726ca0eSAnirudh Venkataramanan 		v_list_itr->vsi_list_info->ref_cnt--;
26865726ca0eSAnirudh Venkataramanan 
26875726ca0eSAnirudh Venkataramanan 		/* now update to newly created list */
26885726ca0eSAnirudh Venkataramanan 		v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;
26895726ca0eSAnirudh Venkataramanan 		v_list_itr->vsi_list_info =
26905726ca0eSAnirudh Venkataramanan 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
26915726ca0eSAnirudh Venkataramanan 						vsi_list_id);
26925726ca0eSAnirudh Venkataramanan 		v_list_itr->vsi_count++;
26935726ca0eSAnirudh Venkataramanan 	}
269480d144c9SAnirudh Venkataramanan 
269580d144c9SAnirudh Venkataramanan exit:
269680d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
269780d144c9SAnirudh Venkataramanan 	return status;
2698d76a60baSAnirudh Venkataramanan }
2699d76a60baSAnirudh Venkataramanan 
2700d76a60baSAnirudh Venkataramanan /**
2701d76a60baSAnirudh Venkataramanan  * ice_add_vlan - Add VLAN based filter rule
2702d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
2703d76a60baSAnirudh Venkataramanan  * @v_list: list of VLAN entries and forwarding information
2704d76a60baSAnirudh Venkataramanan  */
2705ebb462dcSBruce Allan enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
2706d76a60baSAnirudh Venkataramanan {
2707d76a60baSAnirudh Venkataramanan 	struct ice_fltr_list_entry *v_list_itr;
2708d76a60baSAnirudh Venkataramanan 
2709d76a60baSAnirudh Venkataramanan 	if (!v_list || !hw)
2710d76a60baSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
2711d76a60baSAnirudh Venkataramanan 
2712d76a60baSAnirudh Venkataramanan 	list_for_each_entry(v_list_itr, v_list, list_entry) {
2713d76a60baSAnirudh Venkataramanan 		if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
2714d76a60baSAnirudh Venkataramanan 			return ICE_ERR_PARAM;
271580d144c9SAnirudh Venkataramanan 		v_list_itr->fltr_info.flag = ICE_FLTR_TX;
271680d144c9SAnirudh Venkataramanan 		v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr);
271780d144c9SAnirudh Venkataramanan 		if (v_list_itr->status)
271880d144c9SAnirudh Venkataramanan 			return v_list_itr->status;
2719d76a60baSAnirudh Venkataramanan 	}
2720d76a60baSAnirudh Venkataramanan 	return 0;
2721d76a60baSAnirudh Venkataramanan }
2722d76a60baSAnirudh Venkataramanan 
2723d76a60baSAnirudh Venkataramanan /**
2724d95276ceSAkeem G Abodunrin  * ice_add_eth_mac - Add ethertype and MAC based filter rule
2725d95276ceSAkeem G Abodunrin  * @hw: pointer to the hardware structure
2726d95276ceSAkeem G Abodunrin  * @em_list: list of ether type MAC filter, MAC is optional
27272e0e6228SDave Ertman  *
27282e0e6228SDave Ertman  * This function requires the caller to populate the entries in
27292e0e6228SDave Ertman  * the filter list with the necessary fields (including flags to
27302e0e6228SDave Ertman  * indicate Tx or Rx rules).
2731d95276ceSAkeem G Abodunrin  */
2732d95276ceSAkeem G Abodunrin enum ice_status
2733d95276ceSAkeem G Abodunrin ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
2734d95276ceSAkeem G Abodunrin {
2735d95276ceSAkeem G Abodunrin 	struct ice_fltr_list_entry *em_list_itr;
2736d95276ceSAkeem G Abodunrin 
2737d95276ceSAkeem G Abodunrin 	if (!em_list || !hw)
2738d95276ceSAkeem G Abodunrin 		return ICE_ERR_PARAM;
2739d95276ceSAkeem G Abodunrin 
2740d95276ceSAkeem G Abodunrin 	list_for_each_entry(em_list_itr, em_list, list_entry) {
2741d95276ceSAkeem G Abodunrin 		enum ice_sw_lkup_type l_type =
2742d95276ceSAkeem G Abodunrin 			em_list_itr->fltr_info.lkup_type;
2743d95276ceSAkeem G Abodunrin 
2744d95276ceSAkeem G Abodunrin 		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
2745d95276ceSAkeem G Abodunrin 		    l_type != ICE_SW_LKUP_ETHERTYPE)
2746d95276ceSAkeem G Abodunrin 			return ICE_ERR_PARAM;
2747d95276ceSAkeem G Abodunrin 
2748d95276ceSAkeem G Abodunrin 		em_list_itr->status = ice_add_rule_internal(hw, l_type,
2749d95276ceSAkeem G Abodunrin 							    em_list_itr);
2750d95276ceSAkeem G Abodunrin 		if (em_list_itr->status)
2751d95276ceSAkeem G Abodunrin 			return em_list_itr->status;
2752d95276ceSAkeem G Abodunrin 	}
2753d95276ceSAkeem G Abodunrin 	return 0;
2754d95276ceSAkeem G Abodunrin }
2755d95276ceSAkeem G Abodunrin 
2756d95276ceSAkeem G Abodunrin /**
2757d95276ceSAkeem G Abodunrin  * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule
2758d95276ceSAkeem G Abodunrin  * @hw: pointer to the hardware structure
2759d95276ceSAkeem G Abodunrin  * @em_list: list of ethertype or ethertype MAC entries
2760d95276ceSAkeem G Abodunrin  */
2761d95276ceSAkeem G Abodunrin enum ice_status
2762d95276ceSAkeem G Abodunrin ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list)
2763d95276ceSAkeem G Abodunrin {
2764d95276ceSAkeem G Abodunrin 	struct ice_fltr_list_entry *em_list_itr, *tmp;
2765d95276ceSAkeem G Abodunrin 
2766d95276ceSAkeem G Abodunrin 	if (!em_list || !hw)
2767d95276ceSAkeem G Abodunrin 		return ICE_ERR_PARAM;
2768d95276ceSAkeem G Abodunrin 
2769d95276ceSAkeem G Abodunrin 	list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) {
2770d95276ceSAkeem G Abodunrin 		enum ice_sw_lkup_type l_type =
2771d95276ceSAkeem G Abodunrin 			em_list_itr->fltr_info.lkup_type;
2772d95276ceSAkeem G Abodunrin 
2773d95276ceSAkeem G Abodunrin 		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
2774d95276ceSAkeem G Abodunrin 		    l_type != ICE_SW_LKUP_ETHERTYPE)
2775d95276ceSAkeem G Abodunrin 			return ICE_ERR_PARAM;
2776d95276ceSAkeem G Abodunrin 
2777d95276ceSAkeem G Abodunrin 		em_list_itr->status = ice_remove_rule_internal(hw, l_type,
2778d95276ceSAkeem G Abodunrin 							       em_list_itr);
2779d95276ceSAkeem G Abodunrin 		if (em_list_itr->status)
2780d95276ceSAkeem G Abodunrin 			return em_list_itr->status;
2781d95276ceSAkeem G Abodunrin 	}
2782d95276ceSAkeem G Abodunrin 	return 0;
2783d95276ceSAkeem G Abodunrin }
2784d95276ceSAkeem G Abodunrin 
2785d95276ceSAkeem G Abodunrin /**
27860f9d5027SAnirudh Venkataramanan  * ice_rem_sw_rule_info
27870f9d5027SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
27880f9d5027SAnirudh Venkataramanan  * @rule_head: pointer to the switch list structure that we want to delete
27890f9d5027SAnirudh Venkataramanan  */
27900f9d5027SAnirudh Venkataramanan static void
27910f9d5027SAnirudh Venkataramanan ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head)
27920f9d5027SAnirudh Venkataramanan {
27930f9d5027SAnirudh Venkataramanan 	if (!list_empty(rule_head)) {
27940f9d5027SAnirudh Venkataramanan 		struct ice_fltr_mgmt_list_entry *entry;
27950f9d5027SAnirudh Venkataramanan 		struct ice_fltr_mgmt_list_entry *tmp;
27960f9d5027SAnirudh Venkataramanan 
27970f9d5027SAnirudh Venkataramanan 		list_for_each_entry_safe(entry, tmp, rule_head, list_entry) {
27980f9d5027SAnirudh Venkataramanan 			list_del(&entry->list_entry);
27990f9d5027SAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), entry);
28000f9d5027SAnirudh Venkataramanan 		}
28010f9d5027SAnirudh Venkataramanan 	}
28020f9d5027SAnirudh Venkataramanan }
28030f9d5027SAnirudh Venkataramanan 
28040f9d5027SAnirudh Venkataramanan /**
28058b8ef05bSVictor Raj  * ice_rem_adv_rule_info
28068b8ef05bSVictor Raj  * @hw: pointer to the hardware structure
28078b8ef05bSVictor Raj  * @rule_head: pointer to the switch list structure that we want to delete
28088b8ef05bSVictor Raj  */
28098b8ef05bSVictor Raj static void
28108b8ef05bSVictor Raj ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head)
28118b8ef05bSVictor Raj {
28128b8ef05bSVictor Raj 	struct ice_adv_fltr_mgmt_list_entry *tmp_entry;
28138b8ef05bSVictor Raj 	struct ice_adv_fltr_mgmt_list_entry *lst_itr;
28148b8ef05bSVictor Raj 
28158b8ef05bSVictor Raj 	if (list_empty(rule_head))
28168b8ef05bSVictor Raj 		return;
28178b8ef05bSVictor Raj 
28188b8ef05bSVictor Raj 	list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) {
28198b8ef05bSVictor Raj 		list_del(&lst_itr->list_entry);
28208b8ef05bSVictor Raj 		devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups);
28218b8ef05bSVictor Raj 		devm_kfree(ice_hw_to_dev(hw), lst_itr);
28228b8ef05bSVictor Raj 	}
28238b8ef05bSVictor Raj }
28248b8ef05bSVictor Raj 
28258b8ef05bSVictor Raj /**
282680d144c9SAnirudh Venkataramanan  * ice_cfg_dflt_vsi - change state of VSI to set/clear default
2827e94d4478SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
28285726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to set as default
2829e94d4478SAnirudh Venkataramanan  * @set: true to add the above mentioned switch rule, false to remove it
2830e94d4478SAnirudh Venkataramanan  * @direction: ICE_FLTR_RX or ICE_FLTR_TX
283180d144c9SAnirudh Venkataramanan  *
283280d144c9SAnirudh Venkataramanan  * add filter rule to set/unset given VSI as default VSI for the switch
283380d144c9SAnirudh Venkataramanan  * (represented by swid)
2834e94d4478SAnirudh Venkataramanan  */
2835e94d4478SAnirudh Venkataramanan enum ice_status
28365726ca0eSAnirudh Venkataramanan ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction)
2837e94d4478SAnirudh Venkataramanan {
2838e94d4478SAnirudh Venkataramanan 	struct ice_aqc_sw_rules_elem *s_rule;
2839e94d4478SAnirudh Venkataramanan 	struct ice_fltr_info f_info;
2840e94d4478SAnirudh Venkataramanan 	enum ice_adminq_opc opcode;
2841e94d4478SAnirudh Venkataramanan 	enum ice_status status;
2842e94d4478SAnirudh Venkataramanan 	u16 s_rule_size;
28435726ca0eSAnirudh Venkataramanan 	u16 hw_vsi_id;
28445726ca0eSAnirudh Venkataramanan 
28455726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
28465726ca0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
28475726ca0eSAnirudh Venkataramanan 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
2848e94d4478SAnirudh Venkataramanan 
2849e94d4478SAnirudh Venkataramanan 	s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE :
2850e94d4478SAnirudh Venkataramanan 		ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
285166486d89SBruce Allan 
2852e94d4478SAnirudh Venkataramanan 	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
2853e94d4478SAnirudh Venkataramanan 	if (!s_rule)
2854e94d4478SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
2855e94d4478SAnirudh Venkataramanan 
2856e94d4478SAnirudh Venkataramanan 	memset(&f_info, 0, sizeof(f_info));
2857e94d4478SAnirudh Venkataramanan 
2858e94d4478SAnirudh Venkataramanan 	f_info.lkup_type = ICE_SW_LKUP_DFLT;
2859e94d4478SAnirudh Venkataramanan 	f_info.flag = direction;
2860e94d4478SAnirudh Venkataramanan 	f_info.fltr_act = ICE_FWD_TO_VSI;
28615726ca0eSAnirudh Venkataramanan 	f_info.fwd_id.hw_vsi_id = hw_vsi_id;
2862e94d4478SAnirudh Venkataramanan 
2863e94d4478SAnirudh Venkataramanan 	if (f_info.flag & ICE_FLTR_RX) {
2864e94d4478SAnirudh Venkataramanan 		f_info.src = hw->port_info->lport;
28655726ca0eSAnirudh Venkataramanan 		f_info.src_id = ICE_SRC_ID_LPORT;
2866e94d4478SAnirudh Venkataramanan 		if (!set)
2867e94d4478SAnirudh Venkataramanan 			f_info.fltr_rule_id =
2868e94d4478SAnirudh Venkataramanan 				hw->port_info->dflt_rx_vsi_rule_id;
2869e94d4478SAnirudh Venkataramanan 	} else if (f_info.flag & ICE_FLTR_TX) {
28705726ca0eSAnirudh Venkataramanan 		f_info.src_id = ICE_SRC_ID_VSI;
28715726ca0eSAnirudh Venkataramanan 		f_info.src = hw_vsi_id;
2872e94d4478SAnirudh Venkataramanan 		if (!set)
2873e94d4478SAnirudh Venkataramanan 			f_info.fltr_rule_id =
2874e94d4478SAnirudh Venkataramanan 				hw->port_info->dflt_tx_vsi_rule_id;
2875e94d4478SAnirudh Venkataramanan 	}
2876e94d4478SAnirudh Venkataramanan 
2877e94d4478SAnirudh Venkataramanan 	if (set)
2878e94d4478SAnirudh Venkataramanan 		opcode = ice_aqc_opc_add_sw_rules;
2879e94d4478SAnirudh Venkataramanan 	else
2880e94d4478SAnirudh Venkataramanan 		opcode = ice_aqc_opc_remove_sw_rules;
2881e94d4478SAnirudh Venkataramanan 
2882e94d4478SAnirudh Venkataramanan 	ice_fill_sw_rule(hw, &f_info, s_rule, opcode);
2883e94d4478SAnirudh Venkataramanan 
2884e94d4478SAnirudh Venkataramanan 	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opcode, NULL);
2885e94d4478SAnirudh Venkataramanan 	if (status || !(f_info.flag & ICE_FLTR_TX_RX))
2886e94d4478SAnirudh Venkataramanan 		goto out;
2887e94d4478SAnirudh Venkataramanan 	if (set) {
2888e94d4478SAnirudh Venkataramanan 		u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
2889e94d4478SAnirudh Venkataramanan 
2890e94d4478SAnirudh Venkataramanan 		if (f_info.flag & ICE_FLTR_TX) {
28915726ca0eSAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_num = hw_vsi_id;
2892e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_rule_id = index;
2893e94d4478SAnirudh Venkataramanan 		} else if (f_info.flag & ICE_FLTR_RX) {
28945726ca0eSAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_num = hw_vsi_id;
2895e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_rule_id = index;
2896e94d4478SAnirudh Venkataramanan 		}
2897e94d4478SAnirudh Venkataramanan 	} else {
2898e94d4478SAnirudh Venkataramanan 		if (f_info.flag & ICE_FLTR_TX) {
2899e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
2900e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_tx_vsi_rule_id = ICE_INVAL_ACT;
2901e94d4478SAnirudh Venkataramanan 		} else if (f_info.flag & ICE_FLTR_RX) {
2902e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
2903e94d4478SAnirudh Venkataramanan 			hw->port_info->dflt_rx_vsi_rule_id = ICE_INVAL_ACT;
2904e94d4478SAnirudh Venkataramanan 		}
2905e94d4478SAnirudh Venkataramanan 	}
2906e94d4478SAnirudh Venkataramanan 
2907e94d4478SAnirudh Venkataramanan out:
2908e94d4478SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), s_rule);
2909e94d4478SAnirudh Venkataramanan 	return status;
2910e94d4478SAnirudh Venkataramanan }
2911e94d4478SAnirudh Venkataramanan 
2912e94d4478SAnirudh Venkataramanan /**
29138b2c8582SAkeem G Abodunrin  * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry
29148b2c8582SAkeem G Abodunrin  * @hw: pointer to the hardware structure
29158b2c8582SAkeem G Abodunrin  * @recp_id: lookup type for which the specified rule needs to be searched
29168b2c8582SAkeem G Abodunrin  * @f_info: rule information
29178b2c8582SAkeem G Abodunrin  *
29188b2c8582SAkeem G Abodunrin  * Helper function to search for a unicast rule entry - this is to be used
29198b2c8582SAkeem G Abodunrin  * to remove unicast MAC filter that is not shared with other VSIs on the
29208b2c8582SAkeem G Abodunrin  * PF switch.
29218b2c8582SAkeem G Abodunrin  *
29228b2c8582SAkeem G Abodunrin  * Returns pointer to entry storing the rule if found
29238b2c8582SAkeem G Abodunrin  */
29248b2c8582SAkeem G Abodunrin static struct ice_fltr_mgmt_list_entry *
29258b2c8582SAkeem G Abodunrin ice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id,
29268b2c8582SAkeem G Abodunrin 			  struct ice_fltr_info *f_info)
29278b2c8582SAkeem G Abodunrin {
29288b2c8582SAkeem G Abodunrin 	struct ice_switch_info *sw = hw->switch_info;
29298b2c8582SAkeem G Abodunrin 	struct ice_fltr_mgmt_list_entry *list_itr;
29308b2c8582SAkeem G Abodunrin 	struct list_head *list_head;
29318b2c8582SAkeem G Abodunrin 
29328b2c8582SAkeem G Abodunrin 	list_head = &sw->recp_list[recp_id].filt_rules;
29338b2c8582SAkeem G Abodunrin 	list_for_each_entry(list_itr, list_head, list_entry) {
29348b2c8582SAkeem G Abodunrin 		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
29358b2c8582SAkeem G Abodunrin 			    sizeof(f_info->l_data)) &&
29368b2c8582SAkeem G Abodunrin 		    f_info->fwd_id.hw_vsi_id ==
29378b2c8582SAkeem G Abodunrin 		    list_itr->fltr_info.fwd_id.hw_vsi_id &&
29388b2c8582SAkeem G Abodunrin 		    f_info->flag == list_itr->fltr_info.flag)
29398b2c8582SAkeem G Abodunrin 			return list_itr;
29408b2c8582SAkeem G Abodunrin 	}
29418b2c8582SAkeem G Abodunrin 	return NULL;
29428b2c8582SAkeem G Abodunrin }
29438b2c8582SAkeem G Abodunrin 
29448b2c8582SAkeem G Abodunrin /**
294580d144c9SAnirudh Venkataramanan  * ice_remove_mac - remove a MAC address based filter rule
2946d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
294780d144c9SAnirudh Venkataramanan  * @m_list: list of MAC addresses and forwarding information
294880d144c9SAnirudh Venkataramanan  *
294980d144c9SAnirudh Venkataramanan  * This function removes either a MAC filter rule or a specific VSI from a
295080d144c9SAnirudh Venkataramanan  * VSI list for a multicast MAC address.
295180d144c9SAnirudh Venkataramanan  *
295280d144c9SAnirudh Venkataramanan  * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by
295380d144c9SAnirudh Venkataramanan  * ice_add_mac. Caller should be aware that this call will only work if all
295480d144c9SAnirudh Venkataramanan  * the entries passed into m_list were added previously. It will not attempt to
295580d144c9SAnirudh Venkataramanan  * do a partial remove of entries that were found.
2956d76a60baSAnirudh Venkataramanan  */
2957ebb462dcSBruce Allan enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
2958d76a60baSAnirudh Venkataramanan {
2959072f0c3dSDave Ertman 	struct ice_fltr_list_entry *list_itr, *tmp;
29608b2c8582SAkeem G Abodunrin 	struct mutex *rule_lock; /* Lock to protect filter rule list */
2961d76a60baSAnirudh Venkataramanan 
296280d144c9SAnirudh Venkataramanan 	if (!m_list)
2963d76a60baSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
2964d76a60baSAnirudh Venkataramanan 
29658b2c8582SAkeem G Abodunrin 	rule_lock = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
2966072f0c3dSDave Ertman 	list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) {
296780d144c9SAnirudh Venkataramanan 		enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
29688b2c8582SAkeem G Abodunrin 		u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0];
29698b2c8582SAkeem G Abodunrin 		u16 vsi_handle;
297080d144c9SAnirudh Venkataramanan 
297180d144c9SAnirudh Venkataramanan 		if (l_type != ICE_SW_LKUP_MAC)
297280d144c9SAnirudh Venkataramanan 			return ICE_ERR_PARAM;
29738b2c8582SAkeem G Abodunrin 
29748b2c8582SAkeem G Abodunrin 		vsi_handle = list_itr->fltr_info.vsi_handle;
29758b2c8582SAkeem G Abodunrin 		if (!ice_is_vsi_valid(hw, vsi_handle))
29768b2c8582SAkeem G Abodunrin 			return ICE_ERR_PARAM;
29778b2c8582SAkeem G Abodunrin 
29788b2c8582SAkeem G Abodunrin 		list_itr->fltr_info.fwd_id.hw_vsi_id =
29798b2c8582SAkeem G Abodunrin 					ice_get_hw_vsi_num(hw, vsi_handle);
29808b2c8582SAkeem G Abodunrin 		if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
29818b2c8582SAkeem G Abodunrin 			/* Don't remove the unicast address that belongs to
29828b2c8582SAkeem G Abodunrin 			 * another VSI on the switch, since it is not being
29838b2c8582SAkeem G Abodunrin 			 * shared...
29848b2c8582SAkeem G Abodunrin 			 */
29858b2c8582SAkeem G Abodunrin 			mutex_lock(rule_lock);
29868b2c8582SAkeem G Abodunrin 			if (!ice_find_ucast_rule_entry(hw, ICE_SW_LKUP_MAC,
29878b2c8582SAkeem G Abodunrin 						       &list_itr->fltr_info)) {
29888b2c8582SAkeem G Abodunrin 				mutex_unlock(rule_lock);
29898b2c8582SAkeem G Abodunrin 				return ICE_ERR_DOES_NOT_EXIST;
29908b2c8582SAkeem G Abodunrin 			}
29918b2c8582SAkeem G Abodunrin 			mutex_unlock(rule_lock);
29928b2c8582SAkeem G Abodunrin 		}
299380d144c9SAnirudh Venkataramanan 		list_itr->status = ice_remove_rule_internal(hw,
299480d144c9SAnirudh Venkataramanan 							    ICE_SW_LKUP_MAC,
299580d144c9SAnirudh Venkataramanan 							    list_itr);
299680d144c9SAnirudh Venkataramanan 		if (list_itr->status)
299780d144c9SAnirudh Venkataramanan 			return list_itr->status;
299880d144c9SAnirudh Venkataramanan 	}
299980d144c9SAnirudh Venkataramanan 	return 0;
3000d76a60baSAnirudh Venkataramanan }
3001d76a60baSAnirudh Venkataramanan 
3002d76a60baSAnirudh Venkataramanan /**
3003d76a60baSAnirudh Venkataramanan  * ice_remove_vlan - Remove VLAN based filter rule
3004d76a60baSAnirudh Venkataramanan  * @hw: pointer to the hardware structure
3005d76a60baSAnirudh Venkataramanan  * @v_list: list of VLAN entries and forwarding information
3006d76a60baSAnirudh Venkataramanan  */
3007d76a60baSAnirudh Venkataramanan enum ice_status
3008d76a60baSAnirudh Venkataramanan ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)
3009d76a60baSAnirudh Venkataramanan {
3010072f0c3dSDave Ertman 	struct ice_fltr_list_entry *v_list_itr, *tmp;
3011d76a60baSAnirudh Venkataramanan 
3012d76a60baSAnirudh Venkataramanan 	if (!v_list || !hw)
3013d76a60baSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
3014d76a60baSAnirudh Venkataramanan 
3015072f0c3dSDave Ertman 	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
301680d144c9SAnirudh Venkataramanan 		enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;
301780d144c9SAnirudh Venkataramanan 
301880d144c9SAnirudh Venkataramanan 		if (l_type != ICE_SW_LKUP_VLAN)
301980d144c9SAnirudh Venkataramanan 			return ICE_ERR_PARAM;
302080d144c9SAnirudh Venkataramanan 		v_list_itr->status = ice_remove_rule_internal(hw,
302180d144c9SAnirudh Venkataramanan 							      ICE_SW_LKUP_VLAN,
302280d144c9SAnirudh Venkataramanan 							      v_list_itr);
302380d144c9SAnirudh Venkataramanan 		if (v_list_itr->status)
302480d144c9SAnirudh Venkataramanan 			return v_list_itr->status;
3025d76a60baSAnirudh Venkataramanan 	}
302680d144c9SAnirudh Venkataramanan 	return 0;
3027d76a60baSAnirudh Venkataramanan }
302880d144c9SAnirudh Venkataramanan 
302980d144c9SAnirudh Venkataramanan /**
303080d144c9SAnirudh Venkataramanan  * ice_vsi_uses_fltr - Determine if given VSI uses specified filter
303180d144c9SAnirudh Venkataramanan  * @fm_entry: filter entry to inspect
30325726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to compare with filter info
303380d144c9SAnirudh Venkataramanan  */
303480d144c9SAnirudh Venkataramanan static bool
30355726ca0eSAnirudh Venkataramanan ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)
303680d144c9SAnirudh Venkataramanan {
303780d144c9SAnirudh Venkataramanan 	return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
30385726ca0eSAnirudh Venkataramanan 		 fm_entry->fltr_info.vsi_handle == vsi_handle) ||
303980d144c9SAnirudh Venkataramanan 		(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
30407a91d3f0SJacek Bułatek 		 fm_entry->vsi_list_info &&
30415726ca0eSAnirudh Venkataramanan 		 (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map))));
304280d144c9SAnirudh Venkataramanan }
304380d144c9SAnirudh Venkataramanan 
304480d144c9SAnirudh Venkataramanan /**
304580d144c9SAnirudh Venkataramanan  * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list
304680d144c9SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
30475726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
304880d144c9SAnirudh Venkataramanan  * @vsi_list_head: pointer to the list to add entry to
304980d144c9SAnirudh Venkataramanan  * @fi: pointer to fltr_info of filter entry to copy & add
305080d144c9SAnirudh Venkataramanan  *
305180d144c9SAnirudh Venkataramanan  * Helper function, used when creating a list of filters to remove from
305280d144c9SAnirudh Venkataramanan  * a specific VSI. The entry added to vsi_list_head is a COPY of the
305380d144c9SAnirudh Venkataramanan  * original filter entry, with the exception of fltr_info.fltr_act and
305480d144c9SAnirudh Venkataramanan  * fltr_info.fwd_id fields. These are set such that later logic can
305580d144c9SAnirudh Venkataramanan  * extract which VSI to remove the fltr from, and pass on that information.
305680d144c9SAnirudh Venkataramanan  */
305780d144c9SAnirudh Venkataramanan static enum ice_status
30585726ca0eSAnirudh Venkataramanan ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
305980d144c9SAnirudh Venkataramanan 			       struct list_head *vsi_list_head,
306080d144c9SAnirudh Venkataramanan 			       struct ice_fltr_info *fi)
306180d144c9SAnirudh Venkataramanan {
306280d144c9SAnirudh Venkataramanan 	struct ice_fltr_list_entry *tmp;
306380d144c9SAnirudh Venkataramanan 
306480d144c9SAnirudh Venkataramanan 	/* this memory is freed up in the caller function
306580d144c9SAnirudh Venkataramanan 	 * once filters for this VSI are removed
306680d144c9SAnirudh Venkataramanan 	 */
306780d144c9SAnirudh Venkataramanan 	tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL);
306880d144c9SAnirudh Venkataramanan 	if (!tmp)
306980d144c9SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
307080d144c9SAnirudh Venkataramanan 
307180d144c9SAnirudh Venkataramanan 	tmp->fltr_info = *fi;
307280d144c9SAnirudh Venkataramanan 
307380d144c9SAnirudh Venkataramanan 	/* Overwrite these fields to indicate which VSI to remove filter from,
307480d144c9SAnirudh Venkataramanan 	 * so find and remove logic can extract the information from the
307580d144c9SAnirudh Venkataramanan 	 * list entries. Note that original entries will still have proper
307680d144c9SAnirudh Venkataramanan 	 * values.
307780d144c9SAnirudh Venkataramanan 	 */
307880d144c9SAnirudh Venkataramanan 	tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
30795726ca0eSAnirudh Venkataramanan 	tmp->fltr_info.vsi_handle = vsi_handle;
30805726ca0eSAnirudh Venkataramanan 	tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
308180d144c9SAnirudh Venkataramanan 
308280d144c9SAnirudh Venkataramanan 	list_add(&tmp->list_entry, vsi_list_head);
308380d144c9SAnirudh Venkataramanan 
308480d144c9SAnirudh Venkataramanan 	return 0;
3085d76a60baSAnirudh Venkataramanan }
3086d76a60baSAnirudh Venkataramanan 
3087d76a60baSAnirudh Venkataramanan /**
30889daf8208SAnirudh Venkataramanan  * ice_add_to_vsi_fltr_list - Add VSI filters to the list
30899daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
30905726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
30919daf8208SAnirudh Venkataramanan  * @lkup_list_head: pointer to the list that has certain lookup type filters
30925726ca0eSAnirudh Venkataramanan  * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle
309380d144c9SAnirudh Venkataramanan  *
309480d144c9SAnirudh Venkataramanan  * Locates all filters in lkup_list_head that are used by the given VSI,
309580d144c9SAnirudh Venkataramanan  * and adds COPIES of those entries to vsi_list_head (intended to be used
309680d144c9SAnirudh Venkataramanan  * to remove the listed filters).
309780d144c9SAnirudh Venkataramanan  * Note that this means all entries in vsi_list_head must be explicitly
309880d144c9SAnirudh Venkataramanan  * deallocated by the caller when done with list.
30999daf8208SAnirudh Venkataramanan  */
31009daf8208SAnirudh Venkataramanan static enum ice_status
31015726ca0eSAnirudh Venkataramanan ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
31029daf8208SAnirudh Venkataramanan 			 struct list_head *lkup_list_head,
31039daf8208SAnirudh Venkataramanan 			 struct list_head *vsi_list_head)
31049daf8208SAnirudh Venkataramanan {
31059daf8208SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *fm_entry;
310680d144c9SAnirudh Venkataramanan 	enum ice_status status = 0;
31079daf8208SAnirudh Venkataramanan 
3108f9867df6SAnirudh Venkataramanan 	/* check to make sure VSI ID is valid and within boundary */
31095726ca0eSAnirudh Venkataramanan 	if (!ice_is_vsi_valid(hw, vsi_handle))
31109daf8208SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
31119daf8208SAnirudh Venkataramanan 
31129daf8208SAnirudh Venkataramanan 	list_for_each_entry(fm_entry, lkup_list_head, list_entry) {
31137a91d3f0SJacek Bułatek 		if (!ice_vsi_uses_fltr(fm_entry, vsi_handle))
311480d144c9SAnirudh Venkataramanan 			continue;
31159daf8208SAnirudh Venkataramanan 
31165726ca0eSAnirudh Venkataramanan 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
31177a91d3f0SJacek Bułatek 							vsi_list_head,
31187a91d3f0SJacek Bułatek 							&fm_entry->fltr_info);
311980d144c9SAnirudh Venkataramanan 		if (status)
312080d144c9SAnirudh Venkataramanan 			return status;
31219daf8208SAnirudh Venkataramanan 	}
312280d144c9SAnirudh Venkataramanan 	return status;
31239daf8208SAnirudh Venkataramanan }
31249daf8208SAnirudh Venkataramanan 
31259daf8208SAnirudh Venkataramanan /**
31265eda8afdSAkeem G Abodunrin  * ice_determine_promisc_mask
31275eda8afdSAkeem G Abodunrin  * @fi: filter info to parse
31285eda8afdSAkeem G Abodunrin  *
31295eda8afdSAkeem G Abodunrin  * Helper function to determine which ICE_PROMISC_ mask corresponds
31305eda8afdSAkeem G Abodunrin  * to given filter into.
31315eda8afdSAkeem G Abodunrin  */
31325eda8afdSAkeem G Abodunrin static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi)
31335eda8afdSAkeem G Abodunrin {
31345eda8afdSAkeem G Abodunrin 	u16 vid = fi->l_data.mac_vlan.vlan_id;
31355eda8afdSAkeem G Abodunrin 	u8 *macaddr = fi->l_data.mac.mac_addr;
31365eda8afdSAkeem G Abodunrin 	bool is_tx_fltr = false;
31375eda8afdSAkeem G Abodunrin 	u8 promisc_mask = 0;
31385eda8afdSAkeem G Abodunrin 
31395eda8afdSAkeem G Abodunrin 	if (fi->flag == ICE_FLTR_TX)
31405eda8afdSAkeem G Abodunrin 		is_tx_fltr = true;
31415eda8afdSAkeem G Abodunrin 
31425eda8afdSAkeem G Abodunrin 	if (is_broadcast_ether_addr(macaddr))
31435eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
31445eda8afdSAkeem G Abodunrin 			ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX;
31455eda8afdSAkeem G Abodunrin 	else if (is_multicast_ether_addr(macaddr))
31465eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
31475eda8afdSAkeem G Abodunrin 			ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX;
31485eda8afdSAkeem G Abodunrin 	else if (is_unicast_ether_addr(macaddr))
31495eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
31505eda8afdSAkeem G Abodunrin 			ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX;
31515eda8afdSAkeem G Abodunrin 	if (vid)
31525eda8afdSAkeem G Abodunrin 		promisc_mask |= is_tx_fltr ?
31535eda8afdSAkeem G Abodunrin 			ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX;
31545eda8afdSAkeem G Abodunrin 
31555eda8afdSAkeem G Abodunrin 	return promisc_mask;
31565eda8afdSAkeem G Abodunrin }
31575eda8afdSAkeem G Abodunrin 
31585eda8afdSAkeem G Abodunrin /**
31595eda8afdSAkeem G Abodunrin  * ice_remove_promisc - Remove promisc based filter rules
31605eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
3161f9867df6SAnirudh Venkataramanan  * @recp_id: recipe ID for which the rule needs to removed
31625eda8afdSAkeem G Abodunrin  * @v_list: list of promisc entries
31635eda8afdSAkeem G Abodunrin  */
31645eda8afdSAkeem G Abodunrin static enum ice_status
31655eda8afdSAkeem G Abodunrin ice_remove_promisc(struct ice_hw *hw, u8 recp_id,
31665eda8afdSAkeem G Abodunrin 		   struct list_head *v_list)
31675eda8afdSAkeem G Abodunrin {
31685eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry *v_list_itr, *tmp;
31695eda8afdSAkeem G Abodunrin 
31705eda8afdSAkeem G Abodunrin 	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
31715eda8afdSAkeem G Abodunrin 		v_list_itr->status =
31725eda8afdSAkeem G Abodunrin 			ice_remove_rule_internal(hw, recp_id, v_list_itr);
31735eda8afdSAkeem G Abodunrin 		if (v_list_itr->status)
31745eda8afdSAkeem G Abodunrin 			return v_list_itr->status;
31755eda8afdSAkeem G Abodunrin 	}
31765eda8afdSAkeem G Abodunrin 	return 0;
31775eda8afdSAkeem G Abodunrin }
31785eda8afdSAkeem G Abodunrin 
31795eda8afdSAkeem G Abodunrin /**
31805eda8afdSAkeem G Abodunrin  * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI
31815eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
31825eda8afdSAkeem G Abodunrin  * @vsi_handle: VSI handle to clear mode
31835eda8afdSAkeem G Abodunrin  * @promisc_mask: mask of promiscuous config bits to clear
31845eda8afdSAkeem G Abodunrin  * @vid: VLAN ID to clear VLAN promiscuous
31855eda8afdSAkeem G Abodunrin  */
31865eda8afdSAkeem G Abodunrin enum ice_status
31875eda8afdSAkeem G Abodunrin ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
31885eda8afdSAkeem G Abodunrin 		      u16 vid)
31895eda8afdSAkeem G Abodunrin {
31905eda8afdSAkeem G Abodunrin 	struct ice_switch_info *sw = hw->switch_info;
31915eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry *fm_entry, *tmp;
31925eda8afdSAkeem G Abodunrin 	struct list_head remove_list_head;
31935eda8afdSAkeem G Abodunrin 	struct ice_fltr_mgmt_list_entry *itr;
31945eda8afdSAkeem G Abodunrin 	struct list_head *rule_head;
31955eda8afdSAkeem G Abodunrin 	struct mutex *rule_lock;	/* Lock to protect filter rule list */
31965eda8afdSAkeem G Abodunrin 	enum ice_status status = 0;
31975eda8afdSAkeem G Abodunrin 	u8 recipe_id;
31985eda8afdSAkeem G Abodunrin 
31995eda8afdSAkeem G Abodunrin 	if (!ice_is_vsi_valid(hw, vsi_handle))
32005eda8afdSAkeem G Abodunrin 		return ICE_ERR_PARAM;
32015eda8afdSAkeem G Abodunrin 
32021bc7a4abSBrett Creeley 	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX))
32035eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
32045eda8afdSAkeem G Abodunrin 	else
32055eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC;
32065eda8afdSAkeem G Abodunrin 
32075eda8afdSAkeem G Abodunrin 	rule_head = &sw->recp_list[recipe_id].filt_rules;
32085eda8afdSAkeem G Abodunrin 	rule_lock = &sw->recp_list[recipe_id].filt_rule_lock;
32095eda8afdSAkeem G Abodunrin 
32105eda8afdSAkeem G Abodunrin 	INIT_LIST_HEAD(&remove_list_head);
32115eda8afdSAkeem G Abodunrin 
32125eda8afdSAkeem G Abodunrin 	mutex_lock(rule_lock);
32135eda8afdSAkeem G Abodunrin 	list_for_each_entry(itr, rule_head, list_entry) {
32141bc7a4abSBrett Creeley 		struct ice_fltr_info *fltr_info;
32155eda8afdSAkeem G Abodunrin 		u8 fltr_promisc_mask = 0;
32165eda8afdSAkeem G Abodunrin 
32175eda8afdSAkeem G Abodunrin 		if (!ice_vsi_uses_fltr(itr, vsi_handle))
32185eda8afdSAkeem G Abodunrin 			continue;
32191bc7a4abSBrett Creeley 		fltr_info = &itr->fltr_info;
32205eda8afdSAkeem G Abodunrin 
32211bc7a4abSBrett Creeley 		if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN &&
32221bc7a4abSBrett Creeley 		    vid != fltr_info->l_data.mac_vlan.vlan_id)
32231bc7a4abSBrett Creeley 			continue;
32241bc7a4abSBrett Creeley 
32251bc7a4abSBrett Creeley 		fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info);
32265eda8afdSAkeem G Abodunrin 
32275eda8afdSAkeem G Abodunrin 		/* Skip if filter is not completely specified by given mask */
32285eda8afdSAkeem G Abodunrin 		if (fltr_promisc_mask & ~promisc_mask)
32295eda8afdSAkeem G Abodunrin 			continue;
32305eda8afdSAkeem G Abodunrin 
32315eda8afdSAkeem G Abodunrin 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
32325eda8afdSAkeem G Abodunrin 							&remove_list_head,
32331bc7a4abSBrett Creeley 							fltr_info);
32345eda8afdSAkeem G Abodunrin 		if (status) {
32355eda8afdSAkeem G Abodunrin 			mutex_unlock(rule_lock);
32365eda8afdSAkeem G Abodunrin 			goto free_fltr_list;
32375eda8afdSAkeem G Abodunrin 		}
32385eda8afdSAkeem G Abodunrin 	}
32395eda8afdSAkeem G Abodunrin 	mutex_unlock(rule_lock);
32405eda8afdSAkeem G Abodunrin 
32415eda8afdSAkeem G Abodunrin 	status = ice_remove_promisc(hw, recipe_id, &remove_list_head);
32425eda8afdSAkeem G Abodunrin 
32435eda8afdSAkeem G Abodunrin free_fltr_list:
32445eda8afdSAkeem G Abodunrin 	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
32455eda8afdSAkeem G Abodunrin 		list_del(&fm_entry->list_entry);
32465eda8afdSAkeem G Abodunrin 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
32475eda8afdSAkeem G Abodunrin 	}
32485eda8afdSAkeem G Abodunrin 
32495eda8afdSAkeem G Abodunrin 	return status;
32505eda8afdSAkeem G Abodunrin }
32515eda8afdSAkeem G Abodunrin 
32525eda8afdSAkeem G Abodunrin /**
32535eda8afdSAkeem G Abodunrin  * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
32545eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
32555eda8afdSAkeem G Abodunrin  * @vsi_handle: VSI handle to configure
32565eda8afdSAkeem G Abodunrin  * @promisc_mask: mask of promiscuous config bits
32575eda8afdSAkeem G Abodunrin  * @vid: VLAN ID to set VLAN promiscuous
32585eda8afdSAkeem G Abodunrin  */
32595eda8afdSAkeem G Abodunrin enum ice_status
32605eda8afdSAkeem G Abodunrin ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid)
32615eda8afdSAkeem G Abodunrin {
32625eda8afdSAkeem G Abodunrin 	enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };
32635eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry f_list_entry;
32645eda8afdSAkeem G Abodunrin 	struct ice_fltr_info new_fltr;
32655eda8afdSAkeem G Abodunrin 	enum ice_status status = 0;
32665eda8afdSAkeem G Abodunrin 	bool is_tx_fltr;
32675eda8afdSAkeem G Abodunrin 	u16 hw_vsi_id;
32685eda8afdSAkeem G Abodunrin 	int pkt_type;
32695eda8afdSAkeem G Abodunrin 	u8 recipe_id;
32705eda8afdSAkeem G Abodunrin 
32715eda8afdSAkeem G Abodunrin 	if (!ice_is_vsi_valid(hw, vsi_handle))
32725eda8afdSAkeem G Abodunrin 		return ICE_ERR_PARAM;
32735eda8afdSAkeem G Abodunrin 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
32745eda8afdSAkeem G Abodunrin 
32755eda8afdSAkeem G Abodunrin 	memset(&new_fltr, 0, sizeof(new_fltr));
32765eda8afdSAkeem G Abodunrin 
32775eda8afdSAkeem G Abodunrin 	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) {
32785eda8afdSAkeem G Abodunrin 		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;
32795eda8afdSAkeem G Abodunrin 		new_fltr.l_data.mac_vlan.vlan_id = vid;
32805eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
32815eda8afdSAkeem G Abodunrin 	} else {
32825eda8afdSAkeem G Abodunrin 		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC;
32835eda8afdSAkeem G Abodunrin 		recipe_id = ICE_SW_LKUP_PROMISC;
32845eda8afdSAkeem G Abodunrin 	}
32855eda8afdSAkeem G Abodunrin 
32865eda8afdSAkeem G Abodunrin 	/* Separate filters must be set for each direction/packet type
32875eda8afdSAkeem G Abodunrin 	 * combination, so we will loop over the mask value, store the
32885eda8afdSAkeem G Abodunrin 	 * individual type, and clear it out in the input mask as it
32895eda8afdSAkeem G Abodunrin 	 * is found.
32905eda8afdSAkeem G Abodunrin 	 */
32915eda8afdSAkeem G Abodunrin 	while (promisc_mask) {
32925eda8afdSAkeem G Abodunrin 		u8 *mac_addr;
32935eda8afdSAkeem G Abodunrin 
32945eda8afdSAkeem G Abodunrin 		pkt_type = 0;
32955eda8afdSAkeem G Abodunrin 		is_tx_fltr = false;
32965eda8afdSAkeem G Abodunrin 
32975eda8afdSAkeem G Abodunrin 		if (promisc_mask & ICE_PROMISC_UCAST_RX) {
32985eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_UCAST_RX;
32995eda8afdSAkeem G Abodunrin 			pkt_type = UCAST_FLTR;
33005eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_UCAST_TX) {
33015eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_UCAST_TX;
33025eda8afdSAkeem G Abodunrin 			pkt_type = UCAST_FLTR;
33035eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
33045eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_MCAST_RX) {
33055eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_MCAST_RX;
33065eda8afdSAkeem G Abodunrin 			pkt_type = MCAST_FLTR;
33075eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_MCAST_TX) {
33085eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_MCAST_TX;
33095eda8afdSAkeem G Abodunrin 			pkt_type = MCAST_FLTR;
33105eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
33115eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_BCAST_RX) {
33125eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_BCAST_RX;
33135eda8afdSAkeem G Abodunrin 			pkt_type = BCAST_FLTR;
33145eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_BCAST_TX) {
33155eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_BCAST_TX;
33165eda8afdSAkeem G Abodunrin 			pkt_type = BCAST_FLTR;
33175eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
33185eda8afdSAkeem G Abodunrin 		}
33195eda8afdSAkeem G Abodunrin 
33205eda8afdSAkeem G Abodunrin 		/* Check for VLAN promiscuous flag */
33215eda8afdSAkeem G Abodunrin 		if (promisc_mask & ICE_PROMISC_VLAN_RX) {
33225eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_VLAN_RX;
33235eda8afdSAkeem G Abodunrin 		} else if (promisc_mask & ICE_PROMISC_VLAN_TX) {
33245eda8afdSAkeem G Abodunrin 			promisc_mask &= ~ICE_PROMISC_VLAN_TX;
33255eda8afdSAkeem G Abodunrin 			is_tx_fltr = true;
33265eda8afdSAkeem G Abodunrin 		}
33275eda8afdSAkeem G Abodunrin 
33285eda8afdSAkeem G Abodunrin 		/* Set filter DA based on packet type */
33295eda8afdSAkeem G Abodunrin 		mac_addr = new_fltr.l_data.mac.mac_addr;
33305eda8afdSAkeem G Abodunrin 		if (pkt_type == BCAST_FLTR) {
33315eda8afdSAkeem G Abodunrin 			eth_broadcast_addr(mac_addr);
33325eda8afdSAkeem G Abodunrin 		} else if (pkt_type == MCAST_FLTR ||
33335eda8afdSAkeem G Abodunrin 			   pkt_type == UCAST_FLTR) {
33345eda8afdSAkeem G Abodunrin 			/* Use the dummy ether header DA */
33355eda8afdSAkeem G Abodunrin 			ether_addr_copy(mac_addr, dummy_eth_header);
33365eda8afdSAkeem G Abodunrin 			if (pkt_type == MCAST_FLTR)
33375eda8afdSAkeem G Abodunrin 				mac_addr[0] |= 0x1;	/* Set multicast bit */
33385eda8afdSAkeem G Abodunrin 		}
33395eda8afdSAkeem G Abodunrin 
33405eda8afdSAkeem G Abodunrin 		/* Need to reset this to zero for all iterations */
33415eda8afdSAkeem G Abodunrin 		new_fltr.flag = 0;
33425eda8afdSAkeem G Abodunrin 		if (is_tx_fltr) {
33435eda8afdSAkeem G Abodunrin 			new_fltr.flag |= ICE_FLTR_TX;
33445eda8afdSAkeem G Abodunrin 			new_fltr.src = hw_vsi_id;
33455eda8afdSAkeem G Abodunrin 		} else {
33465eda8afdSAkeem G Abodunrin 			new_fltr.flag |= ICE_FLTR_RX;
33475eda8afdSAkeem G Abodunrin 			new_fltr.src = hw->port_info->lport;
33485eda8afdSAkeem G Abodunrin 		}
33495eda8afdSAkeem G Abodunrin 
33505eda8afdSAkeem G Abodunrin 		new_fltr.fltr_act = ICE_FWD_TO_VSI;
33515eda8afdSAkeem G Abodunrin 		new_fltr.vsi_handle = vsi_handle;
33525eda8afdSAkeem G Abodunrin 		new_fltr.fwd_id.hw_vsi_id = hw_vsi_id;
33535eda8afdSAkeem G Abodunrin 		f_list_entry.fltr_info = new_fltr;
33545eda8afdSAkeem G Abodunrin 
33555eda8afdSAkeem G Abodunrin 		status = ice_add_rule_internal(hw, recipe_id, &f_list_entry);
33565eda8afdSAkeem G Abodunrin 		if (status)
33575eda8afdSAkeem G Abodunrin 			goto set_promisc_exit;
33585eda8afdSAkeem G Abodunrin 	}
33595eda8afdSAkeem G Abodunrin 
33605eda8afdSAkeem G Abodunrin set_promisc_exit:
33615eda8afdSAkeem G Abodunrin 	return status;
33625eda8afdSAkeem G Abodunrin }
33635eda8afdSAkeem G Abodunrin 
33645eda8afdSAkeem G Abodunrin /**
33655eda8afdSAkeem G Abodunrin  * ice_set_vlan_vsi_promisc
33665eda8afdSAkeem G Abodunrin  * @hw: pointer to the hardware structure
33675eda8afdSAkeem G Abodunrin  * @vsi_handle: VSI handle to configure
33685eda8afdSAkeem G Abodunrin  * @promisc_mask: mask of promiscuous config bits
33695eda8afdSAkeem G Abodunrin  * @rm_vlan_promisc: Clear VLANs VSI promisc mode
33705eda8afdSAkeem G Abodunrin  *
33715eda8afdSAkeem G Abodunrin  * Configure VSI with all associated VLANs to given promiscuous mode(s)
33725eda8afdSAkeem G Abodunrin  */
33735eda8afdSAkeem G Abodunrin enum ice_status
33745eda8afdSAkeem G Abodunrin ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
33755eda8afdSAkeem G Abodunrin 			 bool rm_vlan_promisc)
33765eda8afdSAkeem G Abodunrin {
33775eda8afdSAkeem G Abodunrin 	struct ice_switch_info *sw = hw->switch_info;
33785eda8afdSAkeem G Abodunrin 	struct ice_fltr_list_entry *list_itr, *tmp;
33795eda8afdSAkeem G Abodunrin 	struct list_head vsi_list_head;
33805eda8afdSAkeem G Abodunrin 	struct list_head *vlan_head;
33815eda8afdSAkeem G Abodunrin 	struct mutex *vlan_lock; /* Lock to protect filter rule list */
33825eda8afdSAkeem G Abodunrin 	enum ice_status status;
33835eda8afdSAkeem G Abodunrin 	u16 vlan_id;
33845eda8afdSAkeem G Abodunrin 
33855eda8afdSAkeem G Abodunrin 	INIT_LIST_HEAD(&vsi_list_head);
33865eda8afdSAkeem G Abodunrin 	vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
33875eda8afdSAkeem G Abodunrin 	vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
33885eda8afdSAkeem G Abodunrin 	mutex_lock(vlan_lock);
33895eda8afdSAkeem G Abodunrin 	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,
33905eda8afdSAkeem G Abodunrin 					  &vsi_list_head);
33915eda8afdSAkeem G Abodunrin 	mutex_unlock(vlan_lock);
33925eda8afdSAkeem G Abodunrin 	if (status)
33935eda8afdSAkeem G Abodunrin 		goto free_fltr_list;
33945eda8afdSAkeem G Abodunrin 
33955eda8afdSAkeem G Abodunrin 	list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
33965eda8afdSAkeem G Abodunrin 		vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
33975eda8afdSAkeem G Abodunrin 		if (rm_vlan_promisc)
33985eda8afdSAkeem G Abodunrin 			status = ice_clear_vsi_promisc(hw, vsi_handle,
33995eda8afdSAkeem G Abodunrin 						       promisc_mask, vlan_id);
34005eda8afdSAkeem G Abodunrin 		else
34015eda8afdSAkeem G Abodunrin 			status = ice_set_vsi_promisc(hw, vsi_handle,
34025eda8afdSAkeem G Abodunrin 						     promisc_mask, vlan_id);
34035eda8afdSAkeem G Abodunrin 		if (status)
34045eda8afdSAkeem G Abodunrin 			break;
34055eda8afdSAkeem G Abodunrin 	}
34065eda8afdSAkeem G Abodunrin 
34075eda8afdSAkeem G Abodunrin free_fltr_list:
34085eda8afdSAkeem G Abodunrin 	list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) {
34095eda8afdSAkeem G Abodunrin 		list_del(&list_itr->list_entry);
34105eda8afdSAkeem G Abodunrin 		devm_kfree(ice_hw_to_dev(hw), list_itr);
34115eda8afdSAkeem G Abodunrin 	}
34125eda8afdSAkeem G Abodunrin 	return status;
34135eda8afdSAkeem G Abodunrin }
34145eda8afdSAkeem G Abodunrin 
34155eda8afdSAkeem G Abodunrin /**
34169daf8208SAnirudh Venkataramanan  * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
34179daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
34185726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
34199daf8208SAnirudh Venkataramanan  * @lkup: switch rule filter lookup type
34209daf8208SAnirudh Venkataramanan  */
34219daf8208SAnirudh Venkataramanan static void
34225726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
34239daf8208SAnirudh Venkataramanan 			 enum ice_sw_lkup_type lkup)
34249daf8208SAnirudh Venkataramanan {
34259daf8208SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
34269daf8208SAnirudh Venkataramanan 	struct ice_fltr_list_entry *fm_entry;
34279daf8208SAnirudh Venkataramanan 	struct list_head remove_list_head;
342880d144c9SAnirudh Venkataramanan 	struct list_head *rule_head;
34299daf8208SAnirudh Venkataramanan 	struct ice_fltr_list_entry *tmp;
343080d144c9SAnirudh Venkataramanan 	struct mutex *rule_lock;	/* Lock to protect filter rule list */
34319daf8208SAnirudh Venkataramanan 	enum ice_status status;
34329daf8208SAnirudh Venkataramanan 
34339daf8208SAnirudh Venkataramanan 	INIT_LIST_HEAD(&remove_list_head);
343480d144c9SAnirudh Venkataramanan 	rule_lock = &sw->recp_list[lkup].filt_rule_lock;
343580d144c9SAnirudh Venkataramanan 	rule_head = &sw->recp_list[lkup].filt_rules;
343680d144c9SAnirudh Venkataramanan 	mutex_lock(rule_lock);
34375726ca0eSAnirudh Venkataramanan 	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,
343880d144c9SAnirudh Venkataramanan 					  &remove_list_head);
343980d144c9SAnirudh Venkataramanan 	mutex_unlock(rule_lock);
344080d144c9SAnirudh Venkataramanan 	if (status)
3441b7eeb527SRobert Malz 		goto free_fltr_list;
344280d144c9SAnirudh Venkataramanan 
34439daf8208SAnirudh Venkataramanan 	switch (lkup) {
34449daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC:
34459daf8208SAnirudh Venkataramanan 		ice_remove_mac(hw, &remove_list_head);
34469daf8208SAnirudh Venkataramanan 		break;
34479daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_VLAN:
3448d76a60baSAnirudh Venkataramanan 		ice_remove_vlan(hw, &remove_list_head);
3449d76a60baSAnirudh Venkataramanan 		break;
34505eda8afdSAkeem G Abodunrin 	case ICE_SW_LKUP_PROMISC:
34515eda8afdSAkeem G Abodunrin 	case ICE_SW_LKUP_PROMISC_VLAN:
34525eda8afdSAkeem G Abodunrin 		ice_remove_promisc(hw, lkup, &remove_list_head);
34535eda8afdSAkeem G Abodunrin 		break;
34549daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_MAC_VLAN:
34559daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE:
34569daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_ETHERTYPE_MAC:
34579daf8208SAnirudh Venkataramanan 	case ICE_SW_LKUP_DFLT:
345880d144c9SAnirudh Venkataramanan 	case ICE_SW_LKUP_LAST:
345980d144c9SAnirudh Venkataramanan 	default:
346080d144c9SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup);
34619daf8208SAnirudh Venkataramanan 		break;
34629daf8208SAnirudh Venkataramanan 	}
34639daf8208SAnirudh Venkataramanan 
3464b7eeb527SRobert Malz free_fltr_list:
34659daf8208SAnirudh Venkataramanan 	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
34669daf8208SAnirudh Venkataramanan 		list_del(&fm_entry->list_entry);
34679daf8208SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
34689daf8208SAnirudh Venkataramanan 	}
34699daf8208SAnirudh Venkataramanan }
34709daf8208SAnirudh Venkataramanan 
34719daf8208SAnirudh Venkataramanan /**
34729daf8208SAnirudh Venkataramanan  * ice_remove_vsi_fltr - Remove all filters for a VSI
34739daf8208SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
34745726ca0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle to remove filters from
34759daf8208SAnirudh Venkataramanan  */
34765726ca0eSAnirudh Venkataramanan void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)
34779daf8208SAnirudh Venkataramanan {
34785726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC);
34795726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN);
34805726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC);
34815726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN);
34825726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT);
34835726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE);
34845726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC);
34855726ca0eSAnirudh Venkataramanan 	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);
34869daf8208SAnirudh Venkataramanan }
34870f9d5027SAnirudh Venkataramanan 
34880f9d5027SAnirudh Venkataramanan /**
3489148beb61SHenry Tieman  * ice_alloc_res_cntr - allocating resource counter
3490148beb61SHenry Tieman  * @hw: pointer to the hardware structure
3491148beb61SHenry Tieman  * @type: type of resource
3492148beb61SHenry Tieman  * @alloc_shared: if set it is shared else dedicated
3493148beb61SHenry Tieman  * @num_items: number of entries requested for FD resource type
3494148beb61SHenry Tieman  * @counter_id: counter index returned by AQ call
3495148beb61SHenry Tieman  */
3496148beb61SHenry Tieman enum ice_status
3497148beb61SHenry Tieman ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
3498148beb61SHenry Tieman 		   u16 *counter_id)
3499148beb61SHenry Tieman {
3500148beb61SHenry Tieman 	struct ice_aqc_alloc_free_res_elem *buf;
3501148beb61SHenry Tieman 	enum ice_status status;
3502148beb61SHenry Tieman 	u16 buf_len;
3503148beb61SHenry Tieman 
3504148beb61SHenry Tieman 	/* Allocate resource */
350566486d89SBruce Allan 	buf_len = struct_size(buf, elem, 1);
3506148beb61SHenry Tieman 	buf = kzalloc(buf_len, GFP_KERNEL);
3507148beb61SHenry Tieman 	if (!buf)
3508148beb61SHenry Tieman 		return ICE_ERR_NO_MEMORY;
3509148beb61SHenry Tieman 
3510148beb61SHenry Tieman 	buf->num_elems = cpu_to_le16(num_items);
3511148beb61SHenry Tieman 	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
3512148beb61SHenry Tieman 				      ICE_AQC_RES_TYPE_M) | alloc_shared);
3513148beb61SHenry Tieman 
3514148beb61SHenry Tieman 	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
3515148beb61SHenry Tieman 				       ice_aqc_opc_alloc_res, NULL);
3516148beb61SHenry Tieman 	if (status)
3517148beb61SHenry Tieman 		goto exit;
3518148beb61SHenry Tieman 
3519148beb61SHenry Tieman 	*counter_id = le16_to_cpu(buf->elem[0].e.sw_resp);
3520148beb61SHenry Tieman 
3521148beb61SHenry Tieman exit:
3522148beb61SHenry Tieman 	kfree(buf);
3523148beb61SHenry Tieman 	return status;
3524148beb61SHenry Tieman }
3525148beb61SHenry Tieman 
3526148beb61SHenry Tieman /**
3527148beb61SHenry Tieman  * ice_free_res_cntr - free resource counter
3528148beb61SHenry Tieman  * @hw: pointer to the hardware structure
3529148beb61SHenry Tieman  * @type: type of resource
3530148beb61SHenry Tieman  * @alloc_shared: if set it is shared else dedicated
3531148beb61SHenry Tieman  * @num_items: number of entries to be freed for FD resource type
3532148beb61SHenry Tieman  * @counter_id: counter ID resource which needs to be freed
3533148beb61SHenry Tieman  */
3534148beb61SHenry Tieman enum ice_status
3535148beb61SHenry Tieman ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
3536148beb61SHenry Tieman 		  u16 counter_id)
3537148beb61SHenry Tieman {
3538148beb61SHenry Tieman 	struct ice_aqc_alloc_free_res_elem *buf;
3539148beb61SHenry Tieman 	enum ice_status status;
3540148beb61SHenry Tieman 	u16 buf_len;
3541148beb61SHenry Tieman 
3542148beb61SHenry Tieman 	/* Free resource */
354366486d89SBruce Allan 	buf_len = struct_size(buf, elem, 1);
3544148beb61SHenry Tieman 	buf = kzalloc(buf_len, GFP_KERNEL);
3545148beb61SHenry Tieman 	if (!buf)
3546148beb61SHenry Tieman 		return ICE_ERR_NO_MEMORY;
3547148beb61SHenry Tieman 
3548148beb61SHenry Tieman 	buf->num_elems = cpu_to_le16(num_items);
3549148beb61SHenry Tieman 	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
3550148beb61SHenry Tieman 				      ICE_AQC_RES_TYPE_M) | alloc_shared);
3551148beb61SHenry Tieman 	buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
3552148beb61SHenry Tieman 
3553148beb61SHenry Tieman 	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
3554148beb61SHenry Tieman 				       ice_aqc_opc_free_res, NULL);
3555148beb61SHenry Tieman 	if (status)
35569228d8b2SJacob Keller 		ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n");
3557148beb61SHenry Tieman 
3558148beb61SHenry Tieman 	kfree(buf);
3559148beb61SHenry Tieman 	return status;
3560148beb61SHenry Tieman }
3561148beb61SHenry Tieman 
3562fd2a6b71SDan Nowlin /* This is mapping table entry that maps every word within a given protocol
3563fd2a6b71SDan Nowlin  * structure to the real byte offset as per the specification of that
3564fd2a6b71SDan Nowlin  * protocol header.
3565fd2a6b71SDan Nowlin  * for example dst address is 3 words in ethertype header and corresponding
3566fd2a6b71SDan Nowlin  * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8
3567fd2a6b71SDan Nowlin  * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a
3568fd2a6b71SDan Nowlin  * matching entry describing its field. This needs to be updated if new
3569fd2a6b71SDan Nowlin  * structure is added to that union.
3570fd2a6b71SDan Nowlin  */
3571fd2a6b71SDan Nowlin static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
3572fd2a6b71SDan Nowlin 	{ ICE_MAC_OFOS,		{ 0, 2, 4, 6, 8, 10, 12 } },
3573fd2a6b71SDan Nowlin 	{ ICE_MAC_IL,		{ 0, 2, 4, 6, 8, 10, 12 } },
3574fd2a6b71SDan Nowlin 	{ ICE_ETYPE_OL,		{ 0 } },
3575fd2a6b71SDan Nowlin 	{ ICE_VLAN_OFOS,	{ 2, 0 } },
3576fd2a6b71SDan Nowlin 	{ ICE_IPV4_OFOS,	{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
3577fd2a6b71SDan Nowlin 	{ ICE_IPV4_IL,		{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
3578fd2a6b71SDan Nowlin 	{ ICE_IPV6_OFOS,	{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
3579fd2a6b71SDan Nowlin 				 26, 28, 30, 32, 34, 36, 38 } },
3580fd2a6b71SDan Nowlin 	{ ICE_IPV6_IL,		{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
3581fd2a6b71SDan Nowlin 				 26, 28, 30, 32, 34, 36, 38 } },
3582fd2a6b71SDan Nowlin 	{ ICE_TCP_IL,		{ 0, 2 } },
3583fd2a6b71SDan Nowlin 	{ ICE_UDP_OF,		{ 0, 2 } },
3584fd2a6b71SDan Nowlin 	{ ICE_UDP_ILOS,		{ 0, 2 } },
3585fd2a6b71SDan Nowlin };
3586fd2a6b71SDan Nowlin 
3587fd2a6b71SDan Nowlin static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
3588fd2a6b71SDan Nowlin 	{ ICE_MAC_OFOS,		ICE_MAC_OFOS_HW },
3589fd2a6b71SDan Nowlin 	{ ICE_MAC_IL,		ICE_MAC_IL_HW },
3590fd2a6b71SDan Nowlin 	{ ICE_ETYPE_OL,		ICE_ETYPE_OL_HW },
3591fd2a6b71SDan Nowlin 	{ ICE_VLAN_OFOS,	ICE_VLAN_OL_HW },
3592fd2a6b71SDan Nowlin 	{ ICE_IPV4_OFOS,	ICE_IPV4_OFOS_HW },
3593fd2a6b71SDan Nowlin 	{ ICE_IPV4_IL,		ICE_IPV4_IL_HW },
3594fd2a6b71SDan Nowlin 	{ ICE_IPV6_OFOS,	ICE_IPV6_OFOS_HW },
3595fd2a6b71SDan Nowlin 	{ ICE_IPV6_IL,		ICE_IPV6_IL_HW },
3596fd2a6b71SDan Nowlin 	{ ICE_TCP_IL,		ICE_TCP_IL_HW },
3597fd2a6b71SDan Nowlin 	{ ICE_UDP_OF,		ICE_UDP_OF_HW },
3598fd2a6b71SDan Nowlin 	{ ICE_UDP_ILOS,		ICE_UDP_ILOS_HW },
3599fd2a6b71SDan Nowlin };
3600fd2a6b71SDan Nowlin 
3601fd2a6b71SDan Nowlin /**
3602fd2a6b71SDan Nowlin  * ice_find_recp - find a recipe
3603fd2a6b71SDan Nowlin  * @hw: pointer to the hardware structure
3604fd2a6b71SDan Nowlin  * @lkup_exts: extension sequence to match
3605fd2a6b71SDan Nowlin  *
3606fd2a6b71SDan Nowlin  * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
3607fd2a6b71SDan Nowlin  */
3608fd2a6b71SDan Nowlin static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts)
3609fd2a6b71SDan Nowlin {
3610fd2a6b71SDan Nowlin 	bool refresh_required = true;
3611fd2a6b71SDan Nowlin 	struct ice_sw_recipe *recp;
3612fd2a6b71SDan Nowlin 	u8 i;
3613fd2a6b71SDan Nowlin 
3614fd2a6b71SDan Nowlin 	/* Walk through existing recipes to find a match */
3615fd2a6b71SDan Nowlin 	recp = hw->switch_info->recp_list;
3616fd2a6b71SDan Nowlin 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
3617fd2a6b71SDan Nowlin 		/* If recipe was not created for this ID, in SW bookkeeping,
3618fd2a6b71SDan Nowlin 		 * check if FW has an entry for this recipe. If the FW has an
3619fd2a6b71SDan Nowlin 		 * entry update it in our SW bookkeeping and continue with the
3620fd2a6b71SDan Nowlin 		 * matching.
3621fd2a6b71SDan Nowlin 		 */
3622fd2a6b71SDan Nowlin 		if (!recp[i].recp_created)
3623fd2a6b71SDan Nowlin 			if (ice_get_recp_frm_fw(hw,
3624fd2a6b71SDan Nowlin 						hw->switch_info->recp_list, i,
3625fd2a6b71SDan Nowlin 						&refresh_required))
3626fd2a6b71SDan Nowlin 				continue;
3627fd2a6b71SDan Nowlin 
3628fd2a6b71SDan Nowlin 		/* Skip inverse action recipes */
3629fd2a6b71SDan Nowlin 		if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl &
3630fd2a6b71SDan Nowlin 		    ICE_AQ_RECIPE_ACT_INV_ACT)
3631fd2a6b71SDan Nowlin 			continue;
3632fd2a6b71SDan Nowlin 
3633fd2a6b71SDan Nowlin 		/* if number of words we are looking for match */
3634fd2a6b71SDan Nowlin 		if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) {
3635fd2a6b71SDan Nowlin 			struct ice_fv_word *ar = recp[i].lkup_exts.fv_words;
3636fd2a6b71SDan Nowlin 			struct ice_fv_word *be = lkup_exts->fv_words;
3637fd2a6b71SDan Nowlin 			u16 *cr = recp[i].lkup_exts.field_mask;
3638fd2a6b71SDan Nowlin 			u16 *de = lkup_exts->field_mask;
3639fd2a6b71SDan Nowlin 			bool found = true;
3640fd2a6b71SDan Nowlin 			u8 pe, qr;
3641fd2a6b71SDan Nowlin 
3642fd2a6b71SDan Nowlin 			/* ar, cr, and qr are related to the recipe words, while
3643fd2a6b71SDan Nowlin 			 * be, de, and pe are related to the lookup words
3644fd2a6b71SDan Nowlin 			 */
3645fd2a6b71SDan Nowlin 			for (pe = 0; pe < lkup_exts->n_val_words; pe++) {
3646fd2a6b71SDan Nowlin 				for (qr = 0; qr < recp[i].lkup_exts.n_val_words;
3647fd2a6b71SDan Nowlin 				     qr++) {
3648fd2a6b71SDan Nowlin 					if (ar[qr].off == be[pe].off &&
3649fd2a6b71SDan Nowlin 					    ar[qr].prot_id == be[pe].prot_id &&
3650fd2a6b71SDan Nowlin 					    cr[qr] == de[pe])
3651fd2a6b71SDan Nowlin 						/* Found the "pe"th word in the
3652fd2a6b71SDan Nowlin 						 * given recipe
3653fd2a6b71SDan Nowlin 						 */
3654fd2a6b71SDan Nowlin 						break;
3655fd2a6b71SDan Nowlin 				}
3656fd2a6b71SDan Nowlin 				/* After walking through all the words in the
3657fd2a6b71SDan Nowlin 				 * "i"th recipe if "p"th word was not found then
3658fd2a6b71SDan Nowlin 				 * this recipe is not what we are looking for.
3659fd2a6b71SDan Nowlin 				 * So break out from this loop and try the next
3660fd2a6b71SDan Nowlin 				 * recipe
3661fd2a6b71SDan Nowlin 				 */
3662fd2a6b71SDan Nowlin 				if (qr >= recp[i].lkup_exts.n_val_words) {
3663fd2a6b71SDan Nowlin 					found = false;
3664fd2a6b71SDan Nowlin 					break;
3665fd2a6b71SDan Nowlin 				}
3666fd2a6b71SDan Nowlin 			}
3667fd2a6b71SDan Nowlin 			/* If for "i"th recipe the found was never set to false
3668fd2a6b71SDan Nowlin 			 * then it means we found our match
3669fd2a6b71SDan Nowlin 			 */
3670fd2a6b71SDan Nowlin 			if (found)
3671fd2a6b71SDan Nowlin 				return i; /* Return the recipe ID */
3672fd2a6b71SDan Nowlin 		}
3673fd2a6b71SDan Nowlin 	}
3674fd2a6b71SDan Nowlin 	return ICE_MAX_NUM_RECIPES;
3675fd2a6b71SDan Nowlin }
3676fd2a6b71SDan Nowlin 
3677fd2a6b71SDan Nowlin /**
3678fd2a6b71SDan Nowlin  * ice_prot_type_to_id - get protocol ID from protocol type
3679fd2a6b71SDan Nowlin  * @type: protocol type
3680fd2a6b71SDan Nowlin  * @id: pointer to variable that will receive the ID
3681fd2a6b71SDan Nowlin  *
3682fd2a6b71SDan Nowlin  * Returns true if found, false otherwise
3683fd2a6b71SDan Nowlin  */
3684fd2a6b71SDan Nowlin static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id)
3685fd2a6b71SDan Nowlin {
3686fd2a6b71SDan Nowlin 	u8 i;
3687fd2a6b71SDan Nowlin 
3688fd2a6b71SDan Nowlin 	for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++)
3689fd2a6b71SDan Nowlin 		if (ice_prot_id_tbl[i].type == type) {
3690fd2a6b71SDan Nowlin 			*id = ice_prot_id_tbl[i].protocol_id;
3691fd2a6b71SDan Nowlin 			return true;
3692fd2a6b71SDan Nowlin 		}
3693fd2a6b71SDan Nowlin 	return false;
3694fd2a6b71SDan Nowlin }
3695fd2a6b71SDan Nowlin 
3696fd2a6b71SDan Nowlin /**
3697fd2a6b71SDan Nowlin  * ice_fill_valid_words - count valid words
3698fd2a6b71SDan Nowlin  * @rule: advanced rule with lookup information
3699fd2a6b71SDan Nowlin  * @lkup_exts: byte offset extractions of the words that are valid
3700fd2a6b71SDan Nowlin  *
3701fd2a6b71SDan Nowlin  * calculate valid words in a lookup rule using mask value
3702fd2a6b71SDan Nowlin  */
3703fd2a6b71SDan Nowlin static u8
3704fd2a6b71SDan Nowlin ice_fill_valid_words(struct ice_adv_lkup_elem *rule,
3705fd2a6b71SDan Nowlin 		     struct ice_prot_lkup_ext *lkup_exts)
3706fd2a6b71SDan Nowlin {
3707fd2a6b71SDan Nowlin 	u8 j, word, prot_id, ret_val;
3708fd2a6b71SDan Nowlin 
3709fd2a6b71SDan Nowlin 	if (!ice_prot_type_to_id(rule->type, &prot_id))
3710fd2a6b71SDan Nowlin 		return 0;
3711fd2a6b71SDan Nowlin 
3712fd2a6b71SDan Nowlin 	word = lkup_exts->n_val_words;
3713fd2a6b71SDan Nowlin 
3714fd2a6b71SDan Nowlin 	for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++)
3715fd2a6b71SDan Nowlin 		if (((u16 *)&rule->m_u)[j] &&
3716fd2a6b71SDan Nowlin 		    rule->type < ARRAY_SIZE(ice_prot_ext)) {
3717fd2a6b71SDan Nowlin 			/* No more space to accommodate */
3718fd2a6b71SDan Nowlin 			if (word >= ICE_MAX_CHAIN_WORDS)
3719fd2a6b71SDan Nowlin 				return 0;
3720fd2a6b71SDan Nowlin 			lkup_exts->fv_words[word].off =
3721fd2a6b71SDan Nowlin 				ice_prot_ext[rule->type].offs[j];
3722fd2a6b71SDan Nowlin 			lkup_exts->fv_words[word].prot_id =
3723fd2a6b71SDan Nowlin 				ice_prot_id_tbl[rule->type].protocol_id;
3724fd2a6b71SDan Nowlin 			lkup_exts->field_mask[word] =
3725fd2a6b71SDan Nowlin 				be16_to_cpu(((__force __be16 *)&rule->m_u)[j]);
3726fd2a6b71SDan Nowlin 			word++;
3727fd2a6b71SDan Nowlin 		}
3728fd2a6b71SDan Nowlin 
3729fd2a6b71SDan Nowlin 	ret_val = word - lkup_exts->n_val_words;
3730fd2a6b71SDan Nowlin 	lkup_exts->n_val_words = word;
3731fd2a6b71SDan Nowlin 
3732fd2a6b71SDan Nowlin 	return ret_val;
3733fd2a6b71SDan Nowlin }
3734fd2a6b71SDan Nowlin 
3735fd2a6b71SDan Nowlin /**
3736fd2a6b71SDan Nowlin  * ice_create_first_fit_recp_def - Create a recipe grouping
3737fd2a6b71SDan Nowlin  * @hw: pointer to the hardware structure
3738fd2a6b71SDan Nowlin  * @lkup_exts: an array of protocol header extractions
3739fd2a6b71SDan Nowlin  * @rg_list: pointer to a list that stores new recipe groups
3740fd2a6b71SDan Nowlin  * @recp_cnt: pointer to a variable that stores returned number of recipe groups
3741fd2a6b71SDan Nowlin  *
3742fd2a6b71SDan Nowlin  * Using first fit algorithm, take all the words that are still not done
3743fd2a6b71SDan Nowlin  * and start grouping them in 4-word groups. Each group makes up one
3744fd2a6b71SDan Nowlin  * recipe.
3745fd2a6b71SDan Nowlin  */
3746fd2a6b71SDan Nowlin static enum ice_status
3747fd2a6b71SDan Nowlin ice_create_first_fit_recp_def(struct ice_hw *hw,
3748fd2a6b71SDan Nowlin 			      struct ice_prot_lkup_ext *lkup_exts,
3749fd2a6b71SDan Nowlin 			      struct list_head *rg_list,
3750fd2a6b71SDan Nowlin 			      u8 *recp_cnt)
3751fd2a6b71SDan Nowlin {
3752fd2a6b71SDan Nowlin 	struct ice_pref_recipe_group *grp = NULL;
3753fd2a6b71SDan Nowlin 	u8 j;
3754fd2a6b71SDan Nowlin 
3755fd2a6b71SDan Nowlin 	*recp_cnt = 0;
3756fd2a6b71SDan Nowlin 
3757fd2a6b71SDan Nowlin 	/* Walk through every word in the rule to check if it is not done. If so
3758fd2a6b71SDan Nowlin 	 * then this word needs to be part of a new recipe.
3759fd2a6b71SDan Nowlin 	 */
3760fd2a6b71SDan Nowlin 	for (j = 0; j < lkup_exts->n_val_words; j++)
3761fd2a6b71SDan Nowlin 		if (!test_bit(j, lkup_exts->done)) {
3762fd2a6b71SDan Nowlin 			if (!grp ||
3763fd2a6b71SDan Nowlin 			    grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) {
3764fd2a6b71SDan Nowlin 				struct ice_recp_grp_entry *entry;
3765fd2a6b71SDan Nowlin 
3766fd2a6b71SDan Nowlin 				entry = devm_kzalloc(ice_hw_to_dev(hw),
3767fd2a6b71SDan Nowlin 						     sizeof(*entry),
3768fd2a6b71SDan Nowlin 						     GFP_KERNEL);
3769fd2a6b71SDan Nowlin 				if (!entry)
3770fd2a6b71SDan Nowlin 					return ICE_ERR_NO_MEMORY;
3771fd2a6b71SDan Nowlin 				list_add(&entry->l_entry, rg_list);
3772fd2a6b71SDan Nowlin 				grp = &entry->r_group;
3773fd2a6b71SDan Nowlin 				(*recp_cnt)++;
3774fd2a6b71SDan Nowlin 			}
3775fd2a6b71SDan Nowlin 
3776fd2a6b71SDan Nowlin 			grp->pairs[grp->n_val_pairs].prot_id =
3777fd2a6b71SDan Nowlin 				lkup_exts->fv_words[j].prot_id;
3778fd2a6b71SDan Nowlin 			grp->pairs[grp->n_val_pairs].off =
3779fd2a6b71SDan Nowlin 				lkup_exts->fv_words[j].off;
3780fd2a6b71SDan Nowlin 			grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j];
3781fd2a6b71SDan Nowlin 			grp->n_val_pairs++;
3782fd2a6b71SDan Nowlin 		}
3783fd2a6b71SDan Nowlin 
3784fd2a6b71SDan Nowlin 	return 0;
3785fd2a6b71SDan Nowlin }
3786fd2a6b71SDan Nowlin 
3787fd2a6b71SDan Nowlin /**
3788fd2a6b71SDan Nowlin  * ice_fill_fv_word_index - fill in the field vector indices for a recipe group
3789fd2a6b71SDan Nowlin  * @hw: pointer to the hardware structure
3790fd2a6b71SDan Nowlin  * @fv_list: field vector with the extraction sequence information
3791fd2a6b71SDan Nowlin  * @rg_list: recipe groupings with protocol-offset pairs
3792fd2a6b71SDan Nowlin  *
3793fd2a6b71SDan Nowlin  * Helper function to fill in the field vector indices for protocol-offset
3794fd2a6b71SDan Nowlin  * pairs. These indexes are then ultimately programmed into a recipe.
3795fd2a6b71SDan Nowlin  */
3796fd2a6b71SDan Nowlin static enum ice_status
3797fd2a6b71SDan Nowlin ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list,
3798fd2a6b71SDan Nowlin 		       struct list_head *rg_list)
3799fd2a6b71SDan Nowlin {
3800fd2a6b71SDan Nowlin 	struct ice_sw_fv_list_entry *fv;
3801fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *rg;
3802fd2a6b71SDan Nowlin 	struct ice_fv_word *fv_ext;
3803fd2a6b71SDan Nowlin 
3804fd2a6b71SDan Nowlin 	if (list_empty(fv_list))
3805fd2a6b71SDan Nowlin 		return 0;
3806fd2a6b71SDan Nowlin 
3807fd2a6b71SDan Nowlin 	fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry,
3808fd2a6b71SDan Nowlin 			      list_entry);
3809fd2a6b71SDan Nowlin 	fv_ext = fv->fv_ptr->ew;
3810fd2a6b71SDan Nowlin 
3811fd2a6b71SDan Nowlin 	list_for_each_entry(rg, rg_list, l_entry) {
3812fd2a6b71SDan Nowlin 		u8 i;
3813fd2a6b71SDan Nowlin 
3814fd2a6b71SDan Nowlin 		for (i = 0; i < rg->r_group.n_val_pairs; i++) {
3815fd2a6b71SDan Nowlin 			struct ice_fv_word *pr;
3816fd2a6b71SDan Nowlin 			bool found = false;
3817fd2a6b71SDan Nowlin 			u16 mask;
3818fd2a6b71SDan Nowlin 			u8 j;
3819fd2a6b71SDan Nowlin 
3820fd2a6b71SDan Nowlin 			pr = &rg->r_group.pairs[i];
3821fd2a6b71SDan Nowlin 			mask = rg->r_group.mask[i];
3822fd2a6b71SDan Nowlin 
3823fd2a6b71SDan Nowlin 			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
3824fd2a6b71SDan Nowlin 				if (fv_ext[j].prot_id == pr->prot_id &&
3825fd2a6b71SDan Nowlin 				    fv_ext[j].off == pr->off) {
3826fd2a6b71SDan Nowlin 					found = true;
3827fd2a6b71SDan Nowlin 
3828fd2a6b71SDan Nowlin 					/* Store index of field vector */
3829fd2a6b71SDan Nowlin 					rg->fv_idx[i] = j;
3830fd2a6b71SDan Nowlin 					rg->fv_mask[i] = mask;
3831fd2a6b71SDan Nowlin 					break;
3832fd2a6b71SDan Nowlin 				}
3833fd2a6b71SDan Nowlin 
3834fd2a6b71SDan Nowlin 			/* Protocol/offset could not be found, caller gave an
3835fd2a6b71SDan Nowlin 			 * invalid pair
3836fd2a6b71SDan Nowlin 			 */
3837fd2a6b71SDan Nowlin 			if (!found)
3838fd2a6b71SDan Nowlin 				return ICE_ERR_PARAM;
3839fd2a6b71SDan Nowlin 		}
3840fd2a6b71SDan Nowlin 	}
3841fd2a6b71SDan Nowlin 
3842fd2a6b71SDan Nowlin 	return 0;
3843fd2a6b71SDan Nowlin }
3844fd2a6b71SDan Nowlin 
3845fd2a6b71SDan Nowlin /**
3846fd2a6b71SDan Nowlin  * ice_find_free_recp_res_idx - find free result indexes for recipe
3847fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
3848fd2a6b71SDan Nowlin  * @profiles: bitmap of profiles that will be associated with the new recipe
3849fd2a6b71SDan Nowlin  * @free_idx: pointer to variable to receive the free index bitmap
3850fd2a6b71SDan Nowlin  *
3851fd2a6b71SDan Nowlin  * The algorithm used here is:
3852fd2a6b71SDan Nowlin  *	1. When creating a new recipe, create a set P which contains all
3853fd2a6b71SDan Nowlin  *	   Profiles that will be associated with our new recipe
3854fd2a6b71SDan Nowlin  *
3855fd2a6b71SDan Nowlin  *	2. For each Profile p in set P:
3856fd2a6b71SDan Nowlin  *	    a. Add all recipes associated with Profile p into set R
3857fd2a6b71SDan Nowlin  *	    b. Optional : PossibleIndexes &= profile[p].possibleIndexes
3858fd2a6b71SDan Nowlin  *		[initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF]
3859fd2a6b71SDan Nowlin  *		i. Or just assume they all have the same possible indexes:
3860fd2a6b71SDan Nowlin  *			44, 45, 46, 47
3861fd2a6b71SDan Nowlin  *			i.e., PossibleIndexes = 0x0000F00000000000
3862fd2a6b71SDan Nowlin  *
3863fd2a6b71SDan Nowlin  *	3. For each Recipe r in set R:
3864fd2a6b71SDan Nowlin  *	    a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes
3865fd2a6b71SDan Nowlin  *	    b. FreeIndexes = UsedIndexes ^ PossibleIndexes
3866fd2a6b71SDan Nowlin  *
3867fd2a6b71SDan Nowlin  *	FreeIndexes will contain the bits indicating the indexes free for use,
3868fd2a6b71SDan Nowlin  *      then the code needs to update the recipe[r].used_result_idx_bits to
3869fd2a6b71SDan Nowlin  *      indicate which indexes were selected for use by this recipe.
3870fd2a6b71SDan Nowlin  */
3871fd2a6b71SDan Nowlin static u16
3872fd2a6b71SDan Nowlin ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
3873fd2a6b71SDan Nowlin 			   unsigned long *free_idx)
3874fd2a6b71SDan Nowlin {
3875fd2a6b71SDan Nowlin 	DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS);
3876fd2a6b71SDan Nowlin 	DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES);
3877fd2a6b71SDan Nowlin 	DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS);
3878fd2a6b71SDan Nowlin 	u16 bit;
3879fd2a6b71SDan Nowlin 
3880fd2a6b71SDan Nowlin 	bitmap_zero(possible_idx, ICE_MAX_FV_WORDS);
3881fd2a6b71SDan Nowlin 	bitmap_zero(recipes, ICE_MAX_NUM_RECIPES);
3882fd2a6b71SDan Nowlin 	bitmap_zero(used_idx, ICE_MAX_FV_WORDS);
3883fd2a6b71SDan Nowlin 	bitmap_zero(free_idx, ICE_MAX_FV_WORDS);
3884fd2a6b71SDan Nowlin 
3885fd2a6b71SDan Nowlin 	bitmap_set(possible_idx, 0, ICE_MAX_FV_WORDS);
3886fd2a6b71SDan Nowlin 
3887fd2a6b71SDan Nowlin 	/* For each profile we are going to associate the recipe with, add the
3888fd2a6b71SDan Nowlin 	 * recipes that are associated with that profile. This will give us
3889fd2a6b71SDan Nowlin 	 * the set of recipes that our recipe may collide with. Also, determine
3890fd2a6b71SDan Nowlin 	 * what possible result indexes are usable given this set of profiles.
3891fd2a6b71SDan Nowlin 	 */
3892fd2a6b71SDan Nowlin 	for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) {
3893fd2a6b71SDan Nowlin 		bitmap_or(recipes, recipes, profile_to_recipe[bit],
3894fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_RECIPES);
3895fd2a6b71SDan Nowlin 		bitmap_and(possible_idx, possible_idx,
3896fd2a6b71SDan Nowlin 			   hw->switch_info->prof_res_bm[bit],
3897fd2a6b71SDan Nowlin 			   ICE_MAX_FV_WORDS);
3898fd2a6b71SDan Nowlin 	}
3899fd2a6b71SDan Nowlin 
3900fd2a6b71SDan Nowlin 	/* For each recipe that our new recipe may collide with, determine
3901fd2a6b71SDan Nowlin 	 * which indexes have been used.
3902fd2a6b71SDan Nowlin 	 */
3903fd2a6b71SDan Nowlin 	for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES)
3904fd2a6b71SDan Nowlin 		bitmap_or(used_idx, used_idx,
3905fd2a6b71SDan Nowlin 			  hw->switch_info->recp_list[bit].res_idxs,
3906fd2a6b71SDan Nowlin 			  ICE_MAX_FV_WORDS);
3907fd2a6b71SDan Nowlin 
3908fd2a6b71SDan Nowlin 	bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS);
3909fd2a6b71SDan Nowlin 
3910fd2a6b71SDan Nowlin 	/* return number of free indexes */
3911fd2a6b71SDan Nowlin 	return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS);
3912fd2a6b71SDan Nowlin }
3913fd2a6b71SDan Nowlin 
3914fd2a6b71SDan Nowlin /**
3915fd2a6b71SDan Nowlin  * ice_add_sw_recipe - function to call AQ calls to create switch recipe
3916fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
3917fd2a6b71SDan Nowlin  * @rm: recipe management list entry
3918fd2a6b71SDan Nowlin  * @match_tun_mask: tunnel mask that needs to be programmed
3919fd2a6b71SDan Nowlin  * @profiles: bitmap of profiles that will be associated.
3920fd2a6b71SDan Nowlin  */
3921fd2a6b71SDan Nowlin static enum ice_status
3922fd2a6b71SDan Nowlin ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
3923fd2a6b71SDan Nowlin 		  u16 match_tun_mask, unsigned long *profiles)
3924fd2a6b71SDan Nowlin {
3925fd2a6b71SDan Nowlin 	DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
3926fd2a6b71SDan Nowlin 	struct ice_aqc_recipe_data_elem *tmp;
3927fd2a6b71SDan Nowlin 	struct ice_aqc_recipe_data_elem *buf;
3928fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *entry;
3929fd2a6b71SDan Nowlin 	enum ice_status status;
3930fd2a6b71SDan Nowlin 	u16 free_res_idx;
3931fd2a6b71SDan Nowlin 	u16 recipe_count;
3932fd2a6b71SDan Nowlin 	u8 chain_idx;
3933fd2a6b71SDan Nowlin 	u8 recps = 0;
3934fd2a6b71SDan Nowlin 
3935fd2a6b71SDan Nowlin 	/* When more than one recipe are required, another recipe is needed to
3936fd2a6b71SDan Nowlin 	 * chain them together. Matching a tunnel metadata ID takes up one of
3937fd2a6b71SDan Nowlin 	 * the match fields in the chaining recipe reducing the number of
3938fd2a6b71SDan Nowlin 	 * chained recipes by one.
3939fd2a6b71SDan Nowlin 	 */
3940fd2a6b71SDan Nowlin 	 /* check number of free result indices */
3941fd2a6b71SDan Nowlin 	bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS);
3942fd2a6b71SDan Nowlin 	free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm);
3943fd2a6b71SDan Nowlin 
3944fd2a6b71SDan Nowlin 	ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n",
3945fd2a6b71SDan Nowlin 		  free_res_idx, rm->n_grp_count);
3946fd2a6b71SDan Nowlin 
3947fd2a6b71SDan Nowlin 	if (rm->n_grp_count > 1) {
3948fd2a6b71SDan Nowlin 		if (rm->n_grp_count > free_res_idx)
3949fd2a6b71SDan Nowlin 			return ICE_ERR_MAX_LIMIT;
3950fd2a6b71SDan Nowlin 
3951fd2a6b71SDan Nowlin 		rm->n_grp_count++;
3952fd2a6b71SDan Nowlin 	}
3953fd2a6b71SDan Nowlin 
3954fd2a6b71SDan Nowlin 	if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE)
3955fd2a6b71SDan Nowlin 		return ICE_ERR_MAX_LIMIT;
3956fd2a6b71SDan Nowlin 
3957fd2a6b71SDan Nowlin 	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
3958fd2a6b71SDan Nowlin 	if (!tmp)
3959fd2a6b71SDan Nowlin 		return ICE_ERR_NO_MEMORY;
3960fd2a6b71SDan Nowlin 
3961fd2a6b71SDan Nowlin 	buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf),
3962fd2a6b71SDan Nowlin 			   GFP_KERNEL);
3963fd2a6b71SDan Nowlin 	if (!buf) {
3964fd2a6b71SDan Nowlin 		status = ICE_ERR_NO_MEMORY;
3965fd2a6b71SDan Nowlin 		goto err_mem;
3966fd2a6b71SDan Nowlin 	}
3967fd2a6b71SDan Nowlin 
3968fd2a6b71SDan Nowlin 	bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES);
3969fd2a6b71SDan Nowlin 	recipe_count = ICE_MAX_NUM_RECIPES;
3970fd2a6b71SDan Nowlin 	status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC,
3971fd2a6b71SDan Nowlin 				   NULL);
3972fd2a6b71SDan Nowlin 	if (status || recipe_count == 0)
3973fd2a6b71SDan Nowlin 		goto err_unroll;
3974fd2a6b71SDan Nowlin 
3975fd2a6b71SDan Nowlin 	/* Allocate the recipe resources, and configure them according to the
3976fd2a6b71SDan Nowlin 	 * match fields from protocol headers and extracted field vectors.
3977fd2a6b71SDan Nowlin 	 */
3978fd2a6b71SDan Nowlin 	chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS);
3979fd2a6b71SDan Nowlin 	list_for_each_entry(entry, &rm->rg_list, l_entry) {
3980fd2a6b71SDan Nowlin 		u8 i;
3981fd2a6b71SDan Nowlin 
3982fd2a6b71SDan Nowlin 		status = ice_alloc_recipe(hw, &entry->rid);
3983fd2a6b71SDan Nowlin 		if (status)
3984fd2a6b71SDan Nowlin 			goto err_unroll;
3985fd2a6b71SDan Nowlin 
3986fd2a6b71SDan Nowlin 		/* Clear the result index of the located recipe, as this will be
3987fd2a6b71SDan Nowlin 		 * updated, if needed, later in the recipe creation process.
3988fd2a6b71SDan Nowlin 		 */
3989fd2a6b71SDan Nowlin 		tmp[0].content.result_indx = 0;
3990fd2a6b71SDan Nowlin 
3991fd2a6b71SDan Nowlin 		buf[recps] = tmp[0];
3992fd2a6b71SDan Nowlin 		buf[recps].recipe_indx = (u8)entry->rid;
3993fd2a6b71SDan Nowlin 		/* if the recipe is a non-root recipe RID should be programmed
3994fd2a6b71SDan Nowlin 		 * as 0 for the rules to be applied correctly.
3995fd2a6b71SDan Nowlin 		 */
3996fd2a6b71SDan Nowlin 		buf[recps].content.rid = 0;
3997fd2a6b71SDan Nowlin 		memset(&buf[recps].content.lkup_indx, 0,
3998fd2a6b71SDan Nowlin 		       sizeof(buf[recps].content.lkup_indx));
3999fd2a6b71SDan Nowlin 
4000fd2a6b71SDan Nowlin 		/* All recipes use look-up index 0 to match switch ID. */
4001fd2a6b71SDan Nowlin 		buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
4002fd2a6b71SDan Nowlin 		buf[recps].content.mask[0] =
4003fd2a6b71SDan Nowlin 			cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
4004fd2a6b71SDan Nowlin 		/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
4005fd2a6b71SDan Nowlin 		 * to be 0
4006fd2a6b71SDan Nowlin 		 */
4007fd2a6b71SDan Nowlin 		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
4008fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] = 0x80;
4009fd2a6b71SDan Nowlin 			buf[recps].content.mask[i] = 0;
4010fd2a6b71SDan Nowlin 		}
4011fd2a6b71SDan Nowlin 
4012fd2a6b71SDan Nowlin 		for (i = 0; i < entry->r_group.n_val_pairs; i++) {
4013fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];
4014fd2a6b71SDan Nowlin 			buf[recps].content.mask[i + 1] =
4015fd2a6b71SDan Nowlin 				cpu_to_le16(entry->fv_mask[i]);
4016fd2a6b71SDan Nowlin 		}
4017fd2a6b71SDan Nowlin 
4018fd2a6b71SDan Nowlin 		if (rm->n_grp_count > 1) {
4019fd2a6b71SDan Nowlin 			/* Checks to see if there really is a valid result index
4020fd2a6b71SDan Nowlin 			 * that can be used.
4021fd2a6b71SDan Nowlin 			 */
4022fd2a6b71SDan Nowlin 			if (chain_idx >= ICE_MAX_FV_WORDS) {
4023fd2a6b71SDan Nowlin 				ice_debug(hw, ICE_DBG_SW, "No chain index available\n");
4024fd2a6b71SDan Nowlin 				status = ICE_ERR_MAX_LIMIT;
4025fd2a6b71SDan Nowlin 				goto err_unroll;
4026fd2a6b71SDan Nowlin 			}
4027fd2a6b71SDan Nowlin 
4028fd2a6b71SDan Nowlin 			entry->chain_idx = chain_idx;
4029fd2a6b71SDan Nowlin 			buf[recps].content.result_indx =
4030fd2a6b71SDan Nowlin 				ICE_AQ_RECIPE_RESULT_EN |
4031fd2a6b71SDan Nowlin 				((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
4032fd2a6b71SDan Nowlin 				 ICE_AQ_RECIPE_RESULT_DATA_M);
4033fd2a6b71SDan Nowlin 			clear_bit(chain_idx, result_idx_bm);
4034fd2a6b71SDan Nowlin 			chain_idx = find_first_bit(result_idx_bm,
4035fd2a6b71SDan Nowlin 						   ICE_MAX_FV_WORDS);
4036fd2a6b71SDan Nowlin 		}
4037fd2a6b71SDan Nowlin 
4038fd2a6b71SDan Nowlin 		/* fill recipe dependencies */
4039fd2a6b71SDan Nowlin 		bitmap_zero((unsigned long *)buf[recps].recipe_bitmap,
4040fd2a6b71SDan Nowlin 			    ICE_MAX_NUM_RECIPES);
4041fd2a6b71SDan Nowlin 		set_bit(buf[recps].recipe_indx,
4042fd2a6b71SDan Nowlin 			(unsigned long *)buf[recps].recipe_bitmap);
4043fd2a6b71SDan Nowlin 		buf[recps].content.act_ctrl_fwd_priority = rm->priority;
4044fd2a6b71SDan Nowlin 		recps++;
4045fd2a6b71SDan Nowlin 	}
4046fd2a6b71SDan Nowlin 
4047fd2a6b71SDan Nowlin 	if (rm->n_grp_count == 1) {
4048fd2a6b71SDan Nowlin 		rm->root_rid = buf[0].recipe_indx;
4049fd2a6b71SDan Nowlin 		set_bit(buf[0].recipe_indx, rm->r_bitmap);
4050fd2a6b71SDan Nowlin 		buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT;
4051fd2a6b71SDan Nowlin 		if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) {
4052fd2a6b71SDan Nowlin 			memcpy(buf[0].recipe_bitmap, rm->r_bitmap,
4053fd2a6b71SDan Nowlin 			       sizeof(buf[0].recipe_bitmap));
4054fd2a6b71SDan Nowlin 		} else {
4055fd2a6b71SDan Nowlin 			status = ICE_ERR_BAD_PTR;
4056fd2a6b71SDan Nowlin 			goto err_unroll;
4057fd2a6b71SDan Nowlin 		}
4058fd2a6b71SDan Nowlin 		/* Applicable only for ROOT_RECIPE, set the fwd_priority for
4059fd2a6b71SDan Nowlin 		 * the recipe which is getting created if specified
4060fd2a6b71SDan Nowlin 		 * by user. Usually any advanced switch filter, which results
4061fd2a6b71SDan Nowlin 		 * into new extraction sequence, ended up creating a new recipe
4062fd2a6b71SDan Nowlin 		 * of type ROOT and usually recipes are associated with profiles
4063fd2a6b71SDan Nowlin 		 * Switch rule referreing newly created recipe, needs to have
4064fd2a6b71SDan Nowlin 		 * either/or 'fwd' or 'join' priority, otherwise switch rule
4065fd2a6b71SDan Nowlin 		 * evaluation will not happen correctly. In other words, if
4066fd2a6b71SDan Nowlin 		 * switch rule to be evaluated on priority basis, then recipe
4067fd2a6b71SDan Nowlin 		 * needs to have priority, otherwise it will be evaluated last.
4068fd2a6b71SDan Nowlin 		 */
4069fd2a6b71SDan Nowlin 		buf[0].content.act_ctrl_fwd_priority = rm->priority;
4070fd2a6b71SDan Nowlin 	} else {
4071fd2a6b71SDan Nowlin 		struct ice_recp_grp_entry *last_chain_entry;
4072fd2a6b71SDan Nowlin 		u16 rid, i;
4073fd2a6b71SDan Nowlin 
4074fd2a6b71SDan Nowlin 		/* Allocate the last recipe that will chain the outcomes of the
4075fd2a6b71SDan Nowlin 		 * other recipes together
4076fd2a6b71SDan Nowlin 		 */
4077fd2a6b71SDan Nowlin 		status = ice_alloc_recipe(hw, &rid);
4078fd2a6b71SDan Nowlin 		if (status)
4079fd2a6b71SDan Nowlin 			goto err_unroll;
4080fd2a6b71SDan Nowlin 
4081fd2a6b71SDan Nowlin 		buf[recps].recipe_indx = (u8)rid;
4082fd2a6b71SDan Nowlin 		buf[recps].content.rid = (u8)rid;
4083fd2a6b71SDan Nowlin 		buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
4084fd2a6b71SDan Nowlin 		/* the new entry created should also be part of rg_list to
4085fd2a6b71SDan Nowlin 		 * make sure we have complete recipe
4086fd2a6b71SDan Nowlin 		 */
4087fd2a6b71SDan Nowlin 		last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw),
4088fd2a6b71SDan Nowlin 						sizeof(*last_chain_entry),
4089fd2a6b71SDan Nowlin 						GFP_KERNEL);
4090fd2a6b71SDan Nowlin 		if (!last_chain_entry) {
4091fd2a6b71SDan Nowlin 			status = ICE_ERR_NO_MEMORY;
4092fd2a6b71SDan Nowlin 			goto err_unroll;
4093fd2a6b71SDan Nowlin 		}
4094fd2a6b71SDan Nowlin 		last_chain_entry->rid = rid;
4095fd2a6b71SDan Nowlin 		memset(&buf[recps].content.lkup_indx, 0,
4096fd2a6b71SDan Nowlin 		       sizeof(buf[recps].content.lkup_indx));
4097fd2a6b71SDan Nowlin 		/* All recipes use look-up index 0 to match switch ID. */
4098fd2a6b71SDan Nowlin 		buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
4099fd2a6b71SDan Nowlin 		buf[recps].content.mask[0] =
4100fd2a6b71SDan Nowlin 			cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
4101fd2a6b71SDan Nowlin 		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
4102fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] =
4103fd2a6b71SDan Nowlin 				ICE_AQ_RECIPE_LKUP_IGNORE;
4104fd2a6b71SDan Nowlin 			buf[recps].content.mask[i] = 0;
4105fd2a6b71SDan Nowlin 		}
4106fd2a6b71SDan Nowlin 
4107fd2a6b71SDan Nowlin 		i = 1;
4108fd2a6b71SDan Nowlin 		/* update r_bitmap with the recp that is used for chaining */
4109fd2a6b71SDan Nowlin 		set_bit(rid, rm->r_bitmap);
4110fd2a6b71SDan Nowlin 		/* this is the recipe that chains all the other recipes so it
4111fd2a6b71SDan Nowlin 		 * should not have a chaining ID to indicate the same
4112fd2a6b71SDan Nowlin 		 */
4113fd2a6b71SDan Nowlin 		last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
4114fd2a6b71SDan Nowlin 		list_for_each_entry(entry, &rm->rg_list, l_entry) {
4115fd2a6b71SDan Nowlin 			last_chain_entry->fv_idx[i] = entry->chain_idx;
4116fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] = entry->chain_idx;
4117fd2a6b71SDan Nowlin 			buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF);
4118fd2a6b71SDan Nowlin 			set_bit(entry->rid, rm->r_bitmap);
4119fd2a6b71SDan Nowlin 		}
4120fd2a6b71SDan Nowlin 		list_add(&last_chain_entry->l_entry, &rm->rg_list);
4121fd2a6b71SDan Nowlin 		if (sizeof(buf[recps].recipe_bitmap) >=
4122fd2a6b71SDan Nowlin 		    sizeof(rm->r_bitmap)) {
4123fd2a6b71SDan Nowlin 			memcpy(buf[recps].recipe_bitmap, rm->r_bitmap,
4124fd2a6b71SDan Nowlin 			       sizeof(buf[recps].recipe_bitmap));
4125fd2a6b71SDan Nowlin 		} else {
4126fd2a6b71SDan Nowlin 			status = ICE_ERR_BAD_PTR;
4127fd2a6b71SDan Nowlin 			goto err_unroll;
4128fd2a6b71SDan Nowlin 		}
4129fd2a6b71SDan Nowlin 		buf[recps].content.act_ctrl_fwd_priority = rm->priority;
4130fd2a6b71SDan Nowlin 
4131fd2a6b71SDan Nowlin 		/* To differentiate among different UDP tunnels, a meta data ID
4132fd2a6b71SDan Nowlin 		 * flag is used.
4133fd2a6b71SDan Nowlin 		 */
4134fd2a6b71SDan Nowlin 		if (match_tun_mask) {
4135fd2a6b71SDan Nowlin 			buf[recps].content.lkup_indx[i] = ICE_TUN_FLAG_FV_IND;
4136fd2a6b71SDan Nowlin 			buf[recps].content.mask[i] =
4137fd2a6b71SDan Nowlin 				cpu_to_le16(match_tun_mask);
4138fd2a6b71SDan Nowlin 		}
4139fd2a6b71SDan Nowlin 
4140fd2a6b71SDan Nowlin 		recps++;
4141fd2a6b71SDan Nowlin 		rm->root_rid = (u8)rid;
4142fd2a6b71SDan Nowlin 	}
4143fd2a6b71SDan Nowlin 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
4144fd2a6b71SDan Nowlin 	if (status)
4145fd2a6b71SDan Nowlin 		goto err_unroll;
4146fd2a6b71SDan Nowlin 
4147fd2a6b71SDan Nowlin 	status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL);
4148fd2a6b71SDan Nowlin 	ice_release_change_lock(hw);
4149fd2a6b71SDan Nowlin 	if (status)
4150fd2a6b71SDan Nowlin 		goto err_unroll;
4151fd2a6b71SDan Nowlin 
4152fd2a6b71SDan Nowlin 	/* Every recipe that just got created add it to the recipe
4153fd2a6b71SDan Nowlin 	 * book keeping list
4154fd2a6b71SDan Nowlin 	 */
4155fd2a6b71SDan Nowlin 	list_for_each_entry(entry, &rm->rg_list, l_entry) {
4156fd2a6b71SDan Nowlin 		struct ice_switch_info *sw = hw->switch_info;
4157fd2a6b71SDan Nowlin 		bool is_root, idx_found = false;
4158fd2a6b71SDan Nowlin 		struct ice_sw_recipe *recp;
4159fd2a6b71SDan Nowlin 		u16 idx, buf_idx = 0;
4160fd2a6b71SDan Nowlin 
4161fd2a6b71SDan Nowlin 		/* find buffer index for copying some data */
4162fd2a6b71SDan Nowlin 		for (idx = 0; idx < rm->n_grp_count; idx++)
4163fd2a6b71SDan Nowlin 			if (buf[idx].recipe_indx == entry->rid) {
4164fd2a6b71SDan Nowlin 				buf_idx = idx;
4165fd2a6b71SDan Nowlin 				idx_found = true;
4166fd2a6b71SDan Nowlin 			}
4167fd2a6b71SDan Nowlin 
4168fd2a6b71SDan Nowlin 		if (!idx_found) {
4169fd2a6b71SDan Nowlin 			status = ICE_ERR_OUT_OF_RANGE;
4170fd2a6b71SDan Nowlin 			goto err_unroll;
4171fd2a6b71SDan Nowlin 		}
4172fd2a6b71SDan Nowlin 
4173fd2a6b71SDan Nowlin 		recp = &sw->recp_list[entry->rid];
4174fd2a6b71SDan Nowlin 		is_root = (rm->root_rid == entry->rid);
4175fd2a6b71SDan Nowlin 		recp->is_root = is_root;
4176fd2a6b71SDan Nowlin 
4177fd2a6b71SDan Nowlin 		recp->root_rid = entry->rid;
4178fd2a6b71SDan Nowlin 		recp->big_recp = (is_root && rm->n_grp_count > 1);
4179fd2a6b71SDan Nowlin 
4180fd2a6b71SDan Nowlin 		memcpy(&recp->ext_words, entry->r_group.pairs,
4181fd2a6b71SDan Nowlin 		       entry->r_group.n_val_pairs * sizeof(struct ice_fv_word));
4182fd2a6b71SDan Nowlin 
4183fd2a6b71SDan Nowlin 		memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap,
4184fd2a6b71SDan Nowlin 		       sizeof(recp->r_bitmap));
4185fd2a6b71SDan Nowlin 
4186fd2a6b71SDan Nowlin 		/* Copy non-result fv index values and masks to recipe. This
4187fd2a6b71SDan Nowlin 		 * call will also update the result recipe bitmask.
4188fd2a6b71SDan Nowlin 		 */
4189fd2a6b71SDan Nowlin 		ice_collect_result_idx(&buf[buf_idx], recp);
4190fd2a6b71SDan Nowlin 
4191fd2a6b71SDan Nowlin 		/* for non-root recipes, also copy to the root, this allows
4192fd2a6b71SDan Nowlin 		 * easier matching of a complete chained recipe
4193fd2a6b71SDan Nowlin 		 */
4194fd2a6b71SDan Nowlin 		if (!is_root)
4195fd2a6b71SDan Nowlin 			ice_collect_result_idx(&buf[buf_idx],
4196fd2a6b71SDan Nowlin 					       &sw->recp_list[rm->root_rid]);
4197fd2a6b71SDan Nowlin 
4198fd2a6b71SDan Nowlin 		recp->n_ext_words = entry->r_group.n_val_pairs;
4199fd2a6b71SDan Nowlin 		recp->chain_idx = entry->chain_idx;
4200fd2a6b71SDan Nowlin 		recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
4201fd2a6b71SDan Nowlin 		recp->n_grp_count = rm->n_grp_count;
4202fd2a6b71SDan Nowlin 		recp->recp_created = true;
4203fd2a6b71SDan Nowlin 	}
4204fd2a6b71SDan Nowlin 	rm->root_buf = buf;
4205fd2a6b71SDan Nowlin 	kfree(tmp);
4206fd2a6b71SDan Nowlin 	return status;
4207fd2a6b71SDan Nowlin 
4208fd2a6b71SDan Nowlin err_unroll:
4209fd2a6b71SDan Nowlin err_mem:
4210fd2a6b71SDan Nowlin 	kfree(tmp);
4211fd2a6b71SDan Nowlin 	devm_kfree(ice_hw_to_dev(hw), buf);
4212fd2a6b71SDan Nowlin 	return status;
4213fd2a6b71SDan Nowlin }
4214fd2a6b71SDan Nowlin 
4215fd2a6b71SDan Nowlin /**
4216fd2a6b71SDan Nowlin  * ice_create_recipe_group - creates recipe group
4217fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4218fd2a6b71SDan Nowlin  * @rm: recipe management list entry
4219fd2a6b71SDan Nowlin  * @lkup_exts: lookup elements
4220fd2a6b71SDan Nowlin  */
4221fd2a6b71SDan Nowlin static enum ice_status
4222fd2a6b71SDan Nowlin ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm,
4223fd2a6b71SDan Nowlin 			struct ice_prot_lkup_ext *lkup_exts)
4224fd2a6b71SDan Nowlin {
4225fd2a6b71SDan Nowlin 	enum ice_status status;
4226fd2a6b71SDan Nowlin 	u8 recp_count = 0;
4227fd2a6b71SDan Nowlin 
4228fd2a6b71SDan Nowlin 	rm->n_grp_count = 0;
4229fd2a6b71SDan Nowlin 
4230fd2a6b71SDan Nowlin 	/* Create recipes for words that are marked not done by packing them
4231fd2a6b71SDan Nowlin 	 * as best fit.
4232fd2a6b71SDan Nowlin 	 */
4233fd2a6b71SDan Nowlin 	status = ice_create_first_fit_recp_def(hw, lkup_exts,
4234fd2a6b71SDan Nowlin 					       &rm->rg_list, &recp_count);
4235fd2a6b71SDan Nowlin 	if (!status) {
4236fd2a6b71SDan Nowlin 		rm->n_grp_count += recp_count;
4237fd2a6b71SDan Nowlin 		rm->n_ext_words = lkup_exts->n_val_words;
4238fd2a6b71SDan Nowlin 		memcpy(&rm->ext_words, lkup_exts->fv_words,
4239fd2a6b71SDan Nowlin 		       sizeof(rm->ext_words));
4240fd2a6b71SDan Nowlin 		memcpy(rm->word_masks, lkup_exts->field_mask,
4241fd2a6b71SDan Nowlin 		       sizeof(rm->word_masks));
4242fd2a6b71SDan Nowlin 	}
4243fd2a6b71SDan Nowlin 
4244fd2a6b71SDan Nowlin 	return status;
4245fd2a6b71SDan Nowlin }
4246fd2a6b71SDan Nowlin 
4247fd2a6b71SDan Nowlin /**
4248fd2a6b71SDan Nowlin  * ice_get_fv - get field vectors/extraction sequences for spec. lookup types
4249fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4250fd2a6b71SDan Nowlin  * @lkups: lookup elements or match criteria for the advanced recipe, one
4251fd2a6b71SDan Nowlin  *	   structure per protocol header
4252fd2a6b71SDan Nowlin  * @lkups_cnt: number of protocols
4253fd2a6b71SDan Nowlin  * @bm: bitmap of field vectors to consider
4254fd2a6b71SDan Nowlin  * @fv_list: pointer to a list that holds the returned field vectors
4255fd2a6b71SDan Nowlin  */
4256fd2a6b71SDan Nowlin static enum ice_status
4257fd2a6b71SDan Nowlin ice_get_fv(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
4258fd2a6b71SDan Nowlin 	   unsigned long *bm, struct list_head *fv_list)
4259fd2a6b71SDan Nowlin {
4260fd2a6b71SDan Nowlin 	enum ice_status status;
4261fd2a6b71SDan Nowlin 	u8 *prot_ids;
4262fd2a6b71SDan Nowlin 	u16 i;
4263fd2a6b71SDan Nowlin 
4264fd2a6b71SDan Nowlin 	prot_ids = kcalloc(lkups_cnt, sizeof(*prot_ids), GFP_KERNEL);
4265fd2a6b71SDan Nowlin 	if (!prot_ids)
4266fd2a6b71SDan Nowlin 		return ICE_ERR_NO_MEMORY;
4267fd2a6b71SDan Nowlin 
4268fd2a6b71SDan Nowlin 	for (i = 0; i < lkups_cnt; i++)
4269fd2a6b71SDan Nowlin 		if (!ice_prot_type_to_id(lkups[i].type, &prot_ids[i])) {
4270fd2a6b71SDan Nowlin 			status = ICE_ERR_CFG;
4271fd2a6b71SDan Nowlin 			goto free_mem;
4272fd2a6b71SDan Nowlin 		}
4273fd2a6b71SDan Nowlin 
4274fd2a6b71SDan Nowlin 	/* Find field vectors that include all specified protocol types */
4275fd2a6b71SDan Nowlin 	status = ice_get_sw_fv_list(hw, prot_ids, lkups_cnt, bm, fv_list);
4276fd2a6b71SDan Nowlin 
4277fd2a6b71SDan Nowlin free_mem:
4278fd2a6b71SDan Nowlin 	kfree(prot_ids);
4279fd2a6b71SDan Nowlin 	return status;
4280fd2a6b71SDan Nowlin }
4281fd2a6b71SDan Nowlin 
4282fd2a6b71SDan Nowlin /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule
4283fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4284fd2a6b71SDan Nowlin  * @rinfo: other information regarding the rule e.g. priority and action info
4285fd2a6b71SDan Nowlin  * @bm: pointer to memory for returning the bitmap of field vectors
4286fd2a6b71SDan Nowlin  */
4287fd2a6b71SDan Nowlin static void
4288fd2a6b71SDan Nowlin ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
4289fd2a6b71SDan Nowlin 			 unsigned long *bm)
4290fd2a6b71SDan Nowlin {
4291fd2a6b71SDan Nowlin 	bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
4292fd2a6b71SDan Nowlin 
4293fd2a6b71SDan Nowlin 	ice_get_sw_fv_bitmap(hw, ICE_PROF_NON_TUN, bm);
4294fd2a6b71SDan Nowlin }
4295fd2a6b71SDan Nowlin 
4296fd2a6b71SDan Nowlin /**
4297fd2a6b71SDan Nowlin  * ice_add_adv_recipe - Add an advanced recipe that is not part of the default
4298fd2a6b71SDan Nowlin  * @hw: pointer to hardware structure
4299fd2a6b71SDan Nowlin  * @lkups: lookup elements or match criteria for the advanced recipe, one
4300fd2a6b71SDan Nowlin  *  structure per protocol header
4301fd2a6b71SDan Nowlin  * @lkups_cnt: number of protocols
4302fd2a6b71SDan Nowlin  * @rinfo: other information regarding the rule e.g. priority and action info
4303fd2a6b71SDan Nowlin  * @rid: return the recipe ID of the recipe created
4304fd2a6b71SDan Nowlin  */
43050f94570dSGrishma Kotecha static enum ice_status
4306fd2a6b71SDan Nowlin ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
4307fd2a6b71SDan Nowlin 		   u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid)
4308fd2a6b71SDan Nowlin {
4309fd2a6b71SDan Nowlin 	DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES);
4310fd2a6b71SDan Nowlin 	DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES);
4311fd2a6b71SDan Nowlin 	struct ice_prot_lkup_ext *lkup_exts;
4312fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *r_entry;
4313fd2a6b71SDan Nowlin 	struct ice_sw_fv_list_entry *fvit;
4314fd2a6b71SDan Nowlin 	struct ice_recp_grp_entry *r_tmp;
4315fd2a6b71SDan Nowlin 	struct ice_sw_fv_list_entry *tmp;
4316fd2a6b71SDan Nowlin 	enum ice_status status = 0;
4317fd2a6b71SDan Nowlin 	struct ice_sw_recipe *rm;
4318fd2a6b71SDan Nowlin 	u16 match_tun_mask = 0;
4319fd2a6b71SDan Nowlin 	u8 i;
4320fd2a6b71SDan Nowlin 
4321fd2a6b71SDan Nowlin 	if (!lkups_cnt)
4322fd2a6b71SDan Nowlin 		return ICE_ERR_PARAM;
4323fd2a6b71SDan Nowlin 
4324fd2a6b71SDan Nowlin 	lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL);
4325fd2a6b71SDan Nowlin 	if (!lkup_exts)
4326fd2a6b71SDan Nowlin 		return ICE_ERR_NO_MEMORY;
4327fd2a6b71SDan Nowlin 
4328fd2a6b71SDan Nowlin 	/* Determine the number of words to be matched and if it exceeds a
4329fd2a6b71SDan Nowlin 	 * recipe's restrictions
4330fd2a6b71SDan Nowlin 	 */
4331fd2a6b71SDan Nowlin 	for (i = 0; i < lkups_cnt; i++) {
4332fd2a6b71SDan Nowlin 		u16 count;
4333fd2a6b71SDan Nowlin 
4334fd2a6b71SDan Nowlin 		if (lkups[i].type >= ICE_PROTOCOL_LAST) {
4335fd2a6b71SDan Nowlin 			status = ICE_ERR_CFG;
4336fd2a6b71SDan Nowlin 			goto err_free_lkup_exts;
4337fd2a6b71SDan Nowlin 		}
4338fd2a6b71SDan Nowlin 
4339fd2a6b71SDan Nowlin 		count = ice_fill_valid_words(&lkups[i], lkup_exts);
4340fd2a6b71SDan Nowlin 		if (!count) {
4341fd2a6b71SDan Nowlin 			status = ICE_ERR_CFG;
4342fd2a6b71SDan Nowlin 			goto err_free_lkup_exts;
4343fd2a6b71SDan Nowlin 		}
4344fd2a6b71SDan Nowlin 	}
4345fd2a6b71SDan Nowlin 
4346fd2a6b71SDan Nowlin 	rm = kzalloc(sizeof(*rm), GFP_KERNEL);
4347fd2a6b71SDan Nowlin 	if (!rm) {
4348fd2a6b71SDan Nowlin 		status = ICE_ERR_NO_MEMORY;
4349fd2a6b71SDan Nowlin 		goto err_free_lkup_exts;
4350fd2a6b71SDan Nowlin 	}
4351fd2a6b71SDan Nowlin 
4352fd2a6b71SDan Nowlin 	/* Get field vectors that contain fields extracted from all the protocol
4353fd2a6b71SDan Nowlin 	 * headers being programmed.
4354fd2a6b71SDan Nowlin 	 */
4355fd2a6b71SDan Nowlin 	INIT_LIST_HEAD(&rm->fv_list);
4356fd2a6b71SDan Nowlin 	INIT_LIST_HEAD(&rm->rg_list);
4357fd2a6b71SDan Nowlin 
4358fd2a6b71SDan Nowlin 	/* Get bitmap of field vectors (profiles) that are compatible with the
4359fd2a6b71SDan Nowlin 	 * rule request; only these will be searched in the subsequent call to
4360fd2a6b71SDan Nowlin 	 * ice_get_fv.
4361fd2a6b71SDan Nowlin 	 */
4362fd2a6b71SDan Nowlin 	ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap);
4363fd2a6b71SDan Nowlin 
4364fd2a6b71SDan Nowlin 	status = ice_get_fv(hw, lkups, lkups_cnt, fv_bitmap, &rm->fv_list);
4365fd2a6b71SDan Nowlin 	if (status)
4366fd2a6b71SDan Nowlin 		goto err_unroll;
4367fd2a6b71SDan Nowlin 
4368fd2a6b71SDan Nowlin 	/* Group match words into recipes using preferred recipe grouping
4369fd2a6b71SDan Nowlin 	 * criteria.
4370fd2a6b71SDan Nowlin 	 */
4371fd2a6b71SDan Nowlin 	status = ice_create_recipe_group(hw, rm, lkup_exts);
4372fd2a6b71SDan Nowlin 	if (status)
4373fd2a6b71SDan Nowlin 		goto err_unroll;
4374fd2a6b71SDan Nowlin 
4375fd2a6b71SDan Nowlin 	/* set the recipe priority if specified */
4376fd2a6b71SDan Nowlin 	rm->priority = (u8)rinfo->priority;
4377fd2a6b71SDan Nowlin 
4378fd2a6b71SDan Nowlin 	/* Find offsets from the field vector. Pick the first one for all the
4379fd2a6b71SDan Nowlin 	 * recipes.
4380fd2a6b71SDan Nowlin 	 */
4381fd2a6b71SDan Nowlin 	status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list);
4382fd2a6b71SDan Nowlin 	if (status)
4383fd2a6b71SDan Nowlin 		goto err_unroll;
4384fd2a6b71SDan Nowlin 
4385fd2a6b71SDan Nowlin 	/* get bitmap of all profiles the recipe will be associated with */
4386fd2a6b71SDan Nowlin 	bitmap_zero(profiles, ICE_MAX_NUM_PROFILES);
4387fd2a6b71SDan Nowlin 	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
4388fd2a6b71SDan Nowlin 		ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id);
4389fd2a6b71SDan Nowlin 		set_bit((u16)fvit->profile_id, profiles);
4390fd2a6b71SDan Nowlin 	}
4391fd2a6b71SDan Nowlin 
4392fd2a6b71SDan Nowlin 	/* Look for a recipe which matches our requested fv / mask list */
4393fd2a6b71SDan Nowlin 	*rid = ice_find_recp(hw, lkup_exts);
4394fd2a6b71SDan Nowlin 	if (*rid < ICE_MAX_NUM_RECIPES)
4395fd2a6b71SDan Nowlin 		/* Success if found a recipe that match the existing criteria */
4396fd2a6b71SDan Nowlin 		goto err_unroll;
4397fd2a6b71SDan Nowlin 
4398fd2a6b71SDan Nowlin 	/* Recipe we need does not exist, add a recipe */
4399fd2a6b71SDan Nowlin 	status = ice_add_sw_recipe(hw, rm, match_tun_mask, profiles);
4400fd2a6b71SDan Nowlin 	if (status)
4401fd2a6b71SDan Nowlin 		goto err_unroll;
4402fd2a6b71SDan Nowlin 
4403fd2a6b71SDan Nowlin 	/* Associate all the recipes created with all the profiles in the
4404fd2a6b71SDan Nowlin 	 * common field vector.
4405fd2a6b71SDan Nowlin 	 */
4406fd2a6b71SDan Nowlin 	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
4407fd2a6b71SDan Nowlin 		DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
4408fd2a6b71SDan Nowlin 		u16 j;
4409fd2a6b71SDan Nowlin 
4410fd2a6b71SDan Nowlin 		status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id,
4411fd2a6b71SDan Nowlin 						      (u8 *)r_bitmap, NULL);
4412fd2a6b71SDan Nowlin 		if (status)
4413fd2a6b71SDan Nowlin 			goto err_unroll;
4414fd2a6b71SDan Nowlin 
4415fd2a6b71SDan Nowlin 		bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap,
4416fd2a6b71SDan Nowlin 			  ICE_MAX_NUM_RECIPES);
4417fd2a6b71SDan Nowlin 		status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
4418fd2a6b71SDan Nowlin 		if (status)
4419fd2a6b71SDan Nowlin 			goto err_unroll;
4420fd2a6b71SDan Nowlin 
4421fd2a6b71SDan Nowlin 		status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,
4422fd2a6b71SDan Nowlin 						      (u8 *)r_bitmap,
4423fd2a6b71SDan Nowlin 						      NULL);
4424fd2a6b71SDan Nowlin 		ice_release_change_lock(hw);
4425fd2a6b71SDan Nowlin 
4426fd2a6b71SDan Nowlin 		if (status)
4427fd2a6b71SDan Nowlin 			goto err_unroll;
4428fd2a6b71SDan Nowlin 
4429fd2a6b71SDan Nowlin 		/* Update profile to recipe bitmap array */
4430fd2a6b71SDan Nowlin 		bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap,
4431fd2a6b71SDan Nowlin 			    ICE_MAX_NUM_RECIPES);
4432fd2a6b71SDan Nowlin 
4433fd2a6b71SDan Nowlin 		/* Update recipe to profile bitmap array */
4434fd2a6b71SDan Nowlin 		for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES)
4435fd2a6b71SDan Nowlin 			set_bit((u16)fvit->profile_id, recipe_to_profile[j]);
4436fd2a6b71SDan Nowlin 	}
4437fd2a6b71SDan Nowlin 
4438fd2a6b71SDan Nowlin 	*rid = rm->root_rid;
4439fd2a6b71SDan Nowlin 	memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts,
4440fd2a6b71SDan Nowlin 	       sizeof(*lkup_exts));
4441fd2a6b71SDan Nowlin err_unroll:
4442fd2a6b71SDan Nowlin 	list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) {
4443fd2a6b71SDan Nowlin 		list_del(&r_entry->l_entry);
4444fd2a6b71SDan Nowlin 		devm_kfree(ice_hw_to_dev(hw), r_entry);
4445fd2a6b71SDan Nowlin 	}
4446fd2a6b71SDan Nowlin 
4447fd2a6b71SDan Nowlin 	list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) {
4448fd2a6b71SDan Nowlin 		list_del(&fvit->list_entry);
4449fd2a6b71SDan Nowlin 		devm_kfree(ice_hw_to_dev(hw), fvit);
4450fd2a6b71SDan Nowlin 	}
4451fd2a6b71SDan Nowlin 
4452fd2a6b71SDan Nowlin 	if (rm->root_buf)
4453fd2a6b71SDan Nowlin 		devm_kfree(ice_hw_to_dev(hw), rm->root_buf);
4454fd2a6b71SDan Nowlin 
4455fd2a6b71SDan Nowlin 	kfree(rm);
4456fd2a6b71SDan Nowlin 
4457fd2a6b71SDan Nowlin err_free_lkup_exts:
4458fd2a6b71SDan Nowlin 	kfree(lkup_exts);
4459fd2a6b71SDan Nowlin 
4460fd2a6b71SDan Nowlin 	return status;
4461fd2a6b71SDan Nowlin }
4462fd2a6b71SDan Nowlin 
4463148beb61SHenry Tieman /**
44640f94570dSGrishma Kotecha  * ice_find_dummy_packet - find dummy packet
44650f94570dSGrishma Kotecha  *
44660f94570dSGrishma Kotecha  * @lkups: lookup elements or match criteria for the advanced recipe, one
44670f94570dSGrishma Kotecha  *	   structure per protocol header
44680f94570dSGrishma Kotecha  * @lkups_cnt: number of protocols
44690f94570dSGrishma Kotecha  * @pkt: dummy packet to fill according to filter match criteria
44700f94570dSGrishma Kotecha  * @pkt_len: packet length of dummy packet
44710f94570dSGrishma Kotecha  * @offsets: pointer to receive the pointer to the offsets for the packet
44720f94570dSGrishma Kotecha  */
44730f94570dSGrishma Kotecha static void
44740f94570dSGrishma Kotecha ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
44750f94570dSGrishma Kotecha 		      const u8 **pkt, u16 *pkt_len,
44760f94570dSGrishma Kotecha 		      const struct ice_dummy_pkt_offsets **offsets)
44770f94570dSGrishma Kotecha {
44780f94570dSGrishma Kotecha 	bool tcp = false, udp = false, ipv6 = false, vlan = false;
44790f94570dSGrishma Kotecha 	u16 i;
44800f94570dSGrishma Kotecha 
44810f94570dSGrishma Kotecha 	for (i = 0; i < lkups_cnt; i++) {
44820f94570dSGrishma Kotecha 		if (lkups[i].type == ICE_UDP_ILOS)
44830f94570dSGrishma Kotecha 			udp = true;
44840f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_TCP_IL)
44850f94570dSGrishma Kotecha 			tcp = true;
44860f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_IPV6_OFOS)
44870f94570dSGrishma Kotecha 			ipv6 = true;
44880f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_VLAN_OFOS)
44890f94570dSGrishma Kotecha 			vlan = true;
44900f94570dSGrishma Kotecha 		else if (lkups[i].type == ICE_ETYPE_OL &&
44910f94570dSGrishma Kotecha 			 lkups[i].h_u.ethertype.ethtype_id ==
44920f94570dSGrishma Kotecha 				cpu_to_be16(ICE_IPV6_ETHER_ID) &&
44930f94570dSGrishma Kotecha 			 lkups[i].m_u.ethertype.ethtype_id ==
44940f94570dSGrishma Kotecha 					cpu_to_be16(0xFFFF))
44950f94570dSGrishma Kotecha 			ipv6 = true;
44960f94570dSGrishma Kotecha 	}
44970f94570dSGrishma Kotecha 
44980f94570dSGrishma Kotecha 	if (udp && !ipv6) {
44990f94570dSGrishma Kotecha 		if (vlan) {
45000f94570dSGrishma Kotecha 			*pkt = dummy_vlan_udp_packet;
45010f94570dSGrishma Kotecha 			*pkt_len = sizeof(dummy_vlan_udp_packet);
45020f94570dSGrishma Kotecha 			*offsets = dummy_vlan_udp_packet_offsets;
45030f94570dSGrishma Kotecha 			return;
45040f94570dSGrishma Kotecha 		}
45050f94570dSGrishma Kotecha 		*pkt = dummy_udp_packet;
45060f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_udp_packet);
45070f94570dSGrishma Kotecha 		*offsets = dummy_udp_packet_offsets;
45080f94570dSGrishma Kotecha 		return;
45090f94570dSGrishma Kotecha 	} else if (udp && ipv6) {
45100f94570dSGrishma Kotecha 		if (vlan) {
45110f94570dSGrishma Kotecha 			*pkt = dummy_vlan_udp_ipv6_packet;
45120f94570dSGrishma Kotecha 			*pkt_len = sizeof(dummy_vlan_udp_ipv6_packet);
45130f94570dSGrishma Kotecha 			*offsets = dummy_vlan_udp_ipv6_packet_offsets;
45140f94570dSGrishma Kotecha 			return;
45150f94570dSGrishma Kotecha 		}
45160f94570dSGrishma Kotecha 		*pkt = dummy_udp_ipv6_packet;
45170f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_udp_ipv6_packet);
45180f94570dSGrishma Kotecha 		*offsets = dummy_udp_ipv6_packet_offsets;
45190f94570dSGrishma Kotecha 		return;
45200f94570dSGrishma Kotecha 	} else if ((tcp && ipv6) || ipv6) {
45210f94570dSGrishma Kotecha 		if (vlan) {
45220f94570dSGrishma Kotecha 			*pkt = dummy_vlan_tcp_ipv6_packet;
45230f94570dSGrishma Kotecha 			*pkt_len = sizeof(dummy_vlan_tcp_ipv6_packet);
45240f94570dSGrishma Kotecha 			*offsets = dummy_vlan_tcp_ipv6_packet_offsets;
45250f94570dSGrishma Kotecha 			return;
45260f94570dSGrishma Kotecha 		}
45270f94570dSGrishma Kotecha 		*pkt = dummy_tcp_ipv6_packet;
45280f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_tcp_ipv6_packet);
45290f94570dSGrishma Kotecha 		*offsets = dummy_tcp_ipv6_packet_offsets;
45300f94570dSGrishma Kotecha 		return;
45310f94570dSGrishma Kotecha 	}
45320f94570dSGrishma Kotecha 
45330f94570dSGrishma Kotecha 	if (vlan) {
45340f94570dSGrishma Kotecha 		*pkt = dummy_vlan_tcp_packet;
45350f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_vlan_tcp_packet);
45360f94570dSGrishma Kotecha 		*offsets = dummy_vlan_tcp_packet_offsets;
45370f94570dSGrishma Kotecha 	} else {
45380f94570dSGrishma Kotecha 		*pkt = dummy_tcp_packet;
45390f94570dSGrishma Kotecha 		*pkt_len = sizeof(dummy_tcp_packet);
45400f94570dSGrishma Kotecha 		*offsets = dummy_tcp_packet_offsets;
45410f94570dSGrishma Kotecha 	}
45420f94570dSGrishma Kotecha }
45430f94570dSGrishma Kotecha 
45440f94570dSGrishma Kotecha /**
45450f94570dSGrishma Kotecha  * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria
45460f94570dSGrishma Kotecha  *
45470f94570dSGrishma Kotecha  * @lkups: lookup elements or match criteria for the advanced recipe, one
45480f94570dSGrishma Kotecha  *	   structure per protocol header
45490f94570dSGrishma Kotecha  * @lkups_cnt: number of protocols
45500f94570dSGrishma Kotecha  * @s_rule: stores rule information from the match criteria
45510f94570dSGrishma Kotecha  * @dummy_pkt: dummy packet to fill according to filter match criteria
45520f94570dSGrishma Kotecha  * @pkt_len: packet length of dummy packet
45530f94570dSGrishma Kotecha  * @offsets: offset info for the dummy packet
45540f94570dSGrishma Kotecha  */
45550f94570dSGrishma Kotecha static enum ice_status
45560f94570dSGrishma Kotecha ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
45570f94570dSGrishma Kotecha 			  struct ice_aqc_sw_rules_elem *s_rule,
45580f94570dSGrishma Kotecha 			  const u8 *dummy_pkt, u16 pkt_len,
45590f94570dSGrishma Kotecha 			  const struct ice_dummy_pkt_offsets *offsets)
45600f94570dSGrishma Kotecha {
45610f94570dSGrishma Kotecha 	u8 *pkt;
45620f94570dSGrishma Kotecha 	u16 i;
45630f94570dSGrishma Kotecha 
45640f94570dSGrishma Kotecha 	/* Start with a packet with a pre-defined/dummy content. Then, fill
45650f94570dSGrishma Kotecha 	 * in the header values to be looked up or matched.
45660f94570dSGrishma Kotecha 	 */
45670f94570dSGrishma Kotecha 	pkt = s_rule->pdata.lkup_tx_rx.hdr;
45680f94570dSGrishma Kotecha 
45690f94570dSGrishma Kotecha 	memcpy(pkt, dummy_pkt, pkt_len);
45700f94570dSGrishma Kotecha 
45710f94570dSGrishma Kotecha 	for (i = 0; i < lkups_cnt; i++) {
45720f94570dSGrishma Kotecha 		enum ice_protocol_type type;
45730f94570dSGrishma Kotecha 		u16 offset = 0, len = 0, j;
45740f94570dSGrishma Kotecha 		bool found = false;
45750f94570dSGrishma Kotecha 
45760f94570dSGrishma Kotecha 		/* find the start of this layer; it should be found since this
45770f94570dSGrishma Kotecha 		 * was already checked when search for the dummy packet
45780f94570dSGrishma Kotecha 		 */
45790f94570dSGrishma Kotecha 		type = lkups[i].type;
45800f94570dSGrishma Kotecha 		for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) {
45810f94570dSGrishma Kotecha 			if (type == offsets[j].type) {
45820f94570dSGrishma Kotecha 				offset = offsets[j].offset;
45830f94570dSGrishma Kotecha 				found = true;
45840f94570dSGrishma Kotecha 				break;
45850f94570dSGrishma Kotecha 			}
45860f94570dSGrishma Kotecha 		}
45870f94570dSGrishma Kotecha 		/* this should never happen in a correct calling sequence */
45880f94570dSGrishma Kotecha 		if (!found)
45890f94570dSGrishma Kotecha 			return ICE_ERR_PARAM;
45900f94570dSGrishma Kotecha 
45910f94570dSGrishma Kotecha 		switch (lkups[i].type) {
45920f94570dSGrishma Kotecha 		case ICE_MAC_OFOS:
45930f94570dSGrishma Kotecha 		case ICE_MAC_IL:
45940f94570dSGrishma Kotecha 			len = sizeof(struct ice_ether_hdr);
45950f94570dSGrishma Kotecha 			break;
45960f94570dSGrishma Kotecha 		case ICE_ETYPE_OL:
45970f94570dSGrishma Kotecha 			len = sizeof(struct ice_ethtype_hdr);
45980f94570dSGrishma Kotecha 			break;
45990f94570dSGrishma Kotecha 		case ICE_VLAN_OFOS:
46000f94570dSGrishma Kotecha 			len = sizeof(struct ice_vlan_hdr);
46010f94570dSGrishma Kotecha 			break;
46020f94570dSGrishma Kotecha 		case ICE_IPV4_OFOS:
46030f94570dSGrishma Kotecha 		case ICE_IPV4_IL:
46040f94570dSGrishma Kotecha 			len = sizeof(struct ice_ipv4_hdr);
46050f94570dSGrishma Kotecha 			break;
46060f94570dSGrishma Kotecha 		case ICE_IPV6_OFOS:
46070f94570dSGrishma Kotecha 		case ICE_IPV6_IL:
46080f94570dSGrishma Kotecha 			len = sizeof(struct ice_ipv6_hdr);
46090f94570dSGrishma Kotecha 			break;
46100f94570dSGrishma Kotecha 		case ICE_TCP_IL:
46110f94570dSGrishma Kotecha 		case ICE_UDP_OF:
46120f94570dSGrishma Kotecha 		case ICE_UDP_ILOS:
46130f94570dSGrishma Kotecha 			len = sizeof(struct ice_l4_hdr);
46140f94570dSGrishma Kotecha 			break;
46150f94570dSGrishma Kotecha 		case ICE_SCTP_IL:
46160f94570dSGrishma Kotecha 			len = sizeof(struct ice_sctp_hdr);
46170f94570dSGrishma Kotecha 			break;
46180f94570dSGrishma Kotecha 		default:
46190f94570dSGrishma Kotecha 			return ICE_ERR_PARAM;
46200f94570dSGrishma Kotecha 		}
46210f94570dSGrishma Kotecha 
46220f94570dSGrishma Kotecha 		/* the length should be a word multiple */
46230f94570dSGrishma Kotecha 		if (len % ICE_BYTES_PER_WORD)
46240f94570dSGrishma Kotecha 			return ICE_ERR_CFG;
46250f94570dSGrishma Kotecha 
46260f94570dSGrishma Kotecha 		/* We have the offset to the header start, the length, the
46270f94570dSGrishma Kotecha 		 * caller's header values and mask. Use this information to
46280f94570dSGrishma Kotecha 		 * copy the data into the dummy packet appropriately based on
46290f94570dSGrishma Kotecha 		 * the mask. Note that we need to only write the bits as
46300f94570dSGrishma Kotecha 		 * indicated by the mask to make sure we don't improperly write
46310f94570dSGrishma Kotecha 		 * over any significant packet data.
46320f94570dSGrishma Kotecha 		 */
46330f94570dSGrishma Kotecha 		for (j = 0; j < len / sizeof(u16); j++)
46340f94570dSGrishma Kotecha 			if (((u16 *)&lkups[i].m_u)[j])
46350f94570dSGrishma Kotecha 				((u16 *)(pkt + offset))[j] =
46360f94570dSGrishma Kotecha 					(((u16 *)(pkt + offset))[j] &
46370f94570dSGrishma Kotecha 					 ~((u16 *)&lkups[i].m_u)[j]) |
46380f94570dSGrishma Kotecha 					(((u16 *)&lkups[i].h_u)[j] &
46390f94570dSGrishma Kotecha 					 ((u16 *)&lkups[i].m_u)[j]);
46400f94570dSGrishma Kotecha 	}
46410f94570dSGrishma Kotecha 
46420f94570dSGrishma Kotecha 	s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(pkt_len);
46430f94570dSGrishma Kotecha 
46440f94570dSGrishma Kotecha 	return 0;
46450f94570dSGrishma Kotecha }
46460f94570dSGrishma Kotecha 
46470f94570dSGrishma Kotecha /**
46480f94570dSGrishma Kotecha  * ice_find_adv_rule_entry - Search a rule entry
46490f94570dSGrishma Kotecha  * @hw: pointer to the hardware structure
46500f94570dSGrishma Kotecha  * @lkups: lookup elements or match criteria for the advanced recipe, one
46510f94570dSGrishma Kotecha  *	   structure per protocol header
46520f94570dSGrishma Kotecha  * @lkups_cnt: number of protocols
46530f94570dSGrishma Kotecha  * @recp_id: recipe ID for which we are finding the rule
46540f94570dSGrishma Kotecha  * @rinfo: other information regarding the rule e.g. priority and action info
46550f94570dSGrishma Kotecha  *
46560f94570dSGrishma Kotecha  * Helper function to search for a given advance rule entry
46570f94570dSGrishma Kotecha  * Returns pointer to entry storing the rule if found
46580f94570dSGrishma Kotecha  */
46590f94570dSGrishma Kotecha static struct ice_adv_fltr_mgmt_list_entry *
46600f94570dSGrishma Kotecha ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
46610f94570dSGrishma Kotecha 			u16 lkups_cnt, u16 recp_id,
46620f94570dSGrishma Kotecha 			struct ice_adv_rule_info *rinfo)
46630f94570dSGrishma Kotecha {
46640f94570dSGrishma Kotecha 	struct ice_adv_fltr_mgmt_list_entry *list_itr;
46650f94570dSGrishma Kotecha 	struct ice_switch_info *sw = hw->switch_info;
46660f94570dSGrishma Kotecha 	int i;
46670f94570dSGrishma Kotecha 
46680f94570dSGrishma Kotecha 	list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules,
46690f94570dSGrishma Kotecha 			    list_entry) {
46700f94570dSGrishma Kotecha 		bool lkups_matched = true;
46710f94570dSGrishma Kotecha 
46720f94570dSGrishma Kotecha 		if (lkups_cnt != list_itr->lkups_cnt)
46730f94570dSGrishma Kotecha 			continue;
46740f94570dSGrishma Kotecha 		for (i = 0; i < list_itr->lkups_cnt; i++)
46750f94570dSGrishma Kotecha 			if (memcmp(&list_itr->lkups[i], &lkups[i],
46760f94570dSGrishma Kotecha 				   sizeof(*lkups))) {
46770f94570dSGrishma Kotecha 				lkups_matched = false;
46780f94570dSGrishma Kotecha 				break;
46790f94570dSGrishma Kotecha 			}
46800f94570dSGrishma Kotecha 		if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag &&
46810f94570dSGrishma Kotecha 		    lkups_matched)
46820f94570dSGrishma Kotecha 			return list_itr;
46830f94570dSGrishma Kotecha 	}
46840f94570dSGrishma Kotecha 	return NULL;
46850f94570dSGrishma Kotecha }
46860f94570dSGrishma Kotecha 
46870f94570dSGrishma Kotecha /**
46880f94570dSGrishma Kotecha  * ice_adv_add_update_vsi_list
46890f94570dSGrishma Kotecha  * @hw: pointer to the hardware structure
46900f94570dSGrishma Kotecha  * @m_entry: pointer to current adv filter management list entry
46910f94570dSGrishma Kotecha  * @cur_fltr: filter information from the book keeping entry
46920f94570dSGrishma Kotecha  * @new_fltr: filter information with the new VSI to be added
46930f94570dSGrishma Kotecha  *
46940f94570dSGrishma Kotecha  * Call AQ command to add or update previously created VSI list with new VSI.
46950f94570dSGrishma Kotecha  *
46960f94570dSGrishma Kotecha  * Helper function to do book keeping associated with adding filter information
46970f94570dSGrishma Kotecha  * The algorithm to do the booking keeping is described below :
46980f94570dSGrishma Kotecha  * When a VSI needs to subscribe to a given advanced filter
46990f94570dSGrishma Kotecha  *	if only one VSI has been added till now
47000f94570dSGrishma Kotecha  *		Allocate a new VSI list and add two VSIs
47010f94570dSGrishma Kotecha  *		to this list using switch rule command
47020f94570dSGrishma Kotecha  *		Update the previously created switch rule with the
47030f94570dSGrishma Kotecha  *		newly created VSI list ID
47040f94570dSGrishma Kotecha  *	if a VSI list was previously created
47050f94570dSGrishma Kotecha  *		Add the new VSI to the previously created VSI list set
47060f94570dSGrishma Kotecha  *		using the update switch rule command
47070f94570dSGrishma Kotecha  */
47080f94570dSGrishma Kotecha static enum ice_status
47090f94570dSGrishma Kotecha ice_adv_add_update_vsi_list(struct ice_hw *hw,
47100f94570dSGrishma Kotecha 			    struct ice_adv_fltr_mgmt_list_entry *m_entry,
47110f94570dSGrishma Kotecha 			    struct ice_adv_rule_info *cur_fltr,
47120f94570dSGrishma Kotecha 			    struct ice_adv_rule_info *new_fltr)
47130f94570dSGrishma Kotecha {
47140f94570dSGrishma Kotecha 	enum ice_status status;
47150f94570dSGrishma Kotecha 	u16 vsi_list_id = 0;
47160f94570dSGrishma Kotecha 
47170f94570dSGrishma Kotecha 	if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||
47180f94570dSGrishma Kotecha 	    cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
47190f94570dSGrishma Kotecha 	    cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET)
47200f94570dSGrishma Kotecha 		return ICE_ERR_NOT_IMPL;
47210f94570dSGrishma Kotecha 
47220f94570dSGrishma Kotecha 	if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||
47230f94570dSGrishma Kotecha 	     new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) &&
47240f94570dSGrishma Kotecha 	    (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI ||
47250f94570dSGrishma Kotecha 	     cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST))
47260f94570dSGrishma Kotecha 		return ICE_ERR_NOT_IMPL;
47270f94570dSGrishma Kotecha 
47280f94570dSGrishma Kotecha 	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
47290f94570dSGrishma Kotecha 		 /* Only one entry existed in the mapping and it was not already
47300f94570dSGrishma Kotecha 		  * a part of a VSI list. So, create a VSI list with the old and
47310f94570dSGrishma Kotecha 		  * new VSIs.
47320f94570dSGrishma Kotecha 		  */
47330f94570dSGrishma Kotecha 		struct ice_fltr_info tmp_fltr;
47340f94570dSGrishma Kotecha 		u16 vsi_handle_arr[2];
47350f94570dSGrishma Kotecha 
47360f94570dSGrishma Kotecha 		/* A rule already exists with the new VSI being added */
47370f94570dSGrishma Kotecha 		if (cur_fltr->sw_act.fwd_id.hw_vsi_id ==
47380f94570dSGrishma Kotecha 		    new_fltr->sw_act.fwd_id.hw_vsi_id)
47390f94570dSGrishma Kotecha 			return ICE_ERR_ALREADY_EXISTS;
47400f94570dSGrishma Kotecha 
47410f94570dSGrishma Kotecha 		vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle;
47420f94570dSGrishma Kotecha 		vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle;
47430f94570dSGrishma Kotecha 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
47440f94570dSGrishma Kotecha 						  &vsi_list_id,
47450f94570dSGrishma Kotecha 						  ICE_SW_LKUP_LAST);
47460f94570dSGrishma Kotecha 		if (status)
47470f94570dSGrishma Kotecha 			return status;
47480f94570dSGrishma Kotecha 
47490f94570dSGrishma Kotecha 		memset(&tmp_fltr, 0, sizeof(tmp_fltr));
47500f94570dSGrishma Kotecha 		tmp_fltr.flag = m_entry->rule_info.sw_act.flag;
47510f94570dSGrishma Kotecha 		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
47520f94570dSGrishma Kotecha 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
47530f94570dSGrishma Kotecha 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
47540f94570dSGrishma Kotecha 		tmp_fltr.lkup_type = ICE_SW_LKUP_LAST;
47550f94570dSGrishma Kotecha 
47560f94570dSGrishma Kotecha 		/* Update the previous switch rule of "forward to VSI" to
47570f94570dSGrishma Kotecha 		 * "fwd to VSI list"
47580f94570dSGrishma Kotecha 		 */
47590f94570dSGrishma Kotecha 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
47600f94570dSGrishma Kotecha 		if (status)
47610f94570dSGrishma Kotecha 			return status;
47620f94570dSGrishma Kotecha 
47630f94570dSGrishma Kotecha 		cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id;
47640f94570dSGrishma Kotecha 		cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST;
47650f94570dSGrishma Kotecha 		m_entry->vsi_list_info =
47660f94570dSGrishma Kotecha 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
47670f94570dSGrishma Kotecha 						vsi_list_id);
47680f94570dSGrishma Kotecha 	} else {
47690f94570dSGrishma Kotecha 		u16 vsi_handle = new_fltr->sw_act.vsi_handle;
47700f94570dSGrishma Kotecha 
47710f94570dSGrishma Kotecha 		if (!m_entry->vsi_list_info)
47720f94570dSGrishma Kotecha 			return ICE_ERR_CFG;
47730f94570dSGrishma Kotecha 
47740f94570dSGrishma Kotecha 		/* A rule already exists with the new VSI being added */
47750f94570dSGrishma Kotecha 		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
47760f94570dSGrishma Kotecha 			return 0;
47770f94570dSGrishma Kotecha 
47780f94570dSGrishma Kotecha 		/* Update the previously created VSI list set with
47790f94570dSGrishma Kotecha 		 * the new VSI ID passed in
47800f94570dSGrishma Kotecha 		 */
47810f94570dSGrishma Kotecha 		vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id;
47820f94570dSGrishma Kotecha 
47830f94570dSGrishma Kotecha 		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
47840f94570dSGrishma Kotecha 						  vsi_list_id, false,
47850f94570dSGrishma Kotecha 						  ice_aqc_opc_update_sw_rules,
47860f94570dSGrishma Kotecha 						  ICE_SW_LKUP_LAST);
47870f94570dSGrishma Kotecha 		/* update VSI list mapping info with new VSI ID */
47880f94570dSGrishma Kotecha 		if (!status)
47890f94570dSGrishma Kotecha 			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
47900f94570dSGrishma Kotecha 	}
47910f94570dSGrishma Kotecha 	if (!status)
47920f94570dSGrishma Kotecha 		m_entry->vsi_count++;
47930f94570dSGrishma Kotecha 	return status;
47940f94570dSGrishma Kotecha }
47950f94570dSGrishma Kotecha 
47960f94570dSGrishma Kotecha /**
47970f94570dSGrishma Kotecha  * ice_add_adv_rule - helper function to create an advanced switch rule
47980f94570dSGrishma Kotecha  * @hw: pointer to the hardware structure
47990f94570dSGrishma Kotecha  * @lkups: information on the words that needs to be looked up. All words
48000f94570dSGrishma Kotecha  * together makes one recipe
48010f94570dSGrishma Kotecha  * @lkups_cnt: num of entries in the lkups array
48020f94570dSGrishma Kotecha  * @rinfo: other information related to the rule that needs to be programmed
48030f94570dSGrishma Kotecha  * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be
48040f94570dSGrishma Kotecha  *               ignored is case of error.
48050f94570dSGrishma Kotecha  *
48060f94570dSGrishma Kotecha  * This function can program only 1 rule at a time. The lkups is used to
48070f94570dSGrishma Kotecha  * describe the all the words that forms the "lookup" portion of the recipe.
48080f94570dSGrishma Kotecha  * These words can span multiple protocols. Callers to this function need to
48090f94570dSGrishma Kotecha  * pass in a list of protocol headers with lookup information along and mask
48100f94570dSGrishma Kotecha  * that determines which words are valid from the given protocol header.
48110f94570dSGrishma Kotecha  * rinfo describes other information related to this rule such as forwarding
48120f94570dSGrishma Kotecha  * IDs, priority of this rule, etc.
48130f94570dSGrishma Kotecha  */
48140f94570dSGrishma Kotecha enum ice_status
48150f94570dSGrishma Kotecha ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
48160f94570dSGrishma Kotecha 		 u16 lkups_cnt, struct ice_adv_rule_info *rinfo,
48170f94570dSGrishma Kotecha 		 struct ice_rule_query_data *added_entry)
48180f94570dSGrishma Kotecha {
48190f94570dSGrishma Kotecha 	struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL;
48200f94570dSGrishma Kotecha 	u16 rid = 0, i, pkt_len, rule_buf_sz, vsi_handle;
48210f94570dSGrishma Kotecha 	const struct ice_dummy_pkt_offsets *pkt_offsets;
48220f94570dSGrishma Kotecha 	struct ice_aqc_sw_rules_elem *s_rule = NULL;
48230f94570dSGrishma Kotecha 	struct list_head *rule_head;
48240f94570dSGrishma Kotecha 	struct ice_switch_info *sw;
48250f94570dSGrishma Kotecha 	enum ice_status status;
48260f94570dSGrishma Kotecha 	const u8 *pkt = NULL;
48270f94570dSGrishma Kotecha 	u16 word_cnt;
48280f94570dSGrishma Kotecha 	u32 act = 0;
48290f94570dSGrishma Kotecha 	u8 q_rgn;
48300f94570dSGrishma Kotecha 
48310f94570dSGrishma Kotecha 	/* Initialize profile to result index bitmap */
48320f94570dSGrishma Kotecha 	if (!hw->switch_info->prof_res_bm_init) {
48330f94570dSGrishma Kotecha 		hw->switch_info->prof_res_bm_init = 1;
48340f94570dSGrishma Kotecha 		ice_init_prof_result_bm(hw);
48350f94570dSGrishma Kotecha 	}
48360f94570dSGrishma Kotecha 
48370f94570dSGrishma Kotecha 	if (!lkups_cnt)
48380f94570dSGrishma Kotecha 		return ICE_ERR_PARAM;
48390f94570dSGrishma Kotecha 
48400f94570dSGrishma Kotecha 	/* get # of words we need to match */
48410f94570dSGrishma Kotecha 	word_cnt = 0;
48420f94570dSGrishma Kotecha 	for (i = 0; i < lkups_cnt; i++) {
48430f94570dSGrishma Kotecha 		u16 j, *ptr;
48440f94570dSGrishma Kotecha 
48450f94570dSGrishma Kotecha 		ptr = (u16 *)&lkups[i].m_u;
48460f94570dSGrishma Kotecha 		for (j = 0; j < sizeof(lkups->m_u) / sizeof(u16); j++)
48470f94570dSGrishma Kotecha 			if (ptr[j] != 0)
48480f94570dSGrishma Kotecha 				word_cnt++;
48490f94570dSGrishma Kotecha 	}
48500f94570dSGrishma Kotecha 
48510f94570dSGrishma Kotecha 	if (!word_cnt || word_cnt > ICE_MAX_CHAIN_WORDS)
48520f94570dSGrishma Kotecha 		return ICE_ERR_PARAM;
48530f94570dSGrishma Kotecha 
48540f94570dSGrishma Kotecha 	/* make sure that we can locate a dummy packet */
48550f94570dSGrishma Kotecha 	ice_find_dummy_packet(lkups, lkups_cnt, &pkt, &pkt_len,
48560f94570dSGrishma Kotecha 			      &pkt_offsets);
48570f94570dSGrishma Kotecha 	if (!pkt) {
48580f94570dSGrishma Kotecha 		status = ICE_ERR_PARAM;
48590f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
48600f94570dSGrishma Kotecha 	}
48610f94570dSGrishma Kotecha 
48620f94570dSGrishma Kotecha 	if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
48630f94570dSGrishma Kotecha 	      rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
48640f94570dSGrishma Kotecha 	      rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
48650f94570dSGrishma Kotecha 	      rinfo->sw_act.fltr_act == ICE_DROP_PACKET))
48660f94570dSGrishma Kotecha 		return ICE_ERR_CFG;
48670f94570dSGrishma Kotecha 
48680f94570dSGrishma Kotecha 	vsi_handle = rinfo->sw_act.vsi_handle;
48690f94570dSGrishma Kotecha 	if (!ice_is_vsi_valid(hw, vsi_handle))
48700f94570dSGrishma Kotecha 		return ICE_ERR_PARAM;
48710f94570dSGrishma Kotecha 
48720f94570dSGrishma Kotecha 	if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
48730f94570dSGrishma Kotecha 		rinfo->sw_act.fwd_id.hw_vsi_id =
48740f94570dSGrishma Kotecha 			ice_get_hw_vsi_num(hw, vsi_handle);
48750f94570dSGrishma Kotecha 	if (rinfo->sw_act.flag & ICE_FLTR_TX)
48760f94570dSGrishma Kotecha 		rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle);
48770f94570dSGrishma Kotecha 
48780f94570dSGrishma Kotecha 	status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid);
48790f94570dSGrishma Kotecha 	if (status)
48800f94570dSGrishma Kotecha 		return status;
48810f94570dSGrishma Kotecha 	m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
48820f94570dSGrishma Kotecha 	if (m_entry) {
48830f94570dSGrishma Kotecha 		/* we have to add VSI to VSI_LIST and increment vsi_count.
48840f94570dSGrishma Kotecha 		 * Also Update VSI list so that we can change forwarding rule
48850f94570dSGrishma Kotecha 		 * if the rule already exists, we will check if it exists with
48860f94570dSGrishma Kotecha 		 * same vsi_id, if not then add it to the VSI list if it already
48870f94570dSGrishma Kotecha 		 * exists if not then create a VSI list and add the existing VSI
48880f94570dSGrishma Kotecha 		 * ID and the new VSI ID to the list
48890f94570dSGrishma Kotecha 		 * We will add that VSI to the list
48900f94570dSGrishma Kotecha 		 */
48910f94570dSGrishma Kotecha 		status = ice_adv_add_update_vsi_list(hw, m_entry,
48920f94570dSGrishma Kotecha 						     &m_entry->rule_info,
48930f94570dSGrishma Kotecha 						     rinfo);
48940f94570dSGrishma Kotecha 		if (added_entry) {
48950f94570dSGrishma Kotecha 			added_entry->rid = rid;
48960f94570dSGrishma Kotecha 			added_entry->rule_id = m_entry->rule_info.fltr_rule_id;
48970f94570dSGrishma Kotecha 			added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
48980f94570dSGrishma Kotecha 		}
48990f94570dSGrishma Kotecha 		return status;
49000f94570dSGrishma Kotecha 	}
49010f94570dSGrishma Kotecha 	rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE + pkt_len;
49020f94570dSGrishma Kotecha 	s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
49030f94570dSGrishma Kotecha 	if (!s_rule)
49040f94570dSGrishma Kotecha 		return ICE_ERR_NO_MEMORY;
490573b483b7SWojciech Drewek 	if (!rinfo->flags_info.act_valid) {
490673b483b7SWojciech Drewek 		act |= ICE_SINGLE_ACT_LAN_ENABLE;
490773b483b7SWojciech Drewek 		act |= ICE_SINGLE_ACT_LB_ENABLE;
490873b483b7SWojciech Drewek 	} else {
490973b483b7SWojciech Drewek 		act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
491073b483b7SWojciech Drewek 						ICE_SINGLE_ACT_LB_ENABLE);
491173b483b7SWojciech Drewek 	}
491273b483b7SWojciech Drewek 
49130f94570dSGrishma Kotecha 	switch (rinfo->sw_act.fltr_act) {
49140f94570dSGrishma Kotecha 	case ICE_FWD_TO_VSI:
49150f94570dSGrishma Kotecha 		act |= (rinfo->sw_act.fwd_id.hw_vsi_id <<
49160f94570dSGrishma Kotecha 			ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M;
49170f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;
49180f94570dSGrishma Kotecha 		break;
49190f94570dSGrishma Kotecha 	case ICE_FWD_TO_Q:
49200f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_TO_Q;
49210f94570dSGrishma Kotecha 		act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
49220f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_Q_INDEX_M;
49230f94570dSGrishma Kotecha 		break;
49240f94570dSGrishma Kotecha 	case ICE_FWD_TO_QGRP:
49250f94570dSGrishma Kotecha 		q_rgn = rinfo->sw_act.qgrp_size > 0 ?
49260f94570dSGrishma Kotecha 			(u8)ilog2(rinfo->sw_act.qgrp_size) : 0;
49270f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_TO_Q;
49280f94570dSGrishma Kotecha 		act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
49290f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_Q_INDEX_M;
49300f94570dSGrishma Kotecha 		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
49310f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_Q_REGION_M;
49320f94570dSGrishma Kotecha 		break;
49330f94570dSGrishma Kotecha 	case ICE_DROP_PACKET:
49340f94570dSGrishma Kotecha 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
49350f94570dSGrishma Kotecha 		       ICE_SINGLE_ACT_VALID_BIT;
49360f94570dSGrishma Kotecha 		break;
49370f94570dSGrishma Kotecha 	default:
49380f94570dSGrishma Kotecha 		status = ICE_ERR_CFG;
49390f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
49400f94570dSGrishma Kotecha 	}
49410f94570dSGrishma Kotecha 
49420f94570dSGrishma Kotecha 	/* set the rule LOOKUP type based on caller specified 'Rx'
49430f94570dSGrishma Kotecha 	 * instead of hardcoding it to be either LOOKUP_TX/RX
49440f94570dSGrishma Kotecha 	 *
49450f94570dSGrishma Kotecha 	 * for 'Rx' set the source to be the port number
49460f94570dSGrishma Kotecha 	 * for 'Tx' set the source to be the source HW VSI number (determined
49470f94570dSGrishma Kotecha 	 * by caller)
49480f94570dSGrishma Kotecha 	 */
49490f94570dSGrishma Kotecha 	if (rinfo->rx) {
49500f94570dSGrishma Kotecha 		s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
49510f94570dSGrishma Kotecha 		s_rule->pdata.lkup_tx_rx.src =
49520f94570dSGrishma Kotecha 			cpu_to_le16(hw->port_info->lport);
49530f94570dSGrishma Kotecha 	} else {
49540f94570dSGrishma Kotecha 		s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
49550f94570dSGrishma Kotecha 		s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(rinfo->sw_act.src);
49560f94570dSGrishma Kotecha 	}
49570f94570dSGrishma Kotecha 
49580f94570dSGrishma Kotecha 	s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(rid);
49590f94570dSGrishma Kotecha 	s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act);
49600f94570dSGrishma Kotecha 
49610f94570dSGrishma Kotecha 	status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, pkt,
49620f94570dSGrishma Kotecha 					   pkt_len, pkt_offsets);
49630f94570dSGrishma Kotecha 	if (status)
49640f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
49650f94570dSGrishma Kotecha 
49660f94570dSGrishma Kotecha 	status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
49670f94570dSGrishma Kotecha 				 rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,
49680f94570dSGrishma Kotecha 				 NULL);
49690f94570dSGrishma Kotecha 	if (status)
49700f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
49710f94570dSGrishma Kotecha 	adv_fltr = devm_kzalloc(ice_hw_to_dev(hw),
49720f94570dSGrishma Kotecha 				sizeof(struct ice_adv_fltr_mgmt_list_entry),
49730f94570dSGrishma Kotecha 				GFP_KERNEL);
49740f94570dSGrishma Kotecha 	if (!adv_fltr) {
49750f94570dSGrishma Kotecha 		status = ICE_ERR_NO_MEMORY;
49760f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
49770f94570dSGrishma Kotecha 	}
49780f94570dSGrishma Kotecha 
49790f94570dSGrishma Kotecha 	adv_fltr->lkups = devm_kmemdup(ice_hw_to_dev(hw), lkups,
49800f94570dSGrishma Kotecha 				       lkups_cnt * sizeof(*lkups), GFP_KERNEL);
49810f94570dSGrishma Kotecha 	if (!adv_fltr->lkups) {
49820f94570dSGrishma Kotecha 		status = ICE_ERR_NO_MEMORY;
49830f94570dSGrishma Kotecha 		goto err_ice_add_adv_rule;
49840f94570dSGrishma Kotecha 	}
49850f94570dSGrishma Kotecha 
49860f94570dSGrishma Kotecha 	adv_fltr->lkups_cnt = lkups_cnt;
49870f94570dSGrishma Kotecha 	adv_fltr->rule_info = *rinfo;
49880f94570dSGrishma Kotecha 	adv_fltr->rule_info.fltr_rule_id =
49890f94570dSGrishma Kotecha 		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
49900f94570dSGrishma Kotecha 	sw = hw->switch_info;
49910f94570dSGrishma Kotecha 	sw->recp_list[rid].adv_rule = true;
49920f94570dSGrishma Kotecha 	rule_head = &sw->recp_list[rid].filt_rules;
49930f94570dSGrishma Kotecha 
49940f94570dSGrishma Kotecha 	if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
49950f94570dSGrishma Kotecha 		adv_fltr->vsi_count = 1;
49960f94570dSGrishma Kotecha 
49970f94570dSGrishma Kotecha 	/* Add rule entry to book keeping list */
49980f94570dSGrishma Kotecha 	list_add(&adv_fltr->list_entry, rule_head);
49990f94570dSGrishma Kotecha 	if (added_entry) {
50000f94570dSGrishma Kotecha 		added_entry->rid = rid;
50010f94570dSGrishma Kotecha 		added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id;
50020f94570dSGrishma Kotecha 		added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
50030f94570dSGrishma Kotecha 	}
50040f94570dSGrishma Kotecha err_ice_add_adv_rule:
50050f94570dSGrishma Kotecha 	if (status && adv_fltr) {
50060f94570dSGrishma Kotecha 		devm_kfree(ice_hw_to_dev(hw), adv_fltr->lkups);
50070f94570dSGrishma Kotecha 		devm_kfree(ice_hw_to_dev(hw), adv_fltr);
50080f94570dSGrishma Kotecha 	}
50090f94570dSGrishma Kotecha 
50100f94570dSGrishma Kotecha 	kfree(s_rule);
50110f94570dSGrishma Kotecha 
50120f94570dSGrishma Kotecha 	return status;
50130f94570dSGrishma Kotecha }
50140f94570dSGrishma Kotecha 
50150f94570dSGrishma Kotecha /**
5016334cb062SAnirudh Venkataramanan  * ice_replay_vsi_fltr - Replay filters for requested VSI
50170f9d5027SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
5018334cb062SAnirudh Venkataramanan  * @vsi_handle: driver VSI handle
5019f9867df6SAnirudh Venkataramanan  * @recp_id: Recipe ID for which rules need to be replayed
5020334cb062SAnirudh Venkataramanan  * @list_head: list for which filters need to be replayed
5021334cb062SAnirudh Venkataramanan  *
5022334cb062SAnirudh Venkataramanan  * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.
5023334cb062SAnirudh Venkataramanan  * It is required to pass valid VSI handle.
50240f9d5027SAnirudh Venkataramanan  */
50250f9d5027SAnirudh Venkataramanan static enum ice_status
5026334cb062SAnirudh Venkataramanan ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id,
5027334cb062SAnirudh Venkataramanan 		    struct list_head *list_head)
50280f9d5027SAnirudh Venkataramanan {
50290f9d5027SAnirudh Venkataramanan 	struct ice_fltr_mgmt_list_entry *itr;
50300f9d5027SAnirudh Venkataramanan 	enum ice_status status = 0;
5031334cb062SAnirudh Venkataramanan 	u16 hw_vsi_id;
50320f9d5027SAnirudh Venkataramanan 
50330f9d5027SAnirudh Venkataramanan 	if (list_empty(list_head))
50340f9d5027SAnirudh Venkataramanan 		return status;
5035334cb062SAnirudh Venkataramanan 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
50360f9d5027SAnirudh Venkataramanan 
5037334cb062SAnirudh Venkataramanan 	list_for_each_entry(itr, list_head, list_entry) {
50380f9d5027SAnirudh Venkataramanan 		struct ice_fltr_list_entry f_entry;
50390f9d5027SAnirudh Venkataramanan 
50400f9d5027SAnirudh Venkataramanan 		f_entry.fltr_info = itr->fltr_info;
5041334cb062SAnirudh Venkataramanan 		if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&
5042334cb062SAnirudh Venkataramanan 		    itr->fltr_info.vsi_handle == vsi_handle) {
5043f9867df6SAnirudh Venkataramanan 			/* update the src in case it is VSI num */
5044334cb062SAnirudh Venkataramanan 			if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
5045334cb062SAnirudh Venkataramanan 				f_entry.fltr_info.src = hw_vsi_id;
50460f9d5027SAnirudh Venkataramanan 			status = ice_add_rule_internal(hw, recp_id, &f_entry);
50470f9d5027SAnirudh Venkataramanan 			if (status)
50480f9d5027SAnirudh Venkataramanan 				goto end;
50490f9d5027SAnirudh Venkataramanan 			continue;
50500f9d5027SAnirudh Venkataramanan 		}
5051072f0c3dSDave Ertman 		if (!itr->vsi_list_info ||
5052072f0c3dSDave Ertman 		    !test_bit(vsi_handle, itr->vsi_list_info->vsi_map))
5053334cb062SAnirudh Venkataramanan 			continue;
5054334cb062SAnirudh Venkataramanan 		/* Clearing it so that the logic can add it back */
5055334cb062SAnirudh Venkataramanan 		clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);
5056334cb062SAnirudh Venkataramanan 		f_entry.fltr_info.vsi_handle = vsi_handle;
50570f9d5027SAnirudh Venkataramanan 		f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
5058f9867df6SAnirudh Venkataramanan 		/* update the src in case it is VSI num */
5059334cb062SAnirudh Venkataramanan 		if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
5060334cb062SAnirudh Venkataramanan 			f_entry.fltr_info.src = hw_vsi_id;
50610f9d5027SAnirudh Venkataramanan 		if (recp_id == ICE_SW_LKUP_VLAN)
50620f9d5027SAnirudh Venkataramanan 			status = ice_add_vlan_internal(hw, &f_entry);
50630f9d5027SAnirudh Venkataramanan 		else
5064334cb062SAnirudh Venkataramanan 			status = ice_add_rule_internal(hw, recp_id, &f_entry);
50650f9d5027SAnirudh Venkataramanan 		if (status)
50660f9d5027SAnirudh Venkataramanan 			goto end;
50670f9d5027SAnirudh Venkataramanan 	}
50680f9d5027SAnirudh Venkataramanan end:
50690f9d5027SAnirudh Venkataramanan 	return status;
50700f9d5027SAnirudh Venkataramanan }
50710f9d5027SAnirudh Venkataramanan 
50720f9d5027SAnirudh Venkataramanan /**
50738bb98f33SShivanshu Shukla  * ice_adv_rem_update_vsi_list
50748bb98f33SShivanshu Shukla  * @hw: pointer to the hardware structure
50758bb98f33SShivanshu Shukla  * @vsi_handle: VSI handle of the VSI to remove
50768bb98f33SShivanshu Shukla  * @fm_list: filter management entry for which the VSI list management needs to
50778bb98f33SShivanshu Shukla  *	     be done
50788bb98f33SShivanshu Shukla  */
50798bb98f33SShivanshu Shukla static enum ice_status
50808bb98f33SShivanshu Shukla ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
50818bb98f33SShivanshu Shukla 			    struct ice_adv_fltr_mgmt_list_entry *fm_list)
50828bb98f33SShivanshu Shukla {
50838bb98f33SShivanshu Shukla 	struct ice_vsi_list_map_info *vsi_list_info;
50848bb98f33SShivanshu Shukla 	enum ice_sw_lkup_type lkup_type;
50858bb98f33SShivanshu Shukla 	enum ice_status status;
50868bb98f33SShivanshu Shukla 	u16 vsi_list_id;
50878bb98f33SShivanshu Shukla 
50888bb98f33SShivanshu Shukla 	if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST ||
50898bb98f33SShivanshu Shukla 	    fm_list->vsi_count == 0)
50908bb98f33SShivanshu Shukla 		return ICE_ERR_PARAM;
50918bb98f33SShivanshu Shukla 
50928bb98f33SShivanshu Shukla 	/* A rule with the VSI being removed does not exist */
50938bb98f33SShivanshu Shukla 	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
50948bb98f33SShivanshu Shukla 		return ICE_ERR_DOES_NOT_EXIST;
50958bb98f33SShivanshu Shukla 
50968bb98f33SShivanshu Shukla 	lkup_type = ICE_SW_LKUP_LAST;
50978bb98f33SShivanshu Shukla 	vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id;
50988bb98f33SShivanshu Shukla 	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
50998bb98f33SShivanshu Shukla 					  ice_aqc_opc_update_sw_rules,
51008bb98f33SShivanshu Shukla 					  lkup_type);
51018bb98f33SShivanshu Shukla 	if (status)
51028bb98f33SShivanshu Shukla 		return status;
51038bb98f33SShivanshu Shukla 
51048bb98f33SShivanshu Shukla 	fm_list->vsi_count--;
51058bb98f33SShivanshu Shukla 	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
51068bb98f33SShivanshu Shukla 	vsi_list_info = fm_list->vsi_list_info;
51078bb98f33SShivanshu Shukla 	if (fm_list->vsi_count == 1) {
51088bb98f33SShivanshu Shukla 		struct ice_fltr_info tmp_fltr;
51098bb98f33SShivanshu Shukla 		u16 rem_vsi_handle;
51108bb98f33SShivanshu Shukla 
51118bb98f33SShivanshu Shukla 		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
51128bb98f33SShivanshu Shukla 						ICE_MAX_VSI);
51138bb98f33SShivanshu Shukla 		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
51148bb98f33SShivanshu Shukla 			return ICE_ERR_OUT_OF_RANGE;
51158bb98f33SShivanshu Shukla 
51168bb98f33SShivanshu Shukla 		/* Make sure VSI list is empty before removing it below */
51178bb98f33SShivanshu Shukla 		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
51188bb98f33SShivanshu Shukla 						  vsi_list_id, true,
51198bb98f33SShivanshu Shukla 						  ice_aqc_opc_update_sw_rules,
51208bb98f33SShivanshu Shukla 						  lkup_type);
51218bb98f33SShivanshu Shukla 		if (status)
51228bb98f33SShivanshu Shukla 			return status;
51238bb98f33SShivanshu Shukla 
51248bb98f33SShivanshu Shukla 		memset(&tmp_fltr, 0, sizeof(tmp_fltr));
51258bb98f33SShivanshu Shukla 		tmp_fltr.flag = fm_list->rule_info.sw_act.flag;
51268bb98f33SShivanshu Shukla 		tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id;
51278bb98f33SShivanshu Shukla 		fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI;
51288bb98f33SShivanshu Shukla 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI;
51298bb98f33SShivanshu Shukla 		tmp_fltr.fwd_id.hw_vsi_id =
51308bb98f33SShivanshu Shukla 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
51318bb98f33SShivanshu Shukla 		fm_list->rule_info.sw_act.fwd_id.hw_vsi_id =
51328bb98f33SShivanshu Shukla 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
51338bb98f33SShivanshu Shukla 		fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle;
51348bb98f33SShivanshu Shukla 
51358bb98f33SShivanshu Shukla 		/* Update the previous switch rule of "MAC forward to VSI" to
51368bb98f33SShivanshu Shukla 		 * "MAC fwd to VSI list"
51378bb98f33SShivanshu Shukla 		 */
51388bb98f33SShivanshu Shukla 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
51398bb98f33SShivanshu Shukla 		if (status) {
51408bb98f33SShivanshu Shukla 			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
51418bb98f33SShivanshu Shukla 				  tmp_fltr.fwd_id.hw_vsi_id, status);
51428bb98f33SShivanshu Shukla 			return status;
51438bb98f33SShivanshu Shukla 		}
51448bb98f33SShivanshu Shukla 		fm_list->vsi_list_info->ref_cnt--;
51458bb98f33SShivanshu Shukla 
51468bb98f33SShivanshu Shukla 		/* Remove the VSI list since it is no longer used */
51478bb98f33SShivanshu Shukla 		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
51488bb98f33SShivanshu Shukla 		if (status) {
51498bb98f33SShivanshu Shukla 			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
51508bb98f33SShivanshu Shukla 				  vsi_list_id, status);
51518bb98f33SShivanshu Shukla 			return status;
51528bb98f33SShivanshu Shukla 		}
51538bb98f33SShivanshu Shukla 
51548bb98f33SShivanshu Shukla 		list_del(&vsi_list_info->list_entry);
51558bb98f33SShivanshu Shukla 		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
51568bb98f33SShivanshu Shukla 		fm_list->vsi_list_info = NULL;
51578bb98f33SShivanshu Shukla 	}
51588bb98f33SShivanshu Shukla 
51598bb98f33SShivanshu Shukla 	return status;
51608bb98f33SShivanshu Shukla }
51618bb98f33SShivanshu Shukla 
51628bb98f33SShivanshu Shukla /**
51638bb98f33SShivanshu Shukla  * ice_rem_adv_rule - removes existing advanced switch rule
51648bb98f33SShivanshu Shukla  * @hw: pointer to the hardware structure
51658bb98f33SShivanshu Shukla  * @lkups: information on the words that needs to be looked up. All words
51668bb98f33SShivanshu Shukla  *         together makes one recipe
51678bb98f33SShivanshu Shukla  * @lkups_cnt: num of entries in the lkups array
51688bb98f33SShivanshu Shukla  * @rinfo: Its the pointer to the rule information for the rule
51698bb98f33SShivanshu Shukla  *
51708bb98f33SShivanshu Shukla  * This function can be used to remove 1 rule at a time. The lkups is
51718bb98f33SShivanshu Shukla  * used to describe all the words that forms the "lookup" portion of the
51728bb98f33SShivanshu Shukla  * rule. These words can span multiple protocols. Callers to this function
51738bb98f33SShivanshu Shukla  * need to pass in a list of protocol headers with lookup information along
51748bb98f33SShivanshu Shukla  * and mask that determines which words are valid from the given protocol
51758bb98f33SShivanshu Shukla  * header. rinfo describes other information related to this rule such as
51768bb98f33SShivanshu Shukla  * forwarding IDs, priority of this rule, etc.
51778bb98f33SShivanshu Shukla  */
51788bb98f33SShivanshu Shukla static enum ice_status
51798bb98f33SShivanshu Shukla ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
51808bb98f33SShivanshu Shukla 		 u16 lkups_cnt, struct ice_adv_rule_info *rinfo)
51818bb98f33SShivanshu Shukla {
51828bb98f33SShivanshu Shukla 	struct ice_adv_fltr_mgmt_list_entry *list_elem;
51838bb98f33SShivanshu Shukla 	struct ice_prot_lkup_ext lkup_exts;
51848bb98f33SShivanshu Shukla 	enum ice_status status = 0;
51858bb98f33SShivanshu Shukla 	bool remove_rule = false;
51868bb98f33SShivanshu Shukla 	struct mutex *rule_lock; /* Lock to protect filter rule list */
51878bb98f33SShivanshu Shukla 	u16 i, rid, vsi_handle;
51888bb98f33SShivanshu Shukla 
51898bb98f33SShivanshu Shukla 	memset(&lkup_exts, 0, sizeof(lkup_exts));
51908bb98f33SShivanshu Shukla 	for (i = 0; i < lkups_cnt; i++) {
51918bb98f33SShivanshu Shukla 		u16 count;
51928bb98f33SShivanshu Shukla 
51938bb98f33SShivanshu Shukla 		if (lkups[i].type >= ICE_PROTOCOL_LAST)
51948bb98f33SShivanshu Shukla 			return ICE_ERR_CFG;
51958bb98f33SShivanshu Shukla 
51968bb98f33SShivanshu Shukla 		count = ice_fill_valid_words(&lkups[i], &lkup_exts);
51978bb98f33SShivanshu Shukla 		if (!count)
51988bb98f33SShivanshu Shukla 			return ICE_ERR_CFG;
51998bb98f33SShivanshu Shukla 	}
52008bb98f33SShivanshu Shukla 
52018bb98f33SShivanshu Shukla 	rid = ice_find_recp(hw, &lkup_exts);
52028bb98f33SShivanshu Shukla 	/* If did not find a recipe that match the existing criteria */
52038bb98f33SShivanshu Shukla 	if (rid == ICE_MAX_NUM_RECIPES)
52048bb98f33SShivanshu Shukla 		return ICE_ERR_PARAM;
52058bb98f33SShivanshu Shukla 
52068bb98f33SShivanshu Shukla 	rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock;
52078bb98f33SShivanshu Shukla 	list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
52088bb98f33SShivanshu Shukla 	/* the rule is already removed */
52098bb98f33SShivanshu Shukla 	if (!list_elem)
52108bb98f33SShivanshu Shukla 		return 0;
52118bb98f33SShivanshu Shukla 	mutex_lock(rule_lock);
52128bb98f33SShivanshu Shukla 	if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) {
52138bb98f33SShivanshu Shukla 		remove_rule = true;
52148bb98f33SShivanshu Shukla 	} else if (list_elem->vsi_count > 1) {
52158bb98f33SShivanshu Shukla 		remove_rule = false;
52168bb98f33SShivanshu Shukla 		vsi_handle = rinfo->sw_act.vsi_handle;
52178bb98f33SShivanshu Shukla 		status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem);
52188bb98f33SShivanshu Shukla 	} else {
52198bb98f33SShivanshu Shukla 		vsi_handle = rinfo->sw_act.vsi_handle;
52208bb98f33SShivanshu Shukla 		status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem);
52218bb98f33SShivanshu Shukla 		if (status) {
52228bb98f33SShivanshu Shukla 			mutex_unlock(rule_lock);
52238bb98f33SShivanshu Shukla 			return status;
52248bb98f33SShivanshu Shukla 		}
52258bb98f33SShivanshu Shukla 		if (list_elem->vsi_count == 0)
52268bb98f33SShivanshu Shukla 			remove_rule = true;
52278bb98f33SShivanshu Shukla 	}
52288bb98f33SShivanshu Shukla 	mutex_unlock(rule_lock);
52298bb98f33SShivanshu Shukla 	if (remove_rule) {
52308bb98f33SShivanshu Shukla 		struct ice_aqc_sw_rules_elem *s_rule;
52318bb98f33SShivanshu Shukla 		u16 rule_buf_sz;
52328bb98f33SShivanshu Shukla 
52338bb98f33SShivanshu Shukla 		rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
52348bb98f33SShivanshu Shukla 		s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
52358bb98f33SShivanshu Shukla 		if (!s_rule)
52368bb98f33SShivanshu Shukla 			return ICE_ERR_NO_MEMORY;
52378bb98f33SShivanshu Shukla 		s_rule->pdata.lkup_tx_rx.act = 0;
52388bb98f33SShivanshu Shukla 		s_rule->pdata.lkup_tx_rx.index =
52398bb98f33SShivanshu Shukla 			cpu_to_le16(list_elem->rule_info.fltr_rule_id);
52408bb98f33SShivanshu Shukla 		s_rule->pdata.lkup_tx_rx.hdr_len = 0;
52418bb98f33SShivanshu Shukla 		status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
52428bb98f33SShivanshu Shukla 					 rule_buf_sz, 1,
52438bb98f33SShivanshu Shukla 					 ice_aqc_opc_remove_sw_rules, NULL);
52448bb98f33SShivanshu Shukla 		if (!status || status == ICE_ERR_DOES_NOT_EXIST) {
52458bb98f33SShivanshu Shukla 			struct ice_switch_info *sw = hw->switch_info;
52468bb98f33SShivanshu Shukla 
52478bb98f33SShivanshu Shukla 			mutex_lock(rule_lock);
52488bb98f33SShivanshu Shukla 			list_del(&list_elem->list_entry);
52498bb98f33SShivanshu Shukla 			devm_kfree(ice_hw_to_dev(hw), list_elem->lkups);
52508bb98f33SShivanshu Shukla 			devm_kfree(ice_hw_to_dev(hw), list_elem);
52518bb98f33SShivanshu Shukla 			mutex_unlock(rule_lock);
52528bb98f33SShivanshu Shukla 			if (list_empty(&sw->recp_list[rid].filt_rules))
52538bb98f33SShivanshu Shukla 				sw->recp_list[rid].adv_rule = false;
52548bb98f33SShivanshu Shukla 		}
52558bb98f33SShivanshu Shukla 		kfree(s_rule);
52568bb98f33SShivanshu Shukla 	}
52578bb98f33SShivanshu Shukla 	return status;
52588bb98f33SShivanshu Shukla }
52598bb98f33SShivanshu Shukla 
52608bb98f33SShivanshu Shukla /**
52618bb98f33SShivanshu Shukla  * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID
52628bb98f33SShivanshu Shukla  * @hw: pointer to the hardware structure
52638bb98f33SShivanshu Shukla  * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID
52648bb98f33SShivanshu Shukla  *
52658bb98f33SShivanshu Shukla  * This function is used to remove 1 rule at a time. The removal is based on
52668bb98f33SShivanshu Shukla  * the remove_entry parameter. This function will remove rule for a given
52678bb98f33SShivanshu Shukla  * vsi_handle with a given rule_id which is passed as parameter in remove_entry
52688bb98f33SShivanshu Shukla  */
52698bb98f33SShivanshu Shukla enum ice_status
52708bb98f33SShivanshu Shukla ice_rem_adv_rule_by_id(struct ice_hw *hw,
52718bb98f33SShivanshu Shukla 		       struct ice_rule_query_data *remove_entry)
52728bb98f33SShivanshu Shukla {
52738bb98f33SShivanshu Shukla 	struct ice_adv_fltr_mgmt_list_entry *list_itr;
52748bb98f33SShivanshu Shukla 	struct list_head *list_head;
52758bb98f33SShivanshu Shukla 	struct ice_adv_rule_info rinfo;
52768bb98f33SShivanshu Shukla 	struct ice_switch_info *sw;
52778bb98f33SShivanshu Shukla 
52788bb98f33SShivanshu Shukla 	sw = hw->switch_info;
52798bb98f33SShivanshu Shukla 	if (!sw->recp_list[remove_entry->rid].recp_created)
52808bb98f33SShivanshu Shukla 		return ICE_ERR_PARAM;
52818bb98f33SShivanshu Shukla 	list_head = &sw->recp_list[remove_entry->rid].filt_rules;
52828bb98f33SShivanshu Shukla 	list_for_each_entry(list_itr, list_head, list_entry) {
52838bb98f33SShivanshu Shukla 		if (list_itr->rule_info.fltr_rule_id ==
52848bb98f33SShivanshu Shukla 		    remove_entry->rule_id) {
52858bb98f33SShivanshu Shukla 			rinfo = list_itr->rule_info;
52868bb98f33SShivanshu Shukla 			rinfo.sw_act.vsi_handle = remove_entry->vsi_handle;
52878bb98f33SShivanshu Shukla 			return ice_rem_adv_rule(hw, list_itr->lkups,
52888bb98f33SShivanshu Shukla 						list_itr->lkups_cnt, &rinfo);
52898bb98f33SShivanshu Shukla 		}
52908bb98f33SShivanshu Shukla 	}
52918bb98f33SShivanshu Shukla 	/* either list is empty or unable to find rule */
52928bb98f33SShivanshu Shukla 	return ICE_ERR_DOES_NOT_EXIST;
52938bb98f33SShivanshu Shukla }
52948bb98f33SShivanshu Shukla 
52958bb98f33SShivanshu Shukla /**
5296334cb062SAnirudh Venkataramanan  * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists
52970f9d5027SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
5298334cb062SAnirudh Venkataramanan  * @vsi_handle: driver VSI handle
52990f9d5027SAnirudh Venkataramanan  *
5300334cb062SAnirudh Venkataramanan  * Replays filters for requested VSI via vsi_handle.
53010f9d5027SAnirudh Venkataramanan  */
5302334cb062SAnirudh Venkataramanan enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle)
53030f9d5027SAnirudh Venkataramanan {
53040f9d5027SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
53050f9d5027SAnirudh Venkataramanan 	enum ice_status status = 0;
53060f9d5027SAnirudh Venkataramanan 	u8 i;
53070f9d5027SAnirudh Venkataramanan 
53080f9d5027SAnirudh Venkataramanan 	for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
5309334cb062SAnirudh Venkataramanan 		struct list_head *head;
53100f9d5027SAnirudh Venkataramanan 
5311334cb062SAnirudh Venkataramanan 		head = &sw->recp_list[i].filt_replay_rules;
5312334cb062SAnirudh Venkataramanan 		status = ice_replay_vsi_fltr(hw, vsi_handle, i, head);
53130f9d5027SAnirudh Venkataramanan 		if (status)
53140f9d5027SAnirudh Venkataramanan 			return status;
53150f9d5027SAnirudh Venkataramanan 	}
53160f9d5027SAnirudh Venkataramanan 	return status;
53170f9d5027SAnirudh Venkataramanan }
5318334cb062SAnirudh Venkataramanan 
5319334cb062SAnirudh Venkataramanan /**
5320334cb062SAnirudh Venkataramanan  * ice_rm_all_sw_replay_rule_info - deletes filter replay rules
5321f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5322334cb062SAnirudh Venkataramanan  *
5323334cb062SAnirudh Venkataramanan  * Deletes the filter replay rules.
5324334cb062SAnirudh Venkataramanan  */
5325334cb062SAnirudh Venkataramanan void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)
5326334cb062SAnirudh Venkataramanan {
5327334cb062SAnirudh Venkataramanan 	struct ice_switch_info *sw = hw->switch_info;
5328334cb062SAnirudh Venkataramanan 	u8 i;
5329334cb062SAnirudh Venkataramanan 
5330334cb062SAnirudh Venkataramanan 	if (!sw)
5331334cb062SAnirudh Venkataramanan 		return;
5332334cb062SAnirudh Venkataramanan 
53338b8ef05bSVictor Raj 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
5334334cb062SAnirudh Venkataramanan 		if (!list_empty(&sw->recp_list[i].filt_replay_rules)) {
5335334cb062SAnirudh Venkataramanan 			struct list_head *l_head;
5336334cb062SAnirudh Venkataramanan 
5337334cb062SAnirudh Venkataramanan 			l_head = &sw->recp_list[i].filt_replay_rules;
53388b8ef05bSVictor Raj 			if (!sw->recp_list[i].adv_rule)
5339334cb062SAnirudh Venkataramanan 				ice_rem_sw_rule_info(hw, l_head);
53408b8ef05bSVictor Raj 			else
53418b8ef05bSVictor Raj 				ice_rem_adv_rule_info(hw, l_head);
5342334cb062SAnirudh Venkataramanan 		}
5343334cb062SAnirudh Venkataramanan 	}
5344334cb062SAnirudh Venkataramanan }
5345