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 /** 22769daf8208SAnirudh Venkataramanan * ice_add_mac - Add a MAC address based filter rule 22779daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 22789daf8208SAnirudh Venkataramanan * @m_list: list of MAC addresses and forwarding information 22799daf8208SAnirudh Venkataramanan * 22809daf8208SAnirudh Venkataramanan * IMPORTANT: When the ucast_shared flag is set to false and m_list has 22819daf8208SAnirudh Venkataramanan * multiple unicast addresses, the function assumes that all the 22829daf8208SAnirudh Venkataramanan * addresses are unique in a given add_mac call. It doesn't 22839daf8208SAnirudh Venkataramanan * check for duplicates in this case, removing duplicates from a given 22849daf8208SAnirudh Venkataramanan * list should be taken care of in the caller of this function. 22859daf8208SAnirudh Venkataramanan */ 2286ebb462dcSBruce Allan enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_list) 22879daf8208SAnirudh Venkataramanan { 22889daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule, *r_iter; 22899daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *m_list_itr; 229080d144c9SAnirudh Venkataramanan struct list_head *rule_head; 229188865fc4SKarol Kolacinski u16 total_elem_left, s_rule_size; 229280d144c9SAnirudh Venkataramanan struct ice_switch_info *sw; 229380d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 22949daf8208SAnirudh Venkataramanan enum ice_status status = 0; 22959daf8208SAnirudh Venkataramanan u16 num_unicast = 0; 229688865fc4SKarol Kolacinski u8 elem_sent; 22979daf8208SAnirudh Venkataramanan 22989daf8208SAnirudh Venkataramanan if (!m_list || !hw) 22999daf8208SAnirudh Venkataramanan return ICE_ERR_PARAM; 23009daf8208SAnirudh Venkataramanan 230180d144c9SAnirudh Venkataramanan s_rule = NULL; 230280d144c9SAnirudh Venkataramanan sw = hw->switch_info; 230380d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; 23049daf8208SAnirudh Venkataramanan list_for_each_entry(m_list_itr, m_list, list_entry) { 23059daf8208SAnirudh Venkataramanan u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; 23065726ca0eSAnirudh Venkataramanan u16 vsi_handle; 23075726ca0eSAnirudh Venkataramanan u16 hw_vsi_id; 23089daf8208SAnirudh Venkataramanan 230980d144c9SAnirudh Venkataramanan m_list_itr->fltr_info.flag = ICE_FLTR_TX; 23105726ca0eSAnirudh Venkataramanan vsi_handle = m_list_itr->fltr_info.vsi_handle; 23115726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 23125726ca0eSAnirudh Venkataramanan return ICE_ERR_PARAM; 23135726ca0eSAnirudh Venkataramanan hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 23145726ca0eSAnirudh Venkataramanan m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; 2315f9867df6SAnirudh Venkataramanan /* update the src in case it is VSI num */ 23165726ca0eSAnirudh Venkataramanan if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) 23175726ca0eSAnirudh Venkataramanan return ICE_ERR_PARAM; 23185726ca0eSAnirudh Venkataramanan m_list_itr->fltr_info.src = hw_vsi_id; 231980d144c9SAnirudh Venkataramanan if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || 232080d144c9SAnirudh Venkataramanan is_zero_ether_addr(add)) 23219daf8208SAnirudh Venkataramanan return ICE_ERR_PARAM; 23229daf8208SAnirudh Venkataramanan if (is_unicast_ether_addr(add) && !hw->ucast_shared) { 23239daf8208SAnirudh Venkataramanan /* Don't overwrite the unicast address */ 232480d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 232580d144c9SAnirudh Venkataramanan if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC, 232680d144c9SAnirudh Venkataramanan &m_list_itr->fltr_info)) { 232780d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 23289daf8208SAnirudh Venkataramanan return ICE_ERR_ALREADY_EXISTS; 232980d144c9SAnirudh Venkataramanan } 233080d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 23319daf8208SAnirudh Venkataramanan num_unicast++; 23329daf8208SAnirudh Venkataramanan } else if (is_multicast_ether_addr(add) || 23339daf8208SAnirudh Venkataramanan (is_unicast_ether_addr(add) && hw->ucast_shared)) { 233480d144c9SAnirudh Venkataramanan m_list_itr->status = 233580d144c9SAnirudh Venkataramanan ice_add_rule_internal(hw, ICE_SW_LKUP_MAC, 233680d144c9SAnirudh Venkataramanan m_list_itr); 233780d144c9SAnirudh Venkataramanan if (m_list_itr->status) 233880d144c9SAnirudh Venkataramanan return m_list_itr->status; 23399daf8208SAnirudh Venkataramanan } 23409daf8208SAnirudh Venkataramanan } 23419daf8208SAnirudh Venkataramanan 234280d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 23439daf8208SAnirudh Venkataramanan /* Exit if no suitable entries were found for adding bulk switch rule */ 234480d144c9SAnirudh Venkataramanan if (!num_unicast) { 234580d144c9SAnirudh Venkataramanan status = 0; 234680d144c9SAnirudh Venkataramanan goto ice_add_mac_exit; 234780d144c9SAnirudh Venkataramanan } 234880d144c9SAnirudh Venkataramanan 234980d144c9SAnirudh Venkataramanan rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; 23509daf8208SAnirudh Venkataramanan 23519daf8208SAnirudh Venkataramanan /* Allocate switch rule buffer for the bulk update for unicast */ 23529daf8208SAnirudh Venkataramanan s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE; 23539daf8208SAnirudh Venkataramanan s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size, 23549daf8208SAnirudh Venkataramanan GFP_KERNEL); 235580d144c9SAnirudh Venkataramanan if (!s_rule) { 235680d144c9SAnirudh Venkataramanan status = ICE_ERR_NO_MEMORY; 235780d144c9SAnirudh Venkataramanan goto ice_add_mac_exit; 235880d144c9SAnirudh Venkataramanan } 23599daf8208SAnirudh Venkataramanan 23609daf8208SAnirudh Venkataramanan r_iter = s_rule; 23619daf8208SAnirudh Venkataramanan list_for_each_entry(m_list_itr, m_list, list_entry) { 23629daf8208SAnirudh Venkataramanan struct ice_fltr_info *f_info = &m_list_itr->fltr_info; 236380d144c9SAnirudh Venkataramanan u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; 23649daf8208SAnirudh Venkataramanan 236580d144c9SAnirudh Venkataramanan if (is_unicast_ether_addr(mac_addr)) { 236680d144c9SAnirudh Venkataramanan ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter, 236780d144c9SAnirudh Venkataramanan ice_aqc_opc_add_sw_rules); 23689daf8208SAnirudh Venkataramanan r_iter = (struct ice_aqc_sw_rules_elem *) 23699daf8208SAnirudh Venkataramanan ((u8 *)r_iter + s_rule_size); 23709daf8208SAnirudh Venkataramanan } 23719daf8208SAnirudh Venkataramanan } 23729daf8208SAnirudh Venkataramanan 23739daf8208SAnirudh Venkataramanan /* Call AQ bulk switch rule update for all unicast addresses */ 23749daf8208SAnirudh Venkataramanan r_iter = s_rule; 23759daf8208SAnirudh Venkataramanan /* Call AQ switch rule in AQ_MAX chunk */ 23769daf8208SAnirudh Venkataramanan for (total_elem_left = num_unicast; total_elem_left > 0; 23779daf8208SAnirudh Venkataramanan total_elem_left -= elem_sent) { 23789daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *entry = r_iter; 23799daf8208SAnirudh Venkataramanan 238088865fc4SKarol Kolacinski elem_sent = min_t(u8, total_elem_left, 238188865fc4SKarol Kolacinski (ICE_AQ_MAX_BUF_LEN / s_rule_size)); 23829daf8208SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size, 23839daf8208SAnirudh Venkataramanan elem_sent, ice_aqc_opc_add_sw_rules, 23849daf8208SAnirudh Venkataramanan NULL); 23859daf8208SAnirudh Venkataramanan if (status) 23869daf8208SAnirudh Venkataramanan goto ice_add_mac_exit; 23879daf8208SAnirudh Venkataramanan r_iter = (struct ice_aqc_sw_rules_elem *) 23889daf8208SAnirudh Venkataramanan ((u8 *)r_iter + (elem_sent * s_rule_size)); 23899daf8208SAnirudh Venkataramanan } 23909daf8208SAnirudh Venkataramanan 2391f9867df6SAnirudh Venkataramanan /* Fill up rule ID based on the value returned from FW */ 23929daf8208SAnirudh Venkataramanan r_iter = s_rule; 23939daf8208SAnirudh Venkataramanan list_for_each_entry(m_list_itr, m_list, list_entry) { 23949daf8208SAnirudh Venkataramanan struct ice_fltr_info *f_info = &m_list_itr->fltr_info; 239580d144c9SAnirudh Venkataramanan u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; 23969daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *fm_entry; 23979daf8208SAnirudh Venkataramanan 239880d144c9SAnirudh Venkataramanan if (is_unicast_ether_addr(mac_addr)) { 23999daf8208SAnirudh Venkataramanan f_info->fltr_rule_id = 24009daf8208SAnirudh Venkataramanan le16_to_cpu(r_iter->pdata.lkup_tx_rx.index); 24019daf8208SAnirudh Venkataramanan f_info->fltr_act = ICE_FWD_TO_VSI; 24029daf8208SAnirudh Venkataramanan /* Create an entry to track this MAC address */ 24039daf8208SAnirudh Venkataramanan fm_entry = devm_kzalloc(ice_hw_to_dev(hw), 24049daf8208SAnirudh Venkataramanan sizeof(*fm_entry), GFP_KERNEL); 24059daf8208SAnirudh Venkataramanan if (!fm_entry) { 24069daf8208SAnirudh Venkataramanan status = ICE_ERR_NO_MEMORY; 24079daf8208SAnirudh Venkataramanan goto ice_add_mac_exit; 24089daf8208SAnirudh Venkataramanan } 24099daf8208SAnirudh Venkataramanan fm_entry->fltr_info = *f_info; 24109daf8208SAnirudh Venkataramanan fm_entry->vsi_count = 1; 24119daf8208SAnirudh Venkataramanan /* The book keeping entries will get removed when 24129daf8208SAnirudh Venkataramanan * base driver calls remove filter AQ command 24139daf8208SAnirudh Venkataramanan */ 24149daf8208SAnirudh Venkataramanan 241580d144c9SAnirudh Venkataramanan list_add(&fm_entry->list_entry, rule_head); 24169daf8208SAnirudh Venkataramanan r_iter = (struct ice_aqc_sw_rules_elem *) 24179daf8208SAnirudh Venkataramanan ((u8 *)r_iter + s_rule_size); 24189daf8208SAnirudh Venkataramanan } 24199daf8208SAnirudh Venkataramanan } 24209daf8208SAnirudh Venkataramanan 24219daf8208SAnirudh Venkataramanan ice_add_mac_exit: 242280d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 242380d144c9SAnirudh Venkataramanan if (s_rule) 24249daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 24259daf8208SAnirudh Venkataramanan return status; 24269daf8208SAnirudh Venkataramanan } 24279daf8208SAnirudh Venkataramanan 24289daf8208SAnirudh Venkataramanan /** 2429d76a60baSAnirudh Venkataramanan * ice_add_vlan_internal - Add one VLAN based filter rule 2430d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 2431d76a60baSAnirudh Venkataramanan * @f_entry: filter entry containing one VLAN information 2432d76a60baSAnirudh Venkataramanan */ 2433d76a60baSAnirudh Venkataramanan static enum ice_status 2434d76a60baSAnirudh Venkataramanan ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) 2435d76a60baSAnirudh Venkataramanan { 243680d144c9SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 2437d76a60baSAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *v_list_itr; 24385726ca0eSAnirudh Venkataramanan struct ice_fltr_info *new_fltr, *cur_fltr; 24395726ca0eSAnirudh Venkataramanan enum ice_sw_lkup_type lkup_type; 24405726ca0eSAnirudh Venkataramanan u16 vsi_list_id = 0, vsi_handle; 244180d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 244280d144c9SAnirudh Venkataramanan enum ice_status status = 0; 2443d76a60baSAnirudh Venkataramanan 24445726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) 24455726ca0eSAnirudh Venkataramanan return ICE_ERR_PARAM; 24465726ca0eSAnirudh Venkataramanan 24475726ca0eSAnirudh Venkataramanan f_entry->fltr_info.fwd_id.hw_vsi_id = 24485726ca0eSAnirudh Venkataramanan ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); 2449d76a60baSAnirudh Venkataramanan new_fltr = &f_entry->fltr_info; 24505726ca0eSAnirudh Venkataramanan 2451f9867df6SAnirudh Venkataramanan /* VLAN ID should only be 12 bits */ 2452d76a60baSAnirudh Venkataramanan if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) 2453d76a60baSAnirudh Venkataramanan return ICE_ERR_PARAM; 2454d76a60baSAnirudh Venkataramanan 24555726ca0eSAnirudh Venkataramanan if (new_fltr->src_id != ICE_SRC_ID_VSI) 24565726ca0eSAnirudh Venkataramanan return ICE_ERR_PARAM; 24575726ca0eSAnirudh Venkataramanan 24585726ca0eSAnirudh Venkataramanan new_fltr->src = new_fltr->fwd_id.hw_vsi_id; 24595726ca0eSAnirudh Venkataramanan lkup_type = new_fltr->lkup_type; 24605726ca0eSAnirudh Venkataramanan vsi_handle = new_fltr->vsi_handle; 246180d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; 246280d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 246380d144c9SAnirudh Venkataramanan v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); 2464d76a60baSAnirudh Venkataramanan if (!v_list_itr) { 24655726ca0eSAnirudh Venkataramanan struct ice_vsi_list_map_info *map_info = NULL; 2466d76a60baSAnirudh Venkataramanan 2467d76a60baSAnirudh Venkataramanan if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { 24685726ca0eSAnirudh Venkataramanan /* All VLAN pruning rules use a VSI list. Check if 24695726ca0eSAnirudh Venkataramanan * there is already a VSI list containing VSI that we 24705726ca0eSAnirudh Venkataramanan * want to add. If found, use the same vsi_list_id for 24715726ca0eSAnirudh Venkataramanan * this new VLAN rule or else create a new list. 2472d76a60baSAnirudh Venkataramanan */ 24735726ca0eSAnirudh Venkataramanan map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN, 24745726ca0eSAnirudh Venkataramanan vsi_handle, 24755726ca0eSAnirudh Venkataramanan &vsi_list_id); 24765726ca0eSAnirudh Venkataramanan if (!map_info) { 24775726ca0eSAnirudh Venkataramanan status = ice_create_vsi_list_rule(hw, 24785726ca0eSAnirudh Venkataramanan &vsi_handle, 24795726ca0eSAnirudh Venkataramanan 1, 2480d76a60baSAnirudh Venkataramanan &vsi_list_id, 2481d76a60baSAnirudh Venkataramanan lkup_type); 2482d76a60baSAnirudh Venkataramanan if (status) 248380d144c9SAnirudh Venkataramanan goto exit; 24845726ca0eSAnirudh Venkataramanan } 24855726ca0eSAnirudh Venkataramanan /* Convert the action to forwarding to a VSI list. */ 2486d76a60baSAnirudh Venkataramanan new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; 2487d76a60baSAnirudh Venkataramanan new_fltr->fwd_id.vsi_list_id = vsi_list_id; 2488d76a60baSAnirudh Venkataramanan } 2489d76a60baSAnirudh Venkataramanan 2490d76a60baSAnirudh Venkataramanan status = ice_create_pkt_fwd_rule(hw, f_entry); 24915726ca0eSAnirudh Venkataramanan if (!status) { 249280d144c9SAnirudh Venkataramanan v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, 249380d144c9SAnirudh Venkataramanan new_fltr); 249480d144c9SAnirudh Venkataramanan if (!v_list_itr) { 249580d144c9SAnirudh Venkataramanan status = ICE_ERR_DOES_NOT_EXIST; 249680d144c9SAnirudh Venkataramanan goto exit; 249780d144c9SAnirudh Venkataramanan } 24985726ca0eSAnirudh Venkataramanan /* reuse VSI list for new rule and increment ref_cnt */ 24995726ca0eSAnirudh Venkataramanan if (map_info) { 25005726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info = map_info; 25015726ca0eSAnirudh Venkataramanan map_info->ref_cnt++; 25025726ca0eSAnirudh Venkataramanan } else { 2503d76a60baSAnirudh Venkataramanan v_list_itr->vsi_list_info = 25045726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(hw, &vsi_handle, 25055726ca0eSAnirudh Venkataramanan 1, vsi_list_id); 2506d76a60baSAnirudh Venkataramanan } 25075726ca0eSAnirudh Venkataramanan } 25085726ca0eSAnirudh Venkataramanan } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { 2509f9867df6SAnirudh Venkataramanan /* Update existing VSI list to add new VSI ID only if it used 25105726ca0eSAnirudh Venkataramanan * by one VLAN rule. 25115726ca0eSAnirudh Venkataramanan */ 25125726ca0eSAnirudh Venkataramanan cur_fltr = &v_list_itr->fltr_info; 25135726ca0eSAnirudh Venkataramanan status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, 25145726ca0eSAnirudh Venkataramanan new_fltr); 25155726ca0eSAnirudh Venkataramanan } else { 25165726ca0eSAnirudh Venkataramanan /* If VLAN rule exists and VSI list being used by this rule is 25175726ca0eSAnirudh Venkataramanan * referenced by more than 1 VLAN rule. Then create a new VSI 25185726ca0eSAnirudh Venkataramanan * list appending previous VSI with new VSI and update existing 2519f9867df6SAnirudh Venkataramanan * VLAN rule to point to new VSI list ID 25205726ca0eSAnirudh Venkataramanan */ 25215726ca0eSAnirudh Venkataramanan struct ice_fltr_info tmp_fltr; 25225726ca0eSAnirudh Venkataramanan u16 vsi_handle_arr[2]; 25235726ca0eSAnirudh Venkataramanan u16 cur_handle; 2524d76a60baSAnirudh Venkataramanan 25255726ca0eSAnirudh Venkataramanan /* Current implementation only supports reusing VSI list with 25265726ca0eSAnirudh Venkataramanan * one VSI count. We should never hit below condition 25275726ca0eSAnirudh Venkataramanan */ 25285726ca0eSAnirudh Venkataramanan if (v_list_itr->vsi_count > 1 && 25295726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info->ref_cnt > 1) { 25309228d8b2SJacob 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"); 25315726ca0eSAnirudh Venkataramanan status = ICE_ERR_CFG; 253280d144c9SAnirudh Venkataramanan goto exit; 2533d76a60baSAnirudh Venkataramanan } 2534d76a60baSAnirudh Venkataramanan 25355726ca0eSAnirudh Venkataramanan cur_handle = 25365726ca0eSAnirudh Venkataramanan find_first_bit(v_list_itr->vsi_list_info->vsi_map, 25375726ca0eSAnirudh Venkataramanan ICE_MAX_VSI); 25385726ca0eSAnirudh Venkataramanan 25395726ca0eSAnirudh Venkataramanan /* A rule already exists with the new VSI being added */ 25405726ca0eSAnirudh Venkataramanan if (cur_handle == vsi_handle) { 25415726ca0eSAnirudh Venkataramanan status = ICE_ERR_ALREADY_EXISTS; 25425726ca0eSAnirudh Venkataramanan goto exit; 25435726ca0eSAnirudh Venkataramanan } 25445726ca0eSAnirudh Venkataramanan 25455726ca0eSAnirudh Venkataramanan vsi_handle_arr[0] = cur_handle; 25465726ca0eSAnirudh Venkataramanan vsi_handle_arr[1] = vsi_handle; 25475726ca0eSAnirudh Venkataramanan status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, 25485726ca0eSAnirudh Venkataramanan &vsi_list_id, lkup_type); 25495726ca0eSAnirudh Venkataramanan if (status) 25505726ca0eSAnirudh Venkataramanan goto exit; 25515726ca0eSAnirudh Venkataramanan 25525726ca0eSAnirudh Venkataramanan tmp_fltr = v_list_itr->fltr_info; 25535726ca0eSAnirudh Venkataramanan tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; 25545726ca0eSAnirudh Venkataramanan tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; 25555726ca0eSAnirudh Venkataramanan tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; 25565726ca0eSAnirudh Venkataramanan /* Update the previous switch rule to a new VSI list which 2557df17b7e0SAnirudh Venkataramanan * includes current VSI that is requested 25585726ca0eSAnirudh Venkataramanan */ 25595726ca0eSAnirudh Venkataramanan status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 25605726ca0eSAnirudh Venkataramanan if (status) 25615726ca0eSAnirudh Venkataramanan goto exit; 25625726ca0eSAnirudh Venkataramanan 25635726ca0eSAnirudh Venkataramanan /* before overriding VSI list map info. decrement ref_cnt of 25645726ca0eSAnirudh Venkataramanan * previous VSI list 25655726ca0eSAnirudh Venkataramanan */ 25665726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info->ref_cnt--; 25675726ca0eSAnirudh Venkataramanan 25685726ca0eSAnirudh Venkataramanan /* now update to newly created list */ 25695726ca0eSAnirudh Venkataramanan v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; 25705726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info = 25715726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, 25725726ca0eSAnirudh Venkataramanan vsi_list_id); 25735726ca0eSAnirudh Venkataramanan v_list_itr->vsi_count++; 25745726ca0eSAnirudh Venkataramanan } 257580d144c9SAnirudh Venkataramanan 257680d144c9SAnirudh Venkataramanan exit: 257780d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 257880d144c9SAnirudh Venkataramanan return status; 2579d76a60baSAnirudh Venkataramanan } 2580d76a60baSAnirudh Venkataramanan 2581d76a60baSAnirudh Venkataramanan /** 2582d76a60baSAnirudh Venkataramanan * ice_add_vlan - Add VLAN based filter rule 2583d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 2584d76a60baSAnirudh Venkataramanan * @v_list: list of VLAN entries and forwarding information 2585d76a60baSAnirudh Venkataramanan */ 2586ebb462dcSBruce Allan enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) 2587d76a60baSAnirudh Venkataramanan { 2588d76a60baSAnirudh Venkataramanan struct ice_fltr_list_entry *v_list_itr; 2589d76a60baSAnirudh Venkataramanan 2590d76a60baSAnirudh Venkataramanan if (!v_list || !hw) 2591d76a60baSAnirudh Venkataramanan return ICE_ERR_PARAM; 2592d76a60baSAnirudh Venkataramanan 2593d76a60baSAnirudh Venkataramanan list_for_each_entry(v_list_itr, v_list, list_entry) { 2594d76a60baSAnirudh Venkataramanan if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN) 2595d76a60baSAnirudh Venkataramanan return ICE_ERR_PARAM; 259680d144c9SAnirudh Venkataramanan v_list_itr->fltr_info.flag = ICE_FLTR_TX; 259780d144c9SAnirudh Venkataramanan v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr); 259880d144c9SAnirudh Venkataramanan if (v_list_itr->status) 259980d144c9SAnirudh Venkataramanan return v_list_itr->status; 2600d76a60baSAnirudh Venkataramanan } 2601d76a60baSAnirudh Venkataramanan return 0; 2602d76a60baSAnirudh Venkataramanan } 2603d76a60baSAnirudh Venkataramanan 2604d76a60baSAnirudh Venkataramanan /** 2605d95276ceSAkeem G Abodunrin * ice_add_eth_mac - Add ethertype and MAC based filter rule 2606d95276ceSAkeem G Abodunrin * @hw: pointer to the hardware structure 2607d95276ceSAkeem G Abodunrin * @em_list: list of ether type MAC filter, MAC is optional 26082e0e6228SDave Ertman * 26092e0e6228SDave Ertman * This function requires the caller to populate the entries in 26102e0e6228SDave Ertman * the filter list with the necessary fields (including flags to 26112e0e6228SDave Ertman * indicate Tx or Rx rules). 2612d95276ceSAkeem G Abodunrin */ 2613d95276ceSAkeem G Abodunrin enum ice_status 2614d95276ceSAkeem G Abodunrin ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list) 2615d95276ceSAkeem G Abodunrin { 2616d95276ceSAkeem G Abodunrin struct ice_fltr_list_entry *em_list_itr; 2617d95276ceSAkeem G Abodunrin 2618d95276ceSAkeem G Abodunrin if (!em_list || !hw) 2619d95276ceSAkeem G Abodunrin return ICE_ERR_PARAM; 2620d95276ceSAkeem G Abodunrin 2621d95276ceSAkeem G Abodunrin list_for_each_entry(em_list_itr, em_list, list_entry) { 2622d95276ceSAkeem G Abodunrin enum ice_sw_lkup_type l_type = 2623d95276ceSAkeem G Abodunrin em_list_itr->fltr_info.lkup_type; 2624d95276ceSAkeem G Abodunrin 2625d95276ceSAkeem G Abodunrin if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && 2626d95276ceSAkeem G Abodunrin l_type != ICE_SW_LKUP_ETHERTYPE) 2627d95276ceSAkeem G Abodunrin return ICE_ERR_PARAM; 2628d95276ceSAkeem G Abodunrin 2629d95276ceSAkeem G Abodunrin em_list_itr->status = ice_add_rule_internal(hw, l_type, 2630d95276ceSAkeem G Abodunrin em_list_itr); 2631d95276ceSAkeem G Abodunrin if (em_list_itr->status) 2632d95276ceSAkeem G Abodunrin return em_list_itr->status; 2633d95276ceSAkeem G Abodunrin } 2634d95276ceSAkeem G Abodunrin return 0; 2635d95276ceSAkeem G Abodunrin } 2636d95276ceSAkeem G Abodunrin 2637d95276ceSAkeem G Abodunrin /** 2638d95276ceSAkeem G Abodunrin * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule 2639d95276ceSAkeem G Abodunrin * @hw: pointer to the hardware structure 2640d95276ceSAkeem G Abodunrin * @em_list: list of ethertype or ethertype MAC entries 2641d95276ceSAkeem G Abodunrin */ 2642d95276ceSAkeem G Abodunrin enum ice_status 2643d95276ceSAkeem G Abodunrin ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list) 2644d95276ceSAkeem G Abodunrin { 2645d95276ceSAkeem G Abodunrin struct ice_fltr_list_entry *em_list_itr, *tmp; 2646d95276ceSAkeem G Abodunrin 2647d95276ceSAkeem G Abodunrin if (!em_list || !hw) 2648d95276ceSAkeem G Abodunrin return ICE_ERR_PARAM; 2649d95276ceSAkeem G Abodunrin 2650d95276ceSAkeem G Abodunrin list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) { 2651d95276ceSAkeem G Abodunrin enum ice_sw_lkup_type l_type = 2652d95276ceSAkeem G Abodunrin em_list_itr->fltr_info.lkup_type; 2653d95276ceSAkeem G Abodunrin 2654d95276ceSAkeem G Abodunrin if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && 2655d95276ceSAkeem G Abodunrin l_type != ICE_SW_LKUP_ETHERTYPE) 2656d95276ceSAkeem G Abodunrin return ICE_ERR_PARAM; 2657d95276ceSAkeem G Abodunrin 2658d95276ceSAkeem G Abodunrin em_list_itr->status = ice_remove_rule_internal(hw, l_type, 2659d95276ceSAkeem G Abodunrin em_list_itr); 2660d95276ceSAkeem G Abodunrin if (em_list_itr->status) 2661d95276ceSAkeem G Abodunrin return em_list_itr->status; 2662d95276ceSAkeem G Abodunrin } 2663d95276ceSAkeem G Abodunrin return 0; 2664d95276ceSAkeem G Abodunrin } 2665d95276ceSAkeem G Abodunrin 2666d95276ceSAkeem G Abodunrin /** 26670f9d5027SAnirudh Venkataramanan * ice_rem_sw_rule_info 26680f9d5027SAnirudh Venkataramanan * @hw: pointer to the hardware structure 26690f9d5027SAnirudh Venkataramanan * @rule_head: pointer to the switch list structure that we want to delete 26700f9d5027SAnirudh Venkataramanan */ 26710f9d5027SAnirudh Venkataramanan static void 26720f9d5027SAnirudh Venkataramanan ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) 26730f9d5027SAnirudh Venkataramanan { 26740f9d5027SAnirudh Venkataramanan if (!list_empty(rule_head)) { 26750f9d5027SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *entry; 26760f9d5027SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *tmp; 26770f9d5027SAnirudh Venkataramanan 26780f9d5027SAnirudh Venkataramanan list_for_each_entry_safe(entry, tmp, rule_head, list_entry) { 26790f9d5027SAnirudh Venkataramanan list_del(&entry->list_entry); 26800f9d5027SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), entry); 26810f9d5027SAnirudh Venkataramanan } 26820f9d5027SAnirudh Venkataramanan } 26830f9d5027SAnirudh Venkataramanan } 26840f9d5027SAnirudh Venkataramanan 26850f9d5027SAnirudh Venkataramanan /** 2686*8b8ef05bSVictor Raj * ice_rem_adv_rule_info 2687*8b8ef05bSVictor Raj * @hw: pointer to the hardware structure 2688*8b8ef05bSVictor Raj * @rule_head: pointer to the switch list structure that we want to delete 2689*8b8ef05bSVictor Raj */ 2690*8b8ef05bSVictor Raj static void 2691*8b8ef05bSVictor Raj ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head) 2692*8b8ef05bSVictor Raj { 2693*8b8ef05bSVictor Raj struct ice_adv_fltr_mgmt_list_entry *tmp_entry; 2694*8b8ef05bSVictor Raj struct ice_adv_fltr_mgmt_list_entry *lst_itr; 2695*8b8ef05bSVictor Raj 2696*8b8ef05bSVictor Raj if (list_empty(rule_head)) 2697*8b8ef05bSVictor Raj return; 2698*8b8ef05bSVictor Raj 2699*8b8ef05bSVictor Raj list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) { 2700*8b8ef05bSVictor Raj list_del(&lst_itr->list_entry); 2701*8b8ef05bSVictor Raj devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups); 2702*8b8ef05bSVictor Raj devm_kfree(ice_hw_to_dev(hw), lst_itr); 2703*8b8ef05bSVictor Raj } 2704*8b8ef05bSVictor Raj } 2705*8b8ef05bSVictor Raj 2706*8b8ef05bSVictor Raj /** 270780d144c9SAnirudh Venkataramanan * ice_cfg_dflt_vsi - change state of VSI to set/clear default 2708e94d4478SAnirudh Venkataramanan * @hw: pointer to the hardware structure 27095726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to set as default 2710e94d4478SAnirudh Venkataramanan * @set: true to add the above mentioned switch rule, false to remove it 2711e94d4478SAnirudh Venkataramanan * @direction: ICE_FLTR_RX or ICE_FLTR_TX 271280d144c9SAnirudh Venkataramanan * 271380d144c9SAnirudh Venkataramanan * add filter rule to set/unset given VSI as default VSI for the switch 271480d144c9SAnirudh Venkataramanan * (represented by swid) 2715e94d4478SAnirudh Venkataramanan */ 2716e94d4478SAnirudh Venkataramanan enum ice_status 27175726ca0eSAnirudh Venkataramanan ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction) 2718e94d4478SAnirudh Venkataramanan { 2719e94d4478SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 2720e94d4478SAnirudh Venkataramanan struct ice_fltr_info f_info; 2721e94d4478SAnirudh Venkataramanan enum ice_adminq_opc opcode; 2722e94d4478SAnirudh Venkataramanan enum ice_status status; 2723e94d4478SAnirudh Venkataramanan u16 s_rule_size; 27245726ca0eSAnirudh Venkataramanan u16 hw_vsi_id; 27255726ca0eSAnirudh Venkataramanan 27265726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 27275726ca0eSAnirudh Venkataramanan return ICE_ERR_PARAM; 27285726ca0eSAnirudh Venkataramanan hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 2729e94d4478SAnirudh Venkataramanan 2730e94d4478SAnirudh Venkataramanan s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE : 2731e94d4478SAnirudh Venkataramanan ICE_SW_RULE_RX_TX_NO_HDR_SIZE; 273266486d89SBruce Allan 2733e94d4478SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); 2734e94d4478SAnirudh Venkataramanan if (!s_rule) 2735e94d4478SAnirudh Venkataramanan return ICE_ERR_NO_MEMORY; 2736e94d4478SAnirudh Venkataramanan 2737e94d4478SAnirudh Venkataramanan memset(&f_info, 0, sizeof(f_info)); 2738e94d4478SAnirudh Venkataramanan 2739e94d4478SAnirudh Venkataramanan f_info.lkup_type = ICE_SW_LKUP_DFLT; 2740e94d4478SAnirudh Venkataramanan f_info.flag = direction; 2741e94d4478SAnirudh Venkataramanan f_info.fltr_act = ICE_FWD_TO_VSI; 27425726ca0eSAnirudh Venkataramanan f_info.fwd_id.hw_vsi_id = hw_vsi_id; 2743e94d4478SAnirudh Venkataramanan 2744e94d4478SAnirudh Venkataramanan if (f_info.flag & ICE_FLTR_RX) { 2745e94d4478SAnirudh Venkataramanan f_info.src = hw->port_info->lport; 27465726ca0eSAnirudh Venkataramanan f_info.src_id = ICE_SRC_ID_LPORT; 2747e94d4478SAnirudh Venkataramanan if (!set) 2748e94d4478SAnirudh Venkataramanan f_info.fltr_rule_id = 2749e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_rule_id; 2750e94d4478SAnirudh Venkataramanan } else if (f_info.flag & ICE_FLTR_TX) { 27515726ca0eSAnirudh Venkataramanan f_info.src_id = ICE_SRC_ID_VSI; 27525726ca0eSAnirudh Venkataramanan f_info.src = hw_vsi_id; 2753e94d4478SAnirudh Venkataramanan if (!set) 2754e94d4478SAnirudh Venkataramanan f_info.fltr_rule_id = 2755e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_rule_id; 2756e94d4478SAnirudh Venkataramanan } 2757e94d4478SAnirudh Venkataramanan 2758e94d4478SAnirudh Venkataramanan if (set) 2759e94d4478SAnirudh Venkataramanan opcode = ice_aqc_opc_add_sw_rules; 2760e94d4478SAnirudh Venkataramanan else 2761e94d4478SAnirudh Venkataramanan opcode = ice_aqc_opc_remove_sw_rules; 2762e94d4478SAnirudh Venkataramanan 2763e94d4478SAnirudh Venkataramanan ice_fill_sw_rule(hw, &f_info, s_rule, opcode); 2764e94d4478SAnirudh Venkataramanan 2765e94d4478SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opcode, NULL); 2766e94d4478SAnirudh Venkataramanan if (status || !(f_info.flag & ICE_FLTR_TX_RX)) 2767e94d4478SAnirudh Venkataramanan goto out; 2768e94d4478SAnirudh Venkataramanan if (set) { 2769e94d4478SAnirudh Venkataramanan u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); 2770e94d4478SAnirudh Venkataramanan 2771e94d4478SAnirudh Venkataramanan if (f_info.flag & ICE_FLTR_TX) { 27725726ca0eSAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_num = hw_vsi_id; 2773e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_rule_id = index; 2774e94d4478SAnirudh Venkataramanan } else if (f_info.flag & ICE_FLTR_RX) { 27755726ca0eSAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_num = hw_vsi_id; 2776e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_rule_id = index; 2777e94d4478SAnirudh Venkataramanan } 2778e94d4478SAnirudh Venkataramanan } else { 2779e94d4478SAnirudh Venkataramanan if (f_info.flag & ICE_FLTR_TX) { 2780e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL; 2781e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_rule_id = ICE_INVAL_ACT; 2782e94d4478SAnirudh Venkataramanan } else if (f_info.flag & ICE_FLTR_RX) { 2783e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL; 2784e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_rule_id = ICE_INVAL_ACT; 2785e94d4478SAnirudh Venkataramanan } 2786e94d4478SAnirudh Venkataramanan } 2787e94d4478SAnirudh Venkataramanan 2788e94d4478SAnirudh Venkataramanan out: 2789e94d4478SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 2790e94d4478SAnirudh Venkataramanan return status; 2791e94d4478SAnirudh Venkataramanan } 2792e94d4478SAnirudh Venkataramanan 2793e94d4478SAnirudh Venkataramanan /** 27948b2c8582SAkeem G Abodunrin * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry 27958b2c8582SAkeem G Abodunrin * @hw: pointer to the hardware structure 27968b2c8582SAkeem G Abodunrin * @recp_id: lookup type for which the specified rule needs to be searched 27978b2c8582SAkeem G Abodunrin * @f_info: rule information 27988b2c8582SAkeem G Abodunrin * 27998b2c8582SAkeem G Abodunrin * Helper function to search for a unicast rule entry - this is to be used 28008b2c8582SAkeem G Abodunrin * to remove unicast MAC filter that is not shared with other VSIs on the 28018b2c8582SAkeem G Abodunrin * PF switch. 28028b2c8582SAkeem G Abodunrin * 28038b2c8582SAkeem G Abodunrin * Returns pointer to entry storing the rule if found 28048b2c8582SAkeem G Abodunrin */ 28058b2c8582SAkeem G Abodunrin static struct ice_fltr_mgmt_list_entry * 28068b2c8582SAkeem G Abodunrin ice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id, 28078b2c8582SAkeem G Abodunrin struct ice_fltr_info *f_info) 28088b2c8582SAkeem G Abodunrin { 28098b2c8582SAkeem G Abodunrin struct ice_switch_info *sw = hw->switch_info; 28108b2c8582SAkeem G Abodunrin struct ice_fltr_mgmt_list_entry *list_itr; 28118b2c8582SAkeem G Abodunrin struct list_head *list_head; 28128b2c8582SAkeem G Abodunrin 28138b2c8582SAkeem G Abodunrin list_head = &sw->recp_list[recp_id].filt_rules; 28148b2c8582SAkeem G Abodunrin list_for_each_entry(list_itr, list_head, list_entry) { 28158b2c8582SAkeem G Abodunrin if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data, 28168b2c8582SAkeem G Abodunrin sizeof(f_info->l_data)) && 28178b2c8582SAkeem G Abodunrin f_info->fwd_id.hw_vsi_id == 28188b2c8582SAkeem G Abodunrin list_itr->fltr_info.fwd_id.hw_vsi_id && 28198b2c8582SAkeem G Abodunrin f_info->flag == list_itr->fltr_info.flag) 28208b2c8582SAkeem G Abodunrin return list_itr; 28218b2c8582SAkeem G Abodunrin } 28228b2c8582SAkeem G Abodunrin return NULL; 28238b2c8582SAkeem G Abodunrin } 28248b2c8582SAkeem G Abodunrin 28258b2c8582SAkeem G Abodunrin /** 282680d144c9SAnirudh Venkataramanan * ice_remove_mac - remove a MAC address based filter rule 2827d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 282880d144c9SAnirudh Venkataramanan * @m_list: list of MAC addresses and forwarding information 282980d144c9SAnirudh Venkataramanan * 283080d144c9SAnirudh Venkataramanan * This function removes either a MAC filter rule or a specific VSI from a 283180d144c9SAnirudh Venkataramanan * VSI list for a multicast MAC address. 283280d144c9SAnirudh Venkataramanan * 283380d144c9SAnirudh Venkataramanan * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by 283480d144c9SAnirudh Venkataramanan * ice_add_mac. Caller should be aware that this call will only work if all 283580d144c9SAnirudh Venkataramanan * the entries passed into m_list were added previously. It will not attempt to 283680d144c9SAnirudh Venkataramanan * do a partial remove of entries that were found. 2837d76a60baSAnirudh Venkataramanan */ 2838ebb462dcSBruce Allan enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) 2839d76a60baSAnirudh Venkataramanan { 2840072f0c3dSDave Ertman struct ice_fltr_list_entry *list_itr, *tmp; 28418b2c8582SAkeem G Abodunrin struct mutex *rule_lock; /* Lock to protect filter rule list */ 2842d76a60baSAnirudh Venkataramanan 284380d144c9SAnirudh Venkataramanan if (!m_list) 2844d76a60baSAnirudh Venkataramanan return ICE_ERR_PARAM; 2845d76a60baSAnirudh Venkataramanan 28468b2c8582SAkeem G Abodunrin rule_lock = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; 2847072f0c3dSDave Ertman list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) { 284880d144c9SAnirudh Venkataramanan enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; 28498b2c8582SAkeem G Abodunrin u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0]; 28508b2c8582SAkeem G Abodunrin u16 vsi_handle; 285180d144c9SAnirudh Venkataramanan 285280d144c9SAnirudh Venkataramanan if (l_type != ICE_SW_LKUP_MAC) 285380d144c9SAnirudh Venkataramanan return ICE_ERR_PARAM; 28548b2c8582SAkeem G Abodunrin 28558b2c8582SAkeem G Abodunrin vsi_handle = list_itr->fltr_info.vsi_handle; 28568b2c8582SAkeem G Abodunrin if (!ice_is_vsi_valid(hw, vsi_handle)) 28578b2c8582SAkeem G Abodunrin return ICE_ERR_PARAM; 28588b2c8582SAkeem G Abodunrin 28598b2c8582SAkeem G Abodunrin list_itr->fltr_info.fwd_id.hw_vsi_id = 28608b2c8582SAkeem G Abodunrin ice_get_hw_vsi_num(hw, vsi_handle); 28618b2c8582SAkeem G Abodunrin if (is_unicast_ether_addr(add) && !hw->ucast_shared) { 28628b2c8582SAkeem G Abodunrin /* Don't remove the unicast address that belongs to 28638b2c8582SAkeem G Abodunrin * another VSI on the switch, since it is not being 28648b2c8582SAkeem G Abodunrin * shared... 28658b2c8582SAkeem G Abodunrin */ 28668b2c8582SAkeem G Abodunrin mutex_lock(rule_lock); 28678b2c8582SAkeem G Abodunrin if (!ice_find_ucast_rule_entry(hw, ICE_SW_LKUP_MAC, 28688b2c8582SAkeem G Abodunrin &list_itr->fltr_info)) { 28698b2c8582SAkeem G Abodunrin mutex_unlock(rule_lock); 28708b2c8582SAkeem G Abodunrin return ICE_ERR_DOES_NOT_EXIST; 28718b2c8582SAkeem G Abodunrin } 28728b2c8582SAkeem G Abodunrin mutex_unlock(rule_lock); 28738b2c8582SAkeem G Abodunrin } 287480d144c9SAnirudh Venkataramanan list_itr->status = ice_remove_rule_internal(hw, 287580d144c9SAnirudh Venkataramanan ICE_SW_LKUP_MAC, 287680d144c9SAnirudh Venkataramanan list_itr); 287780d144c9SAnirudh Venkataramanan if (list_itr->status) 287880d144c9SAnirudh Venkataramanan return list_itr->status; 287980d144c9SAnirudh Venkataramanan } 288080d144c9SAnirudh Venkataramanan return 0; 2881d76a60baSAnirudh Venkataramanan } 2882d76a60baSAnirudh Venkataramanan 2883d76a60baSAnirudh Venkataramanan /** 2884d76a60baSAnirudh Venkataramanan * ice_remove_vlan - Remove VLAN based filter rule 2885d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 2886d76a60baSAnirudh Venkataramanan * @v_list: list of VLAN entries and forwarding information 2887d76a60baSAnirudh Venkataramanan */ 2888d76a60baSAnirudh Venkataramanan enum ice_status 2889d76a60baSAnirudh Venkataramanan ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) 2890d76a60baSAnirudh Venkataramanan { 2891072f0c3dSDave Ertman struct ice_fltr_list_entry *v_list_itr, *tmp; 2892d76a60baSAnirudh Venkataramanan 2893d76a60baSAnirudh Venkataramanan if (!v_list || !hw) 2894d76a60baSAnirudh Venkataramanan return ICE_ERR_PARAM; 2895d76a60baSAnirudh Venkataramanan 2896072f0c3dSDave Ertman list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { 289780d144c9SAnirudh Venkataramanan enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; 289880d144c9SAnirudh Venkataramanan 289980d144c9SAnirudh Venkataramanan if (l_type != ICE_SW_LKUP_VLAN) 290080d144c9SAnirudh Venkataramanan return ICE_ERR_PARAM; 290180d144c9SAnirudh Venkataramanan v_list_itr->status = ice_remove_rule_internal(hw, 290280d144c9SAnirudh Venkataramanan ICE_SW_LKUP_VLAN, 290380d144c9SAnirudh Venkataramanan v_list_itr); 290480d144c9SAnirudh Venkataramanan if (v_list_itr->status) 290580d144c9SAnirudh Venkataramanan return v_list_itr->status; 2906d76a60baSAnirudh Venkataramanan } 290780d144c9SAnirudh Venkataramanan return 0; 2908d76a60baSAnirudh Venkataramanan } 290980d144c9SAnirudh Venkataramanan 291080d144c9SAnirudh Venkataramanan /** 291180d144c9SAnirudh Venkataramanan * ice_vsi_uses_fltr - Determine if given VSI uses specified filter 291280d144c9SAnirudh Venkataramanan * @fm_entry: filter entry to inspect 29135726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to compare with filter info 291480d144c9SAnirudh Venkataramanan */ 291580d144c9SAnirudh Venkataramanan static bool 29165726ca0eSAnirudh Venkataramanan ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) 291780d144c9SAnirudh Venkataramanan { 291880d144c9SAnirudh Venkataramanan return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && 29195726ca0eSAnirudh Venkataramanan fm_entry->fltr_info.vsi_handle == vsi_handle) || 292080d144c9SAnirudh Venkataramanan (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && 29217a91d3f0SJacek Bułatek fm_entry->vsi_list_info && 29225726ca0eSAnirudh Venkataramanan (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); 292380d144c9SAnirudh Venkataramanan } 292480d144c9SAnirudh Venkataramanan 292580d144c9SAnirudh Venkataramanan /** 292680d144c9SAnirudh Venkataramanan * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list 292780d144c9SAnirudh Venkataramanan * @hw: pointer to the hardware structure 29285726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 292980d144c9SAnirudh Venkataramanan * @vsi_list_head: pointer to the list to add entry to 293080d144c9SAnirudh Venkataramanan * @fi: pointer to fltr_info of filter entry to copy & add 293180d144c9SAnirudh Venkataramanan * 293280d144c9SAnirudh Venkataramanan * Helper function, used when creating a list of filters to remove from 293380d144c9SAnirudh Venkataramanan * a specific VSI. The entry added to vsi_list_head is a COPY of the 293480d144c9SAnirudh Venkataramanan * original filter entry, with the exception of fltr_info.fltr_act and 293580d144c9SAnirudh Venkataramanan * fltr_info.fwd_id fields. These are set such that later logic can 293680d144c9SAnirudh Venkataramanan * extract which VSI to remove the fltr from, and pass on that information. 293780d144c9SAnirudh Venkataramanan */ 293880d144c9SAnirudh Venkataramanan static enum ice_status 29395726ca0eSAnirudh Venkataramanan ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, 294080d144c9SAnirudh Venkataramanan struct list_head *vsi_list_head, 294180d144c9SAnirudh Venkataramanan struct ice_fltr_info *fi) 294280d144c9SAnirudh Venkataramanan { 294380d144c9SAnirudh Venkataramanan struct ice_fltr_list_entry *tmp; 294480d144c9SAnirudh Venkataramanan 294580d144c9SAnirudh Venkataramanan /* this memory is freed up in the caller function 294680d144c9SAnirudh Venkataramanan * once filters for this VSI are removed 294780d144c9SAnirudh Venkataramanan */ 294880d144c9SAnirudh Venkataramanan tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL); 294980d144c9SAnirudh Venkataramanan if (!tmp) 295080d144c9SAnirudh Venkataramanan return ICE_ERR_NO_MEMORY; 295180d144c9SAnirudh Venkataramanan 295280d144c9SAnirudh Venkataramanan tmp->fltr_info = *fi; 295380d144c9SAnirudh Venkataramanan 295480d144c9SAnirudh Venkataramanan /* Overwrite these fields to indicate which VSI to remove filter from, 295580d144c9SAnirudh Venkataramanan * so find and remove logic can extract the information from the 295680d144c9SAnirudh Venkataramanan * list entries. Note that original entries will still have proper 295780d144c9SAnirudh Venkataramanan * values. 295880d144c9SAnirudh Venkataramanan */ 295980d144c9SAnirudh Venkataramanan tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; 29605726ca0eSAnirudh Venkataramanan tmp->fltr_info.vsi_handle = vsi_handle; 29615726ca0eSAnirudh Venkataramanan tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 296280d144c9SAnirudh Venkataramanan 296380d144c9SAnirudh Venkataramanan list_add(&tmp->list_entry, vsi_list_head); 296480d144c9SAnirudh Venkataramanan 296580d144c9SAnirudh Venkataramanan return 0; 2966d76a60baSAnirudh Venkataramanan } 2967d76a60baSAnirudh Venkataramanan 2968d76a60baSAnirudh Venkataramanan /** 29699daf8208SAnirudh Venkataramanan * ice_add_to_vsi_fltr_list - Add VSI filters to the list 29709daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 29715726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 29729daf8208SAnirudh Venkataramanan * @lkup_list_head: pointer to the list that has certain lookup type filters 29735726ca0eSAnirudh Venkataramanan * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle 297480d144c9SAnirudh Venkataramanan * 297580d144c9SAnirudh Venkataramanan * Locates all filters in lkup_list_head that are used by the given VSI, 297680d144c9SAnirudh Venkataramanan * and adds COPIES of those entries to vsi_list_head (intended to be used 297780d144c9SAnirudh Venkataramanan * to remove the listed filters). 297880d144c9SAnirudh Venkataramanan * Note that this means all entries in vsi_list_head must be explicitly 297980d144c9SAnirudh Venkataramanan * deallocated by the caller when done with list. 29809daf8208SAnirudh Venkataramanan */ 29819daf8208SAnirudh Venkataramanan static enum ice_status 29825726ca0eSAnirudh Venkataramanan ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, 29839daf8208SAnirudh Venkataramanan struct list_head *lkup_list_head, 29849daf8208SAnirudh Venkataramanan struct list_head *vsi_list_head) 29859daf8208SAnirudh Venkataramanan { 29869daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *fm_entry; 298780d144c9SAnirudh Venkataramanan enum ice_status status = 0; 29889daf8208SAnirudh Venkataramanan 2989f9867df6SAnirudh Venkataramanan /* check to make sure VSI ID is valid and within boundary */ 29905726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 29919daf8208SAnirudh Venkataramanan return ICE_ERR_PARAM; 29929daf8208SAnirudh Venkataramanan 29939daf8208SAnirudh Venkataramanan list_for_each_entry(fm_entry, lkup_list_head, list_entry) { 29947a91d3f0SJacek Bułatek if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) 299580d144c9SAnirudh Venkataramanan continue; 29969daf8208SAnirudh Venkataramanan 29975726ca0eSAnirudh Venkataramanan status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, 29987a91d3f0SJacek Bułatek vsi_list_head, 29997a91d3f0SJacek Bułatek &fm_entry->fltr_info); 300080d144c9SAnirudh Venkataramanan if (status) 300180d144c9SAnirudh Venkataramanan return status; 30029daf8208SAnirudh Venkataramanan } 300380d144c9SAnirudh Venkataramanan return status; 30049daf8208SAnirudh Venkataramanan } 30059daf8208SAnirudh Venkataramanan 30069daf8208SAnirudh Venkataramanan /** 30075eda8afdSAkeem G Abodunrin * ice_determine_promisc_mask 30085eda8afdSAkeem G Abodunrin * @fi: filter info to parse 30095eda8afdSAkeem G Abodunrin * 30105eda8afdSAkeem G Abodunrin * Helper function to determine which ICE_PROMISC_ mask corresponds 30115eda8afdSAkeem G Abodunrin * to given filter into. 30125eda8afdSAkeem G Abodunrin */ 30135eda8afdSAkeem G Abodunrin static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi) 30145eda8afdSAkeem G Abodunrin { 30155eda8afdSAkeem G Abodunrin u16 vid = fi->l_data.mac_vlan.vlan_id; 30165eda8afdSAkeem G Abodunrin u8 *macaddr = fi->l_data.mac.mac_addr; 30175eda8afdSAkeem G Abodunrin bool is_tx_fltr = false; 30185eda8afdSAkeem G Abodunrin u8 promisc_mask = 0; 30195eda8afdSAkeem G Abodunrin 30205eda8afdSAkeem G Abodunrin if (fi->flag == ICE_FLTR_TX) 30215eda8afdSAkeem G Abodunrin is_tx_fltr = true; 30225eda8afdSAkeem G Abodunrin 30235eda8afdSAkeem G Abodunrin if (is_broadcast_ether_addr(macaddr)) 30245eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 30255eda8afdSAkeem G Abodunrin ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX; 30265eda8afdSAkeem G Abodunrin else if (is_multicast_ether_addr(macaddr)) 30275eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 30285eda8afdSAkeem G Abodunrin ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX; 30295eda8afdSAkeem G Abodunrin else if (is_unicast_ether_addr(macaddr)) 30305eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 30315eda8afdSAkeem G Abodunrin ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX; 30325eda8afdSAkeem G Abodunrin if (vid) 30335eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 30345eda8afdSAkeem G Abodunrin ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX; 30355eda8afdSAkeem G Abodunrin 30365eda8afdSAkeem G Abodunrin return promisc_mask; 30375eda8afdSAkeem G Abodunrin } 30385eda8afdSAkeem G Abodunrin 30395eda8afdSAkeem G Abodunrin /** 30405eda8afdSAkeem G Abodunrin * ice_remove_promisc - Remove promisc based filter rules 30415eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 3042f9867df6SAnirudh Venkataramanan * @recp_id: recipe ID for which the rule needs to removed 30435eda8afdSAkeem G Abodunrin * @v_list: list of promisc entries 30445eda8afdSAkeem G Abodunrin */ 30455eda8afdSAkeem G Abodunrin static enum ice_status 30465eda8afdSAkeem G Abodunrin ice_remove_promisc(struct ice_hw *hw, u8 recp_id, 30475eda8afdSAkeem G Abodunrin struct list_head *v_list) 30485eda8afdSAkeem G Abodunrin { 30495eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry *v_list_itr, *tmp; 30505eda8afdSAkeem G Abodunrin 30515eda8afdSAkeem G Abodunrin list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { 30525eda8afdSAkeem G Abodunrin v_list_itr->status = 30535eda8afdSAkeem G Abodunrin ice_remove_rule_internal(hw, recp_id, v_list_itr); 30545eda8afdSAkeem G Abodunrin if (v_list_itr->status) 30555eda8afdSAkeem G Abodunrin return v_list_itr->status; 30565eda8afdSAkeem G Abodunrin } 30575eda8afdSAkeem G Abodunrin return 0; 30585eda8afdSAkeem G Abodunrin } 30595eda8afdSAkeem G Abodunrin 30605eda8afdSAkeem G Abodunrin /** 30615eda8afdSAkeem G Abodunrin * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI 30625eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 30635eda8afdSAkeem G Abodunrin * @vsi_handle: VSI handle to clear mode 30645eda8afdSAkeem G Abodunrin * @promisc_mask: mask of promiscuous config bits to clear 30655eda8afdSAkeem G Abodunrin * @vid: VLAN ID to clear VLAN promiscuous 30665eda8afdSAkeem G Abodunrin */ 30675eda8afdSAkeem G Abodunrin enum ice_status 30685eda8afdSAkeem G Abodunrin ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, 30695eda8afdSAkeem G Abodunrin u16 vid) 30705eda8afdSAkeem G Abodunrin { 30715eda8afdSAkeem G Abodunrin struct ice_switch_info *sw = hw->switch_info; 30725eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry *fm_entry, *tmp; 30735eda8afdSAkeem G Abodunrin struct list_head remove_list_head; 30745eda8afdSAkeem G Abodunrin struct ice_fltr_mgmt_list_entry *itr; 30755eda8afdSAkeem G Abodunrin struct list_head *rule_head; 30765eda8afdSAkeem G Abodunrin struct mutex *rule_lock; /* Lock to protect filter rule list */ 30775eda8afdSAkeem G Abodunrin enum ice_status status = 0; 30785eda8afdSAkeem G Abodunrin u8 recipe_id; 30795eda8afdSAkeem G Abodunrin 30805eda8afdSAkeem G Abodunrin if (!ice_is_vsi_valid(hw, vsi_handle)) 30815eda8afdSAkeem G Abodunrin return ICE_ERR_PARAM; 30825eda8afdSAkeem G Abodunrin 30831bc7a4abSBrett Creeley if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) 30845eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC_VLAN; 30855eda8afdSAkeem G Abodunrin else 30865eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC; 30875eda8afdSAkeem G Abodunrin 30885eda8afdSAkeem G Abodunrin rule_head = &sw->recp_list[recipe_id].filt_rules; 30895eda8afdSAkeem G Abodunrin rule_lock = &sw->recp_list[recipe_id].filt_rule_lock; 30905eda8afdSAkeem G Abodunrin 30915eda8afdSAkeem G Abodunrin INIT_LIST_HEAD(&remove_list_head); 30925eda8afdSAkeem G Abodunrin 30935eda8afdSAkeem G Abodunrin mutex_lock(rule_lock); 30945eda8afdSAkeem G Abodunrin list_for_each_entry(itr, rule_head, list_entry) { 30951bc7a4abSBrett Creeley struct ice_fltr_info *fltr_info; 30965eda8afdSAkeem G Abodunrin u8 fltr_promisc_mask = 0; 30975eda8afdSAkeem G Abodunrin 30985eda8afdSAkeem G Abodunrin if (!ice_vsi_uses_fltr(itr, vsi_handle)) 30995eda8afdSAkeem G Abodunrin continue; 31001bc7a4abSBrett Creeley fltr_info = &itr->fltr_info; 31015eda8afdSAkeem G Abodunrin 31021bc7a4abSBrett Creeley if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN && 31031bc7a4abSBrett Creeley vid != fltr_info->l_data.mac_vlan.vlan_id) 31041bc7a4abSBrett Creeley continue; 31051bc7a4abSBrett Creeley 31061bc7a4abSBrett Creeley fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info); 31075eda8afdSAkeem G Abodunrin 31085eda8afdSAkeem G Abodunrin /* Skip if filter is not completely specified by given mask */ 31095eda8afdSAkeem G Abodunrin if (fltr_promisc_mask & ~promisc_mask) 31105eda8afdSAkeem G Abodunrin continue; 31115eda8afdSAkeem G Abodunrin 31125eda8afdSAkeem G Abodunrin status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, 31135eda8afdSAkeem G Abodunrin &remove_list_head, 31141bc7a4abSBrett Creeley fltr_info); 31155eda8afdSAkeem G Abodunrin if (status) { 31165eda8afdSAkeem G Abodunrin mutex_unlock(rule_lock); 31175eda8afdSAkeem G Abodunrin goto free_fltr_list; 31185eda8afdSAkeem G Abodunrin } 31195eda8afdSAkeem G Abodunrin } 31205eda8afdSAkeem G Abodunrin mutex_unlock(rule_lock); 31215eda8afdSAkeem G Abodunrin 31225eda8afdSAkeem G Abodunrin status = ice_remove_promisc(hw, recipe_id, &remove_list_head); 31235eda8afdSAkeem G Abodunrin 31245eda8afdSAkeem G Abodunrin free_fltr_list: 31255eda8afdSAkeem G Abodunrin list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { 31265eda8afdSAkeem G Abodunrin list_del(&fm_entry->list_entry); 31275eda8afdSAkeem G Abodunrin devm_kfree(ice_hw_to_dev(hw), fm_entry); 31285eda8afdSAkeem G Abodunrin } 31295eda8afdSAkeem G Abodunrin 31305eda8afdSAkeem G Abodunrin return status; 31315eda8afdSAkeem G Abodunrin } 31325eda8afdSAkeem G Abodunrin 31335eda8afdSAkeem G Abodunrin /** 31345eda8afdSAkeem G Abodunrin * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s) 31355eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 31365eda8afdSAkeem G Abodunrin * @vsi_handle: VSI handle to configure 31375eda8afdSAkeem G Abodunrin * @promisc_mask: mask of promiscuous config bits 31385eda8afdSAkeem G Abodunrin * @vid: VLAN ID to set VLAN promiscuous 31395eda8afdSAkeem G Abodunrin */ 31405eda8afdSAkeem G Abodunrin enum ice_status 31415eda8afdSAkeem G Abodunrin ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) 31425eda8afdSAkeem G Abodunrin { 31435eda8afdSAkeem G Abodunrin enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR }; 31445eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry f_list_entry; 31455eda8afdSAkeem G Abodunrin struct ice_fltr_info new_fltr; 31465eda8afdSAkeem G Abodunrin enum ice_status status = 0; 31475eda8afdSAkeem G Abodunrin bool is_tx_fltr; 31485eda8afdSAkeem G Abodunrin u16 hw_vsi_id; 31495eda8afdSAkeem G Abodunrin int pkt_type; 31505eda8afdSAkeem G Abodunrin u8 recipe_id; 31515eda8afdSAkeem G Abodunrin 31525eda8afdSAkeem G Abodunrin if (!ice_is_vsi_valid(hw, vsi_handle)) 31535eda8afdSAkeem G Abodunrin return ICE_ERR_PARAM; 31545eda8afdSAkeem G Abodunrin hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 31555eda8afdSAkeem G Abodunrin 31565eda8afdSAkeem G Abodunrin memset(&new_fltr, 0, sizeof(new_fltr)); 31575eda8afdSAkeem G Abodunrin 31585eda8afdSAkeem G Abodunrin if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) { 31595eda8afdSAkeem G Abodunrin new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN; 31605eda8afdSAkeem G Abodunrin new_fltr.l_data.mac_vlan.vlan_id = vid; 31615eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC_VLAN; 31625eda8afdSAkeem G Abodunrin } else { 31635eda8afdSAkeem G Abodunrin new_fltr.lkup_type = ICE_SW_LKUP_PROMISC; 31645eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC; 31655eda8afdSAkeem G Abodunrin } 31665eda8afdSAkeem G Abodunrin 31675eda8afdSAkeem G Abodunrin /* Separate filters must be set for each direction/packet type 31685eda8afdSAkeem G Abodunrin * combination, so we will loop over the mask value, store the 31695eda8afdSAkeem G Abodunrin * individual type, and clear it out in the input mask as it 31705eda8afdSAkeem G Abodunrin * is found. 31715eda8afdSAkeem G Abodunrin */ 31725eda8afdSAkeem G Abodunrin while (promisc_mask) { 31735eda8afdSAkeem G Abodunrin u8 *mac_addr; 31745eda8afdSAkeem G Abodunrin 31755eda8afdSAkeem G Abodunrin pkt_type = 0; 31765eda8afdSAkeem G Abodunrin is_tx_fltr = false; 31775eda8afdSAkeem G Abodunrin 31785eda8afdSAkeem G Abodunrin if (promisc_mask & ICE_PROMISC_UCAST_RX) { 31795eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_UCAST_RX; 31805eda8afdSAkeem G Abodunrin pkt_type = UCAST_FLTR; 31815eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_UCAST_TX) { 31825eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_UCAST_TX; 31835eda8afdSAkeem G Abodunrin pkt_type = UCAST_FLTR; 31845eda8afdSAkeem G Abodunrin is_tx_fltr = true; 31855eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_MCAST_RX) { 31865eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_MCAST_RX; 31875eda8afdSAkeem G Abodunrin pkt_type = MCAST_FLTR; 31885eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_MCAST_TX) { 31895eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_MCAST_TX; 31905eda8afdSAkeem G Abodunrin pkt_type = MCAST_FLTR; 31915eda8afdSAkeem G Abodunrin is_tx_fltr = true; 31925eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_BCAST_RX) { 31935eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_BCAST_RX; 31945eda8afdSAkeem G Abodunrin pkt_type = BCAST_FLTR; 31955eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_BCAST_TX) { 31965eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_BCAST_TX; 31975eda8afdSAkeem G Abodunrin pkt_type = BCAST_FLTR; 31985eda8afdSAkeem G Abodunrin is_tx_fltr = true; 31995eda8afdSAkeem G Abodunrin } 32005eda8afdSAkeem G Abodunrin 32015eda8afdSAkeem G Abodunrin /* Check for VLAN promiscuous flag */ 32025eda8afdSAkeem G Abodunrin if (promisc_mask & ICE_PROMISC_VLAN_RX) { 32035eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_VLAN_RX; 32045eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_VLAN_TX) { 32055eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_VLAN_TX; 32065eda8afdSAkeem G Abodunrin is_tx_fltr = true; 32075eda8afdSAkeem G Abodunrin } 32085eda8afdSAkeem G Abodunrin 32095eda8afdSAkeem G Abodunrin /* Set filter DA based on packet type */ 32105eda8afdSAkeem G Abodunrin mac_addr = new_fltr.l_data.mac.mac_addr; 32115eda8afdSAkeem G Abodunrin if (pkt_type == BCAST_FLTR) { 32125eda8afdSAkeem G Abodunrin eth_broadcast_addr(mac_addr); 32135eda8afdSAkeem G Abodunrin } else if (pkt_type == MCAST_FLTR || 32145eda8afdSAkeem G Abodunrin pkt_type == UCAST_FLTR) { 32155eda8afdSAkeem G Abodunrin /* Use the dummy ether header DA */ 32165eda8afdSAkeem G Abodunrin ether_addr_copy(mac_addr, dummy_eth_header); 32175eda8afdSAkeem G Abodunrin if (pkt_type == MCAST_FLTR) 32185eda8afdSAkeem G Abodunrin mac_addr[0] |= 0x1; /* Set multicast bit */ 32195eda8afdSAkeem G Abodunrin } 32205eda8afdSAkeem G Abodunrin 32215eda8afdSAkeem G Abodunrin /* Need to reset this to zero for all iterations */ 32225eda8afdSAkeem G Abodunrin new_fltr.flag = 0; 32235eda8afdSAkeem G Abodunrin if (is_tx_fltr) { 32245eda8afdSAkeem G Abodunrin new_fltr.flag |= ICE_FLTR_TX; 32255eda8afdSAkeem G Abodunrin new_fltr.src = hw_vsi_id; 32265eda8afdSAkeem G Abodunrin } else { 32275eda8afdSAkeem G Abodunrin new_fltr.flag |= ICE_FLTR_RX; 32285eda8afdSAkeem G Abodunrin new_fltr.src = hw->port_info->lport; 32295eda8afdSAkeem G Abodunrin } 32305eda8afdSAkeem G Abodunrin 32315eda8afdSAkeem G Abodunrin new_fltr.fltr_act = ICE_FWD_TO_VSI; 32325eda8afdSAkeem G Abodunrin new_fltr.vsi_handle = vsi_handle; 32335eda8afdSAkeem G Abodunrin new_fltr.fwd_id.hw_vsi_id = hw_vsi_id; 32345eda8afdSAkeem G Abodunrin f_list_entry.fltr_info = new_fltr; 32355eda8afdSAkeem G Abodunrin 32365eda8afdSAkeem G Abodunrin status = ice_add_rule_internal(hw, recipe_id, &f_list_entry); 32375eda8afdSAkeem G Abodunrin if (status) 32385eda8afdSAkeem G Abodunrin goto set_promisc_exit; 32395eda8afdSAkeem G Abodunrin } 32405eda8afdSAkeem G Abodunrin 32415eda8afdSAkeem G Abodunrin set_promisc_exit: 32425eda8afdSAkeem G Abodunrin return status; 32435eda8afdSAkeem G Abodunrin } 32445eda8afdSAkeem G Abodunrin 32455eda8afdSAkeem G Abodunrin /** 32465eda8afdSAkeem G Abodunrin * ice_set_vlan_vsi_promisc 32475eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 32485eda8afdSAkeem G Abodunrin * @vsi_handle: VSI handle to configure 32495eda8afdSAkeem G Abodunrin * @promisc_mask: mask of promiscuous config bits 32505eda8afdSAkeem G Abodunrin * @rm_vlan_promisc: Clear VLANs VSI promisc mode 32515eda8afdSAkeem G Abodunrin * 32525eda8afdSAkeem G Abodunrin * Configure VSI with all associated VLANs to given promiscuous mode(s) 32535eda8afdSAkeem G Abodunrin */ 32545eda8afdSAkeem G Abodunrin enum ice_status 32555eda8afdSAkeem G Abodunrin ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, 32565eda8afdSAkeem G Abodunrin bool rm_vlan_promisc) 32575eda8afdSAkeem G Abodunrin { 32585eda8afdSAkeem G Abodunrin struct ice_switch_info *sw = hw->switch_info; 32595eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry *list_itr, *tmp; 32605eda8afdSAkeem G Abodunrin struct list_head vsi_list_head; 32615eda8afdSAkeem G Abodunrin struct list_head *vlan_head; 32625eda8afdSAkeem G Abodunrin struct mutex *vlan_lock; /* Lock to protect filter rule list */ 32635eda8afdSAkeem G Abodunrin enum ice_status status; 32645eda8afdSAkeem G Abodunrin u16 vlan_id; 32655eda8afdSAkeem G Abodunrin 32665eda8afdSAkeem G Abodunrin INIT_LIST_HEAD(&vsi_list_head); 32675eda8afdSAkeem G Abodunrin vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; 32685eda8afdSAkeem G Abodunrin vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; 32695eda8afdSAkeem G Abodunrin mutex_lock(vlan_lock); 32705eda8afdSAkeem G Abodunrin status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head, 32715eda8afdSAkeem G Abodunrin &vsi_list_head); 32725eda8afdSAkeem G Abodunrin mutex_unlock(vlan_lock); 32735eda8afdSAkeem G Abodunrin if (status) 32745eda8afdSAkeem G Abodunrin goto free_fltr_list; 32755eda8afdSAkeem G Abodunrin 32765eda8afdSAkeem G Abodunrin list_for_each_entry(list_itr, &vsi_list_head, list_entry) { 32775eda8afdSAkeem G Abodunrin vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id; 32785eda8afdSAkeem G Abodunrin if (rm_vlan_promisc) 32795eda8afdSAkeem G Abodunrin status = ice_clear_vsi_promisc(hw, vsi_handle, 32805eda8afdSAkeem G Abodunrin promisc_mask, vlan_id); 32815eda8afdSAkeem G Abodunrin else 32825eda8afdSAkeem G Abodunrin status = ice_set_vsi_promisc(hw, vsi_handle, 32835eda8afdSAkeem G Abodunrin promisc_mask, vlan_id); 32845eda8afdSAkeem G Abodunrin if (status) 32855eda8afdSAkeem G Abodunrin break; 32865eda8afdSAkeem G Abodunrin } 32875eda8afdSAkeem G Abodunrin 32885eda8afdSAkeem G Abodunrin free_fltr_list: 32895eda8afdSAkeem G Abodunrin list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) { 32905eda8afdSAkeem G Abodunrin list_del(&list_itr->list_entry); 32915eda8afdSAkeem G Abodunrin devm_kfree(ice_hw_to_dev(hw), list_itr); 32925eda8afdSAkeem G Abodunrin } 32935eda8afdSAkeem G Abodunrin return status; 32945eda8afdSAkeem G Abodunrin } 32955eda8afdSAkeem G Abodunrin 32965eda8afdSAkeem G Abodunrin /** 32979daf8208SAnirudh Venkataramanan * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI 32989daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 32995726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 33009daf8208SAnirudh Venkataramanan * @lkup: switch rule filter lookup type 33019daf8208SAnirudh Venkataramanan */ 33029daf8208SAnirudh Venkataramanan static void 33035726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, 33049daf8208SAnirudh Venkataramanan enum ice_sw_lkup_type lkup) 33059daf8208SAnirudh Venkataramanan { 33069daf8208SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 33079daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *fm_entry; 33089daf8208SAnirudh Venkataramanan struct list_head remove_list_head; 330980d144c9SAnirudh Venkataramanan struct list_head *rule_head; 33109daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *tmp; 331180d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 33129daf8208SAnirudh Venkataramanan enum ice_status status; 33139daf8208SAnirudh Venkataramanan 33149daf8208SAnirudh Venkataramanan INIT_LIST_HEAD(&remove_list_head); 331580d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[lkup].filt_rule_lock; 331680d144c9SAnirudh Venkataramanan rule_head = &sw->recp_list[lkup].filt_rules; 331780d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 33185726ca0eSAnirudh Venkataramanan status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head, 331980d144c9SAnirudh Venkataramanan &remove_list_head); 332080d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 332180d144c9SAnirudh Venkataramanan if (status) 3322b7eeb527SRobert Malz goto free_fltr_list; 332380d144c9SAnirudh Venkataramanan 33249daf8208SAnirudh Venkataramanan switch (lkup) { 33259daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_MAC: 33269daf8208SAnirudh Venkataramanan ice_remove_mac(hw, &remove_list_head); 33279daf8208SAnirudh Venkataramanan break; 33289daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_VLAN: 3329d76a60baSAnirudh Venkataramanan ice_remove_vlan(hw, &remove_list_head); 3330d76a60baSAnirudh Venkataramanan break; 33315eda8afdSAkeem G Abodunrin case ICE_SW_LKUP_PROMISC: 33325eda8afdSAkeem G Abodunrin case ICE_SW_LKUP_PROMISC_VLAN: 33335eda8afdSAkeem G Abodunrin ice_remove_promisc(hw, lkup, &remove_list_head); 33345eda8afdSAkeem G Abodunrin break; 33359daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_MAC_VLAN: 33369daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_ETHERTYPE: 33379daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_ETHERTYPE_MAC: 33389daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_DFLT: 333980d144c9SAnirudh Venkataramanan case ICE_SW_LKUP_LAST: 334080d144c9SAnirudh Venkataramanan default: 334180d144c9SAnirudh Venkataramanan ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); 33429daf8208SAnirudh Venkataramanan break; 33439daf8208SAnirudh Venkataramanan } 33449daf8208SAnirudh Venkataramanan 3345b7eeb527SRobert Malz free_fltr_list: 33469daf8208SAnirudh Venkataramanan list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { 33479daf8208SAnirudh Venkataramanan list_del(&fm_entry->list_entry); 33489daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), fm_entry); 33499daf8208SAnirudh Venkataramanan } 33509daf8208SAnirudh Venkataramanan } 33519daf8208SAnirudh Venkataramanan 33529daf8208SAnirudh Venkataramanan /** 33539daf8208SAnirudh Venkataramanan * ice_remove_vsi_fltr - Remove all filters for a VSI 33549daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 33555726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 33569daf8208SAnirudh Venkataramanan */ 33575726ca0eSAnirudh Venkataramanan void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) 33589daf8208SAnirudh Venkataramanan { 33595726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC); 33605726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN); 33615726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC); 33625726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN); 33635726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT); 33645726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE); 33655726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC); 33665726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN); 33679daf8208SAnirudh Venkataramanan } 33680f9d5027SAnirudh Venkataramanan 33690f9d5027SAnirudh Venkataramanan /** 3370148beb61SHenry Tieman * ice_alloc_res_cntr - allocating resource counter 3371148beb61SHenry Tieman * @hw: pointer to the hardware structure 3372148beb61SHenry Tieman * @type: type of resource 3373148beb61SHenry Tieman * @alloc_shared: if set it is shared else dedicated 3374148beb61SHenry Tieman * @num_items: number of entries requested for FD resource type 3375148beb61SHenry Tieman * @counter_id: counter index returned by AQ call 3376148beb61SHenry Tieman */ 3377148beb61SHenry Tieman enum ice_status 3378148beb61SHenry Tieman ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, 3379148beb61SHenry Tieman u16 *counter_id) 3380148beb61SHenry Tieman { 3381148beb61SHenry Tieman struct ice_aqc_alloc_free_res_elem *buf; 3382148beb61SHenry Tieman enum ice_status status; 3383148beb61SHenry Tieman u16 buf_len; 3384148beb61SHenry Tieman 3385148beb61SHenry Tieman /* Allocate resource */ 338666486d89SBruce Allan buf_len = struct_size(buf, elem, 1); 3387148beb61SHenry Tieman buf = kzalloc(buf_len, GFP_KERNEL); 3388148beb61SHenry Tieman if (!buf) 3389148beb61SHenry Tieman return ICE_ERR_NO_MEMORY; 3390148beb61SHenry Tieman 3391148beb61SHenry Tieman buf->num_elems = cpu_to_le16(num_items); 3392148beb61SHenry Tieman buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & 3393148beb61SHenry Tieman ICE_AQC_RES_TYPE_M) | alloc_shared); 3394148beb61SHenry Tieman 3395148beb61SHenry Tieman status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, 3396148beb61SHenry Tieman ice_aqc_opc_alloc_res, NULL); 3397148beb61SHenry Tieman if (status) 3398148beb61SHenry Tieman goto exit; 3399148beb61SHenry Tieman 3400148beb61SHenry Tieman *counter_id = le16_to_cpu(buf->elem[0].e.sw_resp); 3401148beb61SHenry Tieman 3402148beb61SHenry Tieman exit: 3403148beb61SHenry Tieman kfree(buf); 3404148beb61SHenry Tieman return status; 3405148beb61SHenry Tieman } 3406148beb61SHenry Tieman 3407148beb61SHenry Tieman /** 3408148beb61SHenry Tieman * ice_free_res_cntr - free resource counter 3409148beb61SHenry Tieman * @hw: pointer to the hardware structure 3410148beb61SHenry Tieman * @type: type of resource 3411148beb61SHenry Tieman * @alloc_shared: if set it is shared else dedicated 3412148beb61SHenry Tieman * @num_items: number of entries to be freed for FD resource type 3413148beb61SHenry Tieman * @counter_id: counter ID resource which needs to be freed 3414148beb61SHenry Tieman */ 3415148beb61SHenry Tieman enum ice_status 3416148beb61SHenry Tieman ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, 3417148beb61SHenry Tieman u16 counter_id) 3418148beb61SHenry Tieman { 3419148beb61SHenry Tieman struct ice_aqc_alloc_free_res_elem *buf; 3420148beb61SHenry Tieman enum ice_status status; 3421148beb61SHenry Tieman u16 buf_len; 3422148beb61SHenry Tieman 3423148beb61SHenry Tieman /* Free resource */ 342466486d89SBruce Allan buf_len = struct_size(buf, elem, 1); 3425148beb61SHenry Tieman buf = kzalloc(buf_len, GFP_KERNEL); 3426148beb61SHenry Tieman if (!buf) 3427148beb61SHenry Tieman return ICE_ERR_NO_MEMORY; 3428148beb61SHenry Tieman 3429148beb61SHenry Tieman buf->num_elems = cpu_to_le16(num_items); 3430148beb61SHenry Tieman buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & 3431148beb61SHenry Tieman ICE_AQC_RES_TYPE_M) | alloc_shared); 3432148beb61SHenry Tieman buf->elem[0].e.sw_resp = cpu_to_le16(counter_id); 3433148beb61SHenry Tieman 3434148beb61SHenry Tieman status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, 3435148beb61SHenry Tieman ice_aqc_opc_free_res, NULL); 3436148beb61SHenry Tieman if (status) 34379228d8b2SJacob Keller ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n"); 3438148beb61SHenry Tieman 3439148beb61SHenry Tieman kfree(buf); 3440148beb61SHenry Tieman return status; 3441148beb61SHenry Tieman } 3442148beb61SHenry Tieman 3443fd2a6b71SDan Nowlin /* This is mapping table entry that maps every word within a given protocol 3444fd2a6b71SDan Nowlin * structure to the real byte offset as per the specification of that 3445fd2a6b71SDan Nowlin * protocol header. 3446fd2a6b71SDan Nowlin * for example dst address is 3 words in ethertype header and corresponding 3447fd2a6b71SDan Nowlin * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8 3448fd2a6b71SDan Nowlin * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a 3449fd2a6b71SDan Nowlin * matching entry describing its field. This needs to be updated if new 3450fd2a6b71SDan Nowlin * structure is added to that union. 3451fd2a6b71SDan Nowlin */ 3452fd2a6b71SDan Nowlin static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { 3453fd2a6b71SDan Nowlin { ICE_MAC_OFOS, { 0, 2, 4, 6, 8, 10, 12 } }, 3454fd2a6b71SDan Nowlin { ICE_MAC_IL, { 0, 2, 4, 6, 8, 10, 12 } }, 3455fd2a6b71SDan Nowlin { ICE_ETYPE_OL, { 0 } }, 3456fd2a6b71SDan Nowlin { ICE_VLAN_OFOS, { 2, 0 } }, 3457fd2a6b71SDan Nowlin { ICE_IPV4_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, 3458fd2a6b71SDan Nowlin { ICE_IPV4_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, 3459fd2a6b71SDan Nowlin { ICE_IPV6_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 3460fd2a6b71SDan Nowlin 26, 28, 30, 32, 34, 36, 38 } }, 3461fd2a6b71SDan Nowlin { ICE_IPV6_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 3462fd2a6b71SDan Nowlin 26, 28, 30, 32, 34, 36, 38 } }, 3463fd2a6b71SDan Nowlin { ICE_TCP_IL, { 0, 2 } }, 3464fd2a6b71SDan Nowlin { ICE_UDP_OF, { 0, 2 } }, 3465fd2a6b71SDan Nowlin { ICE_UDP_ILOS, { 0, 2 } }, 3466fd2a6b71SDan Nowlin }; 3467fd2a6b71SDan Nowlin 3468fd2a6b71SDan Nowlin static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { 3469fd2a6b71SDan Nowlin { ICE_MAC_OFOS, ICE_MAC_OFOS_HW }, 3470fd2a6b71SDan Nowlin { ICE_MAC_IL, ICE_MAC_IL_HW }, 3471fd2a6b71SDan Nowlin { ICE_ETYPE_OL, ICE_ETYPE_OL_HW }, 3472fd2a6b71SDan Nowlin { ICE_VLAN_OFOS, ICE_VLAN_OL_HW }, 3473fd2a6b71SDan Nowlin { ICE_IPV4_OFOS, ICE_IPV4_OFOS_HW }, 3474fd2a6b71SDan Nowlin { ICE_IPV4_IL, ICE_IPV4_IL_HW }, 3475fd2a6b71SDan Nowlin { ICE_IPV6_OFOS, ICE_IPV6_OFOS_HW }, 3476fd2a6b71SDan Nowlin { ICE_IPV6_IL, ICE_IPV6_IL_HW }, 3477fd2a6b71SDan Nowlin { ICE_TCP_IL, ICE_TCP_IL_HW }, 3478fd2a6b71SDan Nowlin { ICE_UDP_OF, ICE_UDP_OF_HW }, 3479fd2a6b71SDan Nowlin { ICE_UDP_ILOS, ICE_UDP_ILOS_HW }, 3480fd2a6b71SDan Nowlin }; 3481fd2a6b71SDan Nowlin 3482fd2a6b71SDan Nowlin /** 3483fd2a6b71SDan Nowlin * ice_find_recp - find a recipe 3484fd2a6b71SDan Nowlin * @hw: pointer to the hardware structure 3485fd2a6b71SDan Nowlin * @lkup_exts: extension sequence to match 3486fd2a6b71SDan Nowlin * 3487fd2a6b71SDan Nowlin * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found. 3488fd2a6b71SDan Nowlin */ 3489fd2a6b71SDan Nowlin static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts) 3490fd2a6b71SDan Nowlin { 3491fd2a6b71SDan Nowlin bool refresh_required = true; 3492fd2a6b71SDan Nowlin struct ice_sw_recipe *recp; 3493fd2a6b71SDan Nowlin u8 i; 3494fd2a6b71SDan Nowlin 3495fd2a6b71SDan Nowlin /* Walk through existing recipes to find a match */ 3496fd2a6b71SDan Nowlin recp = hw->switch_info->recp_list; 3497fd2a6b71SDan Nowlin for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { 3498fd2a6b71SDan Nowlin /* If recipe was not created for this ID, in SW bookkeeping, 3499fd2a6b71SDan Nowlin * check if FW has an entry for this recipe. If the FW has an 3500fd2a6b71SDan Nowlin * entry update it in our SW bookkeeping and continue with the 3501fd2a6b71SDan Nowlin * matching. 3502fd2a6b71SDan Nowlin */ 3503fd2a6b71SDan Nowlin if (!recp[i].recp_created) 3504fd2a6b71SDan Nowlin if (ice_get_recp_frm_fw(hw, 3505fd2a6b71SDan Nowlin hw->switch_info->recp_list, i, 3506fd2a6b71SDan Nowlin &refresh_required)) 3507fd2a6b71SDan Nowlin continue; 3508fd2a6b71SDan Nowlin 3509fd2a6b71SDan Nowlin /* Skip inverse action recipes */ 3510fd2a6b71SDan Nowlin if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl & 3511fd2a6b71SDan Nowlin ICE_AQ_RECIPE_ACT_INV_ACT) 3512fd2a6b71SDan Nowlin continue; 3513fd2a6b71SDan Nowlin 3514fd2a6b71SDan Nowlin /* if number of words we are looking for match */ 3515fd2a6b71SDan Nowlin if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) { 3516fd2a6b71SDan Nowlin struct ice_fv_word *ar = recp[i].lkup_exts.fv_words; 3517fd2a6b71SDan Nowlin struct ice_fv_word *be = lkup_exts->fv_words; 3518fd2a6b71SDan Nowlin u16 *cr = recp[i].lkup_exts.field_mask; 3519fd2a6b71SDan Nowlin u16 *de = lkup_exts->field_mask; 3520fd2a6b71SDan Nowlin bool found = true; 3521fd2a6b71SDan Nowlin u8 pe, qr; 3522fd2a6b71SDan Nowlin 3523fd2a6b71SDan Nowlin /* ar, cr, and qr are related to the recipe words, while 3524fd2a6b71SDan Nowlin * be, de, and pe are related to the lookup words 3525fd2a6b71SDan Nowlin */ 3526fd2a6b71SDan Nowlin for (pe = 0; pe < lkup_exts->n_val_words; pe++) { 3527fd2a6b71SDan Nowlin for (qr = 0; qr < recp[i].lkup_exts.n_val_words; 3528fd2a6b71SDan Nowlin qr++) { 3529fd2a6b71SDan Nowlin if (ar[qr].off == be[pe].off && 3530fd2a6b71SDan Nowlin ar[qr].prot_id == be[pe].prot_id && 3531fd2a6b71SDan Nowlin cr[qr] == de[pe]) 3532fd2a6b71SDan Nowlin /* Found the "pe"th word in the 3533fd2a6b71SDan Nowlin * given recipe 3534fd2a6b71SDan Nowlin */ 3535fd2a6b71SDan Nowlin break; 3536fd2a6b71SDan Nowlin } 3537fd2a6b71SDan Nowlin /* After walking through all the words in the 3538fd2a6b71SDan Nowlin * "i"th recipe if "p"th word was not found then 3539fd2a6b71SDan Nowlin * this recipe is not what we are looking for. 3540fd2a6b71SDan Nowlin * So break out from this loop and try the next 3541fd2a6b71SDan Nowlin * recipe 3542fd2a6b71SDan Nowlin */ 3543fd2a6b71SDan Nowlin if (qr >= recp[i].lkup_exts.n_val_words) { 3544fd2a6b71SDan Nowlin found = false; 3545fd2a6b71SDan Nowlin break; 3546fd2a6b71SDan Nowlin } 3547fd2a6b71SDan Nowlin } 3548fd2a6b71SDan Nowlin /* If for "i"th recipe the found was never set to false 3549fd2a6b71SDan Nowlin * then it means we found our match 3550fd2a6b71SDan Nowlin */ 3551fd2a6b71SDan Nowlin if (found) 3552fd2a6b71SDan Nowlin return i; /* Return the recipe ID */ 3553fd2a6b71SDan Nowlin } 3554fd2a6b71SDan Nowlin } 3555fd2a6b71SDan Nowlin return ICE_MAX_NUM_RECIPES; 3556fd2a6b71SDan Nowlin } 3557fd2a6b71SDan Nowlin 3558fd2a6b71SDan Nowlin /** 3559fd2a6b71SDan Nowlin * ice_prot_type_to_id - get protocol ID from protocol type 3560fd2a6b71SDan Nowlin * @type: protocol type 3561fd2a6b71SDan Nowlin * @id: pointer to variable that will receive the ID 3562fd2a6b71SDan Nowlin * 3563fd2a6b71SDan Nowlin * Returns true if found, false otherwise 3564fd2a6b71SDan Nowlin */ 3565fd2a6b71SDan Nowlin static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id) 3566fd2a6b71SDan Nowlin { 3567fd2a6b71SDan Nowlin u8 i; 3568fd2a6b71SDan Nowlin 3569fd2a6b71SDan Nowlin for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) 3570fd2a6b71SDan Nowlin if (ice_prot_id_tbl[i].type == type) { 3571fd2a6b71SDan Nowlin *id = ice_prot_id_tbl[i].protocol_id; 3572fd2a6b71SDan Nowlin return true; 3573fd2a6b71SDan Nowlin } 3574fd2a6b71SDan Nowlin return false; 3575fd2a6b71SDan Nowlin } 3576fd2a6b71SDan Nowlin 3577fd2a6b71SDan Nowlin /** 3578fd2a6b71SDan Nowlin * ice_fill_valid_words - count valid words 3579fd2a6b71SDan Nowlin * @rule: advanced rule with lookup information 3580fd2a6b71SDan Nowlin * @lkup_exts: byte offset extractions of the words that are valid 3581fd2a6b71SDan Nowlin * 3582fd2a6b71SDan Nowlin * calculate valid words in a lookup rule using mask value 3583fd2a6b71SDan Nowlin */ 3584fd2a6b71SDan Nowlin static u8 3585fd2a6b71SDan Nowlin ice_fill_valid_words(struct ice_adv_lkup_elem *rule, 3586fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts) 3587fd2a6b71SDan Nowlin { 3588fd2a6b71SDan Nowlin u8 j, word, prot_id, ret_val; 3589fd2a6b71SDan Nowlin 3590fd2a6b71SDan Nowlin if (!ice_prot_type_to_id(rule->type, &prot_id)) 3591fd2a6b71SDan Nowlin return 0; 3592fd2a6b71SDan Nowlin 3593fd2a6b71SDan Nowlin word = lkup_exts->n_val_words; 3594fd2a6b71SDan Nowlin 3595fd2a6b71SDan Nowlin for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++) 3596fd2a6b71SDan Nowlin if (((u16 *)&rule->m_u)[j] && 3597fd2a6b71SDan Nowlin rule->type < ARRAY_SIZE(ice_prot_ext)) { 3598fd2a6b71SDan Nowlin /* No more space to accommodate */ 3599fd2a6b71SDan Nowlin if (word >= ICE_MAX_CHAIN_WORDS) 3600fd2a6b71SDan Nowlin return 0; 3601fd2a6b71SDan Nowlin lkup_exts->fv_words[word].off = 3602fd2a6b71SDan Nowlin ice_prot_ext[rule->type].offs[j]; 3603fd2a6b71SDan Nowlin lkup_exts->fv_words[word].prot_id = 3604fd2a6b71SDan Nowlin ice_prot_id_tbl[rule->type].protocol_id; 3605fd2a6b71SDan Nowlin lkup_exts->field_mask[word] = 3606fd2a6b71SDan Nowlin be16_to_cpu(((__force __be16 *)&rule->m_u)[j]); 3607fd2a6b71SDan Nowlin word++; 3608fd2a6b71SDan Nowlin } 3609fd2a6b71SDan Nowlin 3610fd2a6b71SDan Nowlin ret_val = word - lkup_exts->n_val_words; 3611fd2a6b71SDan Nowlin lkup_exts->n_val_words = word; 3612fd2a6b71SDan Nowlin 3613fd2a6b71SDan Nowlin return ret_val; 3614fd2a6b71SDan Nowlin } 3615fd2a6b71SDan Nowlin 3616fd2a6b71SDan Nowlin /** 3617fd2a6b71SDan Nowlin * ice_create_first_fit_recp_def - Create a recipe grouping 3618fd2a6b71SDan Nowlin * @hw: pointer to the hardware structure 3619fd2a6b71SDan Nowlin * @lkup_exts: an array of protocol header extractions 3620fd2a6b71SDan Nowlin * @rg_list: pointer to a list that stores new recipe groups 3621fd2a6b71SDan Nowlin * @recp_cnt: pointer to a variable that stores returned number of recipe groups 3622fd2a6b71SDan Nowlin * 3623fd2a6b71SDan Nowlin * Using first fit algorithm, take all the words that are still not done 3624fd2a6b71SDan Nowlin * and start grouping them in 4-word groups. Each group makes up one 3625fd2a6b71SDan Nowlin * recipe. 3626fd2a6b71SDan Nowlin */ 3627fd2a6b71SDan Nowlin static enum ice_status 3628fd2a6b71SDan Nowlin ice_create_first_fit_recp_def(struct ice_hw *hw, 3629fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts, 3630fd2a6b71SDan Nowlin struct list_head *rg_list, 3631fd2a6b71SDan Nowlin u8 *recp_cnt) 3632fd2a6b71SDan Nowlin { 3633fd2a6b71SDan Nowlin struct ice_pref_recipe_group *grp = NULL; 3634fd2a6b71SDan Nowlin u8 j; 3635fd2a6b71SDan Nowlin 3636fd2a6b71SDan Nowlin *recp_cnt = 0; 3637fd2a6b71SDan Nowlin 3638fd2a6b71SDan Nowlin /* Walk through every word in the rule to check if it is not done. If so 3639fd2a6b71SDan Nowlin * then this word needs to be part of a new recipe. 3640fd2a6b71SDan Nowlin */ 3641fd2a6b71SDan Nowlin for (j = 0; j < lkup_exts->n_val_words; j++) 3642fd2a6b71SDan Nowlin if (!test_bit(j, lkup_exts->done)) { 3643fd2a6b71SDan Nowlin if (!grp || 3644fd2a6b71SDan Nowlin grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) { 3645fd2a6b71SDan Nowlin struct ice_recp_grp_entry *entry; 3646fd2a6b71SDan Nowlin 3647fd2a6b71SDan Nowlin entry = devm_kzalloc(ice_hw_to_dev(hw), 3648fd2a6b71SDan Nowlin sizeof(*entry), 3649fd2a6b71SDan Nowlin GFP_KERNEL); 3650fd2a6b71SDan Nowlin if (!entry) 3651fd2a6b71SDan Nowlin return ICE_ERR_NO_MEMORY; 3652fd2a6b71SDan Nowlin list_add(&entry->l_entry, rg_list); 3653fd2a6b71SDan Nowlin grp = &entry->r_group; 3654fd2a6b71SDan Nowlin (*recp_cnt)++; 3655fd2a6b71SDan Nowlin } 3656fd2a6b71SDan Nowlin 3657fd2a6b71SDan Nowlin grp->pairs[grp->n_val_pairs].prot_id = 3658fd2a6b71SDan Nowlin lkup_exts->fv_words[j].prot_id; 3659fd2a6b71SDan Nowlin grp->pairs[grp->n_val_pairs].off = 3660fd2a6b71SDan Nowlin lkup_exts->fv_words[j].off; 3661fd2a6b71SDan Nowlin grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j]; 3662fd2a6b71SDan Nowlin grp->n_val_pairs++; 3663fd2a6b71SDan Nowlin } 3664fd2a6b71SDan Nowlin 3665fd2a6b71SDan Nowlin return 0; 3666fd2a6b71SDan Nowlin } 3667fd2a6b71SDan Nowlin 3668fd2a6b71SDan Nowlin /** 3669fd2a6b71SDan Nowlin * ice_fill_fv_word_index - fill in the field vector indices for a recipe group 3670fd2a6b71SDan Nowlin * @hw: pointer to the hardware structure 3671fd2a6b71SDan Nowlin * @fv_list: field vector with the extraction sequence information 3672fd2a6b71SDan Nowlin * @rg_list: recipe groupings with protocol-offset pairs 3673fd2a6b71SDan Nowlin * 3674fd2a6b71SDan Nowlin * Helper function to fill in the field vector indices for protocol-offset 3675fd2a6b71SDan Nowlin * pairs. These indexes are then ultimately programmed into a recipe. 3676fd2a6b71SDan Nowlin */ 3677fd2a6b71SDan Nowlin static enum ice_status 3678fd2a6b71SDan Nowlin ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list, 3679fd2a6b71SDan Nowlin struct list_head *rg_list) 3680fd2a6b71SDan Nowlin { 3681fd2a6b71SDan Nowlin struct ice_sw_fv_list_entry *fv; 3682fd2a6b71SDan Nowlin struct ice_recp_grp_entry *rg; 3683fd2a6b71SDan Nowlin struct ice_fv_word *fv_ext; 3684fd2a6b71SDan Nowlin 3685fd2a6b71SDan Nowlin if (list_empty(fv_list)) 3686fd2a6b71SDan Nowlin return 0; 3687fd2a6b71SDan Nowlin 3688fd2a6b71SDan Nowlin fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry, 3689fd2a6b71SDan Nowlin list_entry); 3690fd2a6b71SDan Nowlin fv_ext = fv->fv_ptr->ew; 3691fd2a6b71SDan Nowlin 3692fd2a6b71SDan Nowlin list_for_each_entry(rg, rg_list, l_entry) { 3693fd2a6b71SDan Nowlin u8 i; 3694fd2a6b71SDan Nowlin 3695fd2a6b71SDan Nowlin for (i = 0; i < rg->r_group.n_val_pairs; i++) { 3696fd2a6b71SDan Nowlin struct ice_fv_word *pr; 3697fd2a6b71SDan Nowlin bool found = false; 3698fd2a6b71SDan Nowlin u16 mask; 3699fd2a6b71SDan Nowlin u8 j; 3700fd2a6b71SDan Nowlin 3701fd2a6b71SDan Nowlin pr = &rg->r_group.pairs[i]; 3702fd2a6b71SDan Nowlin mask = rg->r_group.mask[i]; 3703fd2a6b71SDan Nowlin 3704fd2a6b71SDan Nowlin for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 3705fd2a6b71SDan Nowlin if (fv_ext[j].prot_id == pr->prot_id && 3706fd2a6b71SDan Nowlin fv_ext[j].off == pr->off) { 3707fd2a6b71SDan Nowlin found = true; 3708fd2a6b71SDan Nowlin 3709fd2a6b71SDan Nowlin /* Store index of field vector */ 3710fd2a6b71SDan Nowlin rg->fv_idx[i] = j; 3711fd2a6b71SDan Nowlin rg->fv_mask[i] = mask; 3712fd2a6b71SDan Nowlin break; 3713fd2a6b71SDan Nowlin } 3714fd2a6b71SDan Nowlin 3715fd2a6b71SDan Nowlin /* Protocol/offset could not be found, caller gave an 3716fd2a6b71SDan Nowlin * invalid pair 3717fd2a6b71SDan Nowlin */ 3718fd2a6b71SDan Nowlin if (!found) 3719fd2a6b71SDan Nowlin return ICE_ERR_PARAM; 3720fd2a6b71SDan Nowlin } 3721fd2a6b71SDan Nowlin } 3722fd2a6b71SDan Nowlin 3723fd2a6b71SDan Nowlin return 0; 3724fd2a6b71SDan Nowlin } 3725fd2a6b71SDan Nowlin 3726fd2a6b71SDan Nowlin /** 3727fd2a6b71SDan Nowlin * ice_find_free_recp_res_idx - find free result indexes for recipe 3728fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 3729fd2a6b71SDan Nowlin * @profiles: bitmap of profiles that will be associated with the new recipe 3730fd2a6b71SDan Nowlin * @free_idx: pointer to variable to receive the free index bitmap 3731fd2a6b71SDan Nowlin * 3732fd2a6b71SDan Nowlin * The algorithm used here is: 3733fd2a6b71SDan Nowlin * 1. When creating a new recipe, create a set P which contains all 3734fd2a6b71SDan Nowlin * Profiles that will be associated with our new recipe 3735fd2a6b71SDan Nowlin * 3736fd2a6b71SDan Nowlin * 2. For each Profile p in set P: 3737fd2a6b71SDan Nowlin * a. Add all recipes associated with Profile p into set R 3738fd2a6b71SDan Nowlin * b. Optional : PossibleIndexes &= profile[p].possibleIndexes 3739fd2a6b71SDan Nowlin * [initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF] 3740fd2a6b71SDan Nowlin * i. Or just assume they all have the same possible indexes: 3741fd2a6b71SDan Nowlin * 44, 45, 46, 47 3742fd2a6b71SDan Nowlin * i.e., PossibleIndexes = 0x0000F00000000000 3743fd2a6b71SDan Nowlin * 3744fd2a6b71SDan Nowlin * 3. For each Recipe r in set R: 3745fd2a6b71SDan Nowlin * a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes 3746fd2a6b71SDan Nowlin * b. FreeIndexes = UsedIndexes ^ PossibleIndexes 3747fd2a6b71SDan Nowlin * 3748fd2a6b71SDan Nowlin * FreeIndexes will contain the bits indicating the indexes free for use, 3749fd2a6b71SDan Nowlin * then the code needs to update the recipe[r].used_result_idx_bits to 3750fd2a6b71SDan Nowlin * indicate which indexes were selected for use by this recipe. 3751fd2a6b71SDan Nowlin */ 3752fd2a6b71SDan Nowlin static u16 3753fd2a6b71SDan Nowlin ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles, 3754fd2a6b71SDan Nowlin unsigned long *free_idx) 3755fd2a6b71SDan Nowlin { 3756fd2a6b71SDan Nowlin DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS); 3757fd2a6b71SDan Nowlin DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES); 3758fd2a6b71SDan Nowlin DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS); 3759fd2a6b71SDan Nowlin u16 bit; 3760fd2a6b71SDan Nowlin 3761fd2a6b71SDan Nowlin bitmap_zero(possible_idx, ICE_MAX_FV_WORDS); 3762fd2a6b71SDan Nowlin bitmap_zero(recipes, ICE_MAX_NUM_RECIPES); 3763fd2a6b71SDan Nowlin bitmap_zero(used_idx, ICE_MAX_FV_WORDS); 3764fd2a6b71SDan Nowlin bitmap_zero(free_idx, ICE_MAX_FV_WORDS); 3765fd2a6b71SDan Nowlin 3766fd2a6b71SDan Nowlin bitmap_set(possible_idx, 0, ICE_MAX_FV_WORDS); 3767fd2a6b71SDan Nowlin 3768fd2a6b71SDan Nowlin /* For each profile we are going to associate the recipe with, add the 3769fd2a6b71SDan Nowlin * recipes that are associated with that profile. This will give us 3770fd2a6b71SDan Nowlin * the set of recipes that our recipe may collide with. Also, determine 3771fd2a6b71SDan Nowlin * what possible result indexes are usable given this set of profiles. 3772fd2a6b71SDan Nowlin */ 3773fd2a6b71SDan Nowlin for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) { 3774fd2a6b71SDan Nowlin bitmap_or(recipes, recipes, profile_to_recipe[bit], 3775fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 3776fd2a6b71SDan Nowlin bitmap_and(possible_idx, possible_idx, 3777fd2a6b71SDan Nowlin hw->switch_info->prof_res_bm[bit], 3778fd2a6b71SDan Nowlin ICE_MAX_FV_WORDS); 3779fd2a6b71SDan Nowlin } 3780fd2a6b71SDan Nowlin 3781fd2a6b71SDan Nowlin /* For each recipe that our new recipe may collide with, determine 3782fd2a6b71SDan Nowlin * which indexes have been used. 3783fd2a6b71SDan Nowlin */ 3784fd2a6b71SDan Nowlin for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES) 3785fd2a6b71SDan Nowlin bitmap_or(used_idx, used_idx, 3786fd2a6b71SDan Nowlin hw->switch_info->recp_list[bit].res_idxs, 3787fd2a6b71SDan Nowlin ICE_MAX_FV_WORDS); 3788fd2a6b71SDan Nowlin 3789fd2a6b71SDan Nowlin bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS); 3790fd2a6b71SDan Nowlin 3791fd2a6b71SDan Nowlin /* return number of free indexes */ 3792fd2a6b71SDan Nowlin return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS); 3793fd2a6b71SDan Nowlin } 3794fd2a6b71SDan Nowlin 3795fd2a6b71SDan Nowlin /** 3796fd2a6b71SDan Nowlin * ice_add_sw_recipe - function to call AQ calls to create switch recipe 3797fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 3798fd2a6b71SDan Nowlin * @rm: recipe management list entry 3799fd2a6b71SDan Nowlin * @match_tun_mask: tunnel mask that needs to be programmed 3800fd2a6b71SDan Nowlin * @profiles: bitmap of profiles that will be associated. 3801fd2a6b71SDan Nowlin */ 3802fd2a6b71SDan Nowlin static enum ice_status 3803fd2a6b71SDan Nowlin ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm, 3804fd2a6b71SDan Nowlin u16 match_tun_mask, unsigned long *profiles) 3805fd2a6b71SDan Nowlin { 3806fd2a6b71SDan Nowlin DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS); 3807fd2a6b71SDan Nowlin struct ice_aqc_recipe_data_elem *tmp; 3808fd2a6b71SDan Nowlin struct ice_aqc_recipe_data_elem *buf; 3809fd2a6b71SDan Nowlin struct ice_recp_grp_entry *entry; 3810fd2a6b71SDan Nowlin enum ice_status status; 3811fd2a6b71SDan Nowlin u16 free_res_idx; 3812fd2a6b71SDan Nowlin u16 recipe_count; 3813fd2a6b71SDan Nowlin u8 chain_idx; 3814fd2a6b71SDan Nowlin u8 recps = 0; 3815fd2a6b71SDan Nowlin 3816fd2a6b71SDan Nowlin /* When more than one recipe are required, another recipe is needed to 3817fd2a6b71SDan Nowlin * chain them together. Matching a tunnel metadata ID takes up one of 3818fd2a6b71SDan Nowlin * the match fields in the chaining recipe reducing the number of 3819fd2a6b71SDan Nowlin * chained recipes by one. 3820fd2a6b71SDan Nowlin */ 3821fd2a6b71SDan Nowlin /* check number of free result indices */ 3822fd2a6b71SDan Nowlin bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS); 3823fd2a6b71SDan Nowlin free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm); 3824fd2a6b71SDan Nowlin 3825fd2a6b71SDan Nowlin ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n", 3826fd2a6b71SDan Nowlin free_res_idx, rm->n_grp_count); 3827fd2a6b71SDan Nowlin 3828fd2a6b71SDan Nowlin if (rm->n_grp_count > 1) { 3829fd2a6b71SDan Nowlin if (rm->n_grp_count > free_res_idx) 3830fd2a6b71SDan Nowlin return ICE_ERR_MAX_LIMIT; 3831fd2a6b71SDan Nowlin 3832fd2a6b71SDan Nowlin rm->n_grp_count++; 3833fd2a6b71SDan Nowlin } 3834fd2a6b71SDan Nowlin 3835fd2a6b71SDan Nowlin if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE) 3836fd2a6b71SDan Nowlin return ICE_ERR_MAX_LIMIT; 3837fd2a6b71SDan Nowlin 3838fd2a6b71SDan Nowlin tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL); 3839fd2a6b71SDan Nowlin if (!tmp) 3840fd2a6b71SDan Nowlin return ICE_ERR_NO_MEMORY; 3841fd2a6b71SDan Nowlin 3842fd2a6b71SDan Nowlin buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf), 3843fd2a6b71SDan Nowlin GFP_KERNEL); 3844fd2a6b71SDan Nowlin if (!buf) { 3845fd2a6b71SDan Nowlin status = ICE_ERR_NO_MEMORY; 3846fd2a6b71SDan Nowlin goto err_mem; 3847fd2a6b71SDan Nowlin } 3848fd2a6b71SDan Nowlin 3849fd2a6b71SDan Nowlin bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES); 3850fd2a6b71SDan Nowlin recipe_count = ICE_MAX_NUM_RECIPES; 3851fd2a6b71SDan Nowlin status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC, 3852fd2a6b71SDan Nowlin NULL); 3853fd2a6b71SDan Nowlin if (status || recipe_count == 0) 3854fd2a6b71SDan Nowlin goto err_unroll; 3855fd2a6b71SDan Nowlin 3856fd2a6b71SDan Nowlin /* Allocate the recipe resources, and configure them according to the 3857fd2a6b71SDan Nowlin * match fields from protocol headers and extracted field vectors. 3858fd2a6b71SDan Nowlin */ 3859fd2a6b71SDan Nowlin chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS); 3860fd2a6b71SDan Nowlin list_for_each_entry(entry, &rm->rg_list, l_entry) { 3861fd2a6b71SDan Nowlin u8 i; 3862fd2a6b71SDan Nowlin 3863fd2a6b71SDan Nowlin status = ice_alloc_recipe(hw, &entry->rid); 3864fd2a6b71SDan Nowlin if (status) 3865fd2a6b71SDan Nowlin goto err_unroll; 3866fd2a6b71SDan Nowlin 3867fd2a6b71SDan Nowlin /* Clear the result index of the located recipe, as this will be 3868fd2a6b71SDan Nowlin * updated, if needed, later in the recipe creation process. 3869fd2a6b71SDan Nowlin */ 3870fd2a6b71SDan Nowlin tmp[0].content.result_indx = 0; 3871fd2a6b71SDan Nowlin 3872fd2a6b71SDan Nowlin buf[recps] = tmp[0]; 3873fd2a6b71SDan Nowlin buf[recps].recipe_indx = (u8)entry->rid; 3874fd2a6b71SDan Nowlin /* if the recipe is a non-root recipe RID should be programmed 3875fd2a6b71SDan Nowlin * as 0 for the rules to be applied correctly. 3876fd2a6b71SDan Nowlin */ 3877fd2a6b71SDan Nowlin buf[recps].content.rid = 0; 3878fd2a6b71SDan Nowlin memset(&buf[recps].content.lkup_indx, 0, 3879fd2a6b71SDan Nowlin sizeof(buf[recps].content.lkup_indx)); 3880fd2a6b71SDan Nowlin 3881fd2a6b71SDan Nowlin /* All recipes use look-up index 0 to match switch ID. */ 3882fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; 3883fd2a6b71SDan Nowlin buf[recps].content.mask[0] = 3884fd2a6b71SDan Nowlin cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); 3885fd2a6b71SDan Nowlin /* Setup lkup_indx 1..4 to INVALID/ignore and set the mask 3886fd2a6b71SDan Nowlin * to be 0 3887fd2a6b71SDan Nowlin */ 3888fd2a6b71SDan Nowlin for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { 3889fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = 0x80; 3890fd2a6b71SDan Nowlin buf[recps].content.mask[i] = 0; 3891fd2a6b71SDan Nowlin } 3892fd2a6b71SDan Nowlin 3893fd2a6b71SDan Nowlin for (i = 0; i < entry->r_group.n_val_pairs; i++) { 3894fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i]; 3895fd2a6b71SDan Nowlin buf[recps].content.mask[i + 1] = 3896fd2a6b71SDan Nowlin cpu_to_le16(entry->fv_mask[i]); 3897fd2a6b71SDan Nowlin } 3898fd2a6b71SDan Nowlin 3899fd2a6b71SDan Nowlin if (rm->n_grp_count > 1) { 3900fd2a6b71SDan Nowlin /* Checks to see if there really is a valid result index 3901fd2a6b71SDan Nowlin * that can be used. 3902fd2a6b71SDan Nowlin */ 3903fd2a6b71SDan Nowlin if (chain_idx >= ICE_MAX_FV_WORDS) { 3904fd2a6b71SDan Nowlin ice_debug(hw, ICE_DBG_SW, "No chain index available\n"); 3905fd2a6b71SDan Nowlin status = ICE_ERR_MAX_LIMIT; 3906fd2a6b71SDan Nowlin goto err_unroll; 3907fd2a6b71SDan Nowlin } 3908fd2a6b71SDan Nowlin 3909fd2a6b71SDan Nowlin entry->chain_idx = chain_idx; 3910fd2a6b71SDan Nowlin buf[recps].content.result_indx = 3911fd2a6b71SDan Nowlin ICE_AQ_RECIPE_RESULT_EN | 3912fd2a6b71SDan Nowlin ((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) & 3913fd2a6b71SDan Nowlin ICE_AQ_RECIPE_RESULT_DATA_M); 3914fd2a6b71SDan Nowlin clear_bit(chain_idx, result_idx_bm); 3915fd2a6b71SDan Nowlin chain_idx = find_first_bit(result_idx_bm, 3916fd2a6b71SDan Nowlin ICE_MAX_FV_WORDS); 3917fd2a6b71SDan Nowlin } 3918fd2a6b71SDan Nowlin 3919fd2a6b71SDan Nowlin /* fill recipe dependencies */ 3920fd2a6b71SDan Nowlin bitmap_zero((unsigned long *)buf[recps].recipe_bitmap, 3921fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 3922fd2a6b71SDan Nowlin set_bit(buf[recps].recipe_indx, 3923fd2a6b71SDan Nowlin (unsigned long *)buf[recps].recipe_bitmap); 3924fd2a6b71SDan Nowlin buf[recps].content.act_ctrl_fwd_priority = rm->priority; 3925fd2a6b71SDan Nowlin recps++; 3926fd2a6b71SDan Nowlin } 3927fd2a6b71SDan Nowlin 3928fd2a6b71SDan Nowlin if (rm->n_grp_count == 1) { 3929fd2a6b71SDan Nowlin rm->root_rid = buf[0].recipe_indx; 3930fd2a6b71SDan Nowlin set_bit(buf[0].recipe_indx, rm->r_bitmap); 3931fd2a6b71SDan Nowlin buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT; 3932fd2a6b71SDan Nowlin if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) { 3933fd2a6b71SDan Nowlin memcpy(buf[0].recipe_bitmap, rm->r_bitmap, 3934fd2a6b71SDan Nowlin sizeof(buf[0].recipe_bitmap)); 3935fd2a6b71SDan Nowlin } else { 3936fd2a6b71SDan Nowlin status = ICE_ERR_BAD_PTR; 3937fd2a6b71SDan Nowlin goto err_unroll; 3938fd2a6b71SDan Nowlin } 3939fd2a6b71SDan Nowlin /* Applicable only for ROOT_RECIPE, set the fwd_priority for 3940fd2a6b71SDan Nowlin * the recipe which is getting created if specified 3941fd2a6b71SDan Nowlin * by user. Usually any advanced switch filter, which results 3942fd2a6b71SDan Nowlin * into new extraction sequence, ended up creating a new recipe 3943fd2a6b71SDan Nowlin * of type ROOT and usually recipes are associated with profiles 3944fd2a6b71SDan Nowlin * Switch rule referreing newly created recipe, needs to have 3945fd2a6b71SDan Nowlin * either/or 'fwd' or 'join' priority, otherwise switch rule 3946fd2a6b71SDan Nowlin * evaluation will not happen correctly. In other words, if 3947fd2a6b71SDan Nowlin * switch rule to be evaluated on priority basis, then recipe 3948fd2a6b71SDan Nowlin * needs to have priority, otherwise it will be evaluated last. 3949fd2a6b71SDan Nowlin */ 3950fd2a6b71SDan Nowlin buf[0].content.act_ctrl_fwd_priority = rm->priority; 3951fd2a6b71SDan Nowlin } else { 3952fd2a6b71SDan Nowlin struct ice_recp_grp_entry *last_chain_entry; 3953fd2a6b71SDan Nowlin u16 rid, i; 3954fd2a6b71SDan Nowlin 3955fd2a6b71SDan Nowlin /* Allocate the last recipe that will chain the outcomes of the 3956fd2a6b71SDan Nowlin * other recipes together 3957fd2a6b71SDan Nowlin */ 3958fd2a6b71SDan Nowlin status = ice_alloc_recipe(hw, &rid); 3959fd2a6b71SDan Nowlin if (status) 3960fd2a6b71SDan Nowlin goto err_unroll; 3961fd2a6b71SDan Nowlin 3962fd2a6b71SDan Nowlin buf[recps].recipe_indx = (u8)rid; 3963fd2a6b71SDan Nowlin buf[recps].content.rid = (u8)rid; 3964fd2a6b71SDan Nowlin buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT; 3965fd2a6b71SDan Nowlin /* the new entry created should also be part of rg_list to 3966fd2a6b71SDan Nowlin * make sure we have complete recipe 3967fd2a6b71SDan Nowlin */ 3968fd2a6b71SDan Nowlin last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw), 3969fd2a6b71SDan Nowlin sizeof(*last_chain_entry), 3970fd2a6b71SDan Nowlin GFP_KERNEL); 3971fd2a6b71SDan Nowlin if (!last_chain_entry) { 3972fd2a6b71SDan Nowlin status = ICE_ERR_NO_MEMORY; 3973fd2a6b71SDan Nowlin goto err_unroll; 3974fd2a6b71SDan Nowlin } 3975fd2a6b71SDan Nowlin last_chain_entry->rid = rid; 3976fd2a6b71SDan Nowlin memset(&buf[recps].content.lkup_indx, 0, 3977fd2a6b71SDan Nowlin sizeof(buf[recps].content.lkup_indx)); 3978fd2a6b71SDan Nowlin /* All recipes use look-up index 0 to match switch ID. */ 3979fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; 3980fd2a6b71SDan Nowlin buf[recps].content.mask[0] = 3981fd2a6b71SDan Nowlin cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); 3982fd2a6b71SDan Nowlin for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { 3983fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = 3984fd2a6b71SDan Nowlin ICE_AQ_RECIPE_LKUP_IGNORE; 3985fd2a6b71SDan Nowlin buf[recps].content.mask[i] = 0; 3986fd2a6b71SDan Nowlin } 3987fd2a6b71SDan Nowlin 3988fd2a6b71SDan Nowlin i = 1; 3989fd2a6b71SDan Nowlin /* update r_bitmap with the recp that is used for chaining */ 3990fd2a6b71SDan Nowlin set_bit(rid, rm->r_bitmap); 3991fd2a6b71SDan Nowlin /* this is the recipe that chains all the other recipes so it 3992fd2a6b71SDan Nowlin * should not have a chaining ID to indicate the same 3993fd2a6b71SDan Nowlin */ 3994fd2a6b71SDan Nowlin last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND; 3995fd2a6b71SDan Nowlin list_for_each_entry(entry, &rm->rg_list, l_entry) { 3996fd2a6b71SDan Nowlin last_chain_entry->fv_idx[i] = entry->chain_idx; 3997fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = entry->chain_idx; 3998fd2a6b71SDan Nowlin buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF); 3999fd2a6b71SDan Nowlin set_bit(entry->rid, rm->r_bitmap); 4000fd2a6b71SDan Nowlin } 4001fd2a6b71SDan Nowlin list_add(&last_chain_entry->l_entry, &rm->rg_list); 4002fd2a6b71SDan Nowlin if (sizeof(buf[recps].recipe_bitmap) >= 4003fd2a6b71SDan Nowlin sizeof(rm->r_bitmap)) { 4004fd2a6b71SDan Nowlin memcpy(buf[recps].recipe_bitmap, rm->r_bitmap, 4005fd2a6b71SDan Nowlin sizeof(buf[recps].recipe_bitmap)); 4006fd2a6b71SDan Nowlin } else { 4007fd2a6b71SDan Nowlin status = ICE_ERR_BAD_PTR; 4008fd2a6b71SDan Nowlin goto err_unroll; 4009fd2a6b71SDan Nowlin } 4010fd2a6b71SDan Nowlin buf[recps].content.act_ctrl_fwd_priority = rm->priority; 4011fd2a6b71SDan Nowlin 4012fd2a6b71SDan Nowlin /* To differentiate among different UDP tunnels, a meta data ID 4013fd2a6b71SDan Nowlin * flag is used. 4014fd2a6b71SDan Nowlin */ 4015fd2a6b71SDan Nowlin if (match_tun_mask) { 4016fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = ICE_TUN_FLAG_FV_IND; 4017fd2a6b71SDan Nowlin buf[recps].content.mask[i] = 4018fd2a6b71SDan Nowlin cpu_to_le16(match_tun_mask); 4019fd2a6b71SDan Nowlin } 4020fd2a6b71SDan Nowlin 4021fd2a6b71SDan Nowlin recps++; 4022fd2a6b71SDan Nowlin rm->root_rid = (u8)rid; 4023fd2a6b71SDan Nowlin } 4024fd2a6b71SDan Nowlin status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 4025fd2a6b71SDan Nowlin if (status) 4026fd2a6b71SDan Nowlin goto err_unroll; 4027fd2a6b71SDan Nowlin 4028fd2a6b71SDan Nowlin status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL); 4029fd2a6b71SDan Nowlin ice_release_change_lock(hw); 4030fd2a6b71SDan Nowlin if (status) 4031fd2a6b71SDan Nowlin goto err_unroll; 4032fd2a6b71SDan Nowlin 4033fd2a6b71SDan Nowlin /* Every recipe that just got created add it to the recipe 4034fd2a6b71SDan Nowlin * book keeping list 4035fd2a6b71SDan Nowlin */ 4036fd2a6b71SDan Nowlin list_for_each_entry(entry, &rm->rg_list, l_entry) { 4037fd2a6b71SDan Nowlin struct ice_switch_info *sw = hw->switch_info; 4038fd2a6b71SDan Nowlin bool is_root, idx_found = false; 4039fd2a6b71SDan Nowlin struct ice_sw_recipe *recp; 4040fd2a6b71SDan Nowlin u16 idx, buf_idx = 0; 4041fd2a6b71SDan Nowlin 4042fd2a6b71SDan Nowlin /* find buffer index for copying some data */ 4043fd2a6b71SDan Nowlin for (idx = 0; idx < rm->n_grp_count; idx++) 4044fd2a6b71SDan Nowlin if (buf[idx].recipe_indx == entry->rid) { 4045fd2a6b71SDan Nowlin buf_idx = idx; 4046fd2a6b71SDan Nowlin idx_found = true; 4047fd2a6b71SDan Nowlin } 4048fd2a6b71SDan Nowlin 4049fd2a6b71SDan Nowlin if (!idx_found) { 4050fd2a6b71SDan Nowlin status = ICE_ERR_OUT_OF_RANGE; 4051fd2a6b71SDan Nowlin goto err_unroll; 4052fd2a6b71SDan Nowlin } 4053fd2a6b71SDan Nowlin 4054fd2a6b71SDan Nowlin recp = &sw->recp_list[entry->rid]; 4055fd2a6b71SDan Nowlin is_root = (rm->root_rid == entry->rid); 4056fd2a6b71SDan Nowlin recp->is_root = is_root; 4057fd2a6b71SDan Nowlin 4058fd2a6b71SDan Nowlin recp->root_rid = entry->rid; 4059fd2a6b71SDan Nowlin recp->big_recp = (is_root && rm->n_grp_count > 1); 4060fd2a6b71SDan Nowlin 4061fd2a6b71SDan Nowlin memcpy(&recp->ext_words, entry->r_group.pairs, 4062fd2a6b71SDan Nowlin entry->r_group.n_val_pairs * sizeof(struct ice_fv_word)); 4063fd2a6b71SDan Nowlin 4064fd2a6b71SDan Nowlin memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap, 4065fd2a6b71SDan Nowlin sizeof(recp->r_bitmap)); 4066fd2a6b71SDan Nowlin 4067fd2a6b71SDan Nowlin /* Copy non-result fv index values and masks to recipe. This 4068fd2a6b71SDan Nowlin * call will also update the result recipe bitmask. 4069fd2a6b71SDan Nowlin */ 4070fd2a6b71SDan Nowlin ice_collect_result_idx(&buf[buf_idx], recp); 4071fd2a6b71SDan Nowlin 4072fd2a6b71SDan Nowlin /* for non-root recipes, also copy to the root, this allows 4073fd2a6b71SDan Nowlin * easier matching of a complete chained recipe 4074fd2a6b71SDan Nowlin */ 4075fd2a6b71SDan Nowlin if (!is_root) 4076fd2a6b71SDan Nowlin ice_collect_result_idx(&buf[buf_idx], 4077fd2a6b71SDan Nowlin &sw->recp_list[rm->root_rid]); 4078fd2a6b71SDan Nowlin 4079fd2a6b71SDan Nowlin recp->n_ext_words = entry->r_group.n_val_pairs; 4080fd2a6b71SDan Nowlin recp->chain_idx = entry->chain_idx; 4081fd2a6b71SDan Nowlin recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority; 4082fd2a6b71SDan Nowlin recp->n_grp_count = rm->n_grp_count; 4083fd2a6b71SDan Nowlin recp->recp_created = true; 4084fd2a6b71SDan Nowlin } 4085fd2a6b71SDan Nowlin rm->root_buf = buf; 4086fd2a6b71SDan Nowlin kfree(tmp); 4087fd2a6b71SDan Nowlin return status; 4088fd2a6b71SDan Nowlin 4089fd2a6b71SDan Nowlin err_unroll: 4090fd2a6b71SDan Nowlin err_mem: 4091fd2a6b71SDan Nowlin kfree(tmp); 4092fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), buf); 4093fd2a6b71SDan Nowlin return status; 4094fd2a6b71SDan Nowlin } 4095fd2a6b71SDan Nowlin 4096fd2a6b71SDan Nowlin /** 4097fd2a6b71SDan Nowlin * ice_create_recipe_group - creates recipe group 4098fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4099fd2a6b71SDan Nowlin * @rm: recipe management list entry 4100fd2a6b71SDan Nowlin * @lkup_exts: lookup elements 4101fd2a6b71SDan Nowlin */ 4102fd2a6b71SDan Nowlin static enum ice_status 4103fd2a6b71SDan Nowlin ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm, 4104fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts) 4105fd2a6b71SDan Nowlin { 4106fd2a6b71SDan Nowlin enum ice_status status; 4107fd2a6b71SDan Nowlin u8 recp_count = 0; 4108fd2a6b71SDan Nowlin 4109fd2a6b71SDan Nowlin rm->n_grp_count = 0; 4110fd2a6b71SDan Nowlin 4111fd2a6b71SDan Nowlin /* Create recipes for words that are marked not done by packing them 4112fd2a6b71SDan Nowlin * as best fit. 4113fd2a6b71SDan Nowlin */ 4114fd2a6b71SDan Nowlin status = ice_create_first_fit_recp_def(hw, lkup_exts, 4115fd2a6b71SDan Nowlin &rm->rg_list, &recp_count); 4116fd2a6b71SDan Nowlin if (!status) { 4117fd2a6b71SDan Nowlin rm->n_grp_count += recp_count; 4118fd2a6b71SDan Nowlin rm->n_ext_words = lkup_exts->n_val_words; 4119fd2a6b71SDan Nowlin memcpy(&rm->ext_words, lkup_exts->fv_words, 4120fd2a6b71SDan Nowlin sizeof(rm->ext_words)); 4121fd2a6b71SDan Nowlin memcpy(rm->word_masks, lkup_exts->field_mask, 4122fd2a6b71SDan Nowlin sizeof(rm->word_masks)); 4123fd2a6b71SDan Nowlin } 4124fd2a6b71SDan Nowlin 4125fd2a6b71SDan Nowlin return status; 4126fd2a6b71SDan Nowlin } 4127fd2a6b71SDan Nowlin 4128fd2a6b71SDan Nowlin /** 4129fd2a6b71SDan Nowlin * ice_get_fv - get field vectors/extraction sequences for spec. lookup types 4130fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4131fd2a6b71SDan Nowlin * @lkups: lookup elements or match criteria for the advanced recipe, one 4132fd2a6b71SDan Nowlin * structure per protocol header 4133fd2a6b71SDan Nowlin * @lkups_cnt: number of protocols 4134fd2a6b71SDan Nowlin * @bm: bitmap of field vectors to consider 4135fd2a6b71SDan Nowlin * @fv_list: pointer to a list that holds the returned field vectors 4136fd2a6b71SDan Nowlin */ 4137fd2a6b71SDan Nowlin static enum ice_status 4138fd2a6b71SDan Nowlin ice_get_fv(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, 4139fd2a6b71SDan Nowlin unsigned long *bm, struct list_head *fv_list) 4140fd2a6b71SDan Nowlin { 4141fd2a6b71SDan Nowlin enum ice_status status; 4142fd2a6b71SDan Nowlin u8 *prot_ids; 4143fd2a6b71SDan Nowlin u16 i; 4144fd2a6b71SDan Nowlin 4145fd2a6b71SDan Nowlin prot_ids = kcalloc(lkups_cnt, sizeof(*prot_ids), GFP_KERNEL); 4146fd2a6b71SDan Nowlin if (!prot_ids) 4147fd2a6b71SDan Nowlin return ICE_ERR_NO_MEMORY; 4148fd2a6b71SDan Nowlin 4149fd2a6b71SDan Nowlin for (i = 0; i < lkups_cnt; i++) 4150fd2a6b71SDan Nowlin if (!ice_prot_type_to_id(lkups[i].type, &prot_ids[i])) { 4151fd2a6b71SDan Nowlin status = ICE_ERR_CFG; 4152fd2a6b71SDan Nowlin goto free_mem; 4153fd2a6b71SDan Nowlin } 4154fd2a6b71SDan Nowlin 4155fd2a6b71SDan Nowlin /* Find field vectors that include all specified protocol types */ 4156fd2a6b71SDan Nowlin status = ice_get_sw_fv_list(hw, prot_ids, lkups_cnt, bm, fv_list); 4157fd2a6b71SDan Nowlin 4158fd2a6b71SDan Nowlin free_mem: 4159fd2a6b71SDan Nowlin kfree(prot_ids); 4160fd2a6b71SDan Nowlin return status; 4161fd2a6b71SDan Nowlin } 4162fd2a6b71SDan Nowlin 4163fd2a6b71SDan Nowlin /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule 4164fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4165fd2a6b71SDan Nowlin * @rinfo: other information regarding the rule e.g. priority and action info 4166fd2a6b71SDan Nowlin * @bm: pointer to memory for returning the bitmap of field vectors 4167fd2a6b71SDan Nowlin */ 4168fd2a6b71SDan Nowlin static void 4169fd2a6b71SDan Nowlin ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo, 4170fd2a6b71SDan Nowlin unsigned long *bm) 4171fd2a6b71SDan Nowlin { 4172fd2a6b71SDan Nowlin bitmap_zero(bm, ICE_MAX_NUM_PROFILES); 4173fd2a6b71SDan Nowlin 4174fd2a6b71SDan Nowlin ice_get_sw_fv_bitmap(hw, ICE_PROF_NON_TUN, bm); 4175fd2a6b71SDan Nowlin } 4176fd2a6b71SDan Nowlin 4177fd2a6b71SDan Nowlin /** 4178fd2a6b71SDan Nowlin * ice_add_adv_recipe - Add an advanced recipe that is not part of the default 4179fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4180fd2a6b71SDan Nowlin * @lkups: lookup elements or match criteria for the advanced recipe, one 4181fd2a6b71SDan Nowlin * structure per protocol header 4182fd2a6b71SDan Nowlin * @lkups_cnt: number of protocols 4183fd2a6b71SDan Nowlin * @rinfo: other information regarding the rule e.g. priority and action info 4184fd2a6b71SDan Nowlin * @rid: return the recipe ID of the recipe created 4185fd2a6b71SDan Nowlin */ 41860f94570dSGrishma Kotecha static enum ice_status 4187fd2a6b71SDan Nowlin ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 4188fd2a6b71SDan Nowlin u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid) 4189fd2a6b71SDan Nowlin { 4190fd2a6b71SDan Nowlin DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES); 4191fd2a6b71SDan Nowlin DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES); 4192fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts; 4193fd2a6b71SDan Nowlin struct ice_recp_grp_entry *r_entry; 4194fd2a6b71SDan Nowlin struct ice_sw_fv_list_entry *fvit; 4195fd2a6b71SDan Nowlin struct ice_recp_grp_entry *r_tmp; 4196fd2a6b71SDan Nowlin struct ice_sw_fv_list_entry *tmp; 4197fd2a6b71SDan Nowlin enum ice_status status = 0; 4198fd2a6b71SDan Nowlin struct ice_sw_recipe *rm; 4199fd2a6b71SDan Nowlin u16 match_tun_mask = 0; 4200fd2a6b71SDan Nowlin u8 i; 4201fd2a6b71SDan Nowlin 4202fd2a6b71SDan Nowlin if (!lkups_cnt) 4203fd2a6b71SDan Nowlin return ICE_ERR_PARAM; 4204fd2a6b71SDan Nowlin 4205fd2a6b71SDan Nowlin lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL); 4206fd2a6b71SDan Nowlin if (!lkup_exts) 4207fd2a6b71SDan Nowlin return ICE_ERR_NO_MEMORY; 4208fd2a6b71SDan Nowlin 4209fd2a6b71SDan Nowlin /* Determine the number of words to be matched and if it exceeds a 4210fd2a6b71SDan Nowlin * recipe's restrictions 4211fd2a6b71SDan Nowlin */ 4212fd2a6b71SDan Nowlin for (i = 0; i < lkups_cnt; i++) { 4213fd2a6b71SDan Nowlin u16 count; 4214fd2a6b71SDan Nowlin 4215fd2a6b71SDan Nowlin if (lkups[i].type >= ICE_PROTOCOL_LAST) { 4216fd2a6b71SDan Nowlin status = ICE_ERR_CFG; 4217fd2a6b71SDan Nowlin goto err_free_lkup_exts; 4218fd2a6b71SDan Nowlin } 4219fd2a6b71SDan Nowlin 4220fd2a6b71SDan Nowlin count = ice_fill_valid_words(&lkups[i], lkup_exts); 4221fd2a6b71SDan Nowlin if (!count) { 4222fd2a6b71SDan Nowlin status = ICE_ERR_CFG; 4223fd2a6b71SDan Nowlin goto err_free_lkup_exts; 4224fd2a6b71SDan Nowlin } 4225fd2a6b71SDan Nowlin } 4226fd2a6b71SDan Nowlin 4227fd2a6b71SDan Nowlin rm = kzalloc(sizeof(*rm), GFP_KERNEL); 4228fd2a6b71SDan Nowlin if (!rm) { 4229fd2a6b71SDan Nowlin status = ICE_ERR_NO_MEMORY; 4230fd2a6b71SDan Nowlin goto err_free_lkup_exts; 4231fd2a6b71SDan Nowlin } 4232fd2a6b71SDan Nowlin 4233fd2a6b71SDan Nowlin /* Get field vectors that contain fields extracted from all the protocol 4234fd2a6b71SDan Nowlin * headers being programmed. 4235fd2a6b71SDan Nowlin */ 4236fd2a6b71SDan Nowlin INIT_LIST_HEAD(&rm->fv_list); 4237fd2a6b71SDan Nowlin INIT_LIST_HEAD(&rm->rg_list); 4238fd2a6b71SDan Nowlin 4239fd2a6b71SDan Nowlin /* Get bitmap of field vectors (profiles) that are compatible with the 4240fd2a6b71SDan Nowlin * rule request; only these will be searched in the subsequent call to 4241fd2a6b71SDan Nowlin * ice_get_fv. 4242fd2a6b71SDan Nowlin */ 4243fd2a6b71SDan Nowlin ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap); 4244fd2a6b71SDan Nowlin 4245fd2a6b71SDan Nowlin status = ice_get_fv(hw, lkups, lkups_cnt, fv_bitmap, &rm->fv_list); 4246fd2a6b71SDan Nowlin if (status) 4247fd2a6b71SDan Nowlin goto err_unroll; 4248fd2a6b71SDan Nowlin 4249fd2a6b71SDan Nowlin /* Group match words into recipes using preferred recipe grouping 4250fd2a6b71SDan Nowlin * criteria. 4251fd2a6b71SDan Nowlin */ 4252fd2a6b71SDan Nowlin status = ice_create_recipe_group(hw, rm, lkup_exts); 4253fd2a6b71SDan Nowlin if (status) 4254fd2a6b71SDan Nowlin goto err_unroll; 4255fd2a6b71SDan Nowlin 4256fd2a6b71SDan Nowlin /* set the recipe priority if specified */ 4257fd2a6b71SDan Nowlin rm->priority = (u8)rinfo->priority; 4258fd2a6b71SDan Nowlin 4259fd2a6b71SDan Nowlin /* Find offsets from the field vector. Pick the first one for all the 4260fd2a6b71SDan Nowlin * recipes. 4261fd2a6b71SDan Nowlin */ 4262fd2a6b71SDan Nowlin status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list); 4263fd2a6b71SDan Nowlin if (status) 4264fd2a6b71SDan Nowlin goto err_unroll; 4265fd2a6b71SDan Nowlin 4266fd2a6b71SDan Nowlin /* get bitmap of all profiles the recipe will be associated with */ 4267fd2a6b71SDan Nowlin bitmap_zero(profiles, ICE_MAX_NUM_PROFILES); 4268fd2a6b71SDan Nowlin list_for_each_entry(fvit, &rm->fv_list, list_entry) { 4269fd2a6b71SDan Nowlin ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id); 4270fd2a6b71SDan Nowlin set_bit((u16)fvit->profile_id, profiles); 4271fd2a6b71SDan Nowlin } 4272fd2a6b71SDan Nowlin 4273fd2a6b71SDan Nowlin /* Look for a recipe which matches our requested fv / mask list */ 4274fd2a6b71SDan Nowlin *rid = ice_find_recp(hw, lkup_exts); 4275fd2a6b71SDan Nowlin if (*rid < ICE_MAX_NUM_RECIPES) 4276fd2a6b71SDan Nowlin /* Success if found a recipe that match the existing criteria */ 4277fd2a6b71SDan Nowlin goto err_unroll; 4278fd2a6b71SDan Nowlin 4279fd2a6b71SDan Nowlin /* Recipe we need does not exist, add a recipe */ 4280fd2a6b71SDan Nowlin status = ice_add_sw_recipe(hw, rm, match_tun_mask, profiles); 4281fd2a6b71SDan Nowlin if (status) 4282fd2a6b71SDan Nowlin goto err_unroll; 4283fd2a6b71SDan Nowlin 4284fd2a6b71SDan Nowlin /* Associate all the recipes created with all the profiles in the 4285fd2a6b71SDan Nowlin * common field vector. 4286fd2a6b71SDan Nowlin */ 4287fd2a6b71SDan Nowlin list_for_each_entry(fvit, &rm->fv_list, list_entry) { 4288fd2a6b71SDan Nowlin DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); 4289fd2a6b71SDan Nowlin u16 j; 4290fd2a6b71SDan Nowlin 4291fd2a6b71SDan Nowlin status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id, 4292fd2a6b71SDan Nowlin (u8 *)r_bitmap, NULL); 4293fd2a6b71SDan Nowlin if (status) 4294fd2a6b71SDan Nowlin goto err_unroll; 4295fd2a6b71SDan Nowlin 4296fd2a6b71SDan Nowlin bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap, 4297fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 4298fd2a6b71SDan Nowlin status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 4299fd2a6b71SDan Nowlin if (status) 4300fd2a6b71SDan Nowlin goto err_unroll; 4301fd2a6b71SDan Nowlin 4302fd2a6b71SDan Nowlin status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id, 4303fd2a6b71SDan Nowlin (u8 *)r_bitmap, 4304fd2a6b71SDan Nowlin NULL); 4305fd2a6b71SDan Nowlin ice_release_change_lock(hw); 4306fd2a6b71SDan Nowlin 4307fd2a6b71SDan Nowlin if (status) 4308fd2a6b71SDan Nowlin goto err_unroll; 4309fd2a6b71SDan Nowlin 4310fd2a6b71SDan Nowlin /* Update profile to recipe bitmap array */ 4311fd2a6b71SDan Nowlin bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap, 4312fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 4313fd2a6b71SDan Nowlin 4314fd2a6b71SDan Nowlin /* Update recipe to profile bitmap array */ 4315fd2a6b71SDan Nowlin for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES) 4316fd2a6b71SDan Nowlin set_bit((u16)fvit->profile_id, recipe_to_profile[j]); 4317fd2a6b71SDan Nowlin } 4318fd2a6b71SDan Nowlin 4319fd2a6b71SDan Nowlin *rid = rm->root_rid; 4320fd2a6b71SDan Nowlin memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts, 4321fd2a6b71SDan Nowlin sizeof(*lkup_exts)); 4322fd2a6b71SDan Nowlin err_unroll: 4323fd2a6b71SDan Nowlin list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) { 4324fd2a6b71SDan Nowlin list_del(&r_entry->l_entry); 4325fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), r_entry); 4326fd2a6b71SDan Nowlin } 4327fd2a6b71SDan Nowlin 4328fd2a6b71SDan Nowlin list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) { 4329fd2a6b71SDan Nowlin list_del(&fvit->list_entry); 4330fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), fvit); 4331fd2a6b71SDan Nowlin } 4332fd2a6b71SDan Nowlin 4333fd2a6b71SDan Nowlin if (rm->root_buf) 4334fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), rm->root_buf); 4335fd2a6b71SDan Nowlin 4336fd2a6b71SDan Nowlin kfree(rm); 4337fd2a6b71SDan Nowlin 4338fd2a6b71SDan Nowlin err_free_lkup_exts: 4339fd2a6b71SDan Nowlin kfree(lkup_exts); 4340fd2a6b71SDan Nowlin 4341fd2a6b71SDan Nowlin return status; 4342fd2a6b71SDan Nowlin } 4343fd2a6b71SDan Nowlin 4344148beb61SHenry Tieman /** 43450f94570dSGrishma Kotecha * ice_find_dummy_packet - find dummy packet 43460f94570dSGrishma Kotecha * 43470f94570dSGrishma Kotecha * @lkups: lookup elements or match criteria for the advanced recipe, one 43480f94570dSGrishma Kotecha * structure per protocol header 43490f94570dSGrishma Kotecha * @lkups_cnt: number of protocols 43500f94570dSGrishma Kotecha * @pkt: dummy packet to fill according to filter match criteria 43510f94570dSGrishma Kotecha * @pkt_len: packet length of dummy packet 43520f94570dSGrishma Kotecha * @offsets: pointer to receive the pointer to the offsets for the packet 43530f94570dSGrishma Kotecha */ 43540f94570dSGrishma Kotecha static void 43550f94570dSGrishma Kotecha ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, 43560f94570dSGrishma Kotecha const u8 **pkt, u16 *pkt_len, 43570f94570dSGrishma Kotecha const struct ice_dummy_pkt_offsets **offsets) 43580f94570dSGrishma Kotecha { 43590f94570dSGrishma Kotecha bool tcp = false, udp = false, ipv6 = false, vlan = false; 43600f94570dSGrishma Kotecha u16 i; 43610f94570dSGrishma Kotecha 43620f94570dSGrishma Kotecha for (i = 0; i < lkups_cnt; i++) { 43630f94570dSGrishma Kotecha if (lkups[i].type == ICE_UDP_ILOS) 43640f94570dSGrishma Kotecha udp = true; 43650f94570dSGrishma Kotecha else if (lkups[i].type == ICE_TCP_IL) 43660f94570dSGrishma Kotecha tcp = true; 43670f94570dSGrishma Kotecha else if (lkups[i].type == ICE_IPV6_OFOS) 43680f94570dSGrishma Kotecha ipv6 = true; 43690f94570dSGrishma Kotecha else if (lkups[i].type == ICE_VLAN_OFOS) 43700f94570dSGrishma Kotecha vlan = true; 43710f94570dSGrishma Kotecha else if (lkups[i].type == ICE_ETYPE_OL && 43720f94570dSGrishma Kotecha lkups[i].h_u.ethertype.ethtype_id == 43730f94570dSGrishma Kotecha cpu_to_be16(ICE_IPV6_ETHER_ID) && 43740f94570dSGrishma Kotecha lkups[i].m_u.ethertype.ethtype_id == 43750f94570dSGrishma Kotecha cpu_to_be16(0xFFFF)) 43760f94570dSGrishma Kotecha ipv6 = true; 43770f94570dSGrishma Kotecha } 43780f94570dSGrishma Kotecha 43790f94570dSGrishma Kotecha if (udp && !ipv6) { 43800f94570dSGrishma Kotecha if (vlan) { 43810f94570dSGrishma Kotecha *pkt = dummy_vlan_udp_packet; 43820f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_udp_packet); 43830f94570dSGrishma Kotecha *offsets = dummy_vlan_udp_packet_offsets; 43840f94570dSGrishma Kotecha return; 43850f94570dSGrishma Kotecha } 43860f94570dSGrishma Kotecha *pkt = dummy_udp_packet; 43870f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_udp_packet); 43880f94570dSGrishma Kotecha *offsets = dummy_udp_packet_offsets; 43890f94570dSGrishma Kotecha return; 43900f94570dSGrishma Kotecha } else if (udp && ipv6) { 43910f94570dSGrishma Kotecha if (vlan) { 43920f94570dSGrishma Kotecha *pkt = dummy_vlan_udp_ipv6_packet; 43930f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_udp_ipv6_packet); 43940f94570dSGrishma Kotecha *offsets = dummy_vlan_udp_ipv6_packet_offsets; 43950f94570dSGrishma Kotecha return; 43960f94570dSGrishma Kotecha } 43970f94570dSGrishma Kotecha *pkt = dummy_udp_ipv6_packet; 43980f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_udp_ipv6_packet); 43990f94570dSGrishma Kotecha *offsets = dummy_udp_ipv6_packet_offsets; 44000f94570dSGrishma Kotecha return; 44010f94570dSGrishma Kotecha } else if ((tcp && ipv6) || ipv6) { 44020f94570dSGrishma Kotecha if (vlan) { 44030f94570dSGrishma Kotecha *pkt = dummy_vlan_tcp_ipv6_packet; 44040f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_tcp_ipv6_packet); 44050f94570dSGrishma Kotecha *offsets = dummy_vlan_tcp_ipv6_packet_offsets; 44060f94570dSGrishma Kotecha return; 44070f94570dSGrishma Kotecha } 44080f94570dSGrishma Kotecha *pkt = dummy_tcp_ipv6_packet; 44090f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_tcp_ipv6_packet); 44100f94570dSGrishma Kotecha *offsets = dummy_tcp_ipv6_packet_offsets; 44110f94570dSGrishma Kotecha return; 44120f94570dSGrishma Kotecha } 44130f94570dSGrishma Kotecha 44140f94570dSGrishma Kotecha if (vlan) { 44150f94570dSGrishma Kotecha *pkt = dummy_vlan_tcp_packet; 44160f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_tcp_packet); 44170f94570dSGrishma Kotecha *offsets = dummy_vlan_tcp_packet_offsets; 44180f94570dSGrishma Kotecha } else { 44190f94570dSGrishma Kotecha *pkt = dummy_tcp_packet; 44200f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_tcp_packet); 44210f94570dSGrishma Kotecha *offsets = dummy_tcp_packet_offsets; 44220f94570dSGrishma Kotecha } 44230f94570dSGrishma Kotecha } 44240f94570dSGrishma Kotecha 44250f94570dSGrishma Kotecha /** 44260f94570dSGrishma Kotecha * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria 44270f94570dSGrishma Kotecha * 44280f94570dSGrishma Kotecha * @lkups: lookup elements or match criteria for the advanced recipe, one 44290f94570dSGrishma Kotecha * structure per protocol header 44300f94570dSGrishma Kotecha * @lkups_cnt: number of protocols 44310f94570dSGrishma Kotecha * @s_rule: stores rule information from the match criteria 44320f94570dSGrishma Kotecha * @dummy_pkt: dummy packet to fill according to filter match criteria 44330f94570dSGrishma Kotecha * @pkt_len: packet length of dummy packet 44340f94570dSGrishma Kotecha * @offsets: offset info for the dummy packet 44350f94570dSGrishma Kotecha */ 44360f94570dSGrishma Kotecha static enum ice_status 44370f94570dSGrishma Kotecha ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, 44380f94570dSGrishma Kotecha struct ice_aqc_sw_rules_elem *s_rule, 44390f94570dSGrishma Kotecha const u8 *dummy_pkt, u16 pkt_len, 44400f94570dSGrishma Kotecha const struct ice_dummy_pkt_offsets *offsets) 44410f94570dSGrishma Kotecha { 44420f94570dSGrishma Kotecha u8 *pkt; 44430f94570dSGrishma Kotecha u16 i; 44440f94570dSGrishma Kotecha 44450f94570dSGrishma Kotecha /* Start with a packet with a pre-defined/dummy content. Then, fill 44460f94570dSGrishma Kotecha * in the header values to be looked up or matched. 44470f94570dSGrishma Kotecha */ 44480f94570dSGrishma Kotecha pkt = s_rule->pdata.lkup_tx_rx.hdr; 44490f94570dSGrishma Kotecha 44500f94570dSGrishma Kotecha memcpy(pkt, dummy_pkt, pkt_len); 44510f94570dSGrishma Kotecha 44520f94570dSGrishma Kotecha for (i = 0; i < lkups_cnt; i++) { 44530f94570dSGrishma Kotecha enum ice_protocol_type type; 44540f94570dSGrishma Kotecha u16 offset = 0, len = 0, j; 44550f94570dSGrishma Kotecha bool found = false; 44560f94570dSGrishma Kotecha 44570f94570dSGrishma Kotecha /* find the start of this layer; it should be found since this 44580f94570dSGrishma Kotecha * was already checked when search for the dummy packet 44590f94570dSGrishma Kotecha */ 44600f94570dSGrishma Kotecha type = lkups[i].type; 44610f94570dSGrishma Kotecha for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) { 44620f94570dSGrishma Kotecha if (type == offsets[j].type) { 44630f94570dSGrishma Kotecha offset = offsets[j].offset; 44640f94570dSGrishma Kotecha found = true; 44650f94570dSGrishma Kotecha break; 44660f94570dSGrishma Kotecha } 44670f94570dSGrishma Kotecha } 44680f94570dSGrishma Kotecha /* this should never happen in a correct calling sequence */ 44690f94570dSGrishma Kotecha if (!found) 44700f94570dSGrishma Kotecha return ICE_ERR_PARAM; 44710f94570dSGrishma Kotecha 44720f94570dSGrishma Kotecha switch (lkups[i].type) { 44730f94570dSGrishma Kotecha case ICE_MAC_OFOS: 44740f94570dSGrishma Kotecha case ICE_MAC_IL: 44750f94570dSGrishma Kotecha len = sizeof(struct ice_ether_hdr); 44760f94570dSGrishma Kotecha break; 44770f94570dSGrishma Kotecha case ICE_ETYPE_OL: 44780f94570dSGrishma Kotecha len = sizeof(struct ice_ethtype_hdr); 44790f94570dSGrishma Kotecha break; 44800f94570dSGrishma Kotecha case ICE_VLAN_OFOS: 44810f94570dSGrishma Kotecha len = sizeof(struct ice_vlan_hdr); 44820f94570dSGrishma Kotecha break; 44830f94570dSGrishma Kotecha case ICE_IPV4_OFOS: 44840f94570dSGrishma Kotecha case ICE_IPV4_IL: 44850f94570dSGrishma Kotecha len = sizeof(struct ice_ipv4_hdr); 44860f94570dSGrishma Kotecha break; 44870f94570dSGrishma Kotecha case ICE_IPV6_OFOS: 44880f94570dSGrishma Kotecha case ICE_IPV6_IL: 44890f94570dSGrishma Kotecha len = sizeof(struct ice_ipv6_hdr); 44900f94570dSGrishma Kotecha break; 44910f94570dSGrishma Kotecha case ICE_TCP_IL: 44920f94570dSGrishma Kotecha case ICE_UDP_OF: 44930f94570dSGrishma Kotecha case ICE_UDP_ILOS: 44940f94570dSGrishma Kotecha len = sizeof(struct ice_l4_hdr); 44950f94570dSGrishma Kotecha break; 44960f94570dSGrishma Kotecha case ICE_SCTP_IL: 44970f94570dSGrishma Kotecha len = sizeof(struct ice_sctp_hdr); 44980f94570dSGrishma Kotecha break; 44990f94570dSGrishma Kotecha default: 45000f94570dSGrishma Kotecha return ICE_ERR_PARAM; 45010f94570dSGrishma Kotecha } 45020f94570dSGrishma Kotecha 45030f94570dSGrishma Kotecha /* the length should be a word multiple */ 45040f94570dSGrishma Kotecha if (len % ICE_BYTES_PER_WORD) 45050f94570dSGrishma Kotecha return ICE_ERR_CFG; 45060f94570dSGrishma Kotecha 45070f94570dSGrishma Kotecha /* We have the offset to the header start, the length, the 45080f94570dSGrishma Kotecha * caller's header values and mask. Use this information to 45090f94570dSGrishma Kotecha * copy the data into the dummy packet appropriately based on 45100f94570dSGrishma Kotecha * the mask. Note that we need to only write the bits as 45110f94570dSGrishma Kotecha * indicated by the mask to make sure we don't improperly write 45120f94570dSGrishma Kotecha * over any significant packet data. 45130f94570dSGrishma Kotecha */ 45140f94570dSGrishma Kotecha for (j = 0; j < len / sizeof(u16); j++) 45150f94570dSGrishma Kotecha if (((u16 *)&lkups[i].m_u)[j]) 45160f94570dSGrishma Kotecha ((u16 *)(pkt + offset))[j] = 45170f94570dSGrishma Kotecha (((u16 *)(pkt + offset))[j] & 45180f94570dSGrishma Kotecha ~((u16 *)&lkups[i].m_u)[j]) | 45190f94570dSGrishma Kotecha (((u16 *)&lkups[i].h_u)[j] & 45200f94570dSGrishma Kotecha ((u16 *)&lkups[i].m_u)[j]); 45210f94570dSGrishma Kotecha } 45220f94570dSGrishma Kotecha 45230f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(pkt_len); 45240f94570dSGrishma Kotecha 45250f94570dSGrishma Kotecha return 0; 45260f94570dSGrishma Kotecha } 45270f94570dSGrishma Kotecha 45280f94570dSGrishma Kotecha /** 45290f94570dSGrishma Kotecha * ice_find_adv_rule_entry - Search a rule entry 45300f94570dSGrishma Kotecha * @hw: pointer to the hardware structure 45310f94570dSGrishma Kotecha * @lkups: lookup elements or match criteria for the advanced recipe, one 45320f94570dSGrishma Kotecha * structure per protocol header 45330f94570dSGrishma Kotecha * @lkups_cnt: number of protocols 45340f94570dSGrishma Kotecha * @recp_id: recipe ID for which we are finding the rule 45350f94570dSGrishma Kotecha * @rinfo: other information regarding the rule e.g. priority and action info 45360f94570dSGrishma Kotecha * 45370f94570dSGrishma Kotecha * Helper function to search for a given advance rule entry 45380f94570dSGrishma Kotecha * Returns pointer to entry storing the rule if found 45390f94570dSGrishma Kotecha */ 45400f94570dSGrishma Kotecha static struct ice_adv_fltr_mgmt_list_entry * 45410f94570dSGrishma Kotecha ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 45420f94570dSGrishma Kotecha u16 lkups_cnt, u16 recp_id, 45430f94570dSGrishma Kotecha struct ice_adv_rule_info *rinfo) 45440f94570dSGrishma Kotecha { 45450f94570dSGrishma Kotecha struct ice_adv_fltr_mgmt_list_entry *list_itr; 45460f94570dSGrishma Kotecha struct ice_switch_info *sw = hw->switch_info; 45470f94570dSGrishma Kotecha int i; 45480f94570dSGrishma Kotecha 45490f94570dSGrishma Kotecha list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules, 45500f94570dSGrishma Kotecha list_entry) { 45510f94570dSGrishma Kotecha bool lkups_matched = true; 45520f94570dSGrishma Kotecha 45530f94570dSGrishma Kotecha if (lkups_cnt != list_itr->lkups_cnt) 45540f94570dSGrishma Kotecha continue; 45550f94570dSGrishma Kotecha for (i = 0; i < list_itr->lkups_cnt; i++) 45560f94570dSGrishma Kotecha if (memcmp(&list_itr->lkups[i], &lkups[i], 45570f94570dSGrishma Kotecha sizeof(*lkups))) { 45580f94570dSGrishma Kotecha lkups_matched = false; 45590f94570dSGrishma Kotecha break; 45600f94570dSGrishma Kotecha } 45610f94570dSGrishma Kotecha if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag && 45620f94570dSGrishma Kotecha lkups_matched) 45630f94570dSGrishma Kotecha return list_itr; 45640f94570dSGrishma Kotecha } 45650f94570dSGrishma Kotecha return NULL; 45660f94570dSGrishma Kotecha } 45670f94570dSGrishma Kotecha 45680f94570dSGrishma Kotecha /** 45690f94570dSGrishma Kotecha * ice_adv_add_update_vsi_list 45700f94570dSGrishma Kotecha * @hw: pointer to the hardware structure 45710f94570dSGrishma Kotecha * @m_entry: pointer to current adv filter management list entry 45720f94570dSGrishma Kotecha * @cur_fltr: filter information from the book keeping entry 45730f94570dSGrishma Kotecha * @new_fltr: filter information with the new VSI to be added 45740f94570dSGrishma Kotecha * 45750f94570dSGrishma Kotecha * Call AQ command to add or update previously created VSI list with new VSI. 45760f94570dSGrishma Kotecha * 45770f94570dSGrishma Kotecha * Helper function to do book keeping associated with adding filter information 45780f94570dSGrishma Kotecha * The algorithm to do the booking keeping is described below : 45790f94570dSGrishma Kotecha * When a VSI needs to subscribe to a given advanced filter 45800f94570dSGrishma Kotecha * if only one VSI has been added till now 45810f94570dSGrishma Kotecha * Allocate a new VSI list and add two VSIs 45820f94570dSGrishma Kotecha * to this list using switch rule command 45830f94570dSGrishma Kotecha * Update the previously created switch rule with the 45840f94570dSGrishma Kotecha * newly created VSI list ID 45850f94570dSGrishma Kotecha * if a VSI list was previously created 45860f94570dSGrishma Kotecha * Add the new VSI to the previously created VSI list set 45870f94570dSGrishma Kotecha * using the update switch rule command 45880f94570dSGrishma Kotecha */ 45890f94570dSGrishma Kotecha static enum ice_status 45900f94570dSGrishma Kotecha ice_adv_add_update_vsi_list(struct ice_hw *hw, 45910f94570dSGrishma Kotecha struct ice_adv_fltr_mgmt_list_entry *m_entry, 45920f94570dSGrishma Kotecha struct ice_adv_rule_info *cur_fltr, 45930f94570dSGrishma Kotecha struct ice_adv_rule_info *new_fltr) 45940f94570dSGrishma Kotecha { 45950f94570dSGrishma Kotecha enum ice_status status; 45960f94570dSGrishma Kotecha u16 vsi_list_id = 0; 45970f94570dSGrishma Kotecha 45980f94570dSGrishma Kotecha if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || 45990f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP || 46000f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET) 46010f94570dSGrishma Kotecha return ICE_ERR_NOT_IMPL; 46020f94570dSGrishma Kotecha 46030f94570dSGrishma Kotecha if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || 46040f94570dSGrishma Kotecha new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) && 46050f94570dSGrishma Kotecha (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI || 46060f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST)) 46070f94570dSGrishma Kotecha return ICE_ERR_NOT_IMPL; 46080f94570dSGrishma Kotecha 46090f94570dSGrishma Kotecha if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { 46100f94570dSGrishma Kotecha /* Only one entry existed in the mapping and it was not already 46110f94570dSGrishma Kotecha * a part of a VSI list. So, create a VSI list with the old and 46120f94570dSGrishma Kotecha * new VSIs. 46130f94570dSGrishma Kotecha */ 46140f94570dSGrishma Kotecha struct ice_fltr_info tmp_fltr; 46150f94570dSGrishma Kotecha u16 vsi_handle_arr[2]; 46160f94570dSGrishma Kotecha 46170f94570dSGrishma Kotecha /* A rule already exists with the new VSI being added */ 46180f94570dSGrishma Kotecha if (cur_fltr->sw_act.fwd_id.hw_vsi_id == 46190f94570dSGrishma Kotecha new_fltr->sw_act.fwd_id.hw_vsi_id) 46200f94570dSGrishma Kotecha return ICE_ERR_ALREADY_EXISTS; 46210f94570dSGrishma Kotecha 46220f94570dSGrishma Kotecha vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle; 46230f94570dSGrishma Kotecha vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle; 46240f94570dSGrishma Kotecha status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, 46250f94570dSGrishma Kotecha &vsi_list_id, 46260f94570dSGrishma Kotecha ICE_SW_LKUP_LAST); 46270f94570dSGrishma Kotecha if (status) 46280f94570dSGrishma Kotecha return status; 46290f94570dSGrishma Kotecha 46300f94570dSGrishma Kotecha memset(&tmp_fltr, 0, sizeof(tmp_fltr)); 46310f94570dSGrishma Kotecha tmp_fltr.flag = m_entry->rule_info.sw_act.flag; 46320f94570dSGrishma Kotecha tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; 46330f94570dSGrishma Kotecha tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; 46340f94570dSGrishma Kotecha tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; 46350f94570dSGrishma Kotecha tmp_fltr.lkup_type = ICE_SW_LKUP_LAST; 46360f94570dSGrishma Kotecha 46370f94570dSGrishma Kotecha /* Update the previous switch rule of "forward to VSI" to 46380f94570dSGrishma Kotecha * "fwd to VSI list" 46390f94570dSGrishma Kotecha */ 46400f94570dSGrishma Kotecha status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 46410f94570dSGrishma Kotecha if (status) 46420f94570dSGrishma Kotecha return status; 46430f94570dSGrishma Kotecha 46440f94570dSGrishma Kotecha cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id; 46450f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST; 46460f94570dSGrishma Kotecha m_entry->vsi_list_info = 46470f94570dSGrishma Kotecha ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, 46480f94570dSGrishma Kotecha vsi_list_id); 46490f94570dSGrishma Kotecha } else { 46500f94570dSGrishma Kotecha u16 vsi_handle = new_fltr->sw_act.vsi_handle; 46510f94570dSGrishma Kotecha 46520f94570dSGrishma Kotecha if (!m_entry->vsi_list_info) 46530f94570dSGrishma Kotecha return ICE_ERR_CFG; 46540f94570dSGrishma Kotecha 46550f94570dSGrishma Kotecha /* A rule already exists with the new VSI being added */ 46560f94570dSGrishma Kotecha if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) 46570f94570dSGrishma Kotecha return 0; 46580f94570dSGrishma Kotecha 46590f94570dSGrishma Kotecha /* Update the previously created VSI list set with 46600f94570dSGrishma Kotecha * the new VSI ID passed in 46610f94570dSGrishma Kotecha */ 46620f94570dSGrishma Kotecha vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id; 46630f94570dSGrishma Kotecha 46640f94570dSGrishma Kotecha status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, 46650f94570dSGrishma Kotecha vsi_list_id, false, 46660f94570dSGrishma Kotecha ice_aqc_opc_update_sw_rules, 46670f94570dSGrishma Kotecha ICE_SW_LKUP_LAST); 46680f94570dSGrishma Kotecha /* update VSI list mapping info with new VSI ID */ 46690f94570dSGrishma Kotecha if (!status) 46700f94570dSGrishma Kotecha set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); 46710f94570dSGrishma Kotecha } 46720f94570dSGrishma Kotecha if (!status) 46730f94570dSGrishma Kotecha m_entry->vsi_count++; 46740f94570dSGrishma Kotecha return status; 46750f94570dSGrishma Kotecha } 46760f94570dSGrishma Kotecha 46770f94570dSGrishma Kotecha /** 46780f94570dSGrishma Kotecha * ice_add_adv_rule - helper function to create an advanced switch rule 46790f94570dSGrishma Kotecha * @hw: pointer to the hardware structure 46800f94570dSGrishma Kotecha * @lkups: information on the words that needs to be looked up. All words 46810f94570dSGrishma Kotecha * together makes one recipe 46820f94570dSGrishma Kotecha * @lkups_cnt: num of entries in the lkups array 46830f94570dSGrishma Kotecha * @rinfo: other information related to the rule that needs to be programmed 46840f94570dSGrishma Kotecha * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be 46850f94570dSGrishma Kotecha * ignored is case of error. 46860f94570dSGrishma Kotecha * 46870f94570dSGrishma Kotecha * This function can program only 1 rule at a time. The lkups is used to 46880f94570dSGrishma Kotecha * describe the all the words that forms the "lookup" portion of the recipe. 46890f94570dSGrishma Kotecha * These words can span multiple protocols. Callers to this function need to 46900f94570dSGrishma Kotecha * pass in a list of protocol headers with lookup information along and mask 46910f94570dSGrishma Kotecha * that determines which words are valid from the given protocol header. 46920f94570dSGrishma Kotecha * rinfo describes other information related to this rule such as forwarding 46930f94570dSGrishma Kotecha * IDs, priority of this rule, etc. 46940f94570dSGrishma Kotecha */ 46950f94570dSGrishma Kotecha enum ice_status 46960f94570dSGrishma Kotecha ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 46970f94570dSGrishma Kotecha u16 lkups_cnt, struct ice_adv_rule_info *rinfo, 46980f94570dSGrishma Kotecha struct ice_rule_query_data *added_entry) 46990f94570dSGrishma Kotecha { 47000f94570dSGrishma Kotecha struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL; 47010f94570dSGrishma Kotecha u16 rid = 0, i, pkt_len, rule_buf_sz, vsi_handle; 47020f94570dSGrishma Kotecha const struct ice_dummy_pkt_offsets *pkt_offsets; 47030f94570dSGrishma Kotecha struct ice_aqc_sw_rules_elem *s_rule = NULL; 47040f94570dSGrishma Kotecha struct list_head *rule_head; 47050f94570dSGrishma Kotecha struct ice_switch_info *sw; 47060f94570dSGrishma Kotecha enum ice_status status; 47070f94570dSGrishma Kotecha const u8 *pkt = NULL; 47080f94570dSGrishma Kotecha u16 word_cnt; 47090f94570dSGrishma Kotecha u32 act = 0; 47100f94570dSGrishma Kotecha u8 q_rgn; 47110f94570dSGrishma Kotecha 47120f94570dSGrishma Kotecha /* Initialize profile to result index bitmap */ 47130f94570dSGrishma Kotecha if (!hw->switch_info->prof_res_bm_init) { 47140f94570dSGrishma Kotecha hw->switch_info->prof_res_bm_init = 1; 47150f94570dSGrishma Kotecha ice_init_prof_result_bm(hw); 47160f94570dSGrishma Kotecha } 47170f94570dSGrishma Kotecha 47180f94570dSGrishma Kotecha if (!lkups_cnt) 47190f94570dSGrishma Kotecha return ICE_ERR_PARAM; 47200f94570dSGrishma Kotecha 47210f94570dSGrishma Kotecha /* get # of words we need to match */ 47220f94570dSGrishma Kotecha word_cnt = 0; 47230f94570dSGrishma Kotecha for (i = 0; i < lkups_cnt; i++) { 47240f94570dSGrishma Kotecha u16 j, *ptr; 47250f94570dSGrishma Kotecha 47260f94570dSGrishma Kotecha ptr = (u16 *)&lkups[i].m_u; 47270f94570dSGrishma Kotecha for (j = 0; j < sizeof(lkups->m_u) / sizeof(u16); j++) 47280f94570dSGrishma Kotecha if (ptr[j] != 0) 47290f94570dSGrishma Kotecha word_cnt++; 47300f94570dSGrishma Kotecha } 47310f94570dSGrishma Kotecha 47320f94570dSGrishma Kotecha if (!word_cnt || word_cnt > ICE_MAX_CHAIN_WORDS) 47330f94570dSGrishma Kotecha return ICE_ERR_PARAM; 47340f94570dSGrishma Kotecha 47350f94570dSGrishma Kotecha /* make sure that we can locate a dummy packet */ 47360f94570dSGrishma Kotecha ice_find_dummy_packet(lkups, lkups_cnt, &pkt, &pkt_len, 47370f94570dSGrishma Kotecha &pkt_offsets); 47380f94570dSGrishma Kotecha if (!pkt) { 47390f94570dSGrishma Kotecha status = ICE_ERR_PARAM; 47400f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 47410f94570dSGrishma Kotecha } 47420f94570dSGrishma Kotecha 47430f94570dSGrishma Kotecha if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || 47440f94570dSGrishma Kotecha rinfo->sw_act.fltr_act == ICE_FWD_TO_Q || 47450f94570dSGrishma Kotecha rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP || 47460f94570dSGrishma Kotecha rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) 47470f94570dSGrishma Kotecha return ICE_ERR_CFG; 47480f94570dSGrishma Kotecha 47490f94570dSGrishma Kotecha vsi_handle = rinfo->sw_act.vsi_handle; 47500f94570dSGrishma Kotecha if (!ice_is_vsi_valid(hw, vsi_handle)) 47510f94570dSGrishma Kotecha return ICE_ERR_PARAM; 47520f94570dSGrishma Kotecha 47530f94570dSGrishma Kotecha if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) 47540f94570dSGrishma Kotecha rinfo->sw_act.fwd_id.hw_vsi_id = 47550f94570dSGrishma Kotecha ice_get_hw_vsi_num(hw, vsi_handle); 47560f94570dSGrishma Kotecha if (rinfo->sw_act.flag & ICE_FLTR_TX) 47570f94570dSGrishma Kotecha rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); 47580f94570dSGrishma Kotecha 47590f94570dSGrishma Kotecha status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid); 47600f94570dSGrishma Kotecha if (status) 47610f94570dSGrishma Kotecha return status; 47620f94570dSGrishma Kotecha m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo); 47630f94570dSGrishma Kotecha if (m_entry) { 47640f94570dSGrishma Kotecha /* we have to add VSI to VSI_LIST and increment vsi_count. 47650f94570dSGrishma Kotecha * Also Update VSI list so that we can change forwarding rule 47660f94570dSGrishma Kotecha * if the rule already exists, we will check if it exists with 47670f94570dSGrishma Kotecha * same vsi_id, if not then add it to the VSI list if it already 47680f94570dSGrishma Kotecha * exists if not then create a VSI list and add the existing VSI 47690f94570dSGrishma Kotecha * ID and the new VSI ID to the list 47700f94570dSGrishma Kotecha * We will add that VSI to the list 47710f94570dSGrishma Kotecha */ 47720f94570dSGrishma Kotecha status = ice_adv_add_update_vsi_list(hw, m_entry, 47730f94570dSGrishma Kotecha &m_entry->rule_info, 47740f94570dSGrishma Kotecha rinfo); 47750f94570dSGrishma Kotecha if (added_entry) { 47760f94570dSGrishma Kotecha added_entry->rid = rid; 47770f94570dSGrishma Kotecha added_entry->rule_id = m_entry->rule_info.fltr_rule_id; 47780f94570dSGrishma Kotecha added_entry->vsi_handle = rinfo->sw_act.vsi_handle; 47790f94570dSGrishma Kotecha } 47800f94570dSGrishma Kotecha return status; 47810f94570dSGrishma Kotecha } 47820f94570dSGrishma Kotecha rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE + pkt_len; 47830f94570dSGrishma Kotecha s_rule = kzalloc(rule_buf_sz, GFP_KERNEL); 47840f94570dSGrishma Kotecha if (!s_rule) 47850f94570dSGrishma Kotecha return ICE_ERR_NO_MEMORY; 47860f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_LB_ENABLE | ICE_SINGLE_ACT_LAN_ENABLE; 47870f94570dSGrishma Kotecha switch (rinfo->sw_act.fltr_act) { 47880f94570dSGrishma Kotecha case ICE_FWD_TO_VSI: 47890f94570dSGrishma Kotecha act |= (rinfo->sw_act.fwd_id.hw_vsi_id << 47900f94570dSGrishma Kotecha ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M; 47910f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT; 47920f94570dSGrishma Kotecha break; 47930f94570dSGrishma Kotecha case ICE_FWD_TO_Q: 47940f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_TO_Q; 47950f94570dSGrishma Kotecha act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & 47960f94570dSGrishma Kotecha ICE_SINGLE_ACT_Q_INDEX_M; 47970f94570dSGrishma Kotecha break; 47980f94570dSGrishma Kotecha case ICE_FWD_TO_QGRP: 47990f94570dSGrishma Kotecha q_rgn = rinfo->sw_act.qgrp_size > 0 ? 48000f94570dSGrishma Kotecha (u8)ilog2(rinfo->sw_act.qgrp_size) : 0; 48010f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_TO_Q; 48020f94570dSGrishma Kotecha act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & 48030f94570dSGrishma Kotecha ICE_SINGLE_ACT_Q_INDEX_M; 48040f94570dSGrishma Kotecha act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & 48050f94570dSGrishma Kotecha ICE_SINGLE_ACT_Q_REGION_M; 48060f94570dSGrishma Kotecha break; 48070f94570dSGrishma Kotecha case ICE_DROP_PACKET: 48080f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | 48090f94570dSGrishma Kotecha ICE_SINGLE_ACT_VALID_BIT; 48100f94570dSGrishma Kotecha break; 48110f94570dSGrishma Kotecha default: 48120f94570dSGrishma Kotecha status = ICE_ERR_CFG; 48130f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 48140f94570dSGrishma Kotecha } 48150f94570dSGrishma Kotecha 48160f94570dSGrishma Kotecha /* set the rule LOOKUP type based on caller specified 'Rx' 48170f94570dSGrishma Kotecha * instead of hardcoding it to be either LOOKUP_TX/RX 48180f94570dSGrishma Kotecha * 48190f94570dSGrishma Kotecha * for 'Rx' set the source to be the port number 48200f94570dSGrishma Kotecha * for 'Tx' set the source to be the source HW VSI number (determined 48210f94570dSGrishma Kotecha * by caller) 48220f94570dSGrishma Kotecha */ 48230f94570dSGrishma Kotecha if (rinfo->rx) { 48240f94570dSGrishma Kotecha s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); 48250f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.src = 48260f94570dSGrishma Kotecha cpu_to_le16(hw->port_info->lport); 48270f94570dSGrishma Kotecha } else { 48280f94570dSGrishma Kotecha s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); 48290f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(rinfo->sw_act.src); 48300f94570dSGrishma Kotecha } 48310f94570dSGrishma Kotecha 48320f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(rid); 48330f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act); 48340f94570dSGrishma Kotecha 48350f94570dSGrishma Kotecha status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, pkt, 48360f94570dSGrishma Kotecha pkt_len, pkt_offsets); 48370f94570dSGrishma Kotecha if (status) 48380f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 48390f94570dSGrishma Kotecha 48400f94570dSGrishma Kotecha status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, 48410f94570dSGrishma Kotecha rule_buf_sz, 1, ice_aqc_opc_add_sw_rules, 48420f94570dSGrishma Kotecha NULL); 48430f94570dSGrishma Kotecha if (status) 48440f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 48450f94570dSGrishma Kotecha adv_fltr = devm_kzalloc(ice_hw_to_dev(hw), 48460f94570dSGrishma Kotecha sizeof(struct ice_adv_fltr_mgmt_list_entry), 48470f94570dSGrishma Kotecha GFP_KERNEL); 48480f94570dSGrishma Kotecha if (!adv_fltr) { 48490f94570dSGrishma Kotecha status = ICE_ERR_NO_MEMORY; 48500f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 48510f94570dSGrishma Kotecha } 48520f94570dSGrishma Kotecha 48530f94570dSGrishma Kotecha adv_fltr->lkups = devm_kmemdup(ice_hw_to_dev(hw), lkups, 48540f94570dSGrishma Kotecha lkups_cnt * sizeof(*lkups), GFP_KERNEL); 48550f94570dSGrishma Kotecha if (!adv_fltr->lkups) { 48560f94570dSGrishma Kotecha status = ICE_ERR_NO_MEMORY; 48570f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 48580f94570dSGrishma Kotecha } 48590f94570dSGrishma Kotecha 48600f94570dSGrishma Kotecha adv_fltr->lkups_cnt = lkups_cnt; 48610f94570dSGrishma Kotecha adv_fltr->rule_info = *rinfo; 48620f94570dSGrishma Kotecha adv_fltr->rule_info.fltr_rule_id = 48630f94570dSGrishma Kotecha le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); 48640f94570dSGrishma Kotecha sw = hw->switch_info; 48650f94570dSGrishma Kotecha sw->recp_list[rid].adv_rule = true; 48660f94570dSGrishma Kotecha rule_head = &sw->recp_list[rid].filt_rules; 48670f94570dSGrishma Kotecha 48680f94570dSGrishma Kotecha if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) 48690f94570dSGrishma Kotecha adv_fltr->vsi_count = 1; 48700f94570dSGrishma Kotecha 48710f94570dSGrishma Kotecha /* Add rule entry to book keeping list */ 48720f94570dSGrishma Kotecha list_add(&adv_fltr->list_entry, rule_head); 48730f94570dSGrishma Kotecha if (added_entry) { 48740f94570dSGrishma Kotecha added_entry->rid = rid; 48750f94570dSGrishma Kotecha added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id; 48760f94570dSGrishma Kotecha added_entry->vsi_handle = rinfo->sw_act.vsi_handle; 48770f94570dSGrishma Kotecha } 48780f94570dSGrishma Kotecha err_ice_add_adv_rule: 48790f94570dSGrishma Kotecha if (status && adv_fltr) { 48800f94570dSGrishma Kotecha devm_kfree(ice_hw_to_dev(hw), adv_fltr->lkups); 48810f94570dSGrishma Kotecha devm_kfree(ice_hw_to_dev(hw), adv_fltr); 48820f94570dSGrishma Kotecha } 48830f94570dSGrishma Kotecha 48840f94570dSGrishma Kotecha kfree(s_rule); 48850f94570dSGrishma Kotecha 48860f94570dSGrishma Kotecha return status; 48870f94570dSGrishma Kotecha } 48880f94570dSGrishma Kotecha 48890f94570dSGrishma Kotecha /** 4890334cb062SAnirudh Venkataramanan * ice_replay_vsi_fltr - Replay filters for requested VSI 48910f9d5027SAnirudh Venkataramanan * @hw: pointer to the hardware structure 4892334cb062SAnirudh Venkataramanan * @vsi_handle: driver VSI handle 4893f9867df6SAnirudh Venkataramanan * @recp_id: Recipe ID for which rules need to be replayed 4894334cb062SAnirudh Venkataramanan * @list_head: list for which filters need to be replayed 4895334cb062SAnirudh Venkataramanan * 4896334cb062SAnirudh Venkataramanan * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. 4897334cb062SAnirudh Venkataramanan * It is required to pass valid VSI handle. 48980f9d5027SAnirudh Venkataramanan */ 48990f9d5027SAnirudh Venkataramanan static enum ice_status 4900334cb062SAnirudh Venkataramanan ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, 4901334cb062SAnirudh Venkataramanan struct list_head *list_head) 49020f9d5027SAnirudh Venkataramanan { 49030f9d5027SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *itr; 49040f9d5027SAnirudh Venkataramanan enum ice_status status = 0; 4905334cb062SAnirudh Venkataramanan u16 hw_vsi_id; 49060f9d5027SAnirudh Venkataramanan 49070f9d5027SAnirudh Venkataramanan if (list_empty(list_head)) 49080f9d5027SAnirudh Venkataramanan return status; 4909334cb062SAnirudh Venkataramanan hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 49100f9d5027SAnirudh Venkataramanan 4911334cb062SAnirudh Venkataramanan list_for_each_entry(itr, list_head, list_entry) { 49120f9d5027SAnirudh Venkataramanan struct ice_fltr_list_entry f_entry; 49130f9d5027SAnirudh Venkataramanan 49140f9d5027SAnirudh Venkataramanan f_entry.fltr_info = itr->fltr_info; 4915334cb062SAnirudh Venkataramanan if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && 4916334cb062SAnirudh Venkataramanan itr->fltr_info.vsi_handle == vsi_handle) { 4917f9867df6SAnirudh Venkataramanan /* update the src in case it is VSI num */ 4918334cb062SAnirudh Venkataramanan if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) 4919334cb062SAnirudh Venkataramanan f_entry.fltr_info.src = hw_vsi_id; 49200f9d5027SAnirudh Venkataramanan status = ice_add_rule_internal(hw, recp_id, &f_entry); 49210f9d5027SAnirudh Venkataramanan if (status) 49220f9d5027SAnirudh Venkataramanan goto end; 49230f9d5027SAnirudh Venkataramanan continue; 49240f9d5027SAnirudh Venkataramanan } 4925072f0c3dSDave Ertman if (!itr->vsi_list_info || 4926072f0c3dSDave Ertman !test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) 4927334cb062SAnirudh Venkataramanan continue; 4928334cb062SAnirudh Venkataramanan /* Clearing it so that the logic can add it back */ 4929334cb062SAnirudh Venkataramanan clear_bit(vsi_handle, itr->vsi_list_info->vsi_map); 4930334cb062SAnirudh Venkataramanan f_entry.fltr_info.vsi_handle = vsi_handle; 49310f9d5027SAnirudh Venkataramanan f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; 4932f9867df6SAnirudh Venkataramanan /* update the src in case it is VSI num */ 4933334cb062SAnirudh Venkataramanan if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) 4934334cb062SAnirudh Venkataramanan f_entry.fltr_info.src = hw_vsi_id; 49350f9d5027SAnirudh Venkataramanan if (recp_id == ICE_SW_LKUP_VLAN) 49360f9d5027SAnirudh Venkataramanan status = ice_add_vlan_internal(hw, &f_entry); 49370f9d5027SAnirudh Venkataramanan else 4938334cb062SAnirudh Venkataramanan status = ice_add_rule_internal(hw, recp_id, &f_entry); 49390f9d5027SAnirudh Venkataramanan if (status) 49400f9d5027SAnirudh Venkataramanan goto end; 49410f9d5027SAnirudh Venkataramanan } 49420f9d5027SAnirudh Venkataramanan end: 49430f9d5027SAnirudh Venkataramanan return status; 49440f9d5027SAnirudh Venkataramanan } 49450f9d5027SAnirudh Venkataramanan 49460f9d5027SAnirudh Venkataramanan /** 49478bb98f33SShivanshu Shukla * ice_adv_rem_update_vsi_list 49488bb98f33SShivanshu Shukla * @hw: pointer to the hardware structure 49498bb98f33SShivanshu Shukla * @vsi_handle: VSI handle of the VSI to remove 49508bb98f33SShivanshu Shukla * @fm_list: filter management entry for which the VSI list management needs to 49518bb98f33SShivanshu Shukla * be done 49528bb98f33SShivanshu Shukla */ 49538bb98f33SShivanshu Shukla static enum ice_status 49548bb98f33SShivanshu Shukla ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, 49558bb98f33SShivanshu Shukla struct ice_adv_fltr_mgmt_list_entry *fm_list) 49568bb98f33SShivanshu Shukla { 49578bb98f33SShivanshu Shukla struct ice_vsi_list_map_info *vsi_list_info; 49588bb98f33SShivanshu Shukla enum ice_sw_lkup_type lkup_type; 49598bb98f33SShivanshu Shukla enum ice_status status; 49608bb98f33SShivanshu Shukla u16 vsi_list_id; 49618bb98f33SShivanshu Shukla 49628bb98f33SShivanshu Shukla if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST || 49638bb98f33SShivanshu Shukla fm_list->vsi_count == 0) 49648bb98f33SShivanshu Shukla return ICE_ERR_PARAM; 49658bb98f33SShivanshu Shukla 49668bb98f33SShivanshu Shukla /* A rule with the VSI being removed does not exist */ 49678bb98f33SShivanshu Shukla if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) 49688bb98f33SShivanshu Shukla return ICE_ERR_DOES_NOT_EXIST; 49698bb98f33SShivanshu Shukla 49708bb98f33SShivanshu Shukla lkup_type = ICE_SW_LKUP_LAST; 49718bb98f33SShivanshu Shukla vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id; 49728bb98f33SShivanshu Shukla status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, 49738bb98f33SShivanshu Shukla ice_aqc_opc_update_sw_rules, 49748bb98f33SShivanshu Shukla lkup_type); 49758bb98f33SShivanshu Shukla if (status) 49768bb98f33SShivanshu Shukla return status; 49778bb98f33SShivanshu Shukla 49788bb98f33SShivanshu Shukla fm_list->vsi_count--; 49798bb98f33SShivanshu Shukla clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); 49808bb98f33SShivanshu Shukla vsi_list_info = fm_list->vsi_list_info; 49818bb98f33SShivanshu Shukla if (fm_list->vsi_count == 1) { 49828bb98f33SShivanshu Shukla struct ice_fltr_info tmp_fltr; 49838bb98f33SShivanshu Shukla u16 rem_vsi_handle; 49848bb98f33SShivanshu Shukla 49858bb98f33SShivanshu Shukla rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, 49868bb98f33SShivanshu Shukla ICE_MAX_VSI); 49878bb98f33SShivanshu Shukla if (!ice_is_vsi_valid(hw, rem_vsi_handle)) 49888bb98f33SShivanshu Shukla return ICE_ERR_OUT_OF_RANGE; 49898bb98f33SShivanshu Shukla 49908bb98f33SShivanshu Shukla /* Make sure VSI list is empty before removing it below */ 49918bb98f33SShivanshu Shukla status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, 49928bb98f33SShivanshu Shukla vsi_list_id, true, 49938bb98f33SShivanshu Shukla ice_aqc_opc_update_sw_rules, 49948bb98f33SShivanshu Shukla lkup_type); 49958bb98f33SShivanshu Shukla if (status) 49968bb98f33SShivanshu Shukla return status; 49978bb98f33SShivanshu Shukla 49988bb98f33SShivanshu Shukla memset(&tmp_fltr, 0, sizeof(tmp_fltr)); 49998bb98f33SShivanshu Shukla tmp_fltr.flag = fm_list->rule_info.sw_act.flag; 50008bb98f33SShivanshu Shukla tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id; 50018bb98f33SShivanshu Shukla fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI; 50028bb98f33SShivanshu Shukla tmp_fltr.fltr_act = ICE_FWD_TO_VSI; 50038bb98f33SShivanshu Shukla tmp_fltr.fwd_id.hw_vsi_id = 50048bb98f33SShivanshu Shukla ice_get_hw_vsi_num(hw, rem_vsi_handle); 50058bb98f33SShivanshu Shukla fm_list->rule_info.sw_act.fwd_id.hw_vsi_id = 50068bb98f33SShivanshu Shukla ice_get_hw_vsi_num(hw, rem_vsi_handle); 50078bb98f33SShivanshu Shukla fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle; 50088bb98f33SShivanshu Shukla 50098bb98f33SShivanshu Shukla /* Update the previous switch rule of "MAC forward to VSI" to 50108bb98f33SShivanshu Shukla * "MAC fwd to VSI list" 50118bb98f33SShivanshu Shukla */ 50128bb98f33SShivanshu Shukla status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 50138bb98f33SShivanshu Shukla if (status) { 50148bb98f33SShivanshu Shukla ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n", 50158bb98f33SShivanshu Shukla tmp_fltr.fwd_id.hw_vsi_id, status); 50168bb98f33SShivanshu Shukla return status; 50178bb98f33SShivanshu Shukla } 50188bb98f33SShivanshu Shukla fm_list->vsi_list_info->ref_cnt--; 50198bb98f33SShivanshu Shukla 50208bb98f33SShivanshu Shukla /* Remove the VSI list since it is no longer used */ 50218bb98f33SShivanshu Shukla status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); 50228bb98f33SShivanshu Shukla if (status) { 50238bb98f33SShivanshu Shukla ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n", 50248bb98f33SShivanshu Shukla vsi_list_id, status); 50258bb98f33SShivanshu Shukla return status; 50268bb98f33SShivanshu Shukla } 50278bb98f33SShivanshu Shukla 50288bb98f33SShivanshu Shukla list_del(&vsi_list_info->list_entry); 50298bb98f33SShivanshu Shukla devm_kfree(ice_hw_to_dev(hw), vsi_list_info); 50308bb98f33SShivanshu Shukla fm_list->vsi_list_info = NULL; 50318bb98f33SShivanshu Shukla } 50328bb98f33SShivanshu Shukla 50338bb98f33SShivanshu Shukla return status; 50348bb98f33SShivanshu Shukla } 50358bb98f33SShivanshu Shukla 50368bb98f33SShivanshu Shukla /** 50378bb98f33SShivanshu Shukla * ice_rem_adv_rule - removes existing advanced switch rule 50388bb98f33SShivanshu Shukla * @hw: pointer to the hardware structure 50398bb98f33SShivanshu Shukla * @lkups: information on the words that needs to be looked up. All words 50408bb98f33SShivanshu Shukla * together makes one recipe 50418bb98f33SShivanshu Shukla * @lkups_cnt: num of entries in the lkups array 50428bb98f33SShivanshu Shukla * @rinfo: Its the pointer to the rule information for the rule 50438bb98f33SShivanshu Shukla * 50448bb98f33SShivanshu Shukla * This function can be used to remove 1 rule at a time. The lkups is 50458bb98f33SShivanshu Shukla * used to describe all the words that forms the "lookup" portion of the 50468bb98f33SShivanshu Shukla * rule. These words can span multiple protocols. Callers to this function 50478bb98f33SShivanshu Shukla * need to pass in a list of protocol headers with lookup information along 50488bb98f33SShivanshu Shukla * and mask that determines which words are valid from the given protocol 50498bb98f33SShivanshu Shukla * header. rinfo describes other information related to this rule such as 50508bb98f33SShivanshu Shukla * forwarding IDs, priority of this rule, etc. 50518bb98f33SShivanshu Shukla */ 50528bb98f33SShivanshu Shukla static enum ice_status 50538bb98f33SShivanshu Shukla ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 50548bb98f33SShivanshu Shukla u16 lkups_cnt, struct ice_adv_rule_info *rinfo) 50558bb98f33SShivanshu Shukla { 50568bb98f33SShivanshu Shukla struct ice_adv_fltr_mgmt_list_entry *list_elem; 50578bb98f33SShivanshu Shukla struct ice_prot_lkup_ext lkup_exts; 50588bb98f33SShivanshu Shukla enum ice_status status = 0; 50598bb98f33SShivanshu Shukla bool remove_rule = false; 50608bb98f33SShivanshu Shukla struct mutex *rule_lock; /* Lock to protect filter rule list */ 50618bb98f33SShivanshu Shukla u16 i, rid, vsi_handle; 50628bb98f33SShivanshu Shukla 50638bb98f33SShivanshu Shukla memset(&lkup_exts, 0, sizeof(lkup_exts)); 50648bb98f33SShivanshu Shukla for (i = 0; i < lkups_cnt; i++) { 50658bb98f33SShivanshu Shukla u16 count; 50668bb98f33SShivanshu Shukla 50678bb98f33SShivanshu Shukla if (lkups[i].type >= ICE_PROTOCOL_LAST) 50688bb98f33SShivanshu Shukla return ICE_ERR_CFG; 50698bb98f33SShivanshu Shukla 50708bb98f33SShivanshu Shukla count = ice_fill_valid_words(&lkups[i], &lkup_exts); 50718bb98f33SShivanshu Shukla if (!count) 50728bb98f33SShivanshu Shukla return ICE_ERR_CFG; 50738bb98f33SShivanshu Shukla } 50748bb98f33SShivanshu Shukla 50758bb98f33SShivanshu Shukla rid = ice_find_recp(hw, &lkup_exts); 50768bb98f33SShivanshu Shukla /* If did not find a recipe that match the existing criteria */ 50778bb98f33SShivanshu Shukla if (rid == ICE_MAX_NUM_RECIPES) 50788bb98f33SShivanshu Shukla return ICE_ERR_PARAM; 50798bb98f33SShivanshu Shukla 50808bb98f33SShivanshu Shukla rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock; 50818bb98f33SShivanshu Shukla list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo); 50828bb98f33SShivanshu Shukla /* the rule is already removed */ 50838bb98f33SShivanshu Shukla if (!list_elem) 50848bb98f33SShivanshu Shukla return 0; 50858bb98f33SShivanshu Shukla mutex_lock(rule_lock); 50868bb98f33SShivanshu Shukla if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) { 50878bb98f33SShivanshu Shukla remove_rule = true; 50888bb98f33SShivanshu Shukla } else if (list_elem->vsi_count > 1) { 50898bb98f33SShivanshu Shukla remove_rule = false; 50908bb98f33SShivanshu Shukla vsi_handle = rinfo->sw_act.vsi_handle; 50918bb98f33SShivanshu Shukla status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem); 50928bb98f33SShivanshu Shukla } else { 50938bb98f33SShivanshu Shukla vsi_handle = rinfo->sw_act.vsi_handle; 50948bb98f33SShivanshu Shukla status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem); 50958bb98f33SShivanshu Shukla if (status) { 50968bb98f33SShivanshu Shukla mutex_unlock(rule_lock); 50978bb98f33SShivanshu Shukla return status; 50988bb98f33SShivanshu Shukla } 50998bb98f33SShivanshu Shukla if (list_elem->vsi_count == 0) 51008bb98f33SShivanshu Shukla remove_rule = true; 51018bb98f33SShivanshu Shukla } 51028bb98f33SShivanshu Shukla mutex_unlock(rule_lock); 51038bb98f33SShivanshu Shukla if (remove_rule) { 51048bb98f33SShivanshu Shukla struct ice_aqc_sw_rules_elem *s_rule; 51058bb98f33SShivanshu Shukla u16 rule_buf_sz; 51068bb98f33SShivanshu Shukla 51078bb98f33SShivanshu Shukla rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE; 51088bb98f33SShivanshu Shukla s_rule = kzalloc(rule_buf_sz, GFP_KERNEL); 51098bb98f33SShivanshu Shukla if (!s_rule) 51108bb98f33SShivanshu Shukla return ICE_ERR_NO_MEMORY; 51118bb98f33SShivanshu Shukla s_rule->pdata.lkup_tx_rx.act = 0; 51128bb98f33SShivanshu Shukla s_rule->pdata.lkup_tx_rx.index = 51138bb98f33SShivanshu Shukla cpu_to_le16(list_elem->rule_info.fltr_rule_id); 51148bb98f33SShivanshu Shukla s_rule->pdata.lkup_tx_rx.hdr_len = 0; 51158bb98f33SShivanshu Shukla status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, 51168bb98f33SShivanshu Shukla rule_buf_sz, 1, 51178bb98f33SShivanshu Shukla ice_aqc_opc_remove_sw_rules, NULL); 51188bb98f33SShivanshu Shukla if (!status || status == ICE_ERR_DOES_NOT_EXIST) { 51198bb98f33SShivanshu Shukla struct ice_switch_info *sw = hw->switch_info; 51208bb98f33SShivanshu Shukla 51218bb98f33SShivanshu Shukla mutex_lock(rule_lock); 51228bb98f33SShivanshu Shukla list_del(&list_elem->list_entry); 51238bb98f33SShivanshu Shukla devm_kfree(ice_hw_to_dev(hw), list_elem->lkups); 51248bb98f33SShivanshu Shukla devm_kfree(ice_hw_to_dev(hw), list_elem); 51258bb98f33SShivanshu Shukla mutex_unlock(rule_lock); 51268bb98f33SShivanshu Shukla if (list_empty(&sw->recp_list[rid].filt_rules)) 51278bb98f33SShivanshu Shukla sw->recp_list[rid].adv_rule = false; 51288bb98f33SShivanshu Shukla } 51298bb98f33SShivanshu Shukla kfree(s_rule); 51308bb98f33SShivanshu Shukla } 51318bb98f33SShivanshu Shukla return status; 51328bb98f33SShivanshu Shukla } 51338bb98f33SShivanshu Shukla 51348bb98f33SShivanshu Shukla /** 51358bb98f33SShivanshu Shukla * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID 51368bb98f33SShivanshu Shukla * @hw: pointer to the hardware structure 51378bb98f33SShivanshu Shukla * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID 51388bb98f33SShivanshu Shukla * 51398bb98f33SShivanshu Shukla * This function is used to remove 1 rule at a time. The removal is based on 51408bb98f33SShivanshu Shukla * the remove_entry parameter. This function will remove rule for a given 51418bb98f33SShivanshu Shukla * vsi_handle with a given rule_id which is passed as parameter in remove_entry 51428bb98f33SShivanshu Shukla */ 51438bb98f33SShivanshu Shukla enum ice_status 51448bb98f33SShivanshu Shukla ice_rem_adv_rule_by_id(struct ice_hw *hw, 51458bb98f33SShivanshu Shukla struct ice_rule_query_data *remove_entry) 51468bb98f33SShivanshu Shukla { 51478bb98f33SShivanshu Shukla struct ice_adv_fltr_mgmt_list_entry *list_itr; 51488bb98f33SShivanshu Shukla struct list_head *list_head; 51498bb98f33SShivanshu Shukla struct ice_adv_rule_info rinfo; 51508bb98f33SShivanshu Shukla struct ice_switch_info *sw; 51518bb98f33SShivanshu Shukla 51528bb98f33SShivanshu Shukla sw = hw->switch_info; 51538bb98f33SShivanshu Shukla if (!sw->recp_list[remove_entry->rid].recp_created) 51548bb98f33SShivanshu Shukla return ICE_ERR_PARAM; 51558bb98f33SShivanshu Shukla list_head = &sw->recp_list[remove_entry->rid].filt_rules; 51568bb98f33SShivanshu Shukla list_for_each_entry(list_itr, list_head, list_entry) { 51578bb98f33SShivanshu Shukla if (list_itr->rule_info.fltr_rule_id == 51588bb98f33SShivanshu Shukla remove_entry->rule_id) { 51598bb98f33SShivanshu Shukla rinfo = list_itr->rule_info; 51608bb98f33SShivanshu Shukla rinfo.sw_act.vsi_handle = remove_entry->vsi_handle; 51618bb98f33SShivanshu Shukla return ice_rem_adv_rule(hw, list_itr->lkups, 51628bb98f33SShivanshu Shukla list_itr->lkups_cnt, &rinfo); 51638bb98f33SShivanshu Shukla } 51648bb98f33SShivanshu Shukla } 51658bb98f33SShivanshu Shukla /* either list is empty or unable to find rule */ 51668bb98f33SShivanshu Shukla return ICE_ERR_DOES_NOT_EXIST; 51678bb98f33SShivanshu Shukla } 51688bb98f33SShivanshu Shukla 51698bb98f33SShivanshu Shukla /** 5170334cb062SAnirudh Venkataramanan * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists 51710f9d5027SAnirudh Venkataramanan * @hw: pointer to the hardware structure 5172334cb062SAnirudh Venkataramanan * @vsi_handle: driver VSI handle 51730f9d5027SAnirudh Venkataramanan * 5174334cb062SAnirudh Venkataramanan * Replays filters for requested VSI via vsi_handle. 51750f9d5027SAnirudh Venkataramanan */ 5176334cb062SAnirudh Venkataramanan enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) 51770f9d5027SAnirudh Venkataramanan { 51780f9d5027SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 51790f9d5027SAnirudh Venkataramanan enum ice_status status = 0; 51800f9d5027SAnirudh Venkataramanan u8 i; 51810f9d5027SAnirudh Venkataramanan 51820f9d5027SAnirudh Venkataramanan for (i = 0; i < ICE_SW_LKUP_LAST; i++) { 5183334cb062SAnirudh Venkataramanan struct list_head *head; 51840f9d5027SAnirudh Venkataramanan 5185334cb062SAnirudh Venkataramanan head = &sw->recp_list[i].filt_replay_rules; 5186334cb062SAnirudh Venkataramanan status = ice_replay_vsi_fltr(hw, vsi_handle, i, head); 51870f9d5027SAnirudh Venkataramanan if (status) 51880f9d5027SAnirudh Venkataramanan return status; 51890f9d5027SAnirudh Venkataramanan } 51900f9d5027SAnirudh Venkataramanan return status; 51910f9d5027SAnirudh Venkataramanan } 5192334cb062SAnirudh Venkataramanan 5193334cb062SAnirudh Venkataramanan /** 5194334cb062SAnirudh Venkataramanan * ice_rm_all_sw_replay_rule_info - deletes filter replay rules 5195f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 5196334cb062SAnirudh Venkataramanan * 5197334cb062SAnirudh Venkataramanan * Deletes the filter replay rules. 5198334cb062SAnirudh Venkataramanan */ 5199334cb062SAnirudh Venkataramanan void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) 5200334cb062SAnirudh Venkataramanan { 5201334cb062SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 5202334cb062SAnirudh Venkataramanan u8 i; 5203334cb062SAnirudh Venkataramanan 5204334cb062SAnirudh Venkataramanan if (!sw) 5205334cb062SAnirudh Venkataramanan return; 5206334cb062SAnirudh Venkataramanan 5207*8b8ef05bSVictor Raj for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { 5208334cb062SAnirudh Venkataramanan if (!list_empty(&sw->recp_list[i].filt_replay_rules)) { 5209334cb062SAnirudh Venkataramanan struct list_head *l_head; 5210334cb062SAnirudh Venkataramanan 5211334cb062SAnirudh Venkataramanan l_head = &sw->recp_list[i].filt_replay_rules; 5212*8b8ef05bSVictor Raj if (!sw->recp_list[i].adv_rule) 5213334cb062SAnirudh Venkataramanan ice_rem_sw_rule_info(hw, l_head); 5214*8b8ef05bSVictor Raj else 5215*8b8ef05bSVictor Raj ice_rem_adv_rule_info(hw, l_head); 5216334cb062SAnirudh Venkataramanan } 5217334cb062SAnirudh Venkataramanan } 5218334cb062SAnirudh Venkataramanan } 5219