19c20346bSAnirudh Venkataramanan // SPDX-License-Identifier: GPL-2.0 29c20346bSAnirudh Venkataramanan /* Copyright (c) 2018, Intel Corporation. */ 39c20346bSAnirudh Venkataramanan 4348048e7SDave Ertman #include "ice_lib.h" 59c20346bSAnirudh Venkataramanan #include "ice_switch.h" 69c20346bSAnirudh Venkataramanan 79daf8208SAnirudh Venkataramanan #define ICE_ETH_DA_OFFSET 0 89daf8208SAnirudh Venkataramanan #define ICE_ETH_ETHTYPE_OFFSET 12 99daf8208SAnirudh Venkataramanan #define ICE_ETH_VLAN_TCI_OFFSET 14 109daf8208SAnirudh Venkataramanan #define ICE_MAX_VLAN_ID 0xFFF 110f94570dSGrishma Kotecha #define ICE_IPV6_ETHER_ID 0x86DD 129daf8208SAnirudh Venkataramanan 139daf8208SAnirudh Venkataramanan /* Dummy ethernet header needed in the ice_aqc_sw_rules_elem 149daf8208SAnirudh Venkataramanan * struct to configure any switch filter rules. 159daf8208SAnirudh Venkataramanan * {DA (6 bytes), SA(6 bytes), 169daf8208SAnirudh Venkataramanan * Ether type (2 bytes for header without VLAN tag) OR 179daf8208SAnirudh Venkataramanan * VLAN tag (4 bytes for header with VLAN tag) } 189daf8208SAnirudh Venkataramanan * 199daf8208SAnirudh Venkataramanan * Word on Hardcoded values 209daf8208SAnirudh Venkataramanan * byte 0 = 0x2: to identify it as locally administered DA MAC 219daf8208SAnirudh Venkataramanan * byte 6 = 0x2: to identify it as locally administered SA MAC 229daf8208SAnirudh Venkataramanan * byte 12 = 0x81 & byte 13 = 0x00: 239daf8208SAnirudh Venkataramanan * In case of VLAN filter first two bytes defines ether type (0x8100) 24f9867df6SAnirudh Venkataramanan * and remaining two bytes are placeholder for programming a given VLAN ID 259daf8208SAnirudh Venkataramanan * In case of Ether type filter it is treated as header without VLAN tag 269daf8208SAnirudh Venkataramanan * and byte 12 and 13 is used to program a given Ether type instead 279daf8208SAnirudh Venkataramanan */ 289daf8208SAnirudh Venkataramanan #define DUMMY_ETH_HDR_LEN 16 299daf8208SAnirudh Venkataramanan static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0, 309daf8208SAnirudh Venkataramanan 0x2, 0, 0, 0, 0, 0, 319daf8208SAnirudh Venkataramanan 0x81, 0, 0, 0}; 329daf8208SAnirudh Venkataramanan 330f94570dSGrishma Kotecha struct ice_dummy_pkt_offsets { 340f94570dSGrishma Kotecha enum ice_protocol_type type; 350f94570dSGrishma Kotecha u16 offset; /* ICE_PROTOCOL_LAST indicates end of list */ 360f94570dSGrishma Kotecha }; 370f94570dSGrishma Kotecha 38f0a35040SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_gre_tcp_packet_offsets[] = { 39f0a35040SMichal Swiatkowski { ICE_MAC_OFOS, 0 }, 40f0a35040SMichal Swiatkowski { ICE_ETYPE_OL, 12 }, 41f0a35040SMichal Swiatkowski { ICE_IPV4_OFOS, 14 }, 42f0a35040SMichal Swiatkowski { ICE_NVGRE, 34 }, 43f0a35040SMichal Swiatkowski { ICE_MAC_IL, 42 }, 44f0a35040SMichal Swiatkowski { ICE_IPV4_IL, 56 }, 45f0a35040SMichal Swiatkowski { ICE_TCP_IL, 76 }, 46f0a35040SMichal Swiatkowski { ICE_PROTOCOL_LAST, 0 }, 47f0a35040SMichal Swiatkowski }; 48f0a35040SMichal Swiatkowski 49f0a35040SMichal Swiatkowski static const u8 dummy_gre_tcp_packet[] = { 50f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 51f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 52f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 53f0a35040SMichal Swiatkowski 54f0a35040SMichal Swiatkowski 0x08, 0x00, /* ICE_ETYPE_OL 12 */ 55f0a35040SMichal Swiatkowski 56f0a35040SMichal Swiatkowski 0x45, 0x00, 0x00, 0x3E, /* ICE_IPV4_OFOS 14 */ 57f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 58f0a35040SMichal Swiatkowski 0x00, 0x2F, 0x00, 0x00, 59f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 60f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 61f0a35040SMichal Swiatkowski 62f0a35040SMichal Swiatkowski 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ 63f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 64f0a35040SMichal Swiatkowski 65f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ 66f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 67f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 68f0a35040SMichal Swiatkowski 0x08, 0x00, 69f0a35040SMichal Swiatkowski 70f0a35040SMichal Swiatkowski 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 56 */ 71f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 72f0a35040SMichal Swiatkowski 0x00, 0x06, 0x00, 0x00, 73f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 74f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 75f0a35040SMichal Swiatkowski 76f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 76 */ 77f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 78f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 79f0a35040SMichal Swiatkowski 0x50, 0x02, 0x20, 0x00, 80f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00 81f0a35040SMichal Swiatkowski }; 82f0a35040SMichal Swiatkowski 83f0a35040SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_gre_udp_packet_offsets[] = { 84f0a35040SMichal Swiatkowski { ICE_MAC_OFOS, 0 }, 85f0a35040SMichal Swiatkowski { ICE_ETYPE_OL, 12 }, 86f0a35040SMichal Swiatkowski { ICE_IPV4_OFOS, 14 }, 87f0a35040SMichal Swiatkowski { ICE_NVGRE, 34 }, 88f0a35040SMichal Swiatkowski { ICE_MAC_IL, 42 }, 89f0a35040SMichal Swiatkowski { ICE_IPV4_IL, 56 }, 90f0a35040SMichal Swiatkowski { ICE_UDP_ILOS, 76 }, 91f0a35040SMichal Swiatkowski { ICE_PROTOCOL_LAST, 0 }, 92f0a35040SMichal Swiatkowski }; 93f0a35040SMichal Swiatkowski 94f0a35040SMichal Swiatkowski static const u8 dummy_gre_udp_packet[] = { 95f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 96f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 97f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 98f0a35040SMichal Swiatkowski 99f0a35040SMichal Swiatkowski 0x08, 0x00, /* ICE_ETYPE_OL 12 */ 100f0a35040SMichal Swiatkowski 101f0a35040SMichal Swiatkowski 0x45, 0x00, 0x00, 0x3E, /* ICE_IPV4_OFOS 14 */ 102f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 103f0a35040SMichal Swiatkowski 0x00, 0x2F, 0x00, 0x00, 104f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 105f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 106f0a35040SMichal Swiatkowski 107f0a35040SMichal Swiatkowski 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ 108f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 109f0a35040SMichal Swiatkowski 110f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ 111f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 112f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 113f0a35040SMichal Swiatkowski 0x08, 0x00, 114f0a35040SMichal Swiatkowski 115f0a35040SMichal Swiatkowski 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 56 */ 116f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 117f0a35040SMichal Swiatkowski 0x00, 0x11, 0x00, 0x00, 118f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 119f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 120f0a35040SMichal Swiatkowski 121f0a35040SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 76 */ 122f0a35040SMichal Swiatkowski 0x00, 0x08, 0x00, 0x00, 123f0a35040SMichal Swiatkowski }; 124f0a35040SMichal Swiatkowski 1258b032a55SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_udp_tun_tcp_packet_offsets[] = { 1268b032a55SMichal Swiatkowski { ICE_MAC_OFOS, 0 }, 1278b032a55SMichal Swiatkowski { ICE_ETYPE_OL, 12 }, 1288b032a55SMichal Swiatkowski { ICE_IPV4_OFOS, 14 }, 1298b032a55SMichal Swiatkowski { ICE_UDP_OF, 34 }, 1308b032a55SMichal Swiatkowski { ICE_VXLAN, 42 }, 1318b032a55SMichal Swiatkowski { ICE_GENEVE, 42 }, 1328b032a55SMichal Swiatkowski { ICE_VXLAN_GPE, 42 }, 1338b032a55SMichal Swiatkowski { ICE_MAC_IL, 50 }, 1348b032a55SMichal Swiatkowski { ICE_IPV4_IL, 64 }, 1358b032a55SMichal Swiatkowski { ICE_TCP_IL, 84 }, 1368b032a55SMichal Swiatkowski { ICE_PROTOCOL_LAST, 0 }, 1378b032a55SMichal Swiatkowski }; 1388b032a55SMichal Swiatkowski 1398b032a55SMichal Swiatkowski static const u8 dummy_udp_tun_tcp_packet[] = { 1408b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 1418b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1428b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1438b032a55SMichal Swiatkowski 1448b032a55SMichal Swiatkowski 0x08, 0x00, /* ICE_ETYPE_OL 12 */ 1458b032a55SMichal Swiatkowski 1468b032a55SMichal Swiatkowski 0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */ 1478b032a55SMichal Swiatkowski 0x00, 0x01, 0x00, 0x00, 1488b032a55SMichal Swiatkowski 0x40, 0x11, 0x00, 0x00, 1498b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1508b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1518b032a55SMichal Swiatkowski 1528b032a55SMichal Swiatkowski 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ 1538b032a55SMichal Swiatkowski 0x00, 0x46, 0x00, 0x00, 1548b032a55SMichal Swiatkowski 1558b032a55SMichal Swiatkowski 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ 1568b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1578b032a55SMichal Swiatkowski 1588b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ 1598b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1608b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1618b032a55SMichal Swiatkowski 0x08, 0x00, 1628b032a55SMichal Swiatkowski 1638b032a55SMichal Swiatkowski 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_IL 64 */ 1648b032a55SMichal Swiatkowski 0x00, 0x01, 0x00, 0x00, 1658b032a55SMichal Swiatkowski 0x40, 0x06, 0x00, 0x00, 1668b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1678b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1688b032a55SMichal Swiatkowski 1698b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 84 */ 1708b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1718b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1728b032a55SMichal Swiatkowski 0x50, 0x02, 0x20, 0x00, 1738b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00 1748b032a55SMichal Swiatkowski }; 1758b032a55SMichal Swiatkowski 1768b032a55SMichal Swiatkowski static const struct ice_dummy_pkt_offsets dummy_udp_tun_udp_packet_offsets[] = { 1778b032a55SMichal Swiatkowski { ICE_MAC_OFOS, 0 }, 1788b032a55SMichal Swiatkowski { ICE_ETYPE_OL, 12 }, 1798b032a55SMichal Swiatkowski { ICE_IPV4_OFOS, 14 }, 1808b032a55SMichal Swiatkowski { ICE_UDP_OF, 34 }, 1818b032a55SMichal Swiatkowski { ICE_VXLAN, 42 }, 1828b032a55SMichal Swiatkowski { ICE_GENEVE, 42 }, 1838b032a55SMichal Swiatkowski { ICE_VXLAN_GPE, 42 }, 1848b032a55SMichal Swiatkowski { ICE_MAC_IL, 50 }, 1858b032a55SMichal Swiatkowski { ICE_IPV4_IL, 64 }, 1868b032a55SMichal Swiatkowski { ICE_UDP_ILOS, 84 }, 1878b032a55SMichal Swiatkowski { ICE_PROTOCOL_LAST, 0 }, 1888b032a55SMichal Swiatkowski }; 1898b032a55SMichal Swiatkowski 1908b032a55SMichal Swiatkowski static const u8 dummy_udp_tun_udp_packet[] = { 1918b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 1928b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1938b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 1948b032a55SMichal Swiatkowski 1958b032a55SMichal Swiatkowski 0x08, 0x00, /* ICE_ETYPE_OL 12 */ 1968b032a55SMichal Swiatkowski 1978b032a55SMichal Swiatkowski 0x45, 0x00, 0x00, 0x4e, /* ICE_IPV4_OFOS 14 */ 1988b032a55SMichal Swiatkowski 0x00, 0x01, 0x00, 0x00, 1998b032a55SMichal Swiatkowski 0x00, 0x11, 0x00, 0x00, 2008b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2018b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2028b032a55SMichal Swiatkowski 2038b032a55SMichal Swiatkowski 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ 2048b032a55SMichal Swiatkowski 0x00, 0x3a, 0x00, 0x00, 2058b032a55SMichal Swiatkowski 2068b032a55SMichal Swiatkowski 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ 2078b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2088b032a55SMichal Swiatkowski 2098b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ 2108b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2118b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2128b032a55SMichal Swiatkowski 0x08, 0x00, 2138b032a55SMichal Swiatkowski 2148b032a55SMichal Swiatkowski 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_IL 64 */ 2158b032a55SMichal Swiatkowski 0x00, 0x01, 0x00, 0x00, 2168b032a55SMichal Swiatkowski 0x00, 0x11, 0x00, 0x00, 2178b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2188b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, 2198b032a55SMichal Swiatkowski 2208b032a55SMichal Swiatkowski 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 84 */ 2218b032a55SMichal Swiatkowski 0x00, 0x08, 0x00, 0x00, 2228b032a55SMichal Swiatkowski }; 2238b032a55SMichal Swiatkowski 2240f94570dSGrishma Kotecha /* offset info for MAC + IPv4 + UDP dummy packet */ 2250f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_udp_packet_offsets[] = { 2260f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 2270f94570dSGrishma Kotecha { ICE_ETYPE_OL, 12 }, 2280f94570dSGrishma Kotecha { ICE_IPV4_OFOS, 14 }, 2290f94570dSGrishma Kotecha { ICE_UDP_ILOS, 34 }, 2300f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 2310f94570dSGrishma Kotecha }; 2320f94570dSGrishma Kotecha 2330f94570dSGrishma Kotecha /* Dummy packet for MAC + IPv4 + UDP */ 2340f94570dSGrishma Kotecha static const u8 dummy_udp_packet[] = { 2350f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 2360f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2370f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2380f94570dSGrishma Kotecha 2390f94570dSGrishma Kotecha 0x08, 0x00, /* ICE_ETYPE_OL 12 */ 2400f94570dSGrishma Kotecha 2410f94570dSGrishma Kotecha 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 14 */ 2420f94570dSGrishma Kotecha 0x00, 0x01, 0x00, 0x00, 2430f94570dSGrishma Kotecha 0x00, 0x11, 0x00, 0x00, 2440f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2450f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2460f94570dSGrishma Kotecha 2470f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 34 */ 2480f94570dSGrishma Kotecha 0x00, 0x08, 0x00, 0x00, 2490f94570dSGrishma Kotecha 2500f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 2510f94570dSGrishma Kotecha }; 2520f94570dSGrishma Kotecha 2530f94570dSGrishma Kotecha /* offset info for MAC + VLAN + IPv4 + UDP dummy packet */ 2540f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_vlan_udp_packet_offsets[] = { 2550f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 2560f94570dSGrishma Kotecha { ICE_VLAN_OFOS, 12 }, 2570f94570dSGrishma Kotecha { ICE_ETYPE_OL, 16 }, 2580f94570dSGrishma Kotecha { ICE_IPV4_OFOS, 18 }, 2590f94570dSGrishma Kotecha { ICE_UDP_ILOS, 38 }, 2600f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 2610f94570dSGrishma Kotecha }; 2620f94570dSGrishma Kotecha 2630f94570dSGrishma Kotecha /* C-tag (801.1Q), IPv4:UDP dummy packet */ 2640f94570dSGrishma Kotecha static const u8 dummy_vlan_udp_packet[] = { 2650f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 2660f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2670f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2680f94570dSGrishma Kotecha 2690f94570dSGrishma Kotecha 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */ 2700f94570dSGrishma Kotecha 2710f94570dSGrishma Kotecha 0x08, 0x00, /* ICE_ETYPE_OL 16 */ 2720f94570dSGrishma Kotecha 2730f94570dSGrishma Kotecha 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 18 */ 2740f94570dSGrishma Kotecha 0x00, 0x01, 0x00, 0x00, 2750f94570dSGrishma Kotecha 0x00, 0x11, 0x00, 0x00, 2760f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2770f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2780f94570dSGrishma Kotecha 2790f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 38 */ 2800f94570dSGrishma Kotecha 0x00, 0x08, 0x00, 0x00, 2810f94570dSGrishma Kotecha 2820f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 2830f94570dSGrishma Kotecha }; 2840f94570dSGrishma Kotecha 2850f94570dSGrishma Kotecha /* offset info for MAC + IPv4 + TCP dummy packet */ 2860f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_tcp_packet_offsets[] = { 2870f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 2880f94570dSGrishma Kotecha { ICE_ETYPE_OL, 12 }, 2890f94570dSGrishma Kotecha { ICE_IPV4_OFOS, 14 }, 2900f94570dSGrishma Kotecha { ICE_TCP_IL, 34 }, 2910f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 2920f94570dSGrishma Kotecha }; 2930f94570dSGrishma Kotecha 2940f94570dSGrishma Kotecha /* Dummy packet for MAC + IPv4 + TCP */ 2950f94570dSGrishma Kotecha static const u8 dummy_tcp_packet[] = { 2960f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 2970f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2980f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 2990f94570dSGrishma Kotecha 3000f94570dSGrishma Kotecha 0x08, 0x00, /* ICE_ETYPE_OL 12 */ 3010f94570dSGrishma Kotecha 3020f94570dSGrishma Kotecha 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 14 */ 3030f94570dSGrishma Kotecha 0x00, 0x01, 0x00, 0x00, 3040f94570dSGrishma Kotecha 0x00, 0x06, 0x00, 0x00, 3050f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3060f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3070f94570dSGrishma Kotecha 3080f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 34 */ 3090f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3100f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3110f94570dSGrishma Kotecha 0x50, 0x00, 0x00, 0x00, 3120f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3130f94570dSGrishma Kotecha 3140f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 3150f94570dSGrishma Kotecha }; 3160f94570dSGrishma Kotecha 3170f94570dSGrishma Kotecha /* offset info for MAC + VLAN (C-tag, 802.1Q) + IPv4 + TCP dummy packet */ 3180f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_vlan_tcp_packet_offsets[] = { 3190f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 3200f94570dSGrishma Kotecha { ICE_VLAN_OFOS, 12 }, 3210f94570dSGrishma Kotecha { ICE_ETYPE_OL, 16 }, 3220f94570dSGrishma Kotecha { ICE_IPV4_OFOS, 18 }, 3230f94570dSGrishma Kotecha { ICE_TCP_IL, 38 }, 3240f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 3250f94570dSGrishma Kotecha }; 3260f94570dSGrishma Kotecha 3270f94570dSGrishma Kotecha /* C-tag (801.1Q), IPv4:TCP dummy packet */ 3280f94570dSGrishma Kotecha static const u8 dummy_vlan_tcp_packet[] = { 3290f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 3300f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3310f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3320f94570dSGrishma Kotecha 3330f94570dSGrishma Kotecha 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */ 3340f94570dSGrishma Kotecha 3350f94570dSGrishma Kotecha 0x08, 0x00, /* ICE_ETYPE_OL 16 */ 3360f94570dSGrishma Kotecha 3370f94570dSGrishma Kotecha 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 18 */ 3380f94570dSGrishma Kotecha 0x00, 0x01, 0x00, 0x00, 3390f94570dSGrishma Kotecha 0x00, 0x06, 0x00, 0x00, 3400f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3410f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3420f94570dSGrishma Kotecha 3430f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 38 */ 3440f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3450f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3460f94570dSGrishma Kotecha 0x50, 0x00, 0x00, 0x00, 3470f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3480f94570dSGrishma Kotecha 3490f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 3500f94570dSGrishma Kotecha }; 3510f94570dSGrishma Kotecha 3520f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_tcp_ipv6_packet_offsets[] = { 3530f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 3540f94570dSGrishma Kotecha { ICE_ETYPE_OL, 12 }, 3550f94570dSGrishma Kotecha { ICE_IPV6_OFOS, 14 }, 3560f94570dSGrishma Kotecha { ICE_TCP_IL, 54 }, 3570f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 3580f94570dSGrishma Kotecha }; 3590f94570dSGrishma Kotecha 3600f94570dSGrishma Kotecha static const u8 dummy_tcp_ipv6_packet[] = { 3610f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 3620f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3630f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3640f94570dSGrishma Kotecha 3650f94570dSGrishma Kotecha 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ 3660f94570dSGrishma Kotecha 3670f94570dSGrishma Kotecha 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */ 3680f94570dSGrishma Kotecha 0x00, 0x14, 0x06, 0x00, /* Next header is TCP */ 3690f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3700f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3710f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3720f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3730f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3740f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3750f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3760f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3770f94570dSGrishma Kotecha 3780f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 54 */ 3790f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3800f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3810f94570dSGrishma Kotecha 0x50, 0x00, 0x00, 0x00, 3820f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 3830f94570dSGrishma Kotecha 3840f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 3850f94570dSGrishma Kotecha }; 3860f94570dSGrishma Kotecha 3870f94570dSGrishma Kotecha /* C-tag (802.1Q): IPv6 + TCP */ 3880f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets 3890f94570dSGrishma Kotecha dummy_vlan_tcp_ipv6_packet_offsets[] = { 3900f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 3910f94570dSGrishma Kotecha { ICE_VLAN_OFOS, 12 }, 3920f94570dSGrishma Kotecha { ICE_ETYPE_OL, 16 }, 3930f94570dSGrishma Kotecha { ICE_IPV6_OFOS, 18 }, 3940f94570dSGrishma Kotecha { ICE_TCP_IL, 58 }, 3950f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 3960f94570dSGrishma Kotecha }; 3970f94570dSGrishma Kotecha 3980f94570dSGrishma Kotecha /* C-tag (802.1Q), IPv6 + TCP dummy packet */ 3990f94570dSGrishma Kotecha static const u8 dummy_vlan_tcp_ipv6_packet[] = { 4000f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 4010f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4020f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4030f94570dSGrishma Kotecha 4040f94570dSGrishma Kotecha 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */ 4050f94570dSGrishma Kotecha 4060f94570dSGrishma Kotecha 0x86, 0xDD, /* ICE_ETYPE_OL 16 */ 4070f94570dSGrishma Kotecha 4080f94570dSGrishma Kotecha 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */ 4090f94570dSGrishma Kotecha 0x00, 0x14, 0x06, 0x00, /* Next header is TCP */ 4100f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4110f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4120f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4130f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4140f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4150f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4160f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4170f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4180f94570dSGrishma Kotecha 4190f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 58 */ 4200f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4210f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4220f94570dSGrishma Kotecha 0x50, 0x00, 0x00, 0x00, 4230f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4240f94570dSGrishma Kotecha 4250f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 4260f94570dSGrishma Kotecha }; 4270f94570dSGrishma Kotecha 4280f94570dSGrishma Kotecha /* IPv6 + UDP */ 4290f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets dummy_udp_ipv6_packet_offsets[] = { 4300f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 4310f94570dSGrishma Kotecha { ICE_ETYPE_OL, 12 }, 4320f94570dSGrishma Kotecha { ICE_IPV6_OFOS, 14 }, 4330f94570dSGrishma Kotecha { ICE_UDP_ILOS, 54 }, 4340f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 4350f94570dSGrishma Kotecha }; 4360f94570dSGrishma Kotecha 4370f94570dSGrishma Kotecha /* IPv6 + UDP dummy packet */ 4380f94570dSGrishma Kotecha static const u8 dummy_udp_ipv6_packet[] = { 4390f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 4400f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4410f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4420f94570dSGrishma Kotecha 4430f94570dSGrishma Kotecha 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ 4440f94570dSGrishma Kotecha 4450f94570dSGrishma Kotecha 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */ 4460f94570dSGrishma Kotecha 0x00, 0x10, 0x11, 0x00, /* Next header UDP */ 4470f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4480f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4490f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4500f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4510f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4520f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4530f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4540f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4550f94570dSGrishma Kotecha 4560f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 54 */ 4570f94570dSGrishma Kotecha 0x00, 0x10, 0x00, 0x00, 4580f94570dSGrishma Kotecha 4590f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* needed for ESP packets */ 4600f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4610f94570dSGrishma Kotecha 4620f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 4630f94570dSGrishma Kotecha }; 4640f94570dSGrishma Kotecha 4650f94570dSGrishma Kotecha /* C-tag (802.1Q): IPv6 + UDP */ 4660f94570dSGrishma Kotecha static const struct ice_dummy_pkt_offsets 4670f94570dSGrishma Kotecha dummy_vlan_udp_ipv6_packet_offsets[] = { 4680f94570dSGrishma Kotecha { ICE_MAC_OFOS, 0 }, 4690f94570dSGrishma Kotecha { ICE_VLAN_OFOS, 12 }, 4700f94570dSGrishma Kotecha { ICE_ETYPE_OL, 16 }, 4710f94570dSGrishma Kotecha { ICE_IPV6_OFOS, 18 }, 4720f94570dSGrishma Kotecha { ICE_UDP_ILOS, 58 }, 4730f94570dSGrishma Kotecha { ICE_PROTOCOL_LAST, 0 }, 4740f94570dSGrishma Kotecha }; 4750f94570dSGrishma Kotecha 4760f94570dSGrishma Kotecha /* C-tag (802.1Q), IPv6 + UDP dummy packet */ 4770f94570dSGrishma Kotecha static const u8 dummy_vlan_udp_ipv6_packet[] = { 4780f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ 4790f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4800f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4810f94570dSGrishma Kotecha 4820f94570dSGrishma Kotecha 0x81, 0x00, 0x00, 0x00,/* ICE_VLAN_OFOS 12 */ 4830f94570dSGrishma Kotecha 4840f94570dSGrishma Kotecha 0x86, 0xDD, /* ICE_ETYPE_OL 16 */ 4850f94570dSGrishma Kotecha 4860f94570dSGrishma Kotecha 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */ 4870f94570dSGrishma Kotecha 0x00, 0x08, 0x11, 0x00, /* Next header UDP */ 4880f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4890f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4900f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4910f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4920f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4930f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4940f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4950f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, 4960f94570dSGrishma Kotecha 4970f94570dSGrishma Kotecha 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 58 */ 4980f94570dSGrishma Kotecha 0x00, 0x08, 0x00, 0x00, 4990f94570dSGrishma Kotecha 5000f94570dSGrishma Kotecha 0x00, 0x00, /* 2 bytes for 4 byte alignment */ 5010f94570dSGrishma Kotecha }; 5020f94570dSGrishma Kotecha 5039daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE \ 50466486d89SBruce Allan (offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr) + \ 50566486d89SBruce Allan (DUMMY_ETH_HDR_LEN * \ 50666486d89SBruce Allan sizeof(((struct ice_sw_rule_lkup_rx_tx *)0)->hdr[0]))) 5079daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_RX_TX_NO_HDR_SIZE \ 50866486d89SBruce Allan (offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr)) 5099daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_LG_ACT_SIZE(n) \ 51066486d89SBruce Allan (offsetof(struct ice_aqc_sw_rules_elem, pdata.lg_act.act) + \ 51166486d89SBruce Allan ((n) * sizeof(((struct ice_sw_rule_lg_act *)0)->act[0]))) 5129daf8208SAnirudh Venkataramanan #define ICE_SW_RULE_VSI_LIST_SIZE(n) \ 51366486d89SBruce Allan (offsetof(struct ice_aqc_sw_rules_elem, pdata.vsi_list.vsi) + \ 51466486d89SBruce Allan ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi[0]))) 5159daf8208SAnirudh Venkataramanan 516fd2a6b71SDan Nowlin /* this is a recipe to profile association bitmap */ 517fd2a6b71SDan Nowlin static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES], 518fd2a6b71SDan Nowlin ICE_MAX_NUM_PROFILES); 519fd2a6b71SDan Nowlin 520fd2a6b71SDan Nowlin /* this is a profile to recipe association bitmap */ 521fd2a6b71SDan Nowlin static DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES], 522fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 523fd2a6b71SDan Nowlin 5249daf8208SAnirudh Venkataramanan /** 52580d144c9SAnirudh Venkataramanan * ice_init_def_sw_recp - initialize the recipe book keeping tables 526f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 52780d144c9SAnirudh Venkataramanan * 52880d144c9SAnirudh Venkataramanan * Allocate memory for the entire recipe table and initialize the structures/ 52980d144c9SAnirudh Venkataramanan * entries corresponding to basic recipes. 53080d144c9SAnirudh Venkataramanan */ 5315e24d598STony Nguyen int ice_init_def_sw_recp(struct ice_hw *hw) 53280d144c9SAnirudh Venkataramanan { 53380d144c9SAnirudh Venkataramanan struct ice_sw_recipe *recps; 53480d144c9SAnirudh Venkataramanan u8 i; 53580d144c9SAnirudh Venkataramanan 53680d144c9SAnirudh Venkataramanan recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES, 537c6dfd690SBruce Allan sizeof(*recps), GFP_KERNEL); 53880d144c9SAnirudh Venkataramanan if (!recps) 539d54699e2STony Nguyen return -ENOMEM; 54080d144c9SAnirudh Venkataramanan 541450052a4SDan Nowlin for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { 54280d144c9SAnirudh Venkataramanan recps[i].root_rid = i; 54380d144c9SAnirudh Venkataramanan INIT_LIST_HEAD(&recps[i].filt_rules); 544334cb062SAnirudh Venkataramanan INIT_LIST_HEAD(&recps[i].filt_replay_rules); 545450052a4SDan Nowlin INIT_LIST_HEAD(&recps[i].rg_list); 54680d144c9SAnirudh Venkataramanan mutex_init(&recps[i].filt_rule_lock); 54780d144c9SAnirudh Venkataramanan } 54880d144c9SAnirudh Venkataramanan 54980d144c9SAnirudh Venkataramanan hw->switch_info->recp_list = recps; 55080d144c9SAnirudh Venkataramanan 55180d144c9SAnirudh Venkataramanan return 0; 55280d144c9SAnirudh Venkataramanan } 55380d144c9SAnirudh Venkataramanan 55480d144c9SAnirudh Venkataramanan /** 5559c20346bSAnirudh Venkataramanan * ice_aq_get_sw_cfg - get switch configuration 5569c20346bSAnirudh Venkataramanan * @hw: pointer to the hardware structure 5579c20346bSAnirudh Venkataramanan * @buf: pointer to the result buffer 5589c20346bSAnirudh Venkataramanan * @buf_size: length of the buffer available for response 5599c20346bSAnirudh Venkataramanan * @req_desc: pointer to requested descriptor 5609c20346bSAnirudh Venkataramanan * @num_elems: pointer to number of elements 5619c20346bSAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 5629c20346bSAnirudh Venkataramanan * 563b3c38904SBruce Allan * Get switch configuration (0x0200) to be placed in buf. 5649c20346bSAnirudh Venkataramanan * This admin command returns information such as initial VSI/port number 5659c20346bSAnirudh Venkataramanan * and switch ID it belongs to. 5669c20346bSAnirudh Venkataramanan * 5679c20346bSAnirudh Venkataramanan * NOTE: *req_desc is both an input/output parameter. 5689c20346bSAnirudh Venkataramanan * The caller of this function first calls this function with *request_desc set 5699c20346bSAnirudh Venkataramanan * to 0. If the response from f/w has *req_desc set to 0, all the switch 5709c20346bSAnirudh Venkataramanan * configuration information has been returned; if non-zero (meaning not all 5719c20346bSAnirudh Venkataramanan * the information was returned), the caller should call this function again 5729c20346bSAnirudh Venkataramanan * with *req_desc set to the previous value returned by f/w to get the 5739c20346bSAnirudh Venkataramanan * next block of switch configuration information. 5749c20346bSAnirudh Venkataramanan * 5759c20346bSAnirudh Venkataramanan * *num_elems is output only parameter. This reflects the number of elements 5769c20346bSAnirudh Venkataramanan * in response buffer. The caller of this function to use *num_elems while 5779c20346bSAnirudh Venkataramanan * parsing the response buffer. 5789c20346bSAnirudh Venkataramanan */ 5795e24d598STony Nguyen static int 580b3c38904SBruce Allan ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf, 5819c20346bSAnirudh Venkataramanan u16 buf_size, u16 *req_desc, u16 *num_elems, 5829c20346bSAnirudh Venkataramanan struct ice_sq_cd *cd) 5839c20346bSAnirudh Venkataramanan { 5849c20346bSAnirudh Venkataramanan struct ice_aqc_get_sw_cfg *cmd; 5859c20346bSAnirudh Venkataramanan struct ice_aq_desc desc; 5865e24d598STony Nguyen int status; 5879c20346bSAnirudh Venkataramanan 5889c20346bSAnirudh Venkataramanan ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg); 5899c20346bSAnirudh Venkataramanan cmd = &desc.params.get_sw_conf; 5909c20346bSAnirudh Venkataramanan cmd->element = cpu_to_le16(*req_desc); 5919c20346bSAnirudh Venkataramanan 5929c20346bSAnirudh Venkataramanan status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 5939c20346bSAnirudh Venkataramanan if (!status) { 5949c20346bSAnirudh Venkataramanan *req_desc = le16_to_cpu(cmd->element); 5959c20346bSAnirudh Venkataramanan *num_elems = le16_to_cpu(cmd->num_elems); 5969c20346bSAnirudh Venkataramanan } 5979c20346bSAnirudh Venkataramanan 5989c20346bSAnirudh Venkataramanan return status; 5999c20346bSAnirudh Venkataramanan } 6009c20346bSAnirudh Venkataramanan 6013a858ba3SAnirudh Venkataramanan /** 6023a858ba3SAnirudh Venkataramanan * ice_aq_add_vsi 603f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 6043a858ba3SAnirudh Venkataramanan * @vsi_ctx: pointer to a VSI context struct 6053a858ba3SAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 6063a858ba3SAnirudh Venkataramanan * 6073a858ba3SAnirudh Venkataramanan * Add a VSI context to the hardware (0x0210) 6083a858ba3SAnirudh Venkataramanan */ 6095e24d598STony Nguyen static int 6103a858ba3SAnirudh Venkataramanan ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, 6113a858ba3SAnirudh Venkataramanan struct ice_sq_cd *cd) 6123a858ba3SAnirudh Venkataramanan { 6133a858ba3SAnirudh Venkataramanan struct ice_aqc_add_update_free_vsi_resp *res; 6143a858ba3SAnirudh Venkataramanan struct ice_aqc_add_get_update_free_vsi *cmd; 6153a858ba3SAnirudh Venkataramanan struct ice_aq_desc desc; 6165e24d598STony Nguyen int status; 6173a858ba3SAnirudh Venkataramanan 6183a858ba3SAnirudh Venkataramanan cmd = &desc.params.vsi_cmd; 6190f9d5027SAnirudh Venkataramanan res = &desc.params.add_update_free_vsi_res; 6203a858ba3SAnirudh Venkataramanan 6213a858ba3SAnirudh Venkataramanan ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi); 6223a858ba3SAnirudh Venkataramanan 6233a858ba3SAnirudh Venkataramanan if (!vsi_ctx->alloc_from_pool) 6243a858ba3SAnirudh Venkataramanan cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | 6253a858ba3SAnirudh Venkataramanan ICE_AQ_VSI_IS_VALID); 6261071a835SAnirudh Venkataramanan cmd->vf_id = vsi_ctx->vf_num; 6273a858ba3SAnirudh Venkataramanan 6283a858ba3SAnirudh Venkataramanan cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags); 6293a858ba3SAnirudh Venkataramanan 6303a858ba3SAnirudh Venkataramanan desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 6313a858ba3SAnirudh Venkataramanan 6323a858ba3SAnirudh Venkataramanan status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info, 6333a858ba3SAnirudh Venkataramanan sizeof(vsi_ctx->info), cd); 6343a858ba3SAnirudh Venkataramanan 6353a858ba3SAnirudh Venkataramanan if (!status) { 6363a858ba3SAnirudh Venkataramanan vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M; 6373a858ba3SAnirudh Venkataramanan vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used); 6383a858ba3SAnirudh Venkataramanan vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free); 6393a858ba3SAnirudh Venkataramanan } 6403a858ba3SAnirudh Venkataramanan 6413a858ba3SAnirudh Venkataramanan return status; 6423a858ba3SAnirudh Venkataramanan } 6433a858ba3SAnirudh Venkataramanan 6443a858ba3SAnirudh Venkataramanan /** 6450f9d5027SAnirudh Venkataramanan * ice_aq_free_vsi 646f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 6470f9d5027SAnirudh Venkataramanan * @vsi_ctx: pointer to a VSI context struct 6480f9d5027SAnirudh Venkataramanan * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources 6490f9d5027SAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 6500f9d5027SAnirudh Venkataramanan * 6510f9d5027SAnirudh Venkataramanan * Free VSI context info from hardware (0x0213) 6520f9d5027SAnirudh Venkataramanan */ 6535e24d598STony Nguyen static int 6540f9d5027SAnirudh Venkataramanan ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, 6550f9d5027SAnirudh Venkataramanan bool keep_vsi_alloc, struct ice_sq_cd *cd) 6560f9d5027SAnirudh Venkataramanan { 6570f9d5027SAnirudh Venkataramanan struct ice_aqc_add_update_free_vsi_resp *resp; 6580f9d5027SAnirudh Venkataramanan struct ice_aqc_add_get_update_free_vsi *cmd; 6590f9d5027SAnirudh Venkataramanan struct ice_aq_desc desc; 6605e24d598STony Nguyen int status; 6610f9d5027SAnirudh Venkataramanan 6620f9d5027SAnirudh Venkataramanan cmd = &desc.params.vsi_cmd; 6630f9d5027SAnirudh Venkataramanan resp = &desc.params.add_update_free_vsi_res; 6640f9d5027SAnirudh Venkataramanan 6650f9d5027SAnirudh Venkataramanan ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi); 6660f9d5027SAnirudh Venkataramanan 6670f9d5027SAnirudh Venkataramanan cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); 6680f9d5027SAnirudh Venkataramanan if (keep_vsi_alloc) 6690f9d5027SAnirudh Venkataramanan cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC); 6700f9d5027SAnirudh Venkataramanan 6710f9d5027SAnirudh Venkataramanan status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); 6720f9d5027SAnirudh Venkataramanan if (!status) { 6730f9d5027SAnirudh Venkataramanan vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); 6740f9d5027SAnirudh Venkataramanan vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); 6750f9d5027SAnirudh Venkataramanan } 6760f9d5027SAnirudh Venkataramanan 6770f9d5027SAnirudh Venkataramanan return status; 6780f9d5027SAnirudh Venkataramanan } 6790f9d5027SAnirudh Venkataramanan 6800f9d5027SAnirudh Venkataramanan /** 6813a858ba3SAnirudh Venkataramanan * ice_aq_update_vsi 682f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 6833a858ba3SAnirudh Venkataramanan * @vsi_ctx: pointer to a VSI context struct 6843a858ba3SAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 6853a858ba3SAnirudh Venkataramanan * 6863a858ba3SAnirudh Venkataramanan * Update VSI context in the hardware (0x0211) 6873a858ba3SAnirudh Venkataramanan */ 6885e24d598STony Nguyen static int 6893a858ba3SAnirudh Venkataramanan ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, 6903a858ba3SAnirudh Venkataramanan struct ice_sq_cd *cd) 6913a858ba3SAnirudh Venkataramanan { 6923a858ba3SAnirudh Venkataramanan struct ice_aqc_add_update_free_vsi_resp *resp; 6933a858ba3SAnirudh Venkataramanan struct ice_aqc_add_get_update_free_vsi *cmd; 6943a858ba3SAnirudh Venkataramanan struct ice_aq_desc desc; 6955e24d598STony Nguyen int status; 6963a858ba3SAnirudh Venkataramanan 6973a858ba3SAnirudh Venkataramanan cmd = &desc.params.vsi_cmd; 6980f9d5027SAnirudh Venkataramanan resp = &desc.params.add_update_free_vsi_res; 6993a858ba3SAnirudh Venkataramanan 7003a858ba3SAnirudh Venkataramanan ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi); 7013a858ba3SAnirudh Venkataramanan 7023a858ba3SAnirudh Venkataramanan cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); 7033a858ba3SAnirudh Venkataramanan 7043a858ba3SAnirudh Venkataramanan desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 7053a858ba3SAnirudh Venkataramanan 7063a858ba3SAnirudh Venkataramanan status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info, 7073a858ba3SAnirudh Venkataramanan sizeof(vsi_ctx->info), cd); 7083a858ba3SAnirudh Venkataramanan 7093a858ba3SAnirudh Venkataramanan if (!status) { 7103a858ba3SAnirudh Venkataramanan vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); 7113a858ba3SAnirudh Venkataramanan vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); 7123a858ba3SAnirudh Venkataramanan } 7133a858ba3SAnirudh Venkataramanan 7143a858ba3SAnirudh Venkataramanan return status; 7153a858ba3SAnirudh Venkataramanan } 7163a858ba3SAnirudh Venkataramanan 7173a858ba3SAnirudh Venkataramanan /** 7180f9d5027SAnirudh Venkataramanan * ice_is_vsi_valid - check whether the VSI is valid or not 719f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 7200f9d5027SAnirudh Venkataramanan * @vsi_handle: VSI handle 7210f9d5027SAnirudh Venkataramanan * 7220f9d5027SAnirudh Venkataramanan * check whether the VSI is valid or not 7230f9d5027SAnirudh Venkataramanan */ 7244fb33f31SAnirudh Venkataramanan bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) 7250f9d5027SAnirudh Venkataramanan { 7260f9d5027SAnirudh Venkataramanan return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle]; 7270f9d5027SAnirudh Venkataramanan } 7280f9d5027SAnirudh Venkataramanan 7290f9d5027SAnirudh Venkataramanan /** 730f9867df6SAnirudh Venkataramanan * ice_get_hw_vsi_num - return the HW VSI number 731f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 7320f9d5027SAnirudh Venkataramanan * @vsi_handle: VSI handle 7330f9d5027SAnirudh Venkataramanan * 734f9867df6SAnirudh Venkataramanan * return the HW VSI number 7350f9d5027SAnirudh Venkataramanan * Caution: call this function only if VSI is valid (ice_is_vsi_valid) 7360f9d5027SAnirudh Venkataramanan */ 7374fb33f31SAnirudh Venkataramanan u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) 7380f9d5027SAnirudh Venkataramanan { 7390f9d5027SAnirudh Venkataramanan return hw->vsi_ctx[vsi_handle]->vsi_num; 7400f9d5027SAnirudh Venkataramanan } 7410f9d5027SAnirudh Venkataramanan 7420f9d5027SAnirudh Venkataramanan /** 7430f9d5027SAnirudh Venkataramanan * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle 744f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 7450f9d5027SAnirudh Venkataramanan * @vsi_handle: VSI handle 7460f9d5027SAnirudh Venkataramanan * 7470f9d5027SAnirudh Venkataramanan * return the VSI context entry for a given VSI handle 7480f9d5027SAnirudh Venkataramanan */ 7494fb33f31SAnirudh Venkataramanan struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) 7500f9d5027SAnirudh Venkataramanan { 7510f9d5027SAnirudh Venkataramanan return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle]; 7520f9d5027SAnirudh Venkataramanan } 7530f9d5027SAnirudh Venkataramanan 7540f9d5027SAnirudh Venkataramanan /** 7550f9d5027SAnirudh Venkataramanan * ice_save_vsi_ctx - save the VSI context for a given VSI handle 756f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 7570f9d5027SAnirudh Venkataramanan * @vsi_handle: VSI handle 7580f9d5027SAnirudh Venkataramanan * @vsi: VSI context pointer 7590f9d5027SAnirudh Venkataramanan * 7600f9d5027SAnirudh Venkataramanan * save the VSI context entry for a given VSI handle 7610f9d5027SAnirudh Venkataramanan */ 762c8b7abddSBruce Allan static void 763c8b7abddSBruce Allan ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi) 7640f9d5027SAnirudh Venkataramanan { 7650f9d5027SAnirudh Venkataramanan hw->vsi_ctx[vsi_handle] = vsi; 7660f9d5027SAnirudh Venkataramanan } 7670f9d5027SAnirudh Venkataramanan 7680f9d5027SAnirudh Venkataramanan /** 769bb87ee0eSAnirudh Venkataramanan * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs 770bb87ee0eSAnirudh Venkataramanan * @hw: pointer to the HW struct 771bb87ee0eSAnirudh Venkataramanan * @vsi_handle: VSI handle 772bb87ee0eSAnirudh Venkataramanan */ 773bb87ee0eSAnirudh Venkataramanan static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle) 774bb87ee0eSAnirudh Venkataramanan { 775bb87ee0eSAnirudh Venkataramanan struct ice_vsi_ctx *vsi; 776bb87ee0eSAnirudh Venkataramanan u8 i; 777bb87ee0eSAnirudh Venkataramanan 778bb87ee0eSAnirudh Venkataramanan vsi = ice_get_vsi_ctx(hw, vsi_handle); 779bb87ee0eSAnirudh Venkataramanan if (!vsi) 780bb87ee0eSAnirudh Venkataramanan return; 781bb87ee0eSAnirudh Venkataramanan ice_for_each_traffic_class(i) { 782bb87ee0eSAnirudh Venkataramanan if (vsi->lan_q_ctx[i]) { 783bb87ee0eSAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]); 784bb87ee0eSAnirudh Venkataramanan vsi->lan_q_ctx[i] = NULL; 785bb87ee0eSAnirudh Venkataramanan } 786348048e7SDave Ertman if (vsi->rdma_q_ctx[i]) { 787348048e7SDave Ertman devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]); 788348048e7SDave Ertman vsi->rdma_q_ctx[i] = NULL; 789348048e7SDave Ertman } 790bb87ee0eSAnirudh Venkataramanan } 791bb87ee0eSAnirudh Venkataramanan } 792bb87ee0eSAnirudh Venkataramanan 793bb87ee0eSAnirudh Venkataramanan /** 7940f9d5027SAnirudh Venkataramanan * ice_clear_vsi_ctx - clear the VSI context entry 795f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 7960f9d5027SAnirudh Venkataramanan * @vsi_handle: VSI handle 7970f9d5027SAnirudh Venkataramanan * 7980f9d5027SAnirudh Venkataramanan * clear the VSI context entry 7990f9d5027SAnirudh Venkataramanan */ 8000f9d5027SAnirudh Venkataramanan static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) 8010f9d5027SAnirudh Venkataramanan { 8020f9d5027SAnirudh Venkataramanan struct ice_vsi_ctx *vsi; 8030f9d5027SAnirudh Venkataramanan 8040f9d5027SAnirudh Venkataramanan vsi = ice_get_vsi_ctx(hw, vsi_handle); 8050f9d5027SAnirudh Venkataramanan if (vsi) { 806bb87ee0eSAnirudh Venkataramanan ice_clear_vsi_q_ctx(hw, vsi_handle); 8070f9d5027SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), vsi); 8080f9d5027SAnirudh Venkataramanan hw->vsi_ctx[vsi_handle] = NULL; 8090f9d5027SAnirudh Venkataramanan } 8100f9d5027SAnirudh Venkataramanan } 8110f9d5027SAnirudh Venkataramanan 8120f9d5027SAnirudh Venkataramanan /** 81333e055fcSVictor Raj * ice_clear_all_vsi_ctx - clear all the VSI context entries 814f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 81533e055fcSVictor Raj */ 81633e055fcSVictor Raj void ice_clear_all_vsi_ctx(struct ice_hw *hw) 81733e055fcSVictor Raj { 81833e055fcSVictor Raj u16 i; 81933e055fcSVictor Raj 82033e055fcSVictor Raj for (i = 0; i < ICE_MAX_VSI; i++) 82133e055fcSVictor Raj ice_clear_vsi_ctx(hw, i); 82233e055fcSVictor Raj } 82333e055fcSVictor Raj 82433e055fcSVictor Raj /** 8250f9d5027SAnirudh Venkataramanan * ice_add_vsi - add VSI context to the hardware and VSI handle list 826f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 8270f9d5027SAnirudh Venkataramanan * @vsi_handle: unique VSI handle provided by drivers 8280f9d5027SAnirudh Venkataramanan * @vsi_ctx: pointer to a VSI context struct 8290f9d5027SAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 8300f9d5027SAnirudh Venkataramanan * 8310f9d5027SAnirudh Venkataramanan * Add a VSI context to the hardware also add it into the VSI handle list. 8320f9d5027SAnirudh Venkataramanan * If this function gets called after reset for existing VSIs then update 8330f9d5027SAnirudh Venkataramanan * with the new HW VSI number in the corresponding VSI handle list entry. 8340f9d5027SAnirudh Venkataramanan */ 8355e24d598STony Nguyen int 8360f9d5027SAnirudh Venkataramanan ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, 8370f9d5027SAnirudh Venkataramanan struct ice_sq_cd *cd) 8380f9d5027SAnirudh Venkataramanan { 8390f9d5027SAnirudh Venkataramanan struct ice_vsi_ctx *tmp_vsi_ctx; 8405e24d598STony Nguyen int status; 8410f9d5027SAnirudh Venkataramanan 8420f9d5027SAnirudh Venkataramanan if (vsi_handle >= ICE_MAX_VSI) 843d54699e2STony Nguyen return -EINVAL; 8440f9d5027SAnirudh Venkataramanan status = ice_aq_add_vsi(hw, vsi_ctx, cd); 8450f9d5027SAnirudh Venkataramanan if (status) 8460f9d5027SAnirudh Venkataramanan return status; 8470f9d5027SAnirudh Venkataramanan tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 8480f9d5027SAnirudh Venkataramanan if (!tmp_vsi_ctx) { 849f9867df6SAnirudh Venkataramanan /* Create a new VSI context */ 8500f9d5027SAnirudh Venkataramanan tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw), 8510f9d5027SAnirudh Venkataramanan sizeof(*tmp_vsi_ctx), GFP_KERNEL); 8520f9d5027SAnirudh Venkataramanan if (!tmp_vsi_ctx) { 8530f9d5027SAnirudh Venkataramanan ice_aq_free_vsi(hw, vsi_ctx, false, cd); 854d54699e2STony Nguyen return -ENOMEM; 8550f9d5027SAnirudh Venkataramanan } 8560f9d5027SAnirudh Venkataramanan *tmp_vsi_ctx = *vsi_ctx; 8570f9d5027SAnirudh Venkataramanan ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx); 8580f9d5027SAnirudh Venkataramanan } else { 8590f9d5027SAnirudh Venkataramanan /* update with new HW VSI num */ 8600f9d5027SAnirudh Venkataramanan tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; 8610f9d5027SAnirudh Venkataramanan } 8620f9d5027SAnirudh Venkataramanan 8631b5c19c7SBruce Allan return 0; 8640f9d5027SAnirudh Venkataramanan } 8650f9d5027SAnirudh Venkataramanan 8660f9d5027SAnirudh Venkataramanan /** 8670f9d5027SAnirudh Venkataramanan * ice_free_vsi- free VSI context from hardware and VSI handle list 868f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 8690f9d5027SAnirudh Venkataramanan * @vsi_handle: unique VSI handle 8703a858ba3SAnirudh Venkataramanan * @vsi_ctx: pointer to a VSI context struct 8713a858ba3SAnirudh Venkataramanan * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources 8723a858ba3SAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 8733a858ba3SAnirudh Venkataramanan * 8740f9d5027SAnirudh Venkataramanan * Free VSI context info from hardware as well as from VSI handle list 8753a858ba3SAnirudh Venkataramanan */ 8765e24d598STony Nguyen int 8770f9d5027SAnirudh Venkataramanan ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, 8783a858ba3SAnirudh Venkataramanan bool keep_vsi_alloc, struct ice_sq_cd *cd) 8793a858ba3SAnirudh Venkataramanan { 8805e24d598STony Nguyen int status; 8813a858ba3SAnirudh Venkataramanan 8820f9d5027SAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 883d54699e2STony Nguyen return -EINVAL; 8840f9d5027SAnirudh Venkataramanan vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); 8850f9d5027SAnirudh Venkataramanan status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd); 8860f9d5027SAnirudh Venkataramanan if (!status) 8870f9d5027SAnirudh Venkataramanan ice_clear_vsi_ctx(hw, vsi_handle); 8883a858ba3SAnirudh Venkataramanan return status; 8893a858ba3SAnirudh Venkataramanan } 8903a858ba3SAnirudh Venkataramanan 8919daf8208SAnirudh Venkataramanan /** 8925726ca0eSAnirudh Venkataramanan * ice_update_vsi 893f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 8945726ca0eSAnirudh Venkataramanan * @vsi_handle: unique VSI handle 8955726ca0eSAnirudh Venkataramanan * @vsi_ctx: pointer to a VSI context struct 8965726ca0eSAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 8975726ca0eSAnirudh Venkataramanan * 8985726ca0eSAnirudh Venkataramanan * Update VSI context in the hardware 8995726ca0eSAnirudh Venkataramanan */ 9005e24d598STony Nguyen int 9015726ca0eSAnirudh Venkataramanan ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, 9025726ca0eSAnirudh Venkataramanan struct ice_sq_cd *cd) 9035726ca0eSAnirudh Venkataramanan { 9045726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 905d54699e2STony Nguyen return -EINVAL; 9065726ca0eSAnirudh Venkataramanan vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); 9075726ca0eSAnirudh Venkataramanan return ice_aq_update_vsi(hw, vsi_ctx, cd); 9085726ca0eSAnirudh Venkataramanan } 9095726ca0eSAnirudh Venkataramanan 9105726ca0eSAnirudh Venkataramanan /** 911348048e7SDave Ertman * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI 912348048e7SDave Ertman * @hw: pointer to HW struct 913348048e7SDave Ertman * @vsi_handle: VSI SW index 914348048e7SDave Ertman * @enable: boolean for enable/disable 915348048e7SDave Ertman */ 916348048e7SDave Ertman int 917348048e7SDave Ertman ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable) 918348048e7SDave Ertman { 919348048e7SDave Ertman struct ice_vsi_ctx *ctx; 920348048e7SDave Ertman 921348048e7SDave Ertman ctx = ice_get_vsi_ctx(hw, vsi_handle); 922348048e7SDave Ertman if (!ctx) 923348048e7SDave Ertman return -EIO; 924348048e7SDave Ertman 925348048e7SDave Ertman if (enable) 926348048e7SDave Ertman ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; 927348048e7SDave Ertman else 928348048e7SDave Ertman ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; 929348048e7SDave Ertman 930d54699e2STony Nguyen return ice_update_vsi(hw, vsi_handle, ctx, NULL); 931348048e7SDave Ertman } 932348048e7SDave Ertman 933348048e7SDave Ertman /** 9349daf8208SAnirudh Venkataramanan * ice_aq_alloc_free_vsi_list 935f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 936f9867df6SAnirudh Venkataramanan * @vsi_list_id: VSI list ID returned or used for lookup 9379daf8208SAnirudh Venkataramanan * @lkup_type: switch rule filter lookup type 9389daf8208SAnirudh Venkataramanan * @opc: switch rules population command type - pass in the command opcode 9399daf8208SAnirudh Venkataramanan * 9409daf8208SAnirudh Venkataramanan * allocates or free a VSI list resource 9419daf8208SAnirudh Venkataramanan */ 9425e24d598STony Nguyen static int 9439daf8208SAnirudh Venkataramanan ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id, 9449daf8208SAnirudh Venkataramanan enum ice_sw_lkup_type lkup_type, 9459daf8208SAnirudh Venkataramanan enum ice_adminq_opc opc) 9469daf8208SAnirudh Venkataramanan { 9479daf8208SAnirudh Venkataramanan struct ice_aqc_alloc_free_res_elem *sw_buf; 9489daf8208SAnirudh Venkataramanan struct ice_aqc_res_elem *vsi_ele; 9499daf8208SAnirudh Venkataramanan u16 buf_len; 9505518ac2aSTony Nguyen int status; 9519daf8208SAnirudh Venkataramanan 95266486d89SBruce Allan buf_len = struct_size(sw_buf, elem, 1); 9539daf8208SAnirudh Venkataramanan sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL); 9549daf8208SAnirudh Venkataramanan if (!sw_buf) 955d54699e2STony Nguyen return -ENOMEM; 9569daf8208SAnirudh Venkataramanan sw_buf->num_elems = cpu_to_le16(1); 9579daf8208SAnirudh Venkataramanan 9589daf8208SAnirudh Venkataramanan if (lkup_type == ICE_SW_LKUP_MAC || 9599daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_MAC_VLAN || 9609daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_ETHERTYPE || 9619daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || 9629daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_PROMISC || 9639daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_PROMISC_VLAN) { 9649daf8208SAnirudh Venkataramanan sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP); 9659daf8208SAnirudh Venkataramanan } else if (lkup_type == ICE_SW_LKUP_VLAN) { 9669daf8208SAnirudh Venkataramanan sw_buf->res_type = 9679daf8208SAnirudh Venkataramanan cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE); 9689daf8208SAnirudh Venkataramanan } else { 969d54699e2STony Nguyen status = -EINVAL; 9709daf8208SAnirudh Venkataramanan goto ice_aq_alloc_free_vsi_list_exit; 9719daf8208SAnirudh Venkataramanan } 9729daf8208SAnirudh Venkataramanan 9739daf8208SAnirudh Venkataramanan if (opc == ice_aqc_opc_free_res) 9749daf8208SAnirudh Venkataramanan sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id); 9759daf8208SAnirudh Venkataramanan 9769daf8208SAnirudh Venkataramanan status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL); 9779daf8208SAnirudh Venkataramanan if (status) 9789daf8208SAnirudh Venkataramanan goto ice_aq_alloc_free_vsi_list_exit; 9799daf8208SAnirudh Venkataramanan 9809daf8208SAnirudh Venkataramanan if (opc == ice_aqc_opc_alloc_res) { 9819daf8208SAnirudh Venkataramanan vsi_ele = &sw_buf->elem[0]; 9829daf8208SAnirudh Venkataramanan *vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp); 9839daf8208SAnirudh Venkataramanan } 9849daf8208SAnirudh Venkataramanan 9859daf8208SAnirudh Venkataramanan ice_aq_alloc_free_vsi_list_exit: 9869daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), sw_buf); 9879daf8208SAnirudh Venkataramanan return status; 9889daf8208SAnirudh Venkataramanan } 9899daf8208SAnirudh Venkataramanan 9909daf8208SAnirudh Venkataramanan /** 9919daf8208SAnirudh Venkataramanan * ice_aq_sw_rules - add/update/remove switch rules 992f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 9939daf8208SAnirudh Venkataramanan * @rule_list: pointer to switch rule population list 9949daf8208SAnirudh Venkataramanan * @rule_list_sz: total size of the rule list in bytes 9959daf8208SAnirudh Venkataramanan * @num_rules: number of switch rules in the rule_list 9969daf8208SAnirudh Venkataramanan * @opc: switch rules population command type - pass in the command opcode 9979daf8208SAnirudh Venkataramanan * @cd: pointer to command details structure or NULL 9989daf8208SAnirudh Venkataramanan * 9999daf8208SAnirudh Venkataramanan * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware 10009daf8208SAnirudh Venkataramanan */ 10015e24d598STony Nguyen int 10029daf8208SAnirudh Venkataramanan ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz, 10039daf8208SAnirudh Venkataramanan u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd) 10049daf8208SAnirudh Venkataramanan { 10059daf8208SAnirudh Venkataramanan struct ice_aq_desc desc; 10065e24d598STony Nguyen int status; 10079daf8208SAnirudh Venkataramanan 10089daf8208SAnirudh Venkataramanan if (opc != ice_aqc_opc_add_sw_rules && 10099daf8208SAnirudh Venkataramanan opc != ice_aqc_opc_update_sw_rules && 10109daf8208SAnirudh Venkataramanan opc != ice_aqc_opc_remove_sw_rules) 1011d54699e2STony Nguyen return -EINVAL; 10129daf8208SAnirudh Venkataramanan 10139daf8208SAnirudh Venkataramanan ice_fill_dflt_direct_cmd_desc(&desc, opc); 10149daf8208SAnirudh Venkataramanan 10159daf8208SAnirudh Venkataramanan desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 10169daf8208SAnirudh Venkataramanan desc.params.sw_rules.num_rules_fltr_entry_index = 10179daf8208SAnirudh Venkataramanan cpu_to_le16(num_rules); 1018ca1fdb88SKiran Patil status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd); 1019ca1fdb88SKiran Patil if (opc != ice_aqc_opc_add_sw_rules && 1020ca1fdb88SKiran Patil hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) 1021d54699e2STony Nguyen status = -ENOENT; 1022ca1fdb88SKiran Patil 1023ca1fdb88SKiran Patil return status; 10249daf8208SAnirudh Venkataramanan } 10259daf8208SAnirudh Venkataramanan 10267715ec32SGrishma Kotecha /** 10277715ec32SGrishma Kotecha * ice_aq_add_recipe - add switch recipe 10287715ec32SGrishma Kotecha * @hw: pointer to the HW struct 10297715ec32SGrishma Kotecha * @s_recipe_list: pointer to switch rule population list 10307715ec32SGrishma Kotecha * @num_recipes: number of switch recipes in the list 10317715ec32SGrishma Kotecha * @cd: pointer to command details structure or NULL 10327715ec32SGrishma Kotecha * 10337715ec32SGrishma Kotecha * Add(0x0290) 10347715ec32SGrishma Kotecha */ 10355e24d598STony Nguyen static int 10367715ec32SGrishma Kotecha ice_aq_add_recipe(struct ice_hw *hw, 10377715ec32SGrishma Kotecha struct ice_aqc_recipe_data_elem *s_recipe_list, 10387715ec32SGrishma Kotecha u16 num_recipes, struct ice_sq_cd *cd) 10397715ec32SGrishma Kotecha { 10407715ec32SGrishma Kotecha struct ice_aqc_add_get_recipe *cmd; 10417715ec32SGrishma Kotecha struct ice_aq_desc desc; 10427715ec32SGrishma Kotecha u16 buf_size; 10437715ec32SGrishma Kotecha 10447715ec32SGrishma Kotecha cmd = &desc.params.add_get_recipe; 10457715ec32SGrishma Kotecha ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_recipe); 10467715ec32SGrishma Kotecha 10477715ec32SGrishma Kotecha cmd->num_sub_recipes = cpu_to_le16(num_recipes); 10487715ec32SGrishma Kotecha desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 10497715ec32SGrishma Kotecha 10507715ec32SGrishma Kotecha buf_size = num_recipes * sizeof(*s_recipe_list); 10517715ec32SGrishma Kotecha 10527715ec32SGrishma Kotecha return ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd); 10537715ec32SGrishma Kotecha } 10547715ec32SGrishma Kotecha 10557715ec32SGrishma Kotecha /** 10567715ec32SGrishma Kotecha * ice_aq_get_recipe - get switch recipe 10577715ec32SGrishma Kotecha * @hw: pointer to the HW struct 10587715ec32SGrishma Kotecha * @s_recipe_list: pointer to switch rule population list 10597715ec32SGrishma Kotecha * @num_recipes: pointer to the number of recipes (input and output) 10607715ec32SGrishma Kotecha * @recipe_root: root recipe number of recipe(s) to retrieve 10617715ec32SGrishma Kotecha * @cd: pointer to command details structure or NULL 10627715ec32SGrishma Kotecha * 10637715ec32SGrishma Kotecha * Get(0x0292) 10647715ec32SGrishma Kotecha * 10657715ec32SGrishma Kotecha * On input, *num_recipes should equal the number of entries in s_recipe_list. 10667715ec32SGrishma Kotecha * On output, *num_recipes will equal the number of entries returned in 10677715ec32SGrishma Kotecha * s_recipe_list. 10687715ec32SGrishma Kotecha * 10697715ec32SGrishma Kotecha * The caller must supply enough space in s_recipe_list to hold all possible 10707715ec32SGrishma Kotecha * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES. 10717715ec32SGrishma Kotecha */ 10725e24d598STony Nguyen static int 10737715ec32SGrishma Kotecha ice_aq_get_recipe(struct ice_hw *hw, 10747715ec32SGrishma Kotecha struct ice_aqc_recipe_data_elem *s_recipe_list, 10757715ec32SGrishma Kotecha u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd) 10767715ec32SGrishma Kotecha { 10777715ec32SGrishma Kotecha struct ice_aqc_add_get_recipe *cmd; 10787715ec32SGrishma Kotecha struct ice_aq_desc desc; 10797715ec32SGrishma Kotecha u16 buf_size; 10805518ac2aSTony Nguyen int status; 10817715ec32SGrishma Kotecha 10827715ec32SGrishma Kotecha if (*num_recipes != ICE_MAX_NUM_RECIPES) 1083d54699e2STony Nguyen return -EINVAL; 10847715ec32SGrishma Kotecha 10857715ec32SGrishma Kotecha cmd = &desc.params.add_get_recipe; 10867715ec32SGrishma Kotecha ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe); 10877715ec32SGrishma Kotecha 10887715ec32SGrishma Kotecha cmd->return_index = cpu_to_le16(recipe_root); 10897715ec32SGrishma Kotecha cmd->num_sub_recipes = 0; 10907715ec32SGrishma Kotecha 10917715ec32SGrishma Kotecha buf_size = *num_recipes * sizeof(*s_recipe_list); 10927715ec32SGrishma Kotecha 10937715ec32SGrishma Kotecha status = ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd); 10947715ec32SGrishma Kotecha *num_recipes = le16_to_cpu(cmd->num_sub_recipes); 10957715ec32SGrishma Kotecha 10967715ec32SGrishma Kotecha return status; 10977715ec32SGrishma Kotecha } 10987715ec32SGrishma Kotecha 10997715ec32SGrishma Kotecha /** 11007715ec32SGrishma Kotecha * ice_aq_map_recipe_to_profile - Map recipe to packet profile 11017715ec32SGrishma Kotecha * @hw: pointer to the HW struct 11027715ec32SGrishma Kotecha * @profile_id: package profile ID to associate the recipe with 11037715ec32SGrishma Kotecha * @r_bitmap: Recipe bitmap filled in and need to be returned as response 11047715ec32SGrishma Kotecha * @cd: pointer to command details structure or NULL 11057715ec32SGrishma Kotecha * Recipe to profile association (0x0291) 11067715ec32SGrishma Kotecha */ 11075e24d598STony Nguyen static int 11087715ec32SGrishma Kotecha ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap, 11097715ec32SGrishma Kotecha struct ice_sq_cd *cd) 11107715ec32SGrishma Kotecha { 11117715ec32SGrishma Kotecha struct ice_aqc_recipe_to_profile *cmd; 11127715ec32SGrishma Kotecha struct ice_aq_desc desc; 11137715ec32SGrishma Kotecha 11147715ec32SGrishma Kotecha cmd = &desc.params.recipe_to_profile; 11157715ec32SGrishma Kotecha ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_recipe_to_profile); 11167715ec32SGrishma Kotecha cmd->profile_id = cpu_to_le16(profile_id); 11177715ec32SGrishma Kotecha /* Set the recipe ID bit in the bitmask to let the device know which 11187715ec32SGrishma Kotecha * profile we are associating the recipe to 11197715ec32SGrishma Kotecha */ 11207715ec32SGrishma Kotecha memcpy(cmd->recipe_assoc, r_bitmap, sizeof(cmd->recipe_assoc)); 11217715ec32SGrishma Kotecha 11227715ec32SGrishma Kotecha return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); 11237715ec32SGrishma Kotecha } 11247715ec32SGrishma Kotecha 11257715ec32SGrishma Kotecha /** 11267715ec32SGrishma Kotecha * ice_aq_get_recipe_to_profile - Map recipe to packet profile 11277715ec32SGrishma Kotecha * @hw: pointer to the HW struct 11287715ec32SGrishma Kotecha * @profile_id: package profile ID to associate the recipe with 11297715ec32SGrishma Kotecha * @r_bitmap: Recipe bitmap filled in and need to be returned as response 11307715ec32SGrishma Kotecha * @cd: pointer to command details structure or NULL 11317715ec32SGrishma Kotecha * Associate profile ID with given recipe (0x0293) 11327715ec32SGrishma Kotecha */ 11335e24d598STony Nguyen static int 11347715ec32SGrishma Kotecha ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap, 11357715ec32SGrishma Kotecha struct ice_sq_cd *cd) 11367715ec32SGrishma Kotecha { 11377715ec32SGrishma Kotecha struct ice_aqc_recipe_to_profile *cmd; 11387715ec32SGrishma Kotecha struct ice_aq_desc desc; 11395e24d598STony Nguyen int status; 11407715ec32SGrishma Kotecha 11417715ec32SGrishma Kotecha cmd = &desc.params.recipe_to_profile; 11427715ec32SGrishma Kotecha ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile); 11437715ec32SGrishma Kotecha cmd->profile_id = cpu_to_le16(profile_id); 11447715ec32SGrishma Kotecha 11457715ec32SGrishma Kotecha status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); 11467715ec32SGrishma Kotecha if (!status) 11477715ec32SGrishma Kotecha memcpy(r_bitmap, cmd->recipe_assoc, sizeof(cmd->recipe_assoc)); 11487715ec32SGrishma Kotecha 11497715ec32SGrishma Kotecha return status; 11507715ec32SGrishma Kotecha } 11517715ec32SGrishma Kotecha 11527715ec32SGrishma Kotecha /** 11537715ec32SGrishma Kotecha * ice_alloc_recipe - add recipe resource 11547715ec32SGrishma Kotecha * @hw: pointer to the hardware structure 11557715ec32SGrishma Kotecha * @rid: recipe ID returned as response to AQ call 11567715ec32SGrishma Kotecha */ 11575e24d598STony Nguyen static int ice_alloc_recipe(struct ice_hw *hw, u16 *rid) 11587715ec32SGrishma Kotecha { 11597715ec32SGrishma Kotecha struct ice_aqc_alloc_free_res_elem *sw_buf; 11607715ec32SGrishma Kotecha u16 buf_len; 11615518ac2aSTony Nguyen int status; 11627715ec32SGrishma Kotecha 11637715ec32SGrishma Kotecha buf_len = struct_size(sw_buf, elem, 1); 11647715ec32SGrishma Kotecha sw_buf = kzalloc(buf_len, GFP_KERNEL); 11657715ec32SGrishma Kotecha if (!sw_buf) 1166d54699e2STony Nguyen return -ENOMEM; 11677715ec32SGrishma Kotecha 11687715ec32SGrishma Kotecha sw_buf->num_elems = cpu_to_le16(1); 11697715ec32SGrishma Kotecha sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE << 11707715ec32SGrishma Kotecha ICE_AQC_RES_TYPE_S) | 11717715ec32SGrishma Kotecha ICE_AQC_RES_TYPE_FLAG_SHARED); 11727715ec32SGrishma Kotecha status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, 11737715ec32SGrishma Kotecha ice_aqc_opc_alloc_res, NULL); 11747715ec32SGrishma Kotecha if (!status) 11757715ec32SGrishma Kotecha *rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp); 11767715ec32SGrishma Kotecha kfree(sw_buf); 11777715ec32SGrishma Kotecha 11787715ec32SGrishma Kotecha return status; 11797715ec32SGrishma Kotecha } 11807715ec32SGrishma Kotecha 1181fd2a6b71SDan Nowlin /** 1182fd2a6b71SDan Nowlin * ice_get_recp_to_prof_map - updates recipe to profile mapping 1183fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 1184fd2a6b71SDan Nowlin * 1185fd2a6b71SDan Nowlin * This function is used to populate recipe_to_profile matrix where index to 1186fd2a6b71SDan Nowlin * this array is the recipe ID and the element is the mapping of which profiles 1187fd2a6b71SDan Nowlin * is this recipe mapped to. 1188fd2a6b71SDan Nowlin */ 1189fd2a6b71SDan Nowlin static void ice_get_recp_to_prof_map(struct ice_hw *hw) 1190fd2a6b71SDan Nowlin { 1191fd2a6b71SDan Nowlin DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); 1192fd2a6b71SDan Nowlin u16 i; 1193fd2a6b71SDan Nowlin 1194fd2a6b71SDan Nowlin for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) { 1195fd2a6b71SDan Nowlin u16 j; 1196fd2a6b71SDan Nowlin 1197fd2a6b71SDan Nowlin bitmap_zero(profile_to_recipe[i], ICE_MAX_NUM_RECIPES); 1198fd2a6b71SDan Nowlin bitmap_zero(r_bitmap, ICE_MAX_NUM_RECIPES); 1199fd2a6b71SDan Nowlin if (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL)) 1200fd2a6b71SDan Nowlin continue; 1201fd2a6b71SDan Nowlin bitmap_copy(profile_to_recipe[i], r_bitmap, 1202fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 1203fd2a6b71SDan Nowlin for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES) 1204fd2a6b71SDan Nowlin set_bit(i, recipe_to_profile[j]); 1205fd2a6b71SDan Nowlin } 1206fd2a6b71SDan Nowlin } 1207fd2a6b71SDan Nowlin 1208fd2a6b71SDan Nowlin /** 1209fd2a6b71SDan Nowlin * ice_collect_result_idx - copy result index values 1210fd2a6b71SDan Nowlin * @buf: buffer that contains the result index 1211fd2a6b71SDan Nowlin * @recp: the recipe struct to copy data into 1212fd2a6b71SDan Nowlin */ 1213fd2a6b71SDan Nowlin static void 1214fd2a6b71SDan Nowlin ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf, 1215fd2a6b71SDan Nowlin struct ice_sw_recipe *recp) 1216fd2a6b71SDan Nowlin { 1217fd2a6b71SDan Nowlin if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN) 1218fd2a6b71SDan Nowlin set_bit(buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, 1219fd2a6b71SDan Nowlin recp->res_idxs); 1220fd2a6b71SDan Nowlin } 1221fd2a6b71SDan Nowlin 1222fd2a6b71SDan Nowlin /** 1223fd2a6b71SDan Nowlin * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries 1224fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 1225fd2a6b71SDan Nowlin * @recps: struct that we need to populate 1226fd2a6b71SDan Nowlin * @rid: recipe ID that we are populating 1227fd2a6b71SDan Nowlin * @refresh_required: true if we should get recipe to profile mapping from FW 1228fd2a6b71SDan Nowlin * 1229fd2a6b71SDan Nowlin * This function is used to populate all the necessary entries into our 1230fd2a6b71SDan Nowlin * bookkeeping so that we have a current list of all the recipes that are 1231fd2a6b71SDan Nowlin * programmed in the firmware. 1232fd2a6b71SDan Nowlin */ 12335e24d598STony Nguyen static int 1234fd2a6b71SDan Nowlin ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, 1235fd2a6b71SDan Nowlin bool *refresh_required) 1236fd2a6b71SDan Nowlin { 1237fd2a6b71SDan Nowlin DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS); 1238fd2a6b71SDan Nowlin struct ice_aqc_recipe_data_elem *tmp; 1239fd2a6b71SDan Nowlin u16 num_recps = ICE_MAX_NUM_RECIPES; 1240fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts; 1241fd2a6b71SDan Nowlin u8 fv_word_idx = 0; 1242fd2a6b71SDan Nowlin u16 sub_recps; 12435518ac2aSTony Nguyen int status; 1244fd2a6b71SDan Nowlin 1245fd2a6b71SDan Nowlin bitmap_zero(result_bm, ICE_MAX_FV_WORDS); 1246fd2a6b71SDan Nowlin 1247fd2a6b71SDan Nowlin /* we need a buffer big enough to accommodate all the recipes */ 1248fd2a6b71SDan Nowlin tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL); 1249fd2a6b71SDan Nowlin if (!tmp) 1250d54699e2STony Nguyen return -ENOMEM; 1251fd2a6b71SDan Nowlin 1252fd2a6b71SDan Nowlin tmp[0].recipe_indx = rid; 1253fd2a6b71SDan Nowlin status = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL); 1254fd2a6b71SDan Nowlin /* non-zero status meaning recipe doesn't exist */ 1255fd2a6b71SDan Nowlin if (status) 1256fd2a6b71SDan Nowlin goto err_unroll; 1257fd2a6b71SDan Nowlin 1258fd2a6b71SDan Nowlin /* Get recipe to profile map so that we can get the fv from lkups that 1259fd2a6b71SDan Nowlin * we read for a recipe from FW. Since we want to minimize the number of 1260fd2a6b71SDan Nowlin * times we make this FW call, just make one call and cache the copy 1261fd2a6b71SDan Nowlin * until a new recipe is added. This operation is only required the 1262fd2a6b71SDan Nowlin * first time to get the changes from FW. Then to search existing 1263fd2a6b71SDan Nowlin * entries we don't need to update the cache again until another recipe 1264fd2a6b71SDan Nowlin * gets added. 1265fd2a6b71SDan Nowlin */ 1266fd2a6b71SDan Nowlin if (*refresh_required) { 1267fd2a6b71SDan Nowlin ice_get_recp_to_prof_map(hw); 1268fd2a6b71SDan Nowlin *refresh_required = false; 1269fd2a6b71SDan Nowlin } 1270fd2a6b71SDan Nowlin 1271fd2a6b71SDan Nowlin /* Start populating all the entries for recps[rid] based on lkups from 1272fd2a6b71SDan Nowlin * firmware. Note that we are only creating the root recipe in our 1273fd2a6b71SDan Nowlin * database. 1274fd2a6b71SDan Nowlin */ 1275fd2a6b71SDan Nowlin lkup_exts = &recps[rid].lkup_exts; 1276fd2a6b71SDan Nowlin 1277fd2a6b71SDan Nowlin for (sub_recps = 0; sub_recps < num_recps; sub_recps++) { 1278fd2a6b71SDan Nowlin struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps]; 1279fd2a6b71SDan Nowlin struct ice_recp_grp_entry *rg_entry; 1280fd2a6b71SDan Nowlin u8 i, prof, idx, prot = 0; 1281fd2a6b71SDan Nowlin bool is_root; 1282fd2a6b71SDan Nowlin u16 off = 0; 1283fd2a6b71SDan Nowlin 1284fd2a6b71SDan Nowlin rg_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rg_entry), 1285fd2a6b71SDan Nowlin GFP_KERNEL); 1286fd2a6b71SDan Nowlin if (!rg_entry) { 1287d54699e2STony Nguyen status = -ENOMEM; 1288fd2a6b71SDan Nowlin goto err_unroll; 1289fd2a6b71SDan Nowlin } 1290fd2a6b71SDan Nowlin 1291fd2a6b71SDan Nowlin idx = root_bufs.recipe_indx; 1292fd2a6b71SDan Nowlin is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT; 1293fd2a6b71SDan Nowlin 1294fd2a6b71SDan Nowlin /* Mark all result indices in this chain */ 1295fd2a6b71SDan Nowlin if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) 1296fd2a6b71SDan Nowlin set_bit(root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, 1297fd2a6b71SDan Nowlin result_bm); 1298fd2a6b71SDan Nowlin 1299fd2a6b71SDan Nowlin /* get the first profile that is associated with rid */ 1300fd2a6b71SDan Nowlin prof = find_first_bit(recipe_to_profile[idx], 1301fd2a6b71SDan Nowlin ICE_MAX_NUM_PROFILES); 1302fd2a6b71SDan Nowlin for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) { 1303fd2a6b71SDan Nowlin u8 lkup_indx = root_bufs.content.lkup_indx[i + 1]; 1304fd2a6b71SDan Nowlin 1305fd2a6b71SDan Nowlin rg_entry->fv_idx[i] = lkup_indx; 1306fd2a6b71SDan Nowlin rg_entry->fv_mask[i] = 1307fd2a6b71SDan Nowlin le16_to_cpu(root_bufs.content.mask[i + 1]); 1308fd2a6b71SDan Nowlin 1309fd2a6b71SDan Nowlin /* If the recipe is a chained recipe then all its 1310fd2a6b71SDan Nowlin * child recipe's result will have a result index. 1311fd2a6b71SDan Nowlin * To fill fv_words we should not use those result 1312fd2a6b71SDan Nowlin * index, we only need the protocol ids and offsets. 1313fd2a6b71SDan Nowlin * We will skip all the fv_idx which stores result 1314fd2a6b71SDan Nowlin * index in them. We also need to skip any fv_idx which 1315fd2a6b71SDan Nowlin * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a 1316fd2a6b71SDan Nowlin * valid offset value. 1317fd2a6b71SDan Nowlin */ 1318fd2a6b71SDan Nowlin if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) || 1319fd2a6b71SDan Nowlin rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE || 1320fd2a6b71SDan Nowlin rg_entry->fv_idx[i] == 0) 1321fd2a6b71SDan Nowlin continue; 1322fd2a6b71SDan Nowlin 1323fd2a6b71SDan Nowlin ice_find_prot_off(hw, ICE_BLK_SW, prof, 1324fd2a6b71SDan Nowlin rg_entry->fv_idx[i], &prot, &off); 1325fd2a6b71SDan Nowlin lkup_exts->fv_words[fv_word_idx].prot_id = prot; 1326fd2a6b71SDan Nowlin lkup_exts->fv_words[fv_word_idx].off = off; 1327fd2a6b71SDan Nowlin lkup_exts->field_mask[fv_word_idx] = 1328fd2a6b71SDan Nowlin rg_entry->fv_mask[i]; 1329fd2a6b71SDan Nowlin fv_word_idx++; 1330fd2a6b71SDan Nowlin } 1331fd2a6b71SDan Nowlin /* populate rg_list with the data from the child entry of this 1332fd2a6b71SDan Nowlin * recipe 1333fd2a6b71SDan Nowlin */ 1334fd2a6b71SDan Nowlin list_add(&rg_entry->l_entry, &recps[rid].rg_list); 1335fd2a6b71SDan Nowlin 1336fd2a6b71SDan Nowlin /* Propagate some data to the recipe database */ 1337fd2a6b71SDan Nowlin recps[idx].is_root = !!is_root; 1338fd2a6b71SDan Nowlin recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; 1339fd2a6b71SDan Nowlin bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS); 1340fd2a6b71SDan Nowlin if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) { 1341fd2a6b71SDan Nowlin recps[idx].chain_idx = root_bufs.content.result_indx & 1342fd2a6b71SDan Nowlin ~ICE_AQ_RECIPE_RESULT_EN; 1343fd2a6b71SDan Nowlin set_bit(recps[idx].chain_idx, recps[idx].res_idxs); 1344fd2a6b71SDan Nowlin } else { 1345fd2a6b71SDan Nowlin recps[idx].chain_idx = ICE_INVAL_CHAIN_IND; 1346fd2a6b71SDan Nowlin } 1347fd2a6b71SDan Nowlin 1348fd2a6b71SDan Nowlin if (!is_root) 1349fd2a6b71SDan Nowlin continue; 1350fd2a6b71SDan Nowlin 1351fd2a6b71SDan Nowlin /* Only do the following for root recipes entries */ 1352fd2a6b71SDan Nowlin memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap, 1353fd2a6b71SDan Nowlin sizeof(recps[idx].r_bitmap)); 1354fd2a6b71SDan Nowlin recps[idx].root_rid = root_bufs.content.rid & 1355fd2a6b71SDan Nowlin ~ICE_AQ_RECIPE_ID_IS_ROOT; 1356fd2a6b71SDan Nowlin recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; 1357fd2a6b71SDan Nowlin } 1358fd2a6b71SDan Nowlin 1359fd2a6b71SDan Nowlin /* Complete initialization of the root recipe entry */ 1360fd2a6b71SDan Nowlin lkup_exts->n_val_words = fv_word_idx; 1361fd2a6b71SDan Nowlin recps[rid].big_recp = (num_recps > 1); 1362fd2a6b71SDan Nowlin recps[rid].n_grp_count = (u8)num_recps; 1363fd2a6b71SDan Nowlin recps[rid].root_buf = devm_kmemdup(ice_hw_to_dev(hw), tmp, 1364fd2a6b71SDan Nowlin recps[rid].n_grp_count * sizeof(*recps[rid].root_buf), 1365fd2a6b71SDan Nowlin GFP_KERNEL); 1366c8e51a01SWang Hai if (!recps[rid].root_buf) { 1367d54699e2STony Nguyen status = -ENOMEM; 1368fd2a6b71SDan Nowlin goto err_unroll; 1369c8e51a01SWang Hai } 1370fd2a6b71SDan Nowlin 1371fd2a6b71SDan Nowlin /* Copy result indexes */ 1372fd2a6b71SDan Nowlin bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS); 1373fd2a6b71SDan Nowlin recps[rid].recp_created = true; 1374fd2a6b71SDan Nowlin 1375fd2a6b71SDan Nowlin err_unroll: 1376fd2a6b71SDan Nowlin kfree(tmp); 1377fd2a6b71SDan Nowlin return status; 1378fd2a6b71SDan Nowlin } 1379fd2a6b71SDan Nowlin 13809c20346bSAnirudh Venkataramanan /* ice_init_port_info - Initialize port_info with switch configuration data 13819c20346bSAnirudh Venkataramanan * @pi: pointer to port_info 13829c20346bSAnirudh Venkataramanan * @vsi_port_num: VSI number or port number 13839c20346bSAnirudh Venkataramanan * @type: Type of switch element (port or VSI) 13849c20346bSAnirudh Venkataramanan * @swid: switch ID of the switch the element is attached to 13859c20346bSAnirudh Venkataramanan * @pf_vf_num: PF or VF number 13869c20346bSAnirudh Venkataramanan * @is_vf: true if the element is a VF, false otherwise 13879c20346bSAnirudh Venkataramanan */ 13889c20346bSAnirudh Venkataramanan static void 13899c20346bSAnirudh Venkataramanan ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type, 13909c20346bSAnirudh Venkataramanan u16 swid, u16 pf_vf_num, bool is_vf) 13919c20346bSAnirudh Venkataramanan { 13929c20346bSAnirudh Venkataramanan switch (type) { 13939c20346bSAnirudh Venkataramanan case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT: 13949c20346bSAnirudh Venkataramanan pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK); 13959c20346bSAnirudh Venkataramanan pi->sw_id = swid; 13969c20346bSAnirudh Venkataramanan pi->pf_vf_num = pf_vf_num; 13979c20346bSAnirudh Venkataramanan pi->is_vf = is_vf; 13989c20346bSAnirudh Venkataramanan pi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL; 13999c20346bSAnirudh Venkataramanan pi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL; 14009c20346bSAnirudh Venkataramanan break; 14019c20346bSAnirudh Venkataramanan default: 14029228d8b2SJacob Keller ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n"); 14039c20346bSAnirudh Venkataramanan break; 14049c20346bSAnirudh Venkataramanan } 14059c20346bSAnirudh Venkataramanan } 14069c20346bSAnirudh Venkataramanan 14079c20346bSAnirudh Venkataramanan /* ice_get_initial_sw_cfg - Get initial port and default VSI data 14089c20346bSAnirudh Venkataramanan * @hw: pointer to the hardware structure 14099c20346bSAnirudh Venkataramanan */ 14105e24d598STony Nguyen int ice_get_initial_sw_cfg(struct ice_hw *hw) 14119c20346bSAnirudh Venkataramanan { 1412b3c38904SBruce Allan struct ice_aqc_get_sw_cfg_resp_elem *rbuf; 14139c20346bSAnirudh Venkataramanan u16 req_desc = 0; 14149c20346bSAnirudh Venkataramanan u16 num_elems; 14155518ac2aSTony Nguyen int status; 14169c20346bSAnirudh Venkataramanan u16 i; 14179c20346bSAnirudh Venkataramanan 14189c20346bSAnirudh Venkataramanan rbuf = devm_kzalloc(ice_hw_to_dev(hw), ICE_SW_CFG_MAX_BUF_LEN, 14199c20346bSAnirudh Venkataramanan GFP_KERNEL); 14209c20346bSAnirudh Venkataramanan 14219c20346bSAnirudh Venkataramanan if (!rbuf) 1422d54699e2STony Nguyen return -ENOMEM; 14239c20346bSAnirudh Venkataramanan 14249c20346bSAnirudh Venkataramanan /* Multiple calls to ice_aq_get_sw_cfg may be required 14259c20346bSAnirudh Venkataramanan * to get all the switch configuration information. The need 14269c20346bSAnirudh Venkataramanan * for additional calls is indicated by ice_aq_get_sw_cfg 14279c20346bSAnirudh Venkataramanan * writing a non-zero value in req_desc 14289c20346bSAnirudh Venkataramanan */ 14299c20346bSAnirudh Venkataramanan do { 1430b3c38904SBruce Allan struct ice_aqc_get_sw_cfg_resp_elem *ele; 1431b3c38904SBruce Allan 14329c20346bSAnirudh Venkataramanan status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN, 14339c20346bSAnirudh Venkataramanan &req_desc, &num_elems, NULL); 14349c20346bSAnirudh Venkataramanan 14359c20346bSAnirudh Venkataramanan if (status) 14369c20346bSAnirudh Venkataramanan break; 14379c20346bSAnirudh Venkataramanan 1438b3c38904SBruce Allan for (i = 0, ele = rbuf; i < num_elems; i++, ele++) { 14399c20346bSAnirudh Venkataramanan u16 pf_vf_num, swid, vsi_port_num; 14409c20346bSAnirudh Venkataramanan bool is_vf = false; 14416dae8aa0SBruce Allan u8 res_type; 14429c20346bSAnirudh Venkataramanan 14439c20346bSAnirudh Venkataramanan vsi_port_num = le16_to_cpu(ele->vsi_port_num) & 14449c20346bSAnirudh Venkataramanan ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M; 14459c20346bSAnirudh Venkataramanan 14469c20346bSAnirudh Venkataramanan pf_vf_num = le16_to_cpu(ele->pf_vf_num) & 14479c20346bSAnirudh Venkataramanan ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M; 14489c20346bSAnirudh Venkataramanan 14499c20346bSAnirudh Venkataramanan swid = le16_to_cpu(ele->swid); 14509c20346bSAnirudh Venkataramanan 14519c20346bSAnirudh Venkataramanan if (le16_to_cpu(ele->pf_vf_num) & 14529c20346bSAnirudh Venkataramanan ICE_AQC_GET_SW_CONF_RESP_IS_VF) 14539c20346bSAnirudh Venkataramanan is_vf = true; 14549c20346bSAnirudh Venkataramanan 145588865fc4SKarol Kolacinski res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >> 145688865fc4SKarol Kolacinski ICE_AQC_GET_SW_CONF_RESP_TYPE_S); 14579c20346bSAnirudh Venkataramanan 14586dae8aa0SBruce Allan if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) { 14599c20346bSAnirudh Venkataramanan /* FW VSI is not needed. Just continue. */ 14609c20346bSAnirudh Venkataramanan continue; 14619c20346bSAnirudh Venkataramanan } 14629c20346bSAnirudh Venkataramanan 14639c20346bSAnirudh Venkataramanan ice_init_port_info(hw->port_info, vsi_port_num, 14646dae8aa0SBruce Allan res_type, swid, pf_vf_num, is_vf); 14659c20346bSAnirudh Venkataramanan } 14669c20346bSAnirudh Venkataramanan } while (req_desc && !status); 14679c20346bSAnirudh Venkataramanan 14687a63dae0SBruce Allan devm_kfree(ice_hw_to_dev(hw), rbuf); 14699c20346bSAnirudh Venkataramanan return status; 14709c20346bSAnirudh Venkataramanan } 14719daf8208SAnirudh Venkataramanan 14729daf8208SAnirudh Venkataramanan /** 14739daf8208SAnirudh Venkataramanan * ice_fill_sw_info - Helper function to populate lb_en and lan_en 14749daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 14756a7e6993SYashaswini Raghuram Prathivadi Bhayankaram * @fi: filter info structure to fill/update 14769daf8208SAnirudh Venkataramanan * 14779daf8208SAnirudh Venkataramanan * This helper function populates the lb_en and lan_en elements of the provided 14789daf8208SAnirudh Venkataramanan * ice_fltr_info struct using the switch's type and characteristics of the 14799daf8208SAnirudh Venkataramanan * switch rule being configured. 14809daf8208SAnirudh Venkataramanan */ 14816a7e6993SYashaswini Raghuram Prathivadi Bhayankaram static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi) 14829daf8208SAnirudh Venkataramanan { 14836a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->lb_en = false; 14846a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->lan_en = false; 14856a7e6993SYashaswini Raghuram Prathivadi Bhayankaram if ((fi->flag & ICE_FLTR_TX) && 14866a7e6993SYashaswini Raghuram Prathivadi Bhayankaram (fi->fltr_act == ICE_FWD_TO_VSI || 14876a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->fltr_act == ICE_FWD_TO_VSI_LIST || 14886a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->fltr_act == ICE_FWD_TO_Q || 14896a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->fltr_act == ICE_FWD_TO_QGRP)) { 1490b58dafbcSChristopher N Bednarz /* Setting LB for prune actions will result in replicated 1491b58dafbcSChristopher N Bednarz * packets to the internal switch that will be dropped. 1492b58dafbcSChristopher N Bednarz */ 1493b58dafbcSChristopher N Bednarz if (fi->lkup_type != ICE_SW_LKUP_VLAN) 14946a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->lb_en = true; 1495b58dafbcSChristopher N Bednarz 1496277b3a45SYashaswini Raghuram Prathivadi Bhayankaram /* Set lan_en to TRUE if 14976a7e6993SYashaswini Raghuram Prathivadi Bhayankaram * 1. The switch is a VEB AND 14986a7e6993SYashaswini Raghuram Prathivadi Bhayankaram * 2 149926069b44SYashaswini Raghuram Prathivadi Bhayankaram * 2.1 The lookup is a directional lookup like ethertype, 1500f9867df6SAnirudh Venkataramanan * promiscuous, ethertype-MAC, promiscuous-VLAN 150126069b44SYashaswini Raghuram Prathivadi Bhayankaram * and default-port OR 150226069b44SYashaswini Raghuram Prathivadi Bhayankaram * 2.2 The lookup is VLAN, OR 1503277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR 1504277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC. 15056a7e6993SYashaswini Raghuram Prathivadi Bhayankaram * 1506277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * OR 1507277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * 1508277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * The switch is a VEPA. 1509277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * 1510277b3a45SYashaswini Raghuram Prathivadi Bhayankaram * In all other cases, the LAN enable has to be set to false. 15116a7e6993SYashaswini Raghuram Prathivadi Bhayankaram */ 1512277b3a45SYashaswini Raghuram Prathivadi Bhayankaram if (hw->evb_veb) { 151326069b44SYashaswini Raghuram Prathivadi Bhayankaram if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE || 151426069b44SYashaswini Raghuram Prathivadi Bhayankaram fi->lkup_type == ICE_SW_LKUP_PROMISC || 151526069b44SYashaswini Raghuram Prathivadi Bhayankaram fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || 151626069b44SYashaswini Raghuram Prathivadi Bhayankaram fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN || 1517277b3a45SYashaswini Raghuram Prathivadi Bhayankaram fi->lkup_type == ICE_SW_LKUP_DFLT || 151826069b44SYashaswini Raghuram Prathivadi Bhayankaram fi->lkup_type == ICE_SW_LKUP_VLAN || 1519277b3a45SYashaswini Raghuram Prathivadi Bhayankaram (fi->lkup_type == ICE_SW_LKUP_MAC && 1520277b3a45SYashaswini Raghuram Prathivadi Bhayankaram !is_unicast_ether_addr(fi->l_data.mac.mac_addr)) || 15216a7e6993SYashaswini Raghuram Prathivadi Bhayankaram (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN && 1522277b3a45SYashaswini Raghuram Prathivadi Bhayankaram !is_unicast_ether_addr(fi->l_data.mac.mac_addr))) 15236a7e6993SYashaswini Raghuram Prathivadi Bhayankaram fi->lan_en = true; 1524277b3a45SYashaswini Raghuram Prathivadi Bhayankaram } else { 1525277b3a45SYashaswini Raghuram Prathivadi Bhayankaram fi->lan_en = true; 1526277b3a45SYashaswini Raghuram Prathivadi Bhayankaram } 15279daf8208SAnirudh Venkataramanan } 15289daf8208SAnirudh Venkataramanan } 15299daf8208SAnirudh Venkataramanan 15309daf8208SAnirudh Venkataramanan /** 15319daf8208SAnirudh Venkataramanan * ice_fill_sw_rule - Helper function to fill switch rule structure 15329daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 15339daf8208SAnirudh Venkataramanan * @f_info: entry containing packet forwarding information 15349daf8208SAnirudh Venkataramanan * @s_rule: switch rule structure to be filled in based on mac_entry 15359daf8208SAnirudh Venkataramanan * @opc: switch rules population command type - pass in the command opcode 15369daf8208SAnirudh Venkataramanan */ 15379daf8208SAnirudh Venkataramanan static void 15389daf8208SAnirudh Venkataramanan ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, 15399daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc) 15409daf8208SAnirudh Venkataramanan { 15419daf8208SAnirudh Venkataramanan u16 vlan_id = ICE_MAX_VLAN_ID + 1; 1542*2bfefa2dSBrett Creeley u16 vlan_tpid = ETH_P_8021Q; 15439daf8208SAnirudh Venkataramanan void *daddr = NULL; 154474118f7aSZhenning Xiao u16 eth_hdr_sz; 154574118f7aSZhenning Xiao u8 *eth_hdr; 15469daf8208SAnirudh Venkataramanan u32 act = 0; 15479daf8208SAnirudh Venkataramanan __be16 *off; 1548be8ff000SAnirudh Venkataramanan u8 q_rgn; 15499daf8208SAnirudh Venkataramanan 15509daf8208SAnirudh Venkataramanan if (opc == ice_aqc_opc_remove_sw_rules) { 15519daf8208SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.act = 0; 15529daf8208SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.index = 15539daf8208SAnirudh Venkataramanan cpu_to_le16(f_info->fltr_rule_id); 15549daf8208SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.hdr_len = 0; 15559daf8208SAnirudh Venkataramanan return; 15569daf8208SAnirudh Venkataramanan } 15579daf8208SAnirudh Venkataramanan 155874118f7aSZhenning Xiao eth_hdr_sz = sizeof(dummy_eth_header); 155974118f7aSZhenning Xiao eth_hdr = s_rule->pdata.lkup_tx_rx.hdr; 156074118f7aSZhenning Xiao 15619daf8208SAnirudh Venkataramanan /* initialize the ether header with a dummy header */ 156274118f7aSZhenning Xiao memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz); 15639daf8208SAnirudh Venkataramanan ice_fill_sw_info(hw, f_info); 15649daf8208SAnirudh Venkataramanan 15659daf8208SAnirudh Venkataramanan switch (f_info->fltr_act) { 15669daf8208SAnirudh Venkataramanan case ICE_FWD_TO_VSI: 15675726ca0eSAnirudh Venkataramanan act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & 15689daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_VSI_ID_M; 15699daf8208SAnirudh Venkataramanan if (f_info->lkup_type != ICE_SW_LKUP_VLAN) 15709daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_VSI_FORWARDING | 15719daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_VALID_BIT; 15729daf8208SAnirudh Venkataramanan break; 15739daf8208SAnirudh Venkataramanan case ICE_FWD_TO_VSI_LIST: 15749daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_VSI_LIST; 15759daf8208SAnirudh Venkataramanan act |= (f_info->fwd_id.vsi_list_id << 15769daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_VSI_LIST_ID_S) & 15779daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_VSI_LIST_ID_M; 15789daf8208SAnirudh Venkataramanan if (f_info->lkup_type != ICE_SW_LKUP_VLAN) 15799daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_VSI_FORWARDING | 15809daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_VALID_BIT; 15819daf8208SAnirudh Venkataramanan break; 15829daf8208SAnirudh Venkataramanan case ICE_FWD_TO_Q: 15839daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_TO_Q; 15849daf8208SAnirudh Venkataramanan act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & 15859daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_Q_INDEX_M; 15869daf8208SAnirudh Venkataramanan break; 15879daf8208SAnirudh Venkataramanan case ICE_DROP_PACKET: 1588be8ff000SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | 1589be8ff000SAnirudh Venkataramanan ICE_SINGLE_ACT_VALID_BIT; 1590be8ff000SAnirudh Venkataramanan break; 1591be8ff000SAnirudh Venkataramanan case ICE_FWD_TO_QGRP: 1592be8ff000SAnirudh Venkataramanan q_rgn = f_info->qgrp_size > 0 ? 1593be8ff000SAnirudh Venkataramanan (u8)ilog2(f_info->qgrp_size) : 0; 1594be8ff000SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_TO_Q; 1595be8ff000SAnirudh Venkataramanan act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & 1596be8ff000SAnirudh Venkataramanan ICE_SINGLE_ACT_Q_INDEX_M; 1597be8ff000SAnirudh Venkataramanan act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & 1598be8ff000SAnirudh Venkataramanan ICE_SINGLE_ACT_Q_REGION_M; 15999daf8208SAnirudh Venkataramanan break; 16009daf8208SAnirudh Venkataramanan default: 16019daf8208SAnirudh Venkataramanan return; 16029daf8208SAnirudh Venkataramanan } 16039daf8208SAnirudh Venkataramanan 16049daf8208SAnirudh Venkataramanan if (f_info->lb_en) 16059daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_LB_ENABLE; 16069daf8208SAnirudh Venkataramanan if (f_info->lan_en) 16079daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_LAN_ENABLE; 16089daf8208SAnirudh Venkataramanan 16099daf8208SAnirudh Venkataramanan switch (f_info->lkup_type) { 16109daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_MAC: 16119daf8208SAnirudh Venkataramanan daddr = f_info->l_data.mac.mac_addr; 16129daf8208SAnirudh Venkataramanan break; 16139daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_VLAN: 16149daf8208SAnirudh Venkataramanan vlan_id = f_info->l_data.vlan.vlan_id; 1615*2bfefa2dSBrett Creeley if (f_info->l_data.vlan.tpid_valid) 1616*2bfefa2dSBrett Creeley vlan_tpid = f_info->l_data.vlan.tpid; 16179daf8208SAnirudh Venkataramanan if (f_info->fltr_act == ICE_FWD_TO_VSI || 16189daf8208SAnirudh Venkataramanan f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { 16199daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_PRUNE; 16209daf8208SAnirudh Venkataramanan act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS; 16219daf8208SAnirudh Venkataramanan } 16229daf8208SAnirudh Venkataramanan break; 16239daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_ETHERTYPE_MAC: 16249daf8208SAnirudh Venkataramanan daddr = f_info->l_data.ethertype_mac.mac_addr; 16254e83fc93SBruce Allan fallthrough; 16269daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_ETHERTYPE: 1627feee3cb3SBruce Allan off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); 16289daf8208SAnirudh Venkataramanan *off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype); 16299daf8208SAnirudh Venkataramanan break; 16309daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_MAC_VLAN: 16319daf8208SAnirudh Venkataramanan daddr = f_info->l_data.mac_vlan.mac_addr; 16329daf8208SAnirudh Venkataramanan vlan_id = f_info->l_data.mac_vlan.vlan_id; 16339daf8208SAnirudh Venkataramanan break; 16349daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_PROMISC_VLAN: 16359daf8208SAnirudh Venkataramanan vlan_id = f_info->l_data.mac_vlan.vlan_id; 16364e83fc93SBruce Allan fallthrough; 16379daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_PROMISC: 16389daf8208SAnirudh Venkataramanan daddr = f_info->l_data.mac_vlan.mac_addr; 16399daf8208SAnirudh Venkataramanan break; 16409daf8208SAnirudh Venkataramanan default: 16419daf8208SAnirudh Venkataramanan break; 16429daf8208SAnirudh Venkataramanan } 16439daf8208SAnirudh Venkataramanan 16449daf8208SAnirudh Venkataramanan s_rule->type = (f_info->flag & ICE_FLTR_RX) ? 16459daf8208SAnirudh Venkataramanan cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) : 16469daf8208SAnirudh Venkataramanan cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); 16479daf8208SAnirudh Venkataramanan 16489daf8208SAnirudh Venkataramanan /* Recipe set depending on lookup type */ 16499daf8208SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(f_info->lkup_type); 16509daf8208SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(f_info->src); 16519daf8208SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act); 16529daf8208SAnirudh Venkataramanan 16539daf8208SAnirudh Venkataramanan if (daddr) 165474118f7aSZhenning Xiao ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr); 16559daf8208SAnirudh Venkataramanan 16569daf8208SAnirudh Venkataramanan if (!(vlan_id > ICE_MAX_VLAN_ID)) { 1657feee3cb3SBruce Allan off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET); 16589daf8208SAnirudh Venkataramanan *off = cpu_to_be16(vlan_id); 1659*2bfefa2dSBrett Creeley off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); 1660*2bfefa2dSBrett Creeley *off = cpu_to_be16(vlan_tpid); 16619daf8208SAnirudh Venkataramanan } 16629daf8208SAnirudh Venkataramanan 16639daf8208SAnirudh Venkataramanan /* Create the switch rule with the final dummy Ethernet header */ 16649daf8208SAnirudh Venkataramanan if (opc != ice_aqc_opc_update_sw_rules) 166574118f7aSZhenning Xiao s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(eth_hdr_sz); 16669daf8208SAnirudh Venkataramanan } 16679daf8208SAnirudh Venkataramanan 16689daf8208SAnirudh Venkataramanan /** 16699daf8208SAnirudh Venkataramanan * ice_add_marker_act 16709daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 16719daf8208SAnirudh Venkataramanan * @m_ent: the management entry for which sw marker needs to be added 16729daf8208SAnirudh Venkataramanan * @sw_marker: sw marker to tag the Rx descriptor with 1673f9867df6SAnirudh Venkataramanan * @l_id: large action resource ID 16749daf8208SAnirudh Venkataramanan * 16759daf8208SAnirudh Venkataramanan * Create a large action to hold software marker and update the switch rule 16769daf8208SAnirudh Venkataramanan * entry pointed by m_ent with newly created large action 16779daf8208SAnirudh Venkataramanan */ 16785e24d598STony Nguyen static int 16799daf8208SAnirudh Venkataramanan ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, 16809daf8208SAnirudh Venkataramanan u16 sw_marker, u16 l_id) 16819daf8208SAnirudh Venkataramanan { 16829daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *lg_act, *rx_tx; 16839daf8208SAnirudh Venkataramanan /* For software marker we need 3 large actions 16849daf8208SAnirudh Venkataramanan * 1. FWD action: FWD TO VSI or VSI LIST 1685f9867df6SAnirudh Venkataramanan * 2. GENERIC VALUE action to hold the profile ID 1686f9867df6SAnirudh Venkataramanan * 3. GENERIC VALUE action to hold the software marker ID 16879daf8208SAnirudh Venkataramanan */ 16889daf8208SAnirudh Venkataramanan const u16 num_lg_acts = 3; 16899daf8208SAnirudh Venkataramanan u16 lg_act_size; 16909daf8208SAnirudh Venkataramanan u16 rules_size; 16915518ac2aSTony Nguyen int status; 16929daf8208SAnirudh Venkataramanan u32 act; 16935726ca0eSAnirudh Venkataramanan u16 id; 16949daf8208SAnirudh Venkataramanan 16959daf8208SAnirudh Venkataramanan if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC) 1696d54699e2STony Nguyen return -EINVAL; 16979daf8208SAnirudh Venkataramanan 16989daf8208SAnirudh Venkataramanan /* Create two back-to-back switch rules and submit them to the HW using 16999daf8208SAnirudh Venkataramanan * one memory buffer: 17009daf8208SAnirudh Venkataramanan * 1. Large Action 1701d337f2afSAnirudh Venkataramanan * 2. Look up Tx Rx 17029daf8208SAnirudh Venkataramanan */ 17039daf8208SAnirudh Venkataramanan lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(num_lg_acts); 17049daf8208SAnirudh Venkataramanan rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE; 17059daf8208SAnirudh Venkataramanan lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL); 17069daf8208SAnirudh Venkataramanan if (!lg_act) 1707d54699e2STony Nguyen return -ENOMEM; 17089daf8208SAnirudh Venkataramanan 17099daf8208SAnirudh Venkataramanan rx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size); 17109daf8208SAnirudh Venkataramanan 17119daf8208SAnirudh Venkataramanan /* Fill in the first switch rule i.e. large action */ 17129daf8208SAnirudh Venkataramanan lg_act->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT); 17139daf8208SAnirudh Venkataramanan lg_act->pdata.lg_act.index = cpu_to_le16(l_id); 17149daf8208SAnirudh Venkataramanan lg_act->pdata.lg_act.size = cpu_to_le16(num_lg_acts); 17159daf8208SAnirudh Venkataramanan 17169daf8208SAnirudh Venkataramanan /* First action VSI forwarding or VSI list forwarding depending on how 17179daf8208SAnirudh Venkataramanan * many VSIs 17189daf8208SAnirudh Venkataramanan */ 17195726ca0eSAnirudh Venkataramanan id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id : 17205726ca0eSAnirudh Venkataramanan m_ent->fltr_info.fwd_id.hw_vsi_id; 17219daf8208SAnirudh Venkataramanan 17229daf8208SAnirudh Venkataramanan act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT; 172366486d89SBruce Allan act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M; 17249daf8208SAnirudh Venkataramanan if (m_ent->vsi_count > 1) 17259daf8208SAnirudh Venkataramanan act |= ICE_LG_ACT_VSI_LIST; 17269daf8208SAnirudh Venkataramanan lg_act->pdata.lg_act.act[0] = cpu_to_le32(act); 17279daf8208SAnirudh Venkataramanan 17289daf8208SAnirudh Venkataramanan /* Second action descriptor type */ 17299daf8208SAnirudh Venkataramanan act = ICE_LG_ACT_GENERIC; 17309daf8208SAnirudh Venkataramanan 17319daf8208SAnirudh Venkataramanan act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M; 17329daf8208SAnirudh Venkataramanan lg_act->pdata.lg_act.act[1] = cpu_to_le32(act); 17339daf8208SAnirudh Venkataramanan 17344381147dSAnirudh Venkataramanan act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX << 17354381147dSAnirudh Venkataramanan ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M; 17369daf8208SAnirudh Venkataramanan 17379daf8208SAnirudh Venkataramanan /* Third action Marker value */ 17389daf8208SAnirudh Venkataramanan act |= ICE_LG_ACT_GENERIC; 17399daf8208SAnirudh Venkataramanan act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) & 17409daf8208SAnirudh Venkataramanan ICE_LG_ACT_GENERIC_VALUE_M; 17419daf8208SAnirudh Venkataramanan 17429daf8208SAnirudh Venkataramanan lg_act->pdata.lg_act.act[2] = cpu_to_le32(act); 17439daf8208SAnirudh Venkataramanan 1744d337f2afSAnirudh Venkataramanan /* call the fill switch rule to fill the lookup Tx Rx structure */ 17459daf8208SAnirudh Venkataramanan ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx, 17469daf8208SAnirudh Venkataramanan ice_aqc_opc_update_sw_rules); 17479daf8208SAnirudh Venkataramanan 1748f9867df6SAnirudh Venkataramanan /* Update the action to point to the large action ID */ 17499daf8208SAnirudh Venkataramanan rx_tx->pdata.lkup_tx_rx.act = 17509daf8208SAnirudh Venkataramanan cpu_to_le32(ICE_SINGLE_ACT_PTR | 17519daf8208SAnirudh Venkataramanan ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) & 17529daf8208SAnirudh Venkataramanan ICE_SINGLE_ACT_PTR_VAL_M)); 17539daf8208SAnirudh Venkataramanan 1754f9867df6SAnirudh Venkataramanan /* Use the filter rule ID of the previously created rule with single 17559daf8208SAnirudh Venkataramanan * act. Once the update happens, hardware will treat this as large 17569daf8208SAnirudh Venkataramanan * action 17579daf8208SAnirudh Venkataramanan */ 17589daf8208SAnirudh Venkataramanan rx_tx->pdata.lkup_tx_rx.index = 17599daf8208SAnirudh Venkataramanan cpu_to_le16(m_ent->fltr_info.fltr_rule_id); 17609daf8208SAnirudh Venkataramanan 17619daf8208SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, lg_act, rules_size, 2, 17629daf8208SAnirudh Venkataramanan ice_aqc_opc_update_sw_rules, NULL); 17639daf8208SAnirudh Venkataramanan if (!status) { 17649daf8208SAnirudh Venkataramanan m_ent->lg_act_idx = l_id; 17659daf8208SAnirudh Venkataramanan m_ent->sw_marker_id = sw_marker; 17669daf8208SAnirudh Venkataramanan } 17679daf8208SAnirudh Venkataramanan 17689daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), lg_act); 17699daf8208SAnirudh Venkataramanan return status; 17709daf8208SAnirudh Venkataramanan } 17719daf8208SAnirudh Venkataramanan 17729daf8208SAnirudh Venkataramanan /** 17739daf8208SAnirudh Venkataramanan * ice_create_vsi_list_map 17749daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 17755726ca0eSAnirudh Venkataramanan * @vsi_handle_arr: array of VSI handles to set in the VSI mapping 17765726ca0eSAnirudh Venkataramanan * @num_vsi: number of VSI handles in the array 1777f9867df6SAnirudh Venkataramanan * @vsi_list_id: VSI list ID generated as part of allocate resource 17789daf8208SAnirudh Venkataramanan * 1779f9867df6SAnirudh Venkataramanan * Helper function to create a new entry of VSI list ID to VSI mapping 1780f9867df6SAnirudh Venkataramanan * using the given VSI list ID 17819daf8208SAnirudh Venkataramanan */ 17829daf8208SAnirudh Venkataramanan static struct ice_vsi_list_map_info * 17835726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, 17849daf8208SAnirudh Venkataramanan u16 vsi_list_id) 17859daf8208SAnirudh Venkataramanan { 17869daf8208SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 17879daf8208SAnirudh Venkataramanan struct ice_vsi_list_map_info *v_map; 17889daf8208SAnirudh Venkataramanan int i; 17899daf8208SAnirudh Venkataramanan 179036ac7911SBruce Allan v_map = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*v_map), GFP_KERNEL); 17919daf8208SAnirudh Venkataramanan if (!v_map) 17929daf8208SAnirudh Venkataramanan return NULL; 17939daf8208SAnirudh Venkataramanan 17949daf8208SAnirudh Venkataramanan v_map->vsi_list_id = vsi_list_id; 17955726ca0eSAnirudh Venkataramanan v_map->ref_cnt = 1; 17969daf8208SAnirudh Venkataramanan for (i = 0; i < num_vsi; i++) 17975726ca0eSAnirudh Venkataramanan set_bit(vsi_handle_arr[i], v_map->vsi_map); 17989daf8208SAnirudh Venkataramanan 17999daf8208SAnirudh Venkataramanan list_add(&v_map->list_entry, &sw->vsi_list_map_head); 18009daf8208SAnirudh Venkataramanan return v_map; 18019daf8208SAnirudh Venkataramanan } 18029daf8208SAnirudh Venkataramanan 18039daf8208SAnirudh Venkataramanan /** 18049daf8208SAnirudh Venkataramanan * ice_update_vsi_list_rule 18059daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 18065726ca0eSAnirudh Venkataramanan * @vsi_handle_arr: array of VSI handles to form a VSI list 18075726ca0eSAnirudh Venkataramanan * @num_vsi: number of VSI handles in the array 1808f9867df6SAnirudh Venkataramanan * @vsi_list_id: VSI list ID generated as part of allocate resource 18099daf8208SAnirudh Venkataramanan * @remove: Boolean value to indicate if this is a remove action 18109daf8208SAnirudh Venkataramanan * @opc: switch rules population command type - pass in the command opcode 18119daf8208SAnirudh Venkataramanan * @lkup_type: lookup type of the filter 18129daf8208SAnirudh Venkataramanan * 18139daf8208SAnirudh Venkataramanan * Call AQ command to add a new switch rule or update existing switch rule 1814f9867df6SAnirudh Venkataramanan * using the given VSI list ID 18159daf8208SAnirudh Venkataramanan */ 18165e24d598STony Nguyen static int 18175726ca0eSAnirudh Venkataramanan ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, 18189daf8208SAnirudh Venkataramanan u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, 18199daf8208SAnirudh Venkataramanan enum ice_sw_lkup_type lkup_type) 18209daf8208SAnirudh Venkataramanan { 18219daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 18229daf8208SAnirudh Venkataramanan u16 s_rule_size; 18236dae8aa0SBruce Allan u16 rule_type; 18245518ac2aSTony Nguyen int status; 18259daf8208SAnirudh Venkataramanan int i; 18269daf8208SAnirudh Venkataramanan 18279daf8208SAnirudh Venkataramanan if (!num_vsi) 1828d54699e2STony Nguyen return -EINVAL; 18299daf8208SAnirudh Venkataramanan 18309daf8208SAnirudh Venkataramanan if (lkup_type == ICE_SW_LKUP_MAC || 18319daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_MAC_VLAN || 18329daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_ETHERTYPE || 18339daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || 18349daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_PROMISC || 18359daf8208SAnirudh Venkataramanan lkup_type == ICE_SW_LKUP_PROMISC_VLAN) 18366dae8aa0SBruce Allan rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR : 18379daf8208SAnirudh Venkataramanan ICE_AQC_SW_RULES_T_VSI_LIST_SET; 18389daf8208SAnirudh Venkataramanan else if (lkup_type == ICE_SW_LKUP_VLAN) 18396dae8aa0SBruce Allan rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR : 18409daf8208SAnirudh Venkataramanan ICE_AQC_SW_RULES_T_PRUNE_LIST_SET; 18419daf8208SAnirudh Venkataramanan else 1842d54699e2STony Nguyen return -EINVAL; 18439daf8208SAnirudh Venkataramanan 18449daf8208SAnirudh Venkataramanan s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(num_vsi); 18459daf8208SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); 18469daf8208SAnirudh Venkataramanan if (!s_rule) 1847d54699e2STony Nguyen return -ENOMEM; 18485726ca0eSAnirudh Venkataramanan for (i = 0; i < num_vsi; i++) { 18495726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) { 1850d54699e2STony Nguyen status = -EINVAL; 18515726ca0eSAnirudh Venkataramanan goto exit; 18525726ca0eSAnirudh Venkataramanan } 18535726ca0eSAnirudh Venkataramanan /* AQ call requires hw_vsi_id(s) */ 18545726ca0eSAnirudh Venkataramanan s_rule->pdata.vsi_list.vsi[i] = 18555726ca0eSAnirudh Venkataramanan cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i])); 18565726ca0eSAnirudh Venkataramanan } 18579daf8208SAnirudh Venkataramanan 18586dae8aa0SBruce Allan s_rule->type = cpu_to_le16(rule_type); 18599daf8208SAnirudh Venkataramanan s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi); 18609daf8208SAnirudh Venkataramanan s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id); 18619daf8208SAnirudh Venkataramanan 18629daf8208SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL); 18639daf8208SAnirudh Venkataramanan 18645726ca0eSAnirudh Venkataramanan exit: 18659daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 18669daf8208SAnirudh Venkataramanan return status; 18679daf8208SAnirudh Venkataramanan } 18689daf8208SAnirudh Venkataramanan 18699daf8208SAnirudh Venkataramanan /** 18709daf8208SAnirudh Venkataramanan * ice_create_vsi_list_rule - Creates and populates a VSI list rule 1871f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 18725726ca0eSAnirudh Venkataramanan * @vsi_handle_arr: array of VSI handles to form a VSI list 18735726ca0eSAnirudh Venkataramanan * @num_vsi: number of VSI handles in the array 18749daf8208SAnirudh Venkataramanan * @vsi_list_id: stores the ID of the VSI list to be created 18759daf8208SAnirudh Venkataramanan * @lkup_type: switch rule filter's lookup type 18769daf8208SAnirudh Venkataramanan */ 18775e24d598STony Nguyen static int 18785726ca0eSAnirudh Venkataramanan ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, 18799daf8208SAnirudh Venkataramanan u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) 18809daf8208SAnirudh Venkataramanan { 18815e24d598STony Nguyen int status; 18829daf8208SAnirudh Venkataramanan 18839daf8208SAnirudh Venkataramanan status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, 18849daf8208SAnirudh Venkataramanan ice_aqc_opc_alloc_res); 18859daf8208SAnirudh Venkataramanan if (status) 18869daf8208SAnirudh Venkataramanan return status; 18879daf8208SAnirudh Venkataramanan 18889daf8208SAnirudh Venkataramanan /* Update the newly created VSI list to include the specified VSIs */ 18895726ca0eSAnirudh Venkataramanan return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi, 18905726ca0eSAnirudh Venkataramanan *vsi_list_id, false, 18915726ca0eSAnirudh Venkataramanan ice_aqc_opc_add_sw_rules, lkup_type); 18929daf8208SAnirudh Venkataramanan } 18939daf8208SAnirudh Venkataramanan 18949daf8208SAnirudh Venkataramanan /** 18959daf8208SAnirudh Venkataramanan * ice_create_pkt_fwd_rule 18969daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 18979daf8208SAnirudh Venkataramanan * @f_entry: entry containing packet forwarding information 18989daf8208SAnirudh Venkataramanan * 18999daf8208SAnirudh Venkataramanan * Create switch rule with given filter information and add an entry 19009daf8208SAnirudh Venkataramanan * to the corresponding filter management list to track this switch rule 19019daf8208SAnirudh Venkataramanan * and VSI mapping 19029daf8208SAnirudh Venkataramanan */ 19035e24d598STony Nguyen static int 19049daf8208SAnirudh Venkataramanan ice_create_pkt_fwd_rule(struct ice_hw *hw, 19059daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *f_entry) 19069daf8208SAnirudh Venkataramanan { 19079daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *fm_entry; 19089daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 19099daf8208SAnirudh Venkataramanan enum ice_sw_lkup_type l_type; 191080d144c9SAnirudh Venkataramanan struct ice_sw_recipe *recp; 19115e24d598STony Nguyen int status; 19129daf8208SAnirudh Venkataramanan 19139daf8208SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), 19149daf8208SAnirudh Venkataramanan ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL); 19159daf8208SAnirudh Venkataramanan if (!s_rule) 1916d54699e2STony Nguyen return -ENOMEM; 19179daf8208SAnirudh Venkataramanan fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry), 19189daf8208SAnirudh Venkataramanan GFP_KERNEL); 19199daf8208SAnirudh Venkataramanan if (!fm_entry) { 1920d54699e2STony Nguyen status = -ENOMEM; 19219daf8208SAnirudh Venkataramanan goto ice_create_pkt_fwd_rule_exit; 19229daf8208SAnirudh Venkataramanan } 19239daf8208SAnirudh Venkataramanan 19249daf8208SAnirudh Venkataramanan fm_entry->fltr_info = f_entry->fltr_info; 19259daf8208SAnirudh Venkataramanan 19269daf8208SAnirudh Venkataramanan /* Initialize all the fields for the management entry */ 19279daf8208SAnirudh Venkataramanan fm_entry->vsi_count = 1; 19289daf8208SAnirudh Venkataramanan fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX; 19299daf8208SAnirudh Venkataramanan fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID; 19309daf8208SAnirudh Venkataramanan fm_entry->counter_index = ICE_INVAL_COUNTER_ID; 19319daf8208SAnirudh Venkataramanan 19329daf8208SAnirudh Venkataramanan ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule, 19339daf8208SAnirudh Venkataramanan ice_aqc_opc_add_sw_rules); 19349daf8208SAnirudh Venkataramanan 19359daf8208SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, 19369daf8208SAnirudh Venkataramanan ice_aqc_opc_add_sw_rules, NULL); 19379daf8208SAnirudh Venkataramanan if (status) { 19389daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), fm_entry); 19399daf8208SAnirudh Venkataramanan goto ice_create_pkt_fwd_rule_exit; 19409daf8208SAnirudh Venkataramanan } 19419daf8208SAnirudh Venkataramanan 19429daf8208SAnirudh Venkataramanan f_entry->fltr_info.fltr_rule_id = 19439daf8208SAnirudh Venkataramanan le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); 19449daf8208SAnirudh Venkataramanan fm_entry->fltr_info.fltr_rule_id = 19459daf8208SAnirudh Venkataramanan le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); 19469daf8208SAnirudh Venkataramanan 19479daf8208SAnirudh Venkataramanan /* The book keeping entries will get removed when base driver 19489daf8208SAnirudh Venkataramanan * calls remove filter AQ command 19499daf8208SAnirudh Venkataramanan */ 19509daf8208SAnirudh Venkataramanan l_type = fm_entry->fltr_info.lkup_type; 195180d144c9SAnirudh Venkataramanan recp = &hw->switch_info->recp_list[l_type]; 195280d144c9SAnirudh Venkataramanan list_add(&fm_entry->list_entry, &recp->filt_rules); 195380d144c9SAnirudh Venkataramanan 19549daf8208SAnirudh Venkataramanan ice_create_pkt_fwd_rule_exit: 19559daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 19569daf8208SAnirudh Venkataramanan return status; 19579daf8208SAnirudh Venkataramanan } 19589daf8208SAnirudh Venkataramanan 19599daf8208SAnirudh Venkataramanan /** 19609daf8208SAnirudh Venkataramanan * ice_update_pkt_fwd_rule 19619daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 196280d144c9SAnirudh Venkataramanan * @f_info: filter information for switch rule 19639daf8208SAnirudh Venkataramanan * 19649daf8208SAnirudh Venkataramanan * Call AQ command to update a previously created switch rule with a 1965f9867df6SAnirudh Venkataramanan * VSI list ID 19669daf8208SAnirudh Venkataramanan */ 19675e24d598STony Nguyen static int 196880d144c9SAnirudh Venkataramanan ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info) 19699daf8208SAnirudh Venkataramanan { 19709daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 19715e24d598STony Nguyen int status; 19729daf8208SAnirudh Venkataramanan 19739daf8208SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), 19749daf8208SAnirudh Venkataramanan ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL); 19759daf8208SAnirudh Venkataramanan if (!s_rule) 1976d54699e2STony Nguyen return -ENOMEM; 19779daf8208SAnirudh Venkataramanan 197880d144c9SAnirudh Venkataramanan ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules); 19799daf8208SAnirudh Venkataramanan 198080d144c9SAnirudh Venkataramanan s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(f_info->fltr_rule_id); 19819daf8208SAnirudh Venkataramanan 19829daf8208SAnirudh Venkataramanan /* Update switch rule with new rule set to forward VSI list */ 19839daf8208SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, 19849daf8208SAnirudh Venkataramanan ice_aqc_opc_update_sw_rules, NULL); 19859daf8208SAnirudh Venkataramanan 19869daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 19879daf8208SAnirudh Venkataramanan return status; 19889daf8208SAnirudh Venkataramanan } 19899daf8208SAnirudh Venkataramanan 19909daf8208SAnirudh Venkataramanan /** 1991b1edc14aSMd Fahad Iqbal Polash * ice_update_sw_rule_bridge_mode 1992f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 1993b1edc14aSMd Fahad Iqbal Polash * 1994b1edc14aSMd Fahad Iqbal Polash * Updates unicast switch filter rules based on VEB/VEPA mode 1995b1edc14aSMd Fahad Iqbal Polash */ 19965e24d598STony Nguyen int ice_update_sw_rule_bridge_mode(struct ice_hw *hw) 1997b1edc14aSMd Fahad Iqbal Polash { 1998b1edc14aSMd Fahad Iqbal Polash struct ice_switch_info *sw = hw->switch_info; 1999b1edc14aSMd Fahad Iqbal Polash struct ice_fltr_mgmt_list_entry *fm_entry; 2000b1edc14aSMd Fahad Iqbal Polash struct list_head *rule_head; 2001b1edc14aSMd Fahad Iqbal Polash struct mutex *rule_lock; /* Lock to protect filter rule list */ 20025518ac2aSTony Nguyen int status = 0; 2003b1edc14aSMd Fahad Iqbal Polash 2004b1edc14aSMd Fahad Iqbal Polash rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; 2005b1edc14aSMd Fahad Iqbal Polash rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; 2006b1edc14aSMd Fahad Iqbal Polash 2007b1edc14aSMd Fahad Iqbal Polash mutex_lock(rule_lock); 2008b1edc14aSMd Fahad Iqbal Polash list_for_each_entry(fm_entry, rule_head, list_entry) { 2009b1edc14aSMd Fahad Iqbal Polash struct ice_fltr_info *fi = &fm_entry->fltr_info; 2010b1edc14aSMd Fahad Iqbal Polash u8 *addr = fi->l_data.mac.mac_addr; 2011b1edc14aSMd Fahad Iqbal Polash 2012b1edc14aSMd Fahad Iqbal Polash /* Update unicast Tx rules to reflect the selected 2013b1edc14aSMd Fahad Iqbal Polash * VEB/VEPA mode 2014b1edc14aSMd Fahad Iqbal Polash */ 2015b1edc14aSMd Fahad Iqbal Polash if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) && 2016b1edc14aSMd Fahad Iqbal Polash (fi->fltr_act == ICE_FWD_TO_VSI || 2017b1edc14aSMd Fahad Iqbal Polash fi->fltr_act == ICE_FWD_TO_VSI_LIST || 2018b1edc14aSMd Fahad Iqbal Polash fi->fltr_act == ICE_FWD_TO_Q || 2019b1edc14aSMd Fahad Iqbal Polash fi->fltr_act == ICE_FWD_TO_QGRP)) { 2020b1edc14aSMd Fahad Iqbal Polash status = ice_update_pkt_fwd_rule(hw, fi); 2021b1edc14aSMd Fahad Iqbal Polash if (status) 2022b1edc14aSMd Fahad Iqbal Polash break; 2023b1edc14aSMd Fahad Iqbal Polash } 2024b1edc14aSMd Fahad Iqbal Polash } 2025b1edc14aSMd Fahad Iqbal Polash 2026b1edc14aSMd Fahad Iqbal Polash mutex_unlock(rule_lock); 2027b1edc14aSMd Fahad Iqbal Polash 2028b1edc14aSMd Fahad Iqbal Polash return status; 2029b1edc14aSMd Fahad Iqbal Polash } 2030b1edc14aSMd Fahad Iqbal Polash 2031b1edc14aSMd Fahad Iqbal Polash /** 203280d144c9SAnirudh Venkataramanan * ice_add_update_vsi_list 20339daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 20349daf8208SAnirudh Venkataramanan * @m_entry: pointer to current filter management list entry 20359daf8208SAnirudh Venkataramanan * @cur_fltr: filter information from the book keeping entry 20369daf8208SAnirudh Venkataramanan * @new_fltr: filter information with the new VSI to be added 20379daf8208SAnirudh Venkataramanan * 20389daf8208SAnirudh Venkataramanan * Call AQ command to add or update previously created VSI list with new VSI. 20399daf8208SAnirudh Venkataramanan * 20409daf8208SAnirudh Venkataramanan * Helper function to do book keeping associated with adding filter information 2041d337f2afSAnirudh Venkataramanan * The algorithm to do the book keeping is described below : 20429daf8208SAnirudh Venkataramanan * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.) 20439daf8208SAnirudh Venkataramanan * if only one VSI has been added till now 20449daf8208SAnirudh Venkataramanan * Allocate a new VSI list and add two VSIs 20459daf8208SAnirudh Venkataramanan * to this list using switch rule command 20469daf8208SAnirudh Venkataramanan * Update the previously created switch rule with the 2047f9867df6SAnirudh Venkataramanan * newly created VSI list ID 20489daf8208SAnirudh Venkataramanan * if a VSI list was previously created 20499daf8208SAnirudh Venkataramanan * Add the new VSI to the previously created VSI list set 20509daf8208SAnirudh Venkataramanan * using the update switch rule command 20519daf8208SAnirudh Venkataramanan */ 20525e24d598STony Nguyen static int 205380d144c9SAnirudh Venkataramanan ice_add_update_vsi_list(struct ice_hw *hw, 20549daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *m_entry, 20559daf8208SAnirudh Venkataramanan struct ice_fltr_info *cur_fltr, 20569daf8208SAnirudh Venkataramanan struct ice_fltr_info *new_fltr) 20579daf8208SAnirudh Venkataramanan { 20589daf8208SAnirudh Venkataramanan u16 vsi_list_id = 0; 20595518ac2aSTony Nguyen int status = 0; 20609daf8208SAnirudh Venkataramanan 20619daf8208SAnirudh Venkataramanan if ((cur_fltr->fltr_act == ICE_FWD_TO_Q || 20629daf8208SAnirudh Venkataramanan cur_fltr->fltr_act == ICE_FWD_TO_QGRP)) 2063d54699e2STony Nguyen return -EOPNOTSUPP; 20649daf8208SAnirudh Venkataramanan 20659daf8208SAnirudh Venkataramanan if ((new_fltr->fltr_act == ICE_FWD_TO_Q || 20669daf8208SAnirudh Venkataramanan new_fltr->fltr_act == ICE_FWD_TO_QGRP) && 20679daf8208SAnirudh Venkataramanan (cur_fltr->fltr_act == ICE_FWD_TO_VSI || 20689daf8208SAnirudh Venkataramanan cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST)) 2069d54699e2STony Nguyen return -EOPNOTSUPP; 20709daf8208SAnirudh Venkataramanan 20719daf8208SAnirudh Venkataramanan if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { 20729daf8208SAnirudh Venkataramanan /* Only one entry existed in the mapping and it was not already 20739daf8208SAnirudh Venkataramanan * a part of a VSI list. So, create a VSI list with the old and 20749daf8208SAnirudh Venkataramanan * new VSIs. 20759daf8208SAnirudh Venkataramanan */ 207680d144c9SAnirudh Venkataramanan struct ice_fltr_info tmp_fltr; 20775726ca0eSAnirudh Venkataramanan u16 vsi_handle_arr[2]; 20789daf8208SAnirudh Venkataramanan 20799daf8208SAnirudh Venkataramanan /* A rule already exists with the new VSI being added */ 20805726ca0eSAnirudh Venkataramanan if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) 2081d54699e2STony Nguyen return -EEXIST; 20829daf8208SAnirudh Venkataramanan 20835726ca0eSAnirudh Venkataramanan vsi_handle_arr[0] = cur_fltr->vsi_handle; 20845726ca0eSAnirudh Venkataramanan vsi_handle_arr[1] = new_fltr->vsi_handle; 20855726ca0eSAnirudh Venkataramanan status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, 20869daf8208SAnirudh Venkataramanan &vsi_list_id, 20879daf8208SAnirudh Venkataramanan new_fltr->lkup_type); 20889daf8208SAnirudh Venkataramanan if (status) 20899daf8208SAnirudh Venkataramanan return status; 20909daf8208SAnirudh Venkataramanan 209180d144c9SAnirudh Venkataramanan tmp_fltr = *new_fltr; 209280d144c9SAnirudh Venkataramanan tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; 209380d144c9SAnirudh Venkataramanan tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; 209480d144c9SAnirudh Venkataramanan tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; 20959daf8208SAnirudh Venkataramanan /* Update the previous switch rule of "MAC forward to VSI" to 20969daf8208SAnirudh Venkataramanan * "MAC fwd to VSI list" 20979daf8208SAnirudh Venkataramanan */ 209880d144c9SAnirudh Venkataramanan status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 20999daf8208SAnirudh Venkataramanan if (status) 21009daf8208SAnirudh Venkataramanan return status; 21019daf8208SAnirudh Venkataramanan 21029daf8208SAnirudh Venkataramanan cur_fltr->fwd_id.vsi_list_id = vsi_list_id; 21039daf8208SAnirudh Venkataramanan cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; 21049daf8208SAnirudh Venkataramanan m_entry->vsi_list_info = 21055726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, 21069daf8208SAnirudh Venkataramanan vsi_list_id); 21079daf8208SAnirudh Venkataramanan 21087a91d3f0SJacek Bułatek if (!m_entry->vsi_list_info) 2109d54699e2STony Nguyen return -ENOMEM; 21107a91d3f0SJacek Bułatek 21119daf8208SAnirudh Venkataramanan /* If this entry was large action then the large action needs 21129daf8208SAnirudh Venkataramanan * to be updated to point to FWD to VSI list 21139daf8208SAnirudh Venkataramanan */ 21149daf8208SAnirudh Venkataramanan if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID) 21159daf8208SAnirudh Venkataramanan status = 21169daf8208SAnirudh Venkataramanan ice_add_marker_act(hw, m_entry, 21179daf8208SAnirudh Venkataramanan m_entry->sw_marker_id, 21189daf8208SAnirudh Venkataramanan m_entry->lg_act_idx); 21199daf8208SAnirudh Venkataramanan } else { 21205726ca0eSAnirudh Venkataramanan u16 vsi_handle = new_fltr->vsi_handle; 21219daf8208SAnirudh Venkataramanan enum ice_adminq_opc opcode; 21229daf8208SAnirudh Venkataramanan 2123f25dad19SBruce Allan if (!m_entry->vsi_list_info) 2124d54699e2STony Nguyen return -EIO; 2125f25dad19SBruce Allan 21269daf8208SAnirudh Venkataramanan /* A rule already exists with the new VSI being added */ 21275726ca0eSAnirudh Venkataramanan if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) 21289daf8208SAnirudh Venkataramanan return 0; 21299daf8208SAnirudh Venkataramanan 21309daf8208SAnirudh Venkataramanan /* Update the previously created VSI list set with 2131f9867df6SAnirudh Venkataramanan * the new VSI ID passed in 21329daf8208SAnirudh Venkataramanan */ 21339daf8208SAnirudh Venkataramanan vsi_list_id = cur_fltr->fwd_id.vsi_list_id; 21349daf8208SAnirudh Venkataramanan opcode = ice_aqc_opc_update_sw_rules; 21359daf8208SAnirudh Venkataramanan 21365726ca0eSAnirudh Venkataramanan status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, 21375726ca0eSAnirudh Venkataramanan vsi_list_id, false, opcode, 21389daf8208SAnirudh Venkataramanan new_fltr->lkup_type); 2139f9867df6SAnirudh Venkataramanan /* update VSI list mapping info with new VSI ID */ 21409daf8208SAnirudh Venkataramanan if (!status) 21415726ca0eSAnirudh Venkataramanan set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); 21429daf8208SAnirudh Venkataramanan } 21439daf8208SAnirudh Venkataramanan if (!status) 21449daf8208SAnirudh Venkataramanan m_entry->vsi_count++; 21459daf8208SAnirudh Venkataramanan return status; 21469daf8208SAnirudh Venkataramanan } 21479daf8208SAnirudh Venkataramanan 21489daf8208SAnirudh Venkataramanan /** 214980d144c9SAnirudh Venkataramanan * ice_find_rule_entry - Search a rule entry 21509daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 215180d144c9SAnirudh Venkataramanan * @recp_id: lookup type for which the specified rule needs to be searched 215280d144c9SAnirudh Venkataramanan * @f_info: rule information 21539daf8208SAnirudh Venkataramanan * 215480d144c9SAnirudh Venkataramanan * Helper function to search for a given rule entry 215580d144c9SAnirudh Venkataramanan * Returns pointer to entry storing the rule if found 21569daf8208SAnirudh Venkataramanan */ 21579daf8208SAnirudh Venkataramanan static struct ice_fltr_mgmt_list_entry * 215880d144c9SAnirudh Venkataramanan ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) 21599daf8208SAnirudh Venkataramanan { 216080d144c9SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL; 21619daf8208SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 216280d144c9SAnirudh Venkataramanan struct list_head *list_head; 21639daf8208SAnirudh Venkataramanan 216480d144c9SAnirudh Venkataramanan list_head = &sw->recp_list[recp_id].filt_rules; 216580d144c9SAnirudh Venkataramanan list_for_each_entry(list_itr, list_head, list_entry) { 216680d144c9SAnirudh Venkataramanan if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data, 216780d144c9SAnirudh Venkataramanan sizeof(f_info->l_data)) && 216880d144c9SAnirudh Venkataramanan f_info->flag == list_itr->fltr_info.flag) { 216980d144c9SAnirudh Venkataramanan ret = list_itr; 21709daf8208SAnirudh Venkataramanan break; 21719daf8208SAnirudh Venkataramanan } 21729daf8208SAnirudh Venkataramanan } 217380d144c9SAnirudh Venkataramanan return ret; 21749daf8208SAnirudh Venkataramanan } 21759daf8208SAnirudh Venkataramanan 21769daf8208SAnirudh Venkataramanan /** 21775726ca0eSAnirudh Venkataramanan * ice_find_vsi_list_entry - Search VSI list map with VSI count 1 21785726ca0eSAnirudh Venkataramanan * @hw: pointer to the hardware structure 21795726ca0eSAnirudh Venkataramanan * @recp_id: lookup type for which VSI lists needs to be searched 21805726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to be found in VSI list 2181f9867df6SAnirudh Venkataramanan * @vsi_list_id: VSI list ID found containing vsi_handle 21825726ca0eSAnirudh Venkataramanan * 21835726ca0eSAnirudh Venkataramanan * Helper function to search a VSI list with single entry containing given VSI 21845726ca0eSAnirudh Venkataramanan * handle element. This can be extended further to search VSI list with more 21855726ca0eSAnirudh Venkataramanan * than 1 vsi_count. Returns pointer to VSI list entry if found. 21865726ca0eSAnirudh Venkataramanan */ 21875726ca0eSAnirudh Venkataramanan static struct ice_vsi_list_map_info * 21885726ca0eSAnirudh Venkataramanan ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle, 21895726ca0eSAnirudh Venkataramanan u16 *vsi_list_id) 21905726ca0eSAnirudh Venkataramanan { 21915726ca0eSAnirudh Venkataramanan struct ice_vsi_list_map_info *map_info = NULL; 21925726ca0eSAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 21935726ca0eSAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *list_itr; 21945726ca0eSAnirudh Venkataramanan struct list_head *list_head; 21955726ca0eSAnirudh Venkataramanan 21965726ca0eSAnirudh Venkataramanan list_head = &sw->recp_list[recp_id].filt_rules; 21975726ca0eSAnirudh Venkataramanan list_for_each_entry(list_itr, list_head, list_entry) { 21985726ca0eSAnirudh Venkataramanan if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) { 21995726ca0eSAnirudh Venkataramanan map_info = list_itr->vsi_list_info; 22005726ca0eSAnirudh Venkataramanan if (test_bit(vsi_handle, map_info->vsi_map)) { 22015726ca0eSAnirudh Venkataramanan *vsi_list_id = map_info->vsi_list_id; 22025726ca0eSAnirudh Venkataramanan return map_info; 22035726ca0eSAnirudh Venkataramanan } 22045726ca0eSAnirudh Venkataramanan } 22055726ca0eSAnirudh Venkataramanan } 22065726ca0eSAnirudh Venkataramanan return NULL; 22075726ca0eSAnirudh Venkataramanan } 22085726ca0eSAnirudh Venkataramanan 22095726ca0eSAnirudh Venkataramanan /** 221080d144c9SAnirudh Venkataramanan * ice_add_rule_internal - add rule for a given lookup type 22119daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 2212f9867df6SAnirudh Venkataramanan * @recp_id: lookup type (recipe ID) for which rule has to be added 22139daf8208SAnirudh Venkataramanan * @f_entry: structure containing MAC forwarding information 22149daf8208SAnirudh Venkataramanan * 221580d144c9SAnirudh Venkataramanan * Adds or updates the rule lists for a given recipe 22169daf8208SAnirudh Venkataramanan */ 22175e24d598STony Nguyen static int 221880d144c9SAnirudh Venkataramanan ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, 221980d144c9SAnirudh Venkataramanan struct ice_fltr_list_entry *f_entry) 22209daf8208SAnirudh Venkataramanan { 222180d144c9SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 22229daf8208SAnirudh Venkataramanan struct ice_fltr_info *new_fltr, *cur_fltr; 22239daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *m_entry; 222480d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 22255e24d598STony Nguyen int status = 0; 22269daf8208SAnirudh Venkataramanan 22275726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) 2228d54699e2STony Nguyen return -EINVAL; 22295726ca0eSAnirudh Venkataramanan f_entry->fltr_info.fwd_id.hw_vsi_id = 22305726ca0eSAnirudh Venkataramanan ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); 22315726ca0eSAnirudh Venkataramanan 223280d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[recp_id].filt_rule_lock; 223380d144c9SAnirudh Venkataramanan 223480d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 22359daf8208SAnirudh Venkataramanan new_fltr = &f_entry->fltr_info; 223680d144c9SAnirudh Venkataramanan if (new_fltr->flag & ICE_FLTR_RX) 223780d144c9SAnirudh Venkataramanan new_fltr->src = hw->port_info->lport; 223880d144c9SAnirudh Venkataramanan else if (new_fltr->flag & ICE_FLTR_TX) 22395726ca0eSAnirudh Venkataramanan new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id; 22409daf8208SAnirudh Venkataramanan 224180d144c9SAnirudh Venkataramanan m_entry = ice_find_rule_entry(hw, recp_id, new_fltr); 224280d144c9SAnirudh Venkataramanan if (!m_entry) { 224380d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 22449daf8208SAnirudh Venkataramanan return ice_create_pkt_fwd_rule(hw, f_entry); 224580d144c9SAnirudh Venkataramanan } 22469daf8208SAnirudh Venkataramanan 22479daf8208SAnirudh Venkataramanan cur_fltr = &m_entry->fltr_info; 224880d144c9SAnirudh Venkataramanan status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr); 224980d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 22509daf8208SAnirudh Venkataramanan 225180d144c9SAnirudh Venkataramanan return status; 225280d144c9SAnirudh Venkataramanan } 225380d144c9SAnirudh Venkataramanan 225480d144c9SAnirudh Venkataramanan /** 225580d144c9SAnirudh Venkataramanan * ice_remove_vsi_list_rule 225680d144c9SAnirudh Venkataramanan * @hw: pointer to the hardware structure 2257f9867df6SAnirudh Venkataramanan * @vsi_list_id: VSI list ID generated as part of allocate resource 225880d144c9SAnirudh Venkataramanan * @lkup_type: switch rule filter lookup type 225980d144c9SAnirudh Venkataramanan * 226080d144c9SAnirudh Venkataramanan * The VSI list should be emptied before this function is called to remove the 226180d144c9SAnirudh Venkataramanan * VSI list. 226280d144c9SAnirudh Venkataramanan */ 22635e24d598STony Nguyen static int 226480d144c9SAnirudh Venkataramanan ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, 226580d144c9SAnirudh Venkataramanan enum ice_sw_lkup_type lkup_type) 226680d144c9SAnirudh Venkataramanan { 226780d144c9SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 226880d144c9SAnirudh Venkataramanan u16 s_rule_size; 22695518ac2aSTony Nguyen int status; 227080d144c9SAnirudh Venkataramanan 227180d144c9SAnirudh Venkataramanan s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0); 227280d144c9SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); 227380d144c9SAnirudh Venkataramanan if (!s_rule) 2274d54699e2STony Nguyen return -ENOMEM; 227580d144c9SAnirudh Venkataramanan 227680d144c9SAnirudh Venkataramanan s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); 227780d144c9SAnirudh Venkataramanan s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id); 227880d144c9SAnirudh Venkataramanan 227980d144c9SAnirudh Venkataramanan /* Free the vsi_list resource that we allocated. It is assumed that the 228080d144c9SAnirudh Venkataramanan * list is empty at this point. 228180d144c9SAnirudh Venkataramanan */ 228280d144c9SAnirudh Venkataramanan status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type, 228380d144c9SAnirudh Venkataramanan ice_aqc_opc_free_res); 228480d144c9SAnirudh Venkataramanan 228580d144c9SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 228680d144c9SAnirudh Venkataramanan return status; 228780d144c9SAnirudh Venkataramanan } 228880d144c9SAnirudh Venkataramanan 228980d144c9SAnirudh Venkataramanan /** 229080d144c9SAnirudh Venkataramanan * ice_rem_update_vsi_list 229180d144c9SAnirudh Venkataramanan * @hw: pointer to the hardware structure 22925726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle of the VSI to remove 229380d144c9SAnirudh Venkataramanan * @fm_list: filter management entry for which the VSI list management needs to 229480d144c9SAnirudh Venkataramanan * be done 229580d144c9SAnirudh Venkataramanan */ 22965e24d598STony Nguyen static int 22975726ca0eSAnirudh Venkataramanan ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, 229880d144c9SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *fm_list) 229980d144c9SAnirudh Venkataramanan { 230080d144c9SAnirudh Venkataramanan enum ice_sw_lkup_type lkup_type; 230180d144c9SAnirudh Venkataramanan u16 vsi_list_id; 23025518ac2aSTony Nguyen int status = 0; 230380d144c9SAnirudh Venkataramanan 230480d144c9SAnirudh Venkataramanan if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST || 230580d144c9SAnirudh Venkataramanan fm_list->vsi_count == 0) 2306d54699e2STony Nguyen return -EINVAL; 230780d144c9SAnirudh Venkataramanan 230880d144c9SAnirudh Venkataramanan /* A rule with the VSI being removed does not exist */ 23095726ca0eSAnirudh Venkataramanan if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) 2310d54699e2STony Nguyen return -ENOENT; 231180d144c9SAnirudh Venkataramanan 231280d144c9SAnirudh Venkataramanan lkup_type = fm_list->fltr_info.lkup_type; 231380d144c9SAnirudh Venkataramanan vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; 23145726ca0eSAnirudh Venkataramanan status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, 231580d144c9SAnirudh Venkataramanan ice_aqc_opc_update_sw_rules, 231680d144c9SAnirudh Venkataramanan lkup_type); 231780d144c9SAnirudh Venkataramanan if (status) 231880d144c9SAnirudh Venkataramanan return status; 231980d144c9SAnirudh Venkataramanan 232080d144c9SAnirudh Venkataramanan fm_list->vsi_count--; 23215726ca0eSAnirudh Venkataramanan clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); 232280d144c9SAnirudh Venkataramanan 2323c60cdb13SBrett Creeley if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) { 2324c60cdb13SBrett Creeley struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info; 232580d144c9SAnirudh Venkataramanan struct ice_vsi_list_map_info *vsi_list_info = 232680d144c9SAnirudh Venkataramanan fm_list->vsi_list_info; 23275726ca0eSAnirudh Venkataramanan u16 rem_vsi_handle; 232880d144c9SAnirudh Venkataramanan 23295726ca0eSAnirudh Venkataramanan rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, 233080d144c9SAnirudh Venkataramanan ICE_MAX_VSI); 23315726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, rem_vsi_handle)) 2332d54699e2STony Nguyen return -EIO; 2333c60cdb13SBrett Creeley 2334c60cdb13SBrett Creeley /* Make sure VSI list is empty before removing it below */ 23355726ca0eSAnirudh Venkataramanan status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, 233680d144c9SAnirudh Venkataramanan vsi_list_id, true, 233780d144c9SAnirudh Venkataramanan ice_aqc_opc_update_sw_rules, 233880d144c9SAnirudh Venkataramanan lkup_type); 233980d144c9SAnirudh Venkataramanan if (status) 234080d144c9SAnirudh Venkataramanan return status; 234180d144c9SAnirudh Venkataramanan 2342c60cdb13SBrett Creeley tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI; 2343c60cdb13SBrett Creeley tmp_fltr_info.fwd_id.hw_vsi_id = 2344c60cdb13SBrett Creeley ice_get_hw_vsi_num(hw, rem_vsi_handle); 2345c60cdb13SBrett Creeley tmp_fltr_info.vsi_handle = rem_vsi_handle; 2346c60cdb13SBrett Creeley status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info); 2347c60cdb13SBrett Creeley if (status) { 23489228d8b2SJacob Keller ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n", 2349c60cdb13SBrett Creeley tmp_fltr_info.fwd_id.hw_vsi_id, status); 2350c60cdb13SBrett Creeley return status; 2351c60cdb13SBrett Creeley } 2352c60cdb13SBrett Creeley 2353c60cdb13SBrett Creeley fm_list->fltr_info = tmp_fltr_info; 2354c60cdb13SBrett Creeley } 2355c60cdb13SBrett Creeley 2356c60cdb13SBrett Creeley if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || 2357c60cdb13SBrett Creeley (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { 2358c60cdb13SBrett Creeley struct ice_vsi_list_map_info *vsi_list_info = 2359c60cdb13SBrett Creeley fm_list->vsi_list_info; 2360c60cdb13SBrett Creeley 236180d144c9SAnirudh Venkataramanan /* Remove the VSI list since it is no longer used */ 236280d144c9SAnirudh Venkataramanan status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); 2363c60cdb13SBrett Creeley if (status) { 23649228d8b2SJacob Keller ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n", 2365c60cdb13SBrett Creeley vsi_list_id, status); 236680d144c9SAnirudh Venkataramanan return status; 2367c60cdb13SBrett Creeley } 236880d144c9SAnirudh Venkataramanan 236980d144c9SAnirudh Venkataramanan list_del(&vsi_list_info->list_entry); 237080d144c9SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), vsi_list_info); 237180d144c9SAnirudh Venkataramanan fm_list->vsi_list_info = NULL; 237280d144c9SAnirudh Venkataramanan } 237380d144c9SAnirudh Venkataramanan 237480d144c9SAnirudh Venkataramanan return status; 237580d144c9SAnirudh Venkataramanan } 237680d144c9SAnirudh Venkataramanan 237780d144c9SAnirudh Venkataramanan /** 237880d144c9SAnirudh Venkataramanan * ice_remove_rule_internal - Remove a filter rule of a given type 237980d144c9SAnirudh Venkataramanan * @hw: pointer to the hardware structure 2380f9867df6SAnirudh Venkataramanan * @recp_id: recipe ID for which the rule needs to removed 238180d144c9SAnirudh Venkataramanan * @f_entry: rule entry containing filter information 238280d144c9SAnirudh Venkataramanan */ 23835e24d598STony Nguyen static int 238480d144c9SAnirudh Venkataramanan ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, 238580d144c9SAnirudh Venkataramanan struct ice_fltr_list_entry *f_entry) 238680d144c9SAnirudh Venkataramanan { 238780d144c9SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 238880d144c9SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *list_elem; 238980d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 239080d144c9SAnirudh Venkataramanan bool remove_rule = false; 23915726ca0eSAnirudh Venkataramanan u16 vsi_handle; 23925518ac2aSTony Nguyen int status = 0; 23935726ca0eSAnirudh Venkataramanan 23945726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) 2395d54699e2STony Nguyen return -EINVAL; 23965726ca0eSAnirudh Venkataramanan f_entry->fltr_info.fwd_id.hw_vsi_id = 23975726ca0eSAnirudh Venkataramanan ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); 239880d144c9SAnirudh Venkataramanan 239980d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[recp_id].filt_rule_lock; 240080d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 240180d144c9SAnirudh Venkataramanan list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info); 240280d144c9SAnirudh Venkataramanan if (!list_elem) { 2403d54699e2STony Nguyen status = -ENOENT; 240480d144c9SAnirudh Venkataramanan goto exit; 240580d144c9SAnirudh Venkataramanan } 240680d144c9SAnirudh Venkataramanan 240780d144c9SAnirudh Venkataramanan if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { 240880d144c9SAnirudh Venkataramanan remove_rule = true; 24095726ca0eSAnirudh Venkataramanan } else if (!list_elem->vsi_list_info) { 2410d54699e2STony Nguyen status = -ENOENT; 24115726ca0eSAnirudh Venkataramanan goto exit; 2412f9264dd6SJacob Keller } else if (list_elem->vsi_list_info->ref_cnt > 1) { 2413f9264dd6SJacob Keller /* a ref_cnt > 1 indicates that the vsi_list is being 2414f9264dd6SJacob Keller * shared by multiple rules. Decrement the ref_cnt and 2415f9264dd6SJacob Keller * remove this rule, but do not modify the list, as it 2416f9264dd6SJacob Keller * is in-use by other rules. 2417f9264dd6SJacob Keller */ 24185726ca0eSAnirudh Venkataramanan list_elem->vsi_list_info->ref_cnt--; 2419f9264dd6SJacob Keller remove_rule = true; 2420f9264dd6SJacob Keller } else { 2421f9264dd6SJacob Keller /* a ref_cnt of 1 indicates the vsi_list is only used 2422f9264dd6SJacob Keller * by one rule. However, the original removal request is only 2423f9264dd6SJacob Keller * for a single VSI. Update the vsi_list first, and only 2424f9264dd6SJacob Keller * remove the rule if there are no further VSIs in this list. 2425f9264dd6SJacob Keller */ 24265726ca0eSAnirudh Venkataramanan vsi_handle = f_entry->fltr_info.vsi_handle; 24275726ca0eSAnirudh Venkataramanan status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem); 242880d144c9SAnirudh Venkataramanan if (status) 242980d144c9SAnirudh Venkataramanan goto exit; 2430f9867df6SAnirudh Venkataramanan /* if VSI count goes to zero after updating the VSI list */ 243180d144c9SAnirudh Venkataramanan if (list_elem->vsi_count == 0) 243280d144c9SAnirudh Venkataramanan remove_rule = true; 243380d144c9SAnirudh Venkataramanan } 243480d144c9SAnirudh Venkataramanan 243580d144c9SAnirudh Venkataramanan if (remove_rule) { 243680d144c9SAnirudh Venkataramanan /* Remove the lookup rule */ 243780d144c9SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 243880d144c9SAnirudh Venkataramanan 243980d144c9SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), 244080d144c9SAnirudh Venkataramanan ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 244180d144c9SAnirudh Venkataramanan GFP_KERNEL); 244280d144c9SAnirudh Venkataramanan if (!s_rule) { 2443d54699e2STony Nguyen status = -ENOMEM; 244480d144c9SAnirudh Venkataramanan goto exit; 244580d144c9SAnirudh Venkataramanan } 244680d144c9SAnirudh Venkataramanan 244780d144c9SAnirudh Venkataramanan ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule, 244880d144c9SAnirudh Venkataramanan ice_aqc_opc_remove_sw_rules); 244980d144c9SAnirudh Venkataramanan 245080d144c9SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, s_rule, 245180d144c9SAnirudh Venkataramanan ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1, 245280d144c9SAnirudh Venkataramanan ice_aqc_opc_remove_sw_rules, NULL); 245380d144c9SAnirudh Venkataramanan 245480d144c9SAnirudh Venkataramanan /* Remove a book keeping from the list */ 245580d144c9SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 245680d144c9SAnirudh Venkataramanan 24578132e17dSJeb Cramer if (status) 24588132e17dSJeb Cramer goto exit; 24598132e17dSJeb Cramer 246080d144c9SAnirudh Venkataramanan list_del(&list_elem->list_entry); 246180d144c9SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), list_elem); 246280d144c9SAnirudh Venkataramanan } 246380d144c9SAnirudh Venkataramanan exit: 246480d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 246580d144c9SAnirudh Venkataramanan return status; 24669daf8208SAnirudh Venkataramanan } 24679daf8208SAnirudh Venkataramanan 24689daf8208SAnirudh Venkataramanan /** 24699fea7498SKiran Patil * ice_mac_fltr_exist - does this MAC filter exist for given VSI 24709fea7498SKiran Patil * @hw: pointer to the hardware structure 24719fea7498SKiran Patil * @mac: MAC address to be checked (for MAC filter) 24729fea7498SKiran Patil * @vsi_handle: check MAC filter for this VSI 24739fea7498SKiran Patil */ 24749fea7498SKiran Patil bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle) 24759fea7498SKiran Patil { 24769fea7498SKiran Patil struct ice_fltr_mgmt_list_entry *entry; 24779fea7498SKiran Patil struct list_head *rule_head; 24789fea7498SKiran Patil struct ice_switch_info *sw; 24799fea7498SKiran Patil struct mutex *rule_lock; /* Lock to protect filter rule list */ 24809fea7498SKiran Patil u16 hw_vsi_id; 24819fea7498SKiran Patil 24829fea7498SKiran Patil if (!ice_is_vsi_valid(hw, vsi_handle)) 24839fea7498SKiran Patil return false; 24849fea7498SKiran Patil 24859fea7498SKiran Patil hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 24869fea7498SKiran Patil sw = hw->switch_info; 24879fea7498SKiran Patil rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; 24889fea7498SKiran Patil if (!rule_head) 24899fea7498SKiran Patil return false; 24909fea7498SKiran Patil 24919fea7498SKiran Patil rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; 24929fea7498SKiran Patil mutex_lock(rule_lock); 24939fea7498SKiran Patil list_for_each_entry(entry, rule_head, list_entry) { 24949fea7498SKiran Patil struct ice_fltr_info *f_info = &entry->fltr_info; 24959fea7498SKiran Patil u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; 24969fea7498SKiran Patil 24979fea7498SKiran Patil if (is_zero_ether_addr(mac_addr)) 24989fea7498SKiran Patil continue; 24999fea7498SKiran Patil 25009fea7498SKiran Patil if (f_info->flag != ICE_FLTR_TX || 25019fea7498SKiran Patil f_info->src_id != ICE_SRC_ID_VSI || 25029fea7498SKiran Patil f_info->lkup_type != ICE_SW_LKUP_MAC || 25039fea7498SKiran Patil f_info->fltr_act != ICE_FWD_TO_VSI || 25049fea7498SKiran Patil hw_vsi_id != f_info->fwd_id.hw_vsi_id) 25059fea7498SKiran Patil continue; 25069fea7498SKiran Patil 25079fea7498SKiran Patil if (ether_addr_equal(mac, mac_addr)) { 25089fea7498SKiran Patil mutex_unlock(rule_lock); 25099fea7498SKiran Patil return true; 25109fea7498SKiran Patil } 25119fea7498SKiran Patil } 25129fea7498SKiran Patil mutex_unlock(rule_lock); 25139fea7498SKiran Patil return false; 25149fea7498SKiran Patil } 25159fea7498SKiran Patil 25169fea7498SKiran Patil /** 25179fea7498SKiran Patil * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI 25189fea7498SKiran Patil * @hw: pointer to the hardware structure 25199fea7498SKiran Patil * @vlan_id: VLAN ID 25209fea7498SKiran Patil * @vsi_handle: check MAC filter for this VSI 25219fea7498SKiran Patil */ 25229fea7498SKiran Patil bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle) 25239fea7498SKiran Patil { 25249fea7498SKiran Patil struct ice_fltr_mgmt_list_entry *entry; 25259fea7498SKiran Patil struct list_head *rule_head; 25269fea7498SKiran Patil struct ice_switch_info *sw; 25279fea7498SKiran Patil struct mutex *rule_lock; /* Lock to protect filter rule list */ 25289fea7498SKiran Patil u16 hw_vsi_id; 25299fea7498SKiran Patil 25309fea7498SKiran Patil if (vlan_id > ICE_MAX_VLAN_ID) 25319fea7498SKiran Patil return false; 25329fea7498SKiran Patil 25339fea7498SKiran Patil if (!ice_is_vsi_valid(hw, vsi_handle)) 25349fea7498SKiran Patil return false; 25359fea7498SKiran Patil 25369fea7498SKiran Patil hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 25379fea7498SKiran Patil sw = hw->switch_info; 25389fea7498SKiran Patil rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; 25399fea7498SKiran Patil if (!rule_head) 25409fea7498SKiran Patil return false; 25419fea7498SKiran Patil 25429fea7498SKiran Patil rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; 25439fea7498SKiran Patil mutex_lock(rule_lock); 25449fea7498SKiran Patil list_for_each_entry(entry, rule_head, list_entry) { 25459fea7498SKiran Patil struct ice_fltr_info *f_info = &entry->fltr_info; 25469fea7498SKiran Patil u16 entry_vlan_id = f_info->l_data.vlan.vlan_id; 25479fea7498SKiran Patil struct ice_vsi_list_map_info *map_info; 25489fea7498SKiran Patil 25499fea7498SKiran Patil if (entry_vlan_id > ICE_MAX_VLAN_ID) 25509fea7498SKiran Patil continue; 25519fea7498SKiran Patil 25529fea7498SKiran Patil if (f_info->flag != ICE_FLTR_TX || 25539fea7498SKiran Patil f_info->src_id != ICE_SRC_ID_VSI || 25549fea7498SKiran Patil f_info->lkup_type != ICE_SW_LKUP_VLAN) 25559fea7498SKiran Patil continue; 25569fea7498SKiran Patil 25579fea7498SKiran Patil /* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */ 25589fea7498SKiran Patil if (f_info->fltr_act != ICE_FWD_TO_VSI && 25599fea7498SKiran Patil f_info->fltr_act != ICE_FWD_TO_VSI_LIST) 25609fea7498SKiran Patil continue; 25619fea7498SKiran Patil 25629fea7498SKiran Patil if (f_info->fltr_act == ICE_FWD_TO_VSI) { 25639fea7498SKiran Patil if (hw_vsi_id != f_info->fwd_id.hw_vsi_id) 25649fea7498SKiran Patil continue; 25659fea7498SKiran Patil } else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { 25669fea7498SKiran Patil /* If filter_action is FWD_TO_VSI_LIST, make sure 25679fea7498SKiran Patil * that VSI being checked is part of VSI list 25689fea7498SKiran Patil */ 25699fea7498SKiran Patil if (entry->vsi_count == 1 && 25709fea7498SKiran Patil entry->vsi_list_info) { 25719fea7498SKiran Patil map_info = entry->vsi_list_info; 25729fea7498SKiran Patil if (!test_bit(vsi_handle, map_info->vsi_map)) 25739fea7498SKiran Patil continue; 25749fea7498SKiran Patil } 25759fea7498SKiran Patil } 25769fea7498SKiran Patil 25779fea7498SKiran Patil if (vlan_id == entry_vlan_id) { 25789fea7498SKiran Patil mutex_unlock(rule_lock); 25799fea7498SKiran Patil return true; 25809fea7498SKiran Patil } 25819fea7498SKiran Patil } 25829fea7498SKiran Patil mutex_unlock(rule_lock); 25839fea7498SKiran Patil 25849fea7498SKiran Patil return false; 25859fea7498SKiran Patil } 25869fea7498SKiran Patil 25879fea7498SKiran Patil /** 25889daf8208SAnirudh Venkataramanan * ice_add_mac - Add a MAC address based filter rule 25899daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 25909daf8208SAnirudh Venkataramanan * @m_list: list of MAC addresses and forwarding information 25919daf8208SAnirudh Venkataramanan * 25929daf8208SAnirudh Venkataramanan * IMPORTANT: When the ucast_shared flag is set to false and m_list has 25939daf8208SAnirudh Venkataramanan * multiple unicast addresses, the function assumes that all the 25949daf8208SAnirudh Venkataramanan * addresses are unique in a given add_mac call. It doesn't 25959daf8208SAnirudh Venkataramanan * check for duplicates in this case, removing duplicates from a given 25969daf8208SAnirudh Venkataramanan * list should be taken care of in the caller of this function. 25979daf8208SAnirudh Venkataramanan */ 25985e24d598STony Nguyen int ice_add_mac(struct ice_hw *hw, struct list_head *m_list) 25999daf8208SAnirudh Venkataramanan { 26009daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule, *r_iter; 26019daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *m_list_itr; 260280d144c9SAnirudh Venkataramanan struct list_head *rule_head; 260388865fc4SKarol Kolacinski u16 total_elem_left, s_rule_size; 260480d144c9SAnirudh Venkataramanan struct ice_switch_info *sw; 260580d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 26069daf8208SAnirudh Venkataramanan u16 num_unicast = 0; 26075518ac2aSTony Nguyen int status = 0; 260888865fc4SKarol Kolacinski u8 elem_sent; 26099daf8208SAnirudh Venkataramanan 26109daf8208SAnirudh Venkataramanan if (!m_list || !hw) 2611d54699e2STony Nguyen return -EINVAL; 26129daf8208SAnirudh Venkataramanan 261380d144c9SAnirudh Venkataramanan s_rule = NULL; 261480d144c9SAnirudh Venkataramanan sw = hw->switch_info; 261580d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; 26169daf8208SAnirudh Venkataramanan list_for_each_entry(m_list_itr, m_list, list_entry) { 26179daf8208SAnirudh Venkataramanan u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; 26185726ca0eSAnirudh Venkataramanan u16 vsi_handle; 26195726ca0eSAnirudh Venkataramanan u16 hw_vsi_id; 26209daf8208SAnirudh Venkataramanan 262180d144c9SAnirudh Venkataramanan m_list_itr->fltr_info.flag = ICE_FLTR_TX; 26225726ca0eSAnirudh Venkataramanan vsi_handle = m_list_itr->fltr_info.vsi_handle; 26235726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 2624d54699e2STony Nguyen return -EINVAL; 26255726ca0eSAnirudh Venkataramanan hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 26265726ca0eSAnirudh Venkataramanan m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; 2627f9867df6SAnirudh Venkataramanan /* update the src in case it is VSI num */ 26285726ca0eSAnirudh Venkataramanan if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) 2629d54699e2STony Nguyen return -EINVAL; 26305726ca0eSAnirudh Venkataramanan m_list_itr->fltr_info.src = hw_vsi_id; 263180d144c9SAnirudh Venkataramanan if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || 263280d144c9SAnirudh Venkataramanan is_zero_ether_addr(add)) 2633d54699e2STony Nguyen return -EINVAL; 26349daf8208SAnirudh Venkataramanan if (is_unicast_ether_addr(add) && !hw->ucast_shared) { 26359daf8208SAnirudh Venkataramanan /* Don't overwrite the unicast address */ 263680d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 263780d144c9SAnirudh Venkataramanan if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC, 263880d144c9SAnirudh Venkataramanan &m_list_itr->fltr_info)) { 263980d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 2640d54699e2STony Nguyen return -EEXIST; 264180d144c9SAnirudh Venkataramanan } 264280d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 26439daf8208SAnirudh Venkataramanan num_unicast++; 26449daf8208SAnirudh Venkataramanan } else if (is_multicast_ether_addr(add) || 26459daf8208SAnirudh Venkataramanan (is_unicast_ether_addr(add) && hw->ucast_shared)) { 264680d144c9SAnirudh Venkataramanan m_list_itr->status = 264780d144c9SAnirudh Venkataramanan ice_add_rule_internal(hw, ICE_SW_LKUP_MAC, 264880d144c9SAnirudh Venkataramanan m_list_itr); 264980d144c9SAnirudh Venkataramanan if (m_list_itr->status) 265080d144c9SAnirudh Venkataramanan return m_list_itr->status; 26519daf8208SAnirudh Venkataramanan } 26529daf8208SAnirudh Venkataramanan } 26539daf8208SAnirudh Venkataramanan 265480d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 26559daf8208SAnirudh Venkataramanan /* Exit if no suitable entries were found for adding bulk switch rule */ 265680d144c9SAnirudh Venkataramanan if (!num_unicast) { 265780d144c9SAnirudh Venkataramanan status = 0; 265880d144c9SAnirudh Venkataramanan goto ice_add_mac_exit; 265980d144c9SAnirudh Venkataramanan } 266080d144c9SAnirudh Venkataramanan 266180d144c9SAnirudh Venkataramanan rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; 26629daf8208SAnirudh Venkataramanan 26639daf8208SAnirudh Venkataramanan /* Allocate switch rule buffer for the bulk update for unicast */ 26649daf8208SAnirudh Venkataramanan s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE; 26659daf8208SAnirudh Venkataramanan s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size, 26669daf8208SAnirudh Venkataramanan GFP_KERNEL); 266780d144c9SAnirudh Venkataramanan if (!s_rule) { 2668d54699e2STony Nguyen status = -ENOMEM; 266980d144c9SAnirudh Venkataramanan goto ice_add_mac_exit; 267080d144c9SAnirudh Venkataramanan } 26719daf8208SAnirudh Venkataramanan 26729daf8208SAnirudh Venkataramanan r_iter = s_rule; 26739daf8208SAnirudh Venkataramanan list_for_each_entry(m_list_itr, m_list, list_entry) { 26749daf8208SAnirudh Venkataramanan struct ice_fltr_info *f_info = &m_list_itr->fltr_info; 267580d144c9SAnirudh Venkataramanan u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; 26769daf8208SAnirudh Venkataramanan 267780d144c9SAnirudh Venkataramanan if (is_unicast_ether_addr(mac_addr)) { 267880d144c9SAnirudh Venkataramanan ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter, 267980d144c9SAnirudh Venkataramanan ice_aqc_opc_add_sw_rules); 26809daf8208SAnirudh Venkataramanan r_iter = (struct ice_aqc_sw_rules_elem *) 26819daf8208SAnirudh Venkataramanan ((u8 *)r_iter + s_rule_size); 26829daf8208SAnirudh Venkataramanan } 26839daf8208SAnirudh Venkataramanan } 26849daf8208SAnirudh Venkataramanan 26859daf8208SAnirudh Venkataramanan /* Call AQ bulk switch rule update for all unicast addresses */ 26869daf8208SAnirudh Venkataramanan r_iter = s_rule; 26879daf8208SAnirudh Venkataramanan /* Call AQ switch rule in AQ_MAX chunk */ 26889daf8208SAnirudh Venkataramanan for (total_elem_left = num_unicast; total_elem_left > 0; 26899daf8208SAnirudh Venkataramanan total_elem_left -= elem_sent) { 26909daf8208SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *entry = r_iter; 26919daf8208SAnirudh Venkataramanan 269288865fc4SKarol Kolacinski elem_sent = min_t(u8, total_elem_left, 269388865fc4SKarol Kolacinski (ICE_AQ_MAX_BUF_LEN / s_rule_size)); 26949daf8208SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size, 26959daf8208SAnirudh Venkataramanan elem_sent, ice_aqc_opc_add_sw_rules, 26969daf8208SAnirudh Venkataramanan NULL); 26979daf8208SAnirudh Venkataramanan if (status) 26989daf8208SAnirudh Venkataramanan goto ice_add_mac_exit; 26999daf8208SAnirudh Venkataramanan r_iter = (struct ice_aqc_sw_rules_elem *) 27009daf8208SAnirudh Venkataramanan ((u8 *)r_iter + (elem_sent * s_rule_size)); 27019daf8208SAnirudh Venkataramanan } 27029daf8208SAnirudh Venkataramanan 2703f9867df6SAnirudh Venkataramanan /* Fill up rule ID based on the value returned from FW */ 27049daf8208SAnirudh Venkataramanan r_iter = s_rule; 27059daf8208SAnirudh Venkataramanan list_for_each_entry(m_list_itr, m_list, list_entry) { 27069daf8208SAnirudh Venkataramanan struct ice_fltr_info *f_info = &m_list_itr->fltr_info; 270780d144c9SAnirudh Venkataramanan u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; 27089daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *fm_entry; 27099daf8208SAnirudh Venkataramanan 271080d144c9SAnirudh Venkataramanan if (is_unicast_ether_addr(mac_addr)) { 27119daf8208SAnirudh Venkataramanan f_info->fltr_rule_id = 27129daf8208SAnirudh Venkataramanan le16_to_cpu(r_iter->pdata.lkup_tx_rx.index); 27139daf8208SAnirudh Venkataramanan f_info->fltr_act = ICE_FWD_TO_VSI; 27149daf8208SAnirudh Venkataramanan /* Create an entry to track this MAC address */ 27159daf8208SAnirudh Venkataramanan fm_entry = devm_kzalloc(ice_hw_to_dev(hw), 27169daf8208SAnirudh Venkataramanan sizeof(*fm_entry), GFP_KERNEL); 27179daf8208SAnirudh Venkataramanan if (!fm_entry) { 2718d54699e2STony Nguyen status = -ENOMEM; 27199daf8208SAnirudh Venkataramanan goto ice_add_mac_exit; 27209daf8208SAnirudh Venkataramanan } 27219daf8208SAnirudh Venkataramanan fm_entry->fltr_info = *f_info; 27229daf8208SAnirudh Venkataramanan fm_entry->vsi_count = 1; 27239daf8208SAnirudh Venkataramanan /* The book keeping entries will get removed when 27249daf8208SAnirudh Venkataramanan * base driver calls remove filter AQ command 27259daf8208SAnirudh Venkataramanan */ 27269daf8208SAnirudh Venkataramanan 272780d144c9SAnirudh Venkataramanan list_add(&fm_entry->list_entry, rule_head); 27289daf8208SAnirudh Venkataramanan r_iter = (struct ice_aqc_sw_rules_elem *) 27299daf8208SAnirudh Venkataramanan ((u8 *)r_iter + s_rule_size); 27309daf8208SAnirudh Venkataramanan } 27319daf8208SAnirudh Venkataramanan } 27329daf8208SAnirudh Venkataramanan 27339daf8208SAnirudh Venkataramanan ice_add_mac_exit: 273480d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 273580d144c9SAnirudh Venkataramanan if (s_rule) 27369daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 27379daf8208SAnirudh Venkataramanan return status; 27389daf8208SAnirudh Venkataramanan } 27399daf8208SAnirudh Venkataramanan 27409daf8208SAnirudh Venkataramanan /** 2741d76a60baSAnirudh Venkataramanan * ice_add_vlan_internal - Add one VLAN based filter rule 2742d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 2743d76a60baSAnirudh Venkataramanan * @f_entry: filter entry containing one VLAN information 2744d76a60baSAnirudh Venkataramanan */ 27455e24d598STony Nguyen static int 2746d76a60baSAnirudh Venkataramanan ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) 2747d76a60baSAnirudh Venkataramanan { 274880d144c9SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 2749d76a60baSAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *v_list_itr; 27505726ca0eSAnirudh Venkataramanan struct ice_fltr_info *new_fltr, *cur_fltr; 27515726ca0eSAnirudh Venkataramanan enum ice_sw_lkup_type lkup_type; 27525726ca0eSAnirudh Venkataramanan u16 vsi_list_id = 0, vsi_handle; 275380d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 27545e24d598STony Nguyen int status = 0; 2755d76a60baSAnirudh Venkataramanan 27565726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) 2757d54699e2STony Nguyen return -EINVAL; 27585726ca0eSAnirudh Venkataramanan 27595726ca0eSAnirudh Venkataramanan f_entry->fltr_info.fwd_id.hw_vsi_id = 27605726ca0eSAnirudh Venkataramanan ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); 2761d76a60baSAnirudh Venkataramanan new_fltr = &f_entry->fltr_info; 27625726ca0eSAnirudh Venkataramanan 2763f9867df6SAnirudh Venkataramanan /* VLAN ID should only be 12 bits */ 2764d76a60baSAnirudh Venkataramanan if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) 2765d54699e2STony Nguyen return -EINVAL; 2766d76a60baSAnirudh Venkataramanan 27675726ca0eSAnirudh Venkataramanan if (new_fltr->src_id != ICE_SRC_ID_VSI) 2768d54699e2STony Nguyen return -EINVAL; 27695726ca0eSAnirudh Venkataramanan 27705726ca0eSAnirudh Venkataramanan new_fltr->src = new_fltr->fwd_id.hw_vsi_id; 27715726ca0eSAnirudh Venkataramanan lkup_type = new_fltr->lkup_type; 27725726ca0eSAnirudh Venkataramanan vsi_handle = new_fltr->vsi_handle; 277380d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; 277480d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 277580d144c9SAnirudh Venkataramanan v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); 2776d76a60baSAnirudh Venkataramanan if (!v_list_itr) { 27775726ca0eSAnirudh Venkataramanan struct ice_vsi_list_map_info *map_info = NULL; 2778d76a60baSAnirudh Venkataramanan 2779d76a60baSAnirudh Venkataramanan if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { 27805726ca0eSAnirudh Venkataramanan /* All VLAN pruning rules use a VSI list. Check if 27815726ca0eSAnirudh Venkataramanan * there is already a VSI list containing VSI that we 27825726ca0eSAnirudh Venkataramanan * want to add. If found, use the same vsi_list_id for 27835726ca0eSAnirudh Venkataramanan * this new VLAN rule or else create a new list. 2784d76a60baSAnirudh Venkataramanan */ 27855726ca0eSAnirudh Venkataramanan map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN, 27865726ca0eSAnirudh Venkataramanan vsi_handle, 27875726ca0eSAnirudh Venkataramanan &vsi_list_id); 27885726ca0eSAnirudh Venkataramanan if (!map_info) { 27895726ca0eSAnirudh Venkataramanan status = ice_create_vsi_list_rule(hw, 27905726ca0eSAnirudh Venkataramanan &vsi_handle, 27915726ca0eSAnirudh Venkataramanan 1, 2792d76a60baSAnirudh Venkataramanan &vsi_list_id, 2793d76a60baSAnirudh Venkataramanan lkup_type); 2794d76a60baSAnirudh Venkataramanan if (status) 279580d144c9SAnirudh Venkataramanan goto exit; 27965726ca0eSAnirudh Venkataramanan } 27975726ca0eSAnirudh Venkataramanan /* Convert the action to forwarding to a VSI list. */ 2798d76a60baSAnirudh Venkataramanan new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; 2799d76a60baSAnirudh Venkataramanan new_fltr->fwd_id.vsi_list_id = vsi_list_id; 2800d76a60baSAnirudh Venkataramanan } 2801d76a60baSAnirudh Venkataramanan 2802d76a60baSAnirudh Venkataramanan status = ice_create_pkt_fwd_rule(hw, f_entry); 28035726ca0eSAnirudh Venkataramanan if (!status) { 280480d144c9SAnirudh Venkataramanan v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, 280580d144c9SAnirudh Venkataramanan new_fltr); 280680d144c9SAnirudh Venkataramanan if (!v_list_itr) { 2807d54699e2STony Nguyen status = -ENOENT; 280880d144c9SAnirudh Venkataramanan goto exit; 280980d144c9SAnirudh Venkataramanan } 28105726ca0eSAnirudh Venkataramanan /* reuse VSI list for new rule and increment ref_cnt */ 28115726ca0eSAnirudh Venkataramanan if (map_info) { 28125726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info = map_info; 28135726ca0eSAnirudh Venkataramanan map_info->ref_cnt++; 28145726ca0eSAnirudh Venkataramanan } else { 2815d76a60baSAnirudh Venkataramanan v_list_itr->vsi_list_info = 28165726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(hw, &vsi_handle, 28175726ca0eSAnirudh Venkataramanan 1, vsi_list_id); 2818d76a60baSAnirudh Venkataramanan } 28195726ca0eSAnirudh Venkataramanan } 28205726ca0eSAnirudh Venkataramanan } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { 2821f9867df6SAnirudh Venkataramanan /* Update existing VSI list to add new VSI ID only if it used 28225726ca0eSAnirudh Venkataramanan * by one VLAN rule. 28235726ca0eSAnirudh Venkataramanan */ 28245726ca0eSAnirudh Venkataramanan cur_fltr = &v_list_itr->fltr_info; 28255726ca0eSAnirudh Venkataramanan status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, 28265726ca0eSAnirudh Venkataramanan new_fltr); 28275726ca0eSAnirudh Venkataramanan } else { 28285726ca0eSAnirudh Venkataramanan /* If VLAN rule exists and VSI list being used by this rule is 28295726ca0eSAnirudh Venkataramanan * referenced by more than 1 VLAN rule. Then create a new VSI 28305726ca0eSAnirudh Venkataramanan * list appending previous VSI with new VSI and update existing 2831f9867df6SAnirudh Venkataramanan * VLAN rule to point to new VSI list ID 28325726ca0eSAnirudh Venkataramanan */ 28335726ca0eSAnirudh Venkataramanan struct ice_fltr_info tmp_fltr; 28345726ca0eSAnirudh Venkataramanan u16 vsi_handle_arr[2]; 28355726ca0eSAnirudh Venkataramanan u16 cur_handle; 2836d76a60baSAnirudh Venkataramanan 28375726ca0eSAnirudh Venkataramanan /* Current implementation only supports reusing VSI list with 28385726ca0eSAnirudh Venkataramanan * one VSI count. We should never hit below condition 28395726ca0eSAnirudh Venkataramanan */ 28405726ca0eSAnirudh Venkataramanan if (v_list_itr->vsi_count > 1 && 28415726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info->ref_cnt > 1) { 28429228d8b2SJacob 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"); 2843d54699e2STony Nguyen status = -EIO; 284480d144c9SAnirudh Venkataramanan goto exit; 2845d76a60baSAnirudh Venkataramanan } 2846d76a60baSAnirudh Venkataramanan 28475726ca0eSAnirudh Venkataramanan cur_handle = 28485726ca0eSAnirudh Venkataramanan find_first_bit(v_list_itr->vsi_list_info->vsi_map, 28495726ca0eSAnirudh Venkataramanan ICE_MAX_VSI); 28505726ca0eSAnirudh Venkataramanan 28515726ca0eSAnirudh Venkataramanan /* A rule already exists with the new VSI being added */ 28525726ca0eSAnirudh Venkataramanan if (cur_handle == vsi_handle) { 2853d54699e2STony Nguyen status = -EEXIST; 28545726ca0eSAnirudh Venkataramanan goto exit; 28555726ca0eSAnirudh Venkataramanan } 28565726ca0eSAnirudh Venkataramanan 28575726ca0eSAnirudh Venkataramanan vsi_handle_arr[0] = cur_handle; 28585726ca0eSAnirudh Venkataramanan vsi_handle_arr[1] = vsi_handle; 28595726ca0eSAnirudh Venkataramanan status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, 28605726ca0eSAnirudh Venkataramanan &vsi_list_id, lkup_type); 28615726ca0eSAnirudh Venkataramanan if (status) 28625726ca0eSAnirudh Venkataramanan goto exit; 28635726ca0eSAnirudh Venkataramanan 28645726ca0eSAnirudh Venkataramanan tmp_fltr = v_list_itr->fltr_info; 28655726ca0eSAnirudh Venkataramanan tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; 28665726ca0eSAnirudh Venkataramanan tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; 28675726ca0eSAnirudh Venkataramanan tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; 28685726ca0eSAnirudh Venkataramanan /* Update the previous switch rule to a new VSI list which 2869df17b7e0SAnirudh Venkataramanan * includes current VSI that is requested 28705726ca0eSAnirudh Venkataramanan */ 28715726ca0eSAnirudh Venkataramanan status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 28725726ca0eSAnirudh Venkataramanan if (status) 28735726ca0eSAnirudh Venkataramanan goto exit; 28745726ca0eSAnirudh Venkataramanan 28755726ca0eSAnirudh Venkataramanan /* before overriding VSI list map info. decrement ref_cnt of 28765726ca0eSAnirudh Venkataramanan * previous VSI list 28775726ca0eSAnirudh Venkataramanan */ 28785726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info->ref_cnt--; 28795726ca0eSAnirudh Venkataramanan 28805726ca0eSAnirudh Venkataramanan /* now update to newly created list */ 28815726ca0eSAnirudh Venkataramanan v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; 28825726ca0eSAnirudh Venkataramanan v_list_itr->vsi_list_info = 28835726ca0eSAnirudh Venkataramanan ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, 28845726ca0eSAnirudh Venkataramanan vsi_list_id); 28855726ca0eSAnirudh Venkataramanan v_list_itr->vsi_count++; 28865726ca0eSAnirudh Venkataramanan } 288780d144c9SAnirudh Venkataramanan 288880d144c9SAnirudh Venkataramanan exit: 288980d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 289080d144c9SAnirudh Venkataramanan return status; 2891d76a60baSAnirudh Venkataramanan } 2892d76a60baSAnirudh Venkataramanan 2893d76a60baSAnirudh Venkataramanan /** 2894d76a60baSAnirudh Venkataramanan * ice_add_vlan - Add VLAN based filter rule 2895d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 2896d76a60baSAnirudh Venkataramanan * @v_list: list of VLAN entries and forwarding information 2897d76a60baSAnirudh Venkataramanan */ 28985e24d598STony Nguyen int ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) 2899d76a60baSAnirudh Venkataramanan { 2900d76a60baSAnirudh Venkataramanan struct ice_fltr_list_entry *v_list_itr; 2901d76a60baSAnirudh Venkataramanan 2902d76a60baSAnirudh Venkataramanan if (!v_list || !hw) 2903d54699e2STony Nguyen return -EINVAL; 2904d76a60baSAnirudh Venkataramanan 2905d76a60baSAnirudh Venkataramanan list_for_each_entry(v_list_itr, v_list, list_entry) { 2906d76a60baSAnirudh Venkataramanan if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN) 2907d54699e2STony Nguyen return -EINVAL; 290880d144c9SAnirudh Venkataramanan v_list_itr->fltr_info.flag = ICE_FLTR_TX; 290980d144c9SAnirudh Venkataramanan v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr); 291080d144c9SAnirudh Venkataramanan if (v_list_itr->status) 291180d144c9SAnirudh Venkataramanan return v_list_itr->status; 2912d76a60baSAnirudh Venkataramanan } 2913d76a60baSAnirudh Venkataramanan return 0; 2914d76a60baSAnirudh Venkataramanan } 2915d76a60baSAnirudh Venkataramanan 2916d76a60baSAnirudh Venkataramanan /** 2917d95276ceSAkeem G Abodunrin * ice_add_eth_mac - Add ethertype and MAC based filter rule 2918d95276ceSAkeem G Abodunrin * @hw: pointer to the hardware structure 2919d95276ceSAkeem G Abodunrin * @em_list: list of ether type MAC filter, MAC is optional 29202e0e6228SDave Ertman * 29212e0e6228SDave Ertman * This function requires the caller to populate the entries in 29222e0e6228SDave Ertman * the filter list with the necessary fields (including flags to 29232e0e6228SDave Ertman * indicate Tx or Rx rules). 2924d95276ceSAkeem G Abodunrin */ 29255518ac2aSTony Nguyen int ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list) 2926d95276ceSAkeem G Abodunrin { 2927d95276ceSAkeem G Abodunrin struct ice_fltr_list_entry *em_list_itr; 2928d95276ceSAkeem G Abodunrin 2929d95276ceSAkeem G Abodunrin if (!em_list || !hw) 2930d54699e2STony Nguyen return -EINVAL; 2931d95276ceSAkeem G Abodunrin 2932d95276ceSAkeem G Abodunrin list_for_each_entry(em_list_itr, em_list, list_entry) { 2933d95276ceSAkeem G Abodunrin enum ice_sw_lkup_type l_type = 2934d95276ceSAkeem G Abodunrin em_list_itr->fltr_info.lkup_type; 2935d95276ceSAkeem G Abodunrin 2936d95276ceSAkeem G Abodunrin if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && 2937d95276ceSAkeem G Abodunrin l_type != ICE_SW_LKUP_ETHERTYPE) 2938d54699e2STony Nguyen return -EINVAL; 2939d95276ceSAkeem G Abodunrin 2940d95276ceSAkeem G Abodunrin em_list_itr->status = ice_add_rule_internal(hw, l_type, 2941d95276ceSAkeem G Abodunrin em_list_itr); 2942d95276ceSAkeem G Abodunrin if (em_list_itr->status) 2943d95276ceSAkeem G Abodunrin return em_list_itr->status; 2944d95276ceSAkeem G Abodunrin } 2945d95276ceSAkeem G Abodunrin return 0; 2946d95276ceSAkeem G Abodunrin } 2947d95276ceSAkeem G Abodunrin 2948d95276ceSAkeem G Abodunrin /** 2949d95276ceSAkeem G Abodunrin * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule 2950d95276ceSAkeem G Abodunrin * @hw: pointer to the hardware structure 2951d95276ceSAkeem G Abodunrin * @em_list: list of ethertype or ethertype MAC entries 2952d95276ceSAkeem G Abodunrin */ 29535518ac2aSTony Nguyen int ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list) 2954d95276ceSAkeem G Abodunrin { 2955d95276ceSAkeem G Abodunrin struct ice_fltr_list_entry *em_list_itr, *tmp; 2956d95276ceSAkeem G Abodunrin 2957d95276ceSAkeem G Abodunrin if (!em_list || !hw) 2958d54699e2STony Nguyen return -EINVAL; 2959d95276ceSAkeem G Abodunrin 2960d95276ceSAkeem G Abodunrin list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) { 2961d95276ceSAkeem G Abodunrin enum ice_sw_lkup_type l_type = 2962d95276ceSAkeem G Abodunrin em_list_itr->fltr_info.lkup_type; 2963d95276ceSAkeem G Abodunrin 2964d95276ceSAkeem G Abodunrin if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && 2965d95276ceSAkeem G Abodunrin l_type != ICE_SW_LKUP_ETHERTYPE) 2966d54699e2STony Nguyen return -EINVAL; 2967d95276ceSAkeem G Abodunrin 2968d95276ceSAkeem G Abodunrin em_list_itr->status = ice_remove_rule_internal(hw, l_type, 2969d95276ceSAkeem G Abodunrin em_list_itr); 2970d95276ceSAkeem G Abodunrin if (em_list_itr->status) 2971d95276ceSAkeem G Abodunrin return em_list_itr->status; 2972d95276ceSAkeem G Abodunrin } 2973d95276ceSAkeem G Abodunrin return 0; 2974d95276ceSAkeem G Abodunrin } 2975d95276ceSAkeem G Abodunrin 2976d95276ceSAkeem G Abodunrin /** 29770f9d5027SAnirudh Venkataramanan * ice_rem_sw_rule_info 29780f9d5027SAnirudh Venkataramanan * @hw: pointer to the hardware structure 29790f9d5027SAnirudh Venkataramanan * @rule_head: pointer to the switch list structure that we want to delete 29800f9d5027SAnirudh Venkataramanan */ 29810f9d5027SAnirudh Venkataramanan static void 29820f9d5027SAnirudh Venkataramanan ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) 29830f9d5027SAnirudh Venkataramanan { 29840f9d5027SAnirudh Venkataramanan if (!list_empty(rule_head)) { 29850f9d5027SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *entry; 29860f9d5027SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *tmp; 29870f9d5027SAnirudh Venkataramanan 29880f9d5027SAnirudh Venkataramanan list_for_each_entry_safe(entry, tmp, rule_head, list_entry) { 29890f9d5027SAnirudh Venkataramanan list_del(&entry->list_entry); 29900f9d5027SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), entry); 29910f9d5027SAnirudh Venkataramanan } 29920f9d5027SAnirudh Venkataramanan } 29930f9d5027SAnirudh Venkataramanan } 29940f9d5027SAnirudh Venkataramanan 29950f9d5027SAnirudh Venkataramanan /** 29968b8ef05bSVictor Raj * ice_rem_adv_rule_info 29978b8ef05bSVictor Raj * @hw: pointer to the hardware structure 29988b8ef05bSVictor Raj * @rule_head: pointer to the switch list structure that we want to delete 29998b8ef05bSVictor Raj */ 30008b8ef05bSVictor Raj static void 30018b8ef05bSVictor Raj ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head) 30028b8ef05bSVictor Raj { 30038b8ef05bSVictor Raj struct ice_adv_fltr_mgmt_list_entry *tmp_entry; 30048b8ef05bSVictor Raj struct ice_adv_fltr_mgmt_list_entry *lst_itr; 30058b8ef05bSVictor Raj 30068b8ef05bSVictor Raj if (list_empty(rule_head)) 30078b8ef05bSVictor Raj return; 30088b8ef05bSVictor Raj 30098b8ef05bSVictor Raj list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) { 30108b8ef05bSVictor Raj list_del(&lst_itr->list_entry); 30118b8ef05bSVictor Raj devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups); 30128b8ef05bSVictor Raj devm_kfree(ice_hw_to_dev(hw), lst_itr); 30138b8ef05bSVictor Raj } 30148b8ef05bSVictor Raj } 30158b8ef05bSVictor Raj 30168b8ef05bSVictor Raj /** 301780d144c9SAnirudh Venkataramanan * ice_cfg_dflt_vsi - change state of VSI to set/clear default 3018e94d4478SAnirudh Venkataramanan * @hw: pointer to the hardware structure 30195726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to set as default 3020e94d4478SAnirudh Venkataramanan * @set: true to add the above mentioned switch rule, false to remove it 3021e94d4478SAnirudh Venkataramanan * @direction: ICE_FLTR_RX or ICE_FLTR_TX 302280d144c9SAnirudh Venkataramanan * 302380d144c9SAnirudh Venkataramanan * add filter rule to set/unset given VSI as default VSI for the switch 302480d144c9SAnirudh Venkataramanan * (represented by swid) 3025e94d4478SAnirudh Venkataramanan */ 30265518ac2aSTony Nguyen int ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction) 3027e94d4478SAnirudh Venkataramanan { 3028e94d4478SAnirudh Venkataramanan struct ice_aqc_sw_rules_elem *s_rule; 3029e94d4478SAnirudh Venkataramanan struct ice_fltr_info f_info; 3030e94d4478SAnirudh Venkataramanan enum ice_adminq_opc opcode; 3031e94d4478SAnirudh Venkataramanan u16 s_rule_size; 30325726ca0eSAnirudh Venkataramanan u16 hw_vsi_id; 30335518ac2aSTony Nguyen int status; 30345726ca0eSAnirudh Venkataramanan 30355726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 3036d54699e2STony Nguyen return -EINVAL; 30375726ca0eSAnirudh Venkataramanan hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 3038e94d4478SAnirudh Venkataramanan 3039e94d4478SAnirudh Venkataramanan s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE : 3040e94d4478SAnirudh Venkataramanan ICE_SW_RULE_RX_TX_NO_HDR_SIZE; 304166486d89SBruce Allan 3042e94d4478SAnirudh Venkataramanan s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); 3043e94d4478SAnirudh Venkataramanan if (!s_rule) 3044d54699e2STony Nguyen return -ENOMEM; 3045e94d4478SAnirudh Venkataramanan 3046e94d4478SAnirudh Venkataramanan memset(&f_info, 0, sizeof(f_info)); 3047e94d4478SAnirudh Venkataramanan 3048e94d4478SAnirudh Venkataramanan f_info.lkup_type = ICE_SW_LKUP_DFLT; 3049e94d4478SAnirudh Venkataramanan f_info.flag = direction; 3050e94d4478SAnirudh Venkataramanan f_info.fltr_act = ICE_FWD_TO_VSI; 30515726ca0eSAnirudh Venkataramanan f_info.fwd_id.hw_vsi_id = hw_vsi_id; 3052e94d4478SAnirudh Venkataramanan 3053e94d4478SAnirudh Venkataramanan if (f_info.flag & ICE_FLTR_RX) { 3054e94d4478SAnirudh Venkataramanan f_info.src = hw->port_info->lport; 30555726ca0eSAnirudh Venkataramanan f_info.src_id = ICE_SRC_ID_LPORT; 3056e94d4478SAnirudh Venkataramanan if (!set) 3057e94d4478SAnirudh Venkataramanan f_info.fltr_rule_id = 3058e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_rule_id; 3059e94d4478SAnirudh Venkataramanan } else if (f_info.flag & ICE_FLTR_TX) { 30605726ca0eSAnirudh Venkataramanan f_info.src_id = ICE_SRC_ID_VSI; 30615726ca0eSAnirudh Venkataramanan f_info.src = hw_vsi_id; 3062e94d4478SAnirudh Venkataramanan if (!set) 3063e94d4478SAnirudh Venkataramanan f_info.fltr_rule_id = 3064e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_rule_id; 3065e94d4478SAnirudh Venkataramanan } 3066e94d4478SAnirudh Venkataramanan 3067e94d4478SAnirudh Venkataramanan if (set) 3068e94d4478SAnirudh Venkataramanan opcode = ice_aqc_opc_add_sw_rules; 3069e94d4478SAnirudh Venkataramanan else 3070e94d4478SAnirudh Venkataramanan opcode = ice_aqc_opc_remove_sw_rules; 3071e94d4478SAnirudh Venkataramanan 3072e94d4478SAnirudh Venkataramanan ice_fill_sw_rule(hw, &f_info, s_rule, opcode); 3073e94d4478SAnirudh Venkataramanan 3074e94d4478SAnirudh Venkataramanan status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opcode, NULL); 3075e94d4478SAnirudh Venkataramanan if (status || !(f_info.flag & ICE_FLTR_TX_RX)) 3076e94d4478SAnirudh Venkataramanan goto out; 3077e94d4478SAnirudh Venkataramanan if (set) { 3078e94d4478SAnirudh Venkataramanan u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); 3079e94d4478SAnirudh Venkataramanan 3080e94d4478SAnirudh Venkataramanan if (f_info.flag & ICE_FLTR_TX) { 30815726ca0eSAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_num = hw_vsi_id; 3082e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_rule_id = index; 3083e94d4478SAnirudh Venkataramanan } else if (f_info.flag & ICE_FLTR_RX) { 30845726ca0eSAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_num = hw_vsi_id; 3085e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_rule_id = index; 3086e94d4478SAnirudh Venkataramanan } 3087e94d4478SAnirudh Venkataramanan } else { 3088e94d4478SAnirudh Venkataramanan if (f_info.flag & ICE_FLTR_TX) { 3089e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL; 3090e94d4478SAnirudh Venkataramanan hw->port_info->dflt_tx_vsi_rule_id = ICE_INVAL_ACT; 3091e94d4478SAnirudh Venkataramanan } else if (f_info.flag & ICE_FLTR_RX) { 3092e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL; 3093e94d4478SAnirudh Venkataramanan hw->port_info->dflt_rx_vsi_rule_id = ICE_INVAL_ACT; 3094e94d4478SAnirudh Venkataramanan } 3095e94d4478SAnirudh Venkataramanan } 3096e94d4478SAnirudh Venkataramanan 3097e94d4478SAnirudh Venkataramanan out: 3098e94d4478SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), s_rule); 3099e94d4478SAnirudh Venkataramanan return status; 3100e94d4478SAnirudh Venkataramanan } 3101e94d4478SAnirudh Venkataramanan 3102e94d4478SAnirudh Venkataramanan /** 31038b2c8582SAkeem G Abodunrin * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry 31048b2c8582SAkeem G Abodunrin * @hw: pointer to the hardware structure 31058b2c8582SAkeem G Abodunrin * @recp_id: lookup type for which the specified rule needs to be searched 31068b2c8582SAkeem G Abodunrin * @f_info: rule information 31078b2c8582SAkeem G Abodunrin * 31088b2c8582SAkeem G Abodunrin * Helper function to search for a unicast rule entry - this is to be used 31098b2c8582SAkeem G Abodunrin * to remove unicast MAC filter that is not shared with other VSIs on the 31108b2c8582SAkeem G Abodunrin * PF switch. 31118b2c8582SAkeem G Abodunrin * 31128b2c8582SAkeem G Abodunrin * Returns pointer to entry storing the rule if found 31138b2c8582SAkeem G Abodunrin */ 31148b2c8582SAkeem G Abodunrin static struct ice_fltr_mgmt_list_entry * 31158b2c8582SAkeem G Abodunrin ice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id, 31168b2c8582SAkeem G Abodunrin struct ice_fltr_info *f_info) 31178b2c8582SAkeem G Abodunrin { 31188b2c8582SAkeem G Abodunrin struct ice_switch_info *sw = hw->switch_info; 31198b2c8582SAkeem G Abodunrin struct ice_fltr_mgmt_list_entry *list_itr; 31208b2c8582SAkeem G Abodunrin struct list_head *list_head; 31218b2c8582SAkeem G Abodunrin 31228b2c8582SAkeem G Abodunrin list_head = &sw->recp_list[recp_id].filt_rules; 31238b2c8582SAkeem G Abodunrin list_for_each_entry(list_itr, list_head, list_entry) { 31248b2c8582SAkeem G Abodunrin if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data, 31258b2c8582SAkeem G Abodunrin sizeof(f_info->l_data)) && 31268b2c8582SAkeem G Abodunrin f_info->fwd_id.hw_vsi_id == 31278b2c8582SAkeem G Abodunrin list_itr->fltr_info.fwd_id.hw_vsi_id && 31288b2c8582SAkeem G Abodunrin f_info->flag == list_itr->fltr_info.flag) 31298b2c8582SAkeem G Abodunrin return list_itr; 31308b2c8582SAkeem G Abodunrin } 31318b2c8582SAkeem G Abodunrin return NULL; 31328b2c8582SAkeem G Abodunrin } 31338b2c8582SAkeem G Abodunrin 31348b2c8582SAkeem G Abodunrin /** 313580d144c9SAnirudh Venkataramanan * ice_remove_mac - remove a MAC address based filter rule 3136d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 313780d144c9SAnirudh Venkataramanan * @m_list: list of MAC addresses and forwarding information 313880d144c9SAnirudh Venkataramanan * 313980d144c9SAnirudh Venkataramanan * This function removes either a MAC filter rule or a specific VSI from a 314080d144c9SAnirudh Venkataramanan * VSI list for a multicast MAC address. 314180d144c9SAnirudh Venkataramanan * 31425518ac2aSTony Nguyen * Returns -ENOENT if a given entry was not added by ice_add_mac. Caller should 31435518ac2aSTony Nguyen * be aware that this call will only work if all the entries passed into m_list 31445518ac2aSTony Nguyen * were added previously. It will not attempt to do a partial remove of entries 31455518ac2aSTony Nguyen * that were found. 3146d76a60baSAnirudh Venkataramanan */ 31475e24d598STony Nguyen int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) 3148d76a60baSAnirudh Venkataramanan { 3149072f0c3dSDave Ertman struct ice_fltr_list_entry *list_itr, *tmp; 31508b2c8582SAkeem G Abodunrin struct mutex *rule_lock; /* Lock to protect filter rule list */ 3151d76a60baSAnirudh Venkataramanan 315280d144c9SAnirudh Venkataramanan if (!m_list) 3153d54699e2STony Nguyen return -EINVAL; 3154d76a60baSAnirudh Venkataramanan 31558b2c8582SAkeem G Abodunrin rule_lock = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; 3156072f0c3dSDave Ertman list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) { 315780d144c9SAnirudh Venkataramanan enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; 31588b2c8582SAkeem G Abodunrin u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0]; 31598b2c8582SAkeem G Abodunrin u16 vsi_handle; 316080d144c9SAnirudh Venkataramanan 316180d144c9SAnirudh Venkataramanan if (l_type != ICE_SW_LKUP_MAC) 3162d54699e2STony Nguyen return -EINVAL; 31638b2c8582SAkeem G Abodunrin 31648b2c8582SAkeem G Abodunrin vsi_handle = list_itr->fltr_info.vsi_handle; 31658b2c8582SAkeem G Abodunrin if (!ice_is_vsi_valid(hw, vsi_handle)) 3166d54699e2STony Nguyen return -EINVAL; 31678b2c8582SAkeem G Abodunrin 31688b2c8582SAkeem G Abodunrin list_itr->fltr_info.fwd_id.hw_vsi_id = 31698b2c8582SAkeem G Abodunrin ice_get_hw_vsi_num(hw, vsi_handle); 31708b2c8582SAkeem G Abodunrin if (is_unicast_ether_addr(add) && !hw->ucast_shared) { 31718b2c8582SAkeem G Abodunrin /* Don't remove the unicast address that belongs to 31728b2c8582SAkeem G Abodunrin * another VSI on the switch, since it is not being 31738b2c8582SAkeem G Abodunrin * shared... 31748b2c8582SAkeem G Abodunrin */ 31758b2c8582SAkeem G Abodunrin mutex_lock(rule_lock); 31768b2c8582SAkeem G Abodunrin if (!ice_find_ucast_rule_entry(hw, ICE_SW_LKUP_MAC, 31778b2c8582SAkeem G Abodunrin &list_itr->fltr_info)) { 31788b2c8582SAkeem G Abodunrin mutex_unlock(rule_lock); 3179d54699e2STony Nguyen return -ENOENT; 31808b2c8582SAkeem G Abodunrin } 31818b2c8582SAkeem G Abodunrin mutex_unlock(rule_lock); 31828b2c8582SAkeem G Abodunrin } 318380d144c9SAnirudh Venkataramanan list_itr->status = ice_remove_rule_internal(hw, 318480d144c9SAnirudh Venkataramanan ICE_SW_LKUP_MAC, 318580d144c9SAnirudh Venkataramanan list_itr); 318680d144c9SAnirudh Venkataramanan if (list_itr->status) 318780d144c9SAnirudh Venkataramanan return list_itr->status; 318880d144c9SAnirudh Venkataramanan } 318980d144c9SAnirudh Venkataramanan return 0; 3190d76a60baSAnirudh Venkataramanan } 3191d76a60baSAnirudh Venkataramanan 3192d76a60baSAnirudh Venkataramanan /** 3193d76a60baSAnirudh Venkataramanan * ice_remove_vlan - Remove VLAN based filter rule 3194d76a60baSAnirudh Venkataramanan * @hw: pointer to the hardware structure 3195d76a60baSAnirudh Venkataramanan * @v_list: list of VLAN entries and forwarding information 3196d76a60baSAnirudh Venkataramanan */ 31975518ac2aSTony Nguyen int ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) 3198d76a60baSAnirudh Venkataramanan { 3199072f0c3dSDave Ertman struct ice_fltr_list_entry *v_list_itr, *tmp; 3200d76a60baSAnirudh Venkataramanan 3201d76a60baSAnirudh Venkataramanan if (!v_list || !hw) 3202d54699e2STony Nguyen return -EINVAL; 3203d76a60baSAnirudh Venkataramanan 3204072f0c3dSDave Ertman list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { 320580d144c9SAnirudh Venkataramanan enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; 320680d144c9SAnirudh Venkataramanan 320780d144c9SAnirudh Venkataramanan if (l_type != ICE_SW_LKUP_VLAN) 3208d54699e2STony Nguyen return -EINVAL; 320980d144c9SAnirudh Venkataramanan v_list_itr->status = ice_remove_rule_internal(hw, 321080d144c9SAnirudh Venkataramanan ICE_SW_LKUP_VLAN, 321180d144c9SAnirudh Venkataramanan v_list_itr); 321280d144c9SAnirudh Venkataramanan if (v_list_itr->status) 321380d144c9SAnirudh Venkataramanan return v_list_itr->status; 3214d76a60baSAnirudh Venkataramanan } 321580d144c9SAnirudh Venkataramanan return 0; 3216d76a60baSAnirudh Venkataramanan } 321780d144c9SAnirudh Venkataramanan 321880d144c9SAnirudh Venkataramanan /** 321980d144c9SAnirudh Venkataramanan * ice_vsi_uses_fltr - Determine if given VSI uses specified filter 322080d144c9SAnirudh Venkataramanan * @fm_entry: filter entry to inspect 32215726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to compare with filter info 322280d144c9SAnirudh Venkataramanan */ 322380d144c9SAnirudh Venkataramanan static bool 32245726ca0eSAnirudh Venkataramanan ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) 322580d144c9SAnirudh Venkataramanan { 322680d144c9SAnirudh Venkataramanan return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && 32275726ca0eSAnirudh Venkataramanan fm_entry->fltr_info.vsi_handle == vsi_handle) || 322880d144c9SAnirudh Venkataramanan (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && 32297a91d3f0SJacek Bułatek fm_entry->vsi_list_info && 32305726ca0eSAnirudh Venkataramanan (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); 323180d144c9SAnirudh Venkataramanan } 323280d144c9SAnirudh Venkataramanan 323380d144c9SAnirudh Venkataramanan /** 323480d144c9SAnirudh Venkataramanan * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list 323580d144c9SAnirudh Venkataramanan * @hw: pointer to the hardware structure 32365726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 323780d144c9SAnirudh Venkataramanan * @vsi_list_head: pointer to the list to add entry to 323880d144c9SAnirudh Venkataramanan * @fi: pointer to fltr_info of filter entry to copy & add 323980d144c9SAnirudh Venkataramanan * 324080d144c9SAnirudh Venkataramanan * Helper function, used when creating a list of filters to remove from 324180d144c9SAnirudh Venkataramanan * a specific VSI. The entry added to vsi_list_head is a COPY of the 324280d144c9SAnirudh Venkataramanan * original filter entry, with the exception of fltr_info.fltr_act and 324380d144c9SAnirudh Venkataramanan * fltr_info.fwd_id fields. These are set such that later logic can 324480d144c9SAnirudh Venkataramanan * extract which VSI to remove the fltr from, and pass on that information. 324580d144c9SAnirudh Venkataramanan */ 32465e24d598STony Nguyen static int 32475726ca0eSAnirudh Venkataramanan ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, 324880d144c9SAnirudh Venkataramanan struct list_head *vsi_list_head, 324980d144c9SAnirudh Venkataramanan struct ice_fltr_info *fi) 325080d144c9SAnirudh Venkataramanan { 325180d144c9SAnirudh Venkataramanan struct ice_fltr_list_entry *tmp; 325280d144c9SAnirudh Venkataramanan 325380d144c9SAnirudh Venkataramanan /* this memory is freed up in the caller function 325480d144c9SAnirudh Venkataramanan * once filters for this VSI are removed 325580d144c9SAnirudh Venkataramanan */ 325680d144c9SAnirudh Venkataramanan tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL); 325780d144c9SAnirudh Venkataramanan if (!tmp) 3258d54699e2STony Nguyen return -ENOMEM; 325980d144c9SAnirudh Venkataramanan 326080d144c9SAnirudh Venkataramanan tmp->fltr_info = *fi; 326180d144c9SAnirudh Venkataramanan 326280d144c9SAnirudh Venkataramanan /* Overwrite these fields to indicate which VSI to remove filter from, 326380d144c9SAnirudh Venkataramanan * so find and remove logic can extract the information from the 326480d144c9SAnirudh Venkataramanan * list entries. Note that original entries will still have proper 326580d144c9SAnirudh Venkataramanan * values. 326680d144c9SAnirudh Venkataramanan */ 326780d144c9SAnirudh Venkataramanan tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; 32685726ca0eSAnirudh Venkataramanan tmp->fltr_info.vsi_handle = vsi_handle; 32695726ca0eSAnirudh Venkataramanan tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 327080d144c9SAnirudh Venkataramanan 327180d144c9SAnirudh Venkataramanan list_add(&tmp->list_entry, vsi_list_head); 327280d144c9SAnirudh Venkataramanan 327380d144c9SAnirudh Venkataramanan return 0; 3274d76a60baSAnirudh Venkataramanan } 3275d76a60baSAnirudh Venkataramanan 3276d76a60baSAnirudh Venkataramanan /** 32779daf8208SAnirudh Venkataramanan * ice_add_to_vsi_fltr_list - Add VSI filters to the list 32789daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 32795726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 32809daf8208SAnirudh Venkataramanan * @lkup_list_head: pointer to the list that has certain lookup type filters 32815726ca0eSAnirudh Venkataramanan * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle 328280d144c9SAnirudh Venkataramanan * 328380d144c9SAnirudh Venkataramanan * Locates all filters in lkup_list_head that are used by the given VSI, 328480d144c9SAnirudh Venkataramanan * and adds COPIES of those entries to vsi_list_head (intended to be used 328580d144c9SAnirudh Venkataramanan * to remove the listed filters). 328680d144c9SAnirudh Venkataramanan * Note that this means all entries in vsi_list_head must be explicitly 328780d144c9SAnirudh Venkataramanan * deallocated by the caller when done with list. 32889daf8208SAnirudh Venkataramanan */ 32895e24d598STony Nguyen static int 32905726ca0eSAnirudh Venkataramanan ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, 32919daf8208SAnirudh Venkataramanan struct list_head *lkup_list_head, 32929daf8208SAnirudh Venkataramanan struct list_head *vsi_list_head) 32939daf8208SAnirudh Venkataramanan { 32949daf8208SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *fm_entry; 32955e24d598STony Nguyen int status = 0; 32969daf8208SAnirudh Venkataramanan 3297f9867df6SAnirudh Venkataramanan /* check to make sure VSI ID is valid and within boundary */ 32985726ca0eSAnirudh Venkataramanan if (!ice_is_vsi_valid(hw, vsi_handle)) 3299d54699e2STony Nguyen return -EINVAL; 33009daf8208SAnirudh Venkataramanan 33019daf8208SAnirudh Venkataramanan list_for_each_entry(fm_entry, lkup_list_head, list_entry) { 33027a91d3f0SJacek Bułatek if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) 330380d144c9SAnirudh Venkataramanan continue; 33049daf8208SAnirudh Venkataramanan 33055726ca0eSAnirudh Venkataramanan status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, 33067a91d3f0SJacek Bułatek vsi_list_head, 33077a91d3f0SJacek Bułatek &fm_entry->fltr_info); 330880d144c9SAnirudh Venkataramanan if (status) 330980d144c9SAnirudh Venkataramanan return status; 33109daf8208SAnirudh Venkataramanan } 331180d144c9SAnirudh Venkataramanan return status; 33129daf8208SAnirudh Venkataramanan } 33139daf8208SAnirudh Venkataramanan 33149daf8208SAnirudh Venkataramanan /** 33155eda8afdSAkeem G Abodunrin * ice_determine_promisc_mask 33165eda8afdSAkeem G Abodunrin * @fi: filter info to parse 33175eda8afdSAkeem G Abodunrin * 33185eda8afdSAkeem G Abodunrin * Helper function to determine which ICE_PROMISC_ mask corresponds 33195eda8afdSAkeem G Abodunrin * to given filter into. 33205eda8afdSAkeem G Abodunrin */ 33215eda8afdSAkeem G Abodunrin static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi) 33225eda8afdSAkeem G Abodunrin { 33235eda8afdSAkeem G Abodunrin u16 vid = fi->l_data.mac_vlan.vlan_id; 33245eda8afdSAkeem G Abodunrin u8 *macaddr = fi->l_data.mac.mac_addr; 33255eda8afdSAkeem G Abodunrin bool is_tx_fltr = false; 33265eda8afdSAkeem G Abodunrin u8 promisc_mask = 0; 33275eda8afdSAkeem G Abodunrin 33285eda8afdSAkeem G Abodunrin if (fi->flag == ICE_FLTR_TX) 33295eda8afdSAkeem G Abodunrin is_tx_fltr = true; 33305eda8afdSAkeem G Abodunrin 33315eda8afdSAkeem G Abodunrin if (is_broadcast_ether_addr(macaddr)) 33325eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 33335eda8afdSAkeem G Abodunrin ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX; 33345eda8afdSAkeem G Abodunrin else if (is_multicast_ether_addr(macaddr)) 33355eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 33365eda8afdSAkeem G Abodunrin ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX; 33375eda8afdSAkeem G Abodunrin else if (is_unicast_ether_addr(macaddr)) 33385eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 33395eda8afdSAkeem G Abodunrin ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX; 33405eda8afdSAkeem G Abodunrin if (vid) 33415eda8afdSAkeem G Abodunrin promisc_mask |= is_tx_fltr ? 33425eda8afdSAkeem G Abodunrin ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX; 33435eda8afdSAkeem G Abodunrin 33445eda8afdSAkeem G Abodunrin return promisc_mask; 33455eda8afdSAkeem G Abodunrin } 33465eda8afdSAkeem G Abodunrin 33475eda8afdSAkeem G Abodunrin /** 33485eda8afdSAkeem G Abodunrin * ice_remove_promisc - Remove promisc based filter rules 33495eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 3350f9867df6SAnirudh Venkataramanan * @recp_id: recipe ID for which the rule needs to removed 33515eda8afdSAkeem G Abodunrin * @v_list: list of promisc entries 33525eda8afdSAkeem G Abodunrin */ 33535e24d598STony Nguyen static int 33545518ac2aSTony Nguyen ice_remove_promisc(struct ice_hw *hw, u8 recp_id, struct list_head *v_list) 33555eda8afdSAkeem G Abodunrin { 33565eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry *v_list_itr, *tmp; 33575eda8afdSAkeem G Abodunrin 33585eda8afdSAkeem G Abodunrin list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { 33595eda8afdSAkeem G Abodunrin v_list_itr->status = 33605eda8afdSAkeem G Abodunrin ice_remove_rule_internal(hw, recp_id, v_list_itr); 33615eda8afdSAkeem G Abodunrin if (v_list_itr->status) 33625eda8afdSAkeem G Abodunrin return v_list_itr->status; 33635eda8afdSAkeem G Abodunrin } 33645eda8afdSAkeem G Abodunrin return 0; 33655eda8afdSAkeem G Abodunrin } 33665eda8afdSAkeem G Abodunrin 33675eda8afdSAkeem G Abodunrin /** 33685eda8afdSAkeem G Abodunrin * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI 33695eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 33705eda8afdSAkeem G Abodunrin * @vsi_handle: VSI handle to clear mode 33715eda8afdSAkeem G Abodunrin * @promisc_mask: mask of promiscuous config bits to clear 33725eda8afdSAkeem G Abodunrin * @vid: VLAN ID to clear VLAN promiscuous 33735eda8afdSAkeem G Abodunrin */ 33745e24d598STony Nguyen int 33755eda8afdSAkeem G Abodunrin ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, 33765eda8afdSAkeem G Abodunrin u16 vid) 33775eda8afdSAkeem G Abodunrin { 33785eda8afdSAkeem G Abodunrin struct ice_switch_info *sw = hw->switch_info; 33795eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry *fm_entry, *tmp; 33805eda8afdSAkeem G Abodunrin struct list_head remove_list_head; 33815eda8afdSAkeem G Abodunrin struct ice_fltr_mgmt_list_entry *itr; 33825eda8afdSAkeem G Abodunrin struct list_head *rule_head; 33835eda8afdSAkeem G Abodunrin struct mutex *rule_lock; /* Lock to protect filter rule list */ 33845e24d598STony Nguyen int status = 0; 33855eda8afdSAkeem G Abodunrin u8 recipe_id; 33865eda8afdSAkeem G Abodunrin 33875eda8afdSAkeem G Abodunrin if (!ice_is_vsi_valid(hw, vsi_handle)) 3388d54699e2STony Nguyen return -EINVAL; 33895eda8afdSAkeem G Abodunrin 33901bc7a4abSBrett Creeley if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) 33915eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC_VLAN; 33925eda8afdSAkeem G Abodunrin else 33935eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC; 33945eda8afdSAkeem G Abodunrin 33955eda8afdSAkeem G Abodunrin rule_head = &sw->recp_list[recipe_id].filt_rules; 33965eda8afdSAkeem G Abodunrin rule_lock = &sw->recp_list[recipe_id].filt_rule_lock; 33975eda8afdSAkeem G Abodunrin 33985eda8afdSAkeem G Abodunrin INIT_LIST_HEAD(&remove_list_head); 33995eda8afdSAkeem G Abodunrin 34005eda8afdSAkeem G Abodunrin mutex_lock(rule_lock); 34015eda8afdSAkeem G Abodunrin list_for_each_entry(itr, rule_head, list_entry) { 34021bc7a4abSBrett Creeley struct ice_fltr_info *fltr_info; 34035eda8afdSAkeem G Abodunrin u8 fltr_promisc_mask = 0; 34045eda8afdSAkeem G Abodunrin 34055eda8afdSAkeem G Abodunrin if (!ice_vsi_uses_fltr(itr, vsi_handle)) 34065eda8afdSAkeem G Abodunrin continue; 34071bc7a4abSBrett Creeley fltr_info = &itr->fltr_info; 34085eda8afdSAkeem G Abodunrin 34091bc7a4abSBrett Creeley if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN && 34101bc7a4abSBrett Creeley vid != fltr_info->l_data.mac_vlan.vlan_id) 34111bc7a4abSBrett Creeley continue; 34121bc7a4abSBrett Creeley 34131bc7a4abSBrett Creeley fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info); 34145eda8afdSAkeem G Abodunrin 34155eda8afdSAkeem G Abodunrin /* Skip if filter is not completely specified by given mask */ 34165eda8afdSAkeem G Abodunrin if (fltr_promisc_mask & ~promisc_mask) 34175eda8afdSAkeem G Abodunrin continue; 34185eda8afdSAkeem G Abodunrin 34195eda8afdSAkeem G Abodunrin status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, 34205eda8afdSAkeem G Abodunrin &remove_list_head, 34211bc7a4abSBrett Creeley fltr_info); 34225eda8afdSAkeem G Abodunrin if (status) { 34235eda8afdSAkeem G Abodunrin mutex_unlock(rule_lock); 34245eda8afdSAkeem G Abodunrin goto free_fltr_list; 34255eda8afdSAkeem G Abodunrin } 34265eda8afdSAkeem G Abodunrin } 34275eda8afdSAkeem G Abodunrin mutex_unlock(rule_lock); 34285eda8afdSAkeem G Abodunrin 34295eda8afdSAkeem G Abodunrin status = ice_remove_promisc(hw, recipe_id, &remove_list_head); 34305eda8afdSAkeem G Abodunrin 34315eda8afdSAkeem G Abodunrin free_fltr_list: 34325eda8afdSAkeem G Abodunrin list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { 34335eda8afdSAkeem G Abodunrin list_del(&fm_entry->list_entry); 34345eda8afdSAkeem G Abodunrin devm_kfree(ice_hw_to_dev(hw), fm_entry); 34355eda8afdSAkeem G Abodunrin } 34365eda8afdSAkeem G Abodunrin 34375eda8afdSAkeem G Abodunrin return status; 34385eda8afdSAkeem G Abodunrin } 34395eda8afdSAkeem G Abodunrin 34405eda8afdSAkeem G Abodunrin /** 34415eda8afdSAkeem G Abodunrin * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s) 34425eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 34435eda8afdSAkeem G Abodunrin * @vsi_handle: VSI handle to configure 34445eda8afdSAkeem G Abodunrin * @promisc_mask: mask of promiscuous config bits 34455eda8afdSAkeem G Abodunrin * @vid: VLAN ID to set VLAN promiscuous 34465eda8afdSAkeem G Abodunrin */ 34475e24d598STony Nguyen int 34485eda8afdSAkeem G Abodunrin ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) 34495eda8afdSAkeem G Abodunrin { 34505eda8afdSAkeem G Abodunrin enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR }; 34515eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry f_list_entry; 34525eda8afdSAkeem G Abodunrin struct ice_fltr_info new_fltr; 34535eda8afdSAkeem G Abodunrin bool is_tx_fltr; 34545518ac2aSTony Nguyen int status = 0; 34555eda8afdSAkeem G Abodunrin u16 hw_vsi_id; 34565eda8afdSAkeem G Abodunrin int pkt_type; 34575eda8afdSAkeem G Abodunrin u8 recipe_id; 34585eda8afdSAkeem G Abodunrin 34595eda8afdSAkeem G Abodunrin if (!ice_is_vsi_valid(hw, vsi_handle)) 3460d54699e2STony Nguyen return -EINVAL; 34615eda8afdSAkeem G Abodunrin hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 34625eda8afdSAkeem G Abodunrin 34635eda8afdSAkeem G Abodunrin memset(&new_fltr, 0, sizeof(new_fltr)); 34645eda8afdSAkeem G Abodunrin 34655eda8afdSAkeem G Abodunrin if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) { 34665eda8afdSAkeem G Abodunrin new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN; 34675eda8afdSAkeem G Abodunrin new_fltr.l_data.mac_vlan.vlan_id = vid; 34685eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC_VLAN; 34695eda8afdSAkeem G Abodunrin } else { 34705eda8afdSAkeem G Abodunrin new_fltr.lkup_type = ICE_SW_LKUP_PROMISC; 34715eda8afdSAkeem G Abodunrin recipe_id = ICE_SW_LKUP_PROMISC; 34725eda8afdSAkeem G Abodunrin } 34735eda8afdSAkeem G Abodunrin 34745eda8afdSAkeem G Abodunrin /* Separate filters must be set for each direction/packet type 34755eda8afdSAkeem G Abodunrin * combination, so we will loop over the mask value, store the 34765eda8afdSAkeem G Abodunrin * individual type, and clear it out in the input mask as it 34775eda8afdSAkeem G Abodunrin * is found. 34785eda8afdSAkeem G Abodunrin */ 34795eda8afdSAkeem G Abodunrin while (promisc_mask) { 34805eda8afdSAkeem G Abodunrin u8 *mac_addr; 34815eda8afdSAkeem G Abodunrin 34825eda8afdSAkeem G Abodunrin pkt_type = 0; 34835eda8afdSAkeem G Abodunrin is_tx_fltr = false; 34845eda8afdSAkeem G Abodunrin 34855eda8afdSAkeem G Abodunrin if (promisc_mask & ICE_PROMISC_UCAST_RX) { 34865eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_UCAST_RX; 34875eda8afdSAkeem G Abodunrin pkt_type = UCAST_FLTR; 34885eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_UCAST_TX) { 34895eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_UCAST_TX; 34905eda8afdSAkeem G Abodunrin pkt_type = UCAST_FLTR; 34915eda8afdSAkeem G Abodunrin is_tx_fltr = true; 34925eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_MCAST_RX) { 34935eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_MCAST_RX; 34945eda8afdSAkeem G Abodunrin pkt_type = MCAST_FLTR; 34955eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_MCAST_TX) { 34965eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_MCAST_TX; 34975eda8afdSAkeem G Abodunrin pkt_type = MCAST_FLTR; 34985eda8afdSAkeem G Abodunrin is_tx_fltr = true; 34995eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_BCAST_RX) { 35005eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_BCAST_RX; 35015eda8afdSAkeem G Abodunrin pkt_type = BCAST_FLTR; 35025eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_BCAST_TX) { 35035eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_BCAST_TX; 35045eda8afdSAkeem G Abodunrin pkt_type = BCAST_FLTR; 35055eda8afdSAkeem G Abodunrin is_tx_fltr = true; 35065eda8afdSAkeem G Abodunrin } 35075eda8afdSAkeem G Abodunrin 35085eda8afdSAkeem G Abodunrin /* Check for VLAN promiscuous flag */ 35095eda8afdSAkeem G Abodunrin if (promisc_mask & ICE_PROMISC_VLAN_RX) { 35105eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_VLAN_RX; 35115eda8afdSAkeem G Abodunrin } else if (promisc_mask & ICE_PROMISC_VLAN_TX) { 35125eda8afdSAkeem G Abodunrin promisc_mask &= ~ICE_PROMISC_VLAN_TX; 35135eda8afdSAkeem G Abodunrin is_tx_fltr = true; 35145eda8afdSAkeem G Abodunrin } 35155eda8afdSAkeem G Abodunrin 35165eda8afdSAkeem G Abodunrin /* Set filter DA based on packet type */ 35175eda8afdSAkeem G Abodunrin mac_addr = new_fltr.l_data.mac.mac_addr; 35185eda8afdSAkeem G Abodunrin if (pkt_type == BCAST_FLTR) { 35195eda8afdSAkeem G Abodunrin eth_broadcast_addr(mac_addr); 35205eda8afdSAkeem G Abodunrin } else if (pkt_type == MCAST_FLTR || 35215eda8afdSAkeem G Abodunrin pkt_type == UCAST_FLTR) { 35225eda8afdSAkeem G Abodunrin /* Use the dummy ether header DA */ 35235eda8afdSAkeem G Abodunrin ether_addr_copy(mac_addr, dummy_eth_header); 35245eda8afdSAkeem G Abodunrin if (pkt_type == MCAST_FLTR) 35255eda8afdSAkeem G Abodunrin mac_addr[0] |= 0x1; /* Set multicast bit */ 35265eda8afdSAkeem G Abodunrin } 35275eda8afdSAkeem G Abodunrin 35285eda8afdSAkeem G Abodunrin /* Need to reset this to zero for all iterations */ 35295eda8afdSAkeem G Abodunrin new_fltr.flag = 0; 35305eda8afdSAkeem G Abodunrin if (is_tx_fltr) { 35315eda8afdSAkeem G Abodunrin new_fltr.flag |= ICE_FLTR_TX; 35325eda8afdSAkeem G Abodunrin new_fltr.src = hw_vsi_id; 35335eda8afdSAkeem G Abodunrin } else { 35345eda8afdSAkeem G Abodunrin new_fltr.flag |= ICE_FLTR_RX; 35355eda8afdSAkeem G Abodunrin new_fltr.src = hw->port_info->lport; 35365eda8afdSAkeem G Abodunrin } 35375eda8afdSAkeem G Abodunrin 35385eda8afdSAkeem G Abodunrin new_fltr.fltr_act = ICE_FWD_TO_VSI; 35395eda8afdSAkeem G Abodunrin new_fltr.vsi_handle = vsi_handle; 35405eda8afdSAkeem G Abodunrin new_fltr.fwd_id.hw_vsi_id = hw_vsi_id; 35415eda8afdSAkeem G Abodunrin f_list_entry.fltr_info = new_fltr; 35425eda8afdSAkeem G Abodunrin 35435eda8afdSAkeem G Abodunrin status = ice_add_rule_internal(hw, recipe_id, &f_list_entry); 35445eda8afdSAkeem G Abodunrin if (status) 35455eda8afdSAkeem G Abodunrin goto set_promisc_exit; 35465eda8afdSAkeem G Abodunrin } 35475eda8afdSAkeem G Abodunrin 35485eda8afdSAkeem G Abodunrin set_promisc_exit: 35495eda8afdSAkeem G Abodunrin return status; 35505eda8afdSAkeem G Abodunrin } 35515eda8afdSAkeem G Abodunrin 35525eda8afdSAkeem G Abodunrin /** 35535eda8afdSAkeem G Abodunrin * ice_set_vlan_vsi_promisc 35545eda8afdSAkeem G Abodunrin * @hw: pointer to the hardware structure 35555eda8afdSAkeem G Abodunrin * @vsi_handle: VSI handle to configure 35565eda8afdSAkeem G Abodunrin * @promisc_mask: mask of promiscuous config bits 35575eda8afdSAkeem G Abodunrin * @rm_vlan_promisc: Clear VLANs VSI promisc mode 35585eda8afdSAkeem G Abodunrin * 35595eda8afdSAkeem G Abodunrin * Configure VSI with all associated VLANs to given promiscuous mode(s) 35605eda8afdSAkeem G Abodunrin */ 35615e24d598STony Nguyen int 35625eda8afdSAkeem G Abodunrin ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, 35635eda8afdSAkeem G Abodunrin bool rm_vlan_promisc) 35645eda8afdSAkeem G Abodunrin { 35655eda8afdSAkeem G Abodunrin struct ice_switch_info *sw = hw->switch_info; 35665eda8afdSAkeem G Abodunrin struct ice_fltr_list_entry *list_itr, *tmp; 35675eda8afdSAkeem G Abodunrin struct list_head vsi_list_head; 35685eda8afdSAkeem G Abodunrin struct list_head *vlan_head; 35695eda8afdSAkeem G Abodunrin struct mutex *vlan_lock; /* Lock to protect filter rule list */ 35705eda8afdSAkeem G Abodunrin u16 vlan_id; 35715518ac2aSTony Nguyen int status; 35725eda8afdSAkeem G Abodunrin 35735eda8afdSAkeem G Abodunrin INIT_LIST_HEAD(&vsi_list_head); 35745eda8afdSAkeem G Abodunrin vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; 35755eda8afdSAkeem G Abodunrin vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; 35765eda8afdSAkeem G Abodunrin mutex_lock(vlan_lock); 35775eda8afdSAkeem G Abodunrin status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head, 35785eda8afdSAkeem G Abodunrin &vsi_list_head); 35795eda8afdSAkeem G Abodunrin mutex_unlock(vlan_lock); 35805eda8afdSAkeem G Abodunrin if (status) 35815eda8afdSAkeem G Abodunrin goto free_fltr_list; 35825eda8afdSAkeem G Abodunrin 35835eda8afdSAkeem G Abodunrin list_for_each_entry(list_itr, &vsi_list_head, list_entry) { 35845eda8afdSAkeem G Abodunrin vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id; 35855eda8afdSAkeem G Abodunrin if (rm_vlan_promisc) 35865eda8afdSAkeem G Abodunrin status = ice_clear_vsi_promisc(hw, vsi_handle, 35875eda8afdSAkeem G Abodunrin promisc_mask, vlan_id); 35885eda8afdSAkeem G Abodunrin else 35895eda8afdSAkeem G Abodunrin status = ice_set_vsi_promisc(hw, vsi_handle, 35905eda8afdSAkeem G Abodunrin promisc_mask, vlan_id); 35915eda8afdSAkeem G Abodunrin if (status) 35925eda8afdSAkeem G Abodunrin break; 35935eda8afdSAkeem G Abodunrin } 35945eda8afdSAkeem G Abodunrin 35955eda8afdSAkeem G Abodunrin free_fltr_list: 35965eda8afdSAkeem G Abodunrin list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) { 35975eda8afdSAkeem G Abodunrin list_del(&list_itr->list_entry); 35985eda8afdSAkeem G Abodunrin devm_kfree(ice_hw_to_dev(hw), list_itr); 35995eda8afdSAkeem G Abodunrin } 36005eda8afdSAkeem G Abodunrin return status; 36015eda8afdSAkeem G Abodunrin } 36025eda8afdSAkeem G Abodunrin 36035eda8afdSAkeem G Abodunrin /** 36049daf8208SAnirudh Venkataramanan * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI 36059daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 36065726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 36079daf8208SAnirudh Venkataramanan * @lkup: switch rule filter lookup type 36089daf8208SAnirudh Venkataramanan */ 36099daf8208SAnirudh Venkataramanan static void 36105726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, 36119daf8208SAnirudh Venkataramanan enum ice_sw_lkup_type lkup) 36129daf8208SAnirudh Venkataramanan { 36139daf8208SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 36149daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *fm_entry; 36159daf8208SAnirudh Venkataramanan struct list_head remove_list_head; 361680d144c9SAnirudh Venkataramanan struct list_head *rule_head; 36179daf8208SAnirudh Venkataramanan struct ice_fltr_list_entry *tmp; 361880d144c9SAnirudh Venkataramanan struct mutex *rule_lock; /* Lock to protect filter rule list */ 36195e24d598STony Nguyen int status; 36209daf8208SAnirudh Venkataramanan 36219daf8208SAnirudh Venkataramanan INIT_LIST_HEAD(&remove_list_head); 362280d144c9SAnirudh Venkataramanan rule_lock = &sw->recp_list[lkup].filt_rule_lock; 362380d144c9SAnirudh Venkataramanan rule_head = &sw->recp_list[lkup].filt_rules; 362480d144c9SAnirudh Venkataramanan mutex_lock(rule_lock); 36255726ca0eSAnirudh Venkataramanan status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head, 362680d144c9SAnirudh Venkataramanan &remove_list_head); 362780d144c9SAnirudh Venkataramanan mutex_unlock(rule_lock); 362880d144c9SAnirudh Venkataramanan if (status) 3629b7eeb527SRobert Malz goto free_fltr_list; 363080d144c9SAnirudh Venkataramanan 36319daf8208SAnirudh Venkataramanan switch (lkup) { 36329daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_MAC: 36339daf8208SAnirudh Venkataramanan ice_remove_mac(hw, &remove_list_head); 36349daf8208SAnirudh Venkataramanan break; 36359daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_VLAN: 3636d76a60baSAnirudh Venkataramanan ice_remove_vlan(hw, &remove_list_head); 3637d76a60baSAnirudh Venkataramanan break; 36385eda8afdSAkeem G Abodunrin case ICE_SW_LKUP_PROMISC: 36395eda8afdSAkeem G Abodunrin case ICE_SW_LKUP_PROMISC_VLAN: 36405eda8afdSAkeem G Abodunrin ice_remove_promisc(hw, lkup, &remove_list_head); 36415eda8afdSAkeem G Abodunrin break; 36429daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_MAC_VLAN: 36439daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_ETHERTYPE: 36449daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_ETHERTYPE_MAC: 36459daf8208SAnirudh Venkataramanan case ICE_SW_LKUP_DFLT: 364680d144c9SAnirudh Venkataramanan case ICE_SW_LKUP_LAST: 364780d144c9SAnirudh Venkataramanan default: 364880d144c9SAnirudh Venkataramanan ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); 36499daf8208SAnirudh Venkataramanan break; 36509daf8208SAnirudh Venkataramanan } 36519daf8208SAnirudh Venkataramanan 3652b7eeb527SRobert Malz free_fltr_list: 36539daf8208SAnirudh Venkataramanan list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { 36549daf8208SAnirudh Venkataramanan list_del(&fm_entry->list_entry); 36559daf8208SAnirudh Venkataramanan devm_kfree(ice_hw_to_dev(hw), fm_entry); 36569daf8208SAnirudh Venkataramanan } 36579daf8208SAnirudh Venkataramanan } 36589daf8208SAnirudh Venkataramanan 36599daf8208SAnirudh Venkataramanan /** 36609daf8208SAnirudh Venkataramanan * ice_remove_vsi_fltr - Remove all filters for a VSI 36619daf8208SAnirudh Venkataramanan * @hw: pointer to the hardware structure 36625726ca0eSAnirudh Venkataramanan * @vsi_handle: VSI handle to remove filters from 36639daf8208SAnirudh Venkataramanan */ 36645726ca0eSAnirudh Venkataramanan void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) 36659daf8208SAnirudh Venkataramanan { 36665726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC); 36675726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN); 36685726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC); 36695726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN); 36705726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT); 36715726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE); 36725726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC); 36735726ca0eSAnirudh Venkataramanan ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN); 36749daf8208SAnirudh Venkataramanan } 36750f9d5027SAnirudh Venkataramanan 36760f9d5027SAnirudh Venkataramanan /** 3677148beb61SHenry Tieman * ice_alloc_res_cntr - allocating resource counter 3678148beb61SHenry Tieman * @hw: pointer to the hardware structure 3679148beb61SHenry Tieman * @type: type of resource 3680148beb61SHenry Tieman * @alloc_shared: if set it is shared else dedicated 3681148beb61SHenry Tieman * @num_items: number of entries requested for FD resource type 3682148beb61SHenry Tieman * @counter_id: counter index returned by AQ call 3683148beb61SHenry Tieman */ 36845e24d598STony Nguyen int 3685148beb61SHenry Tieman ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, 3686148beb61SHenry Tieman u16 *counter_id) 3687148beb61SHenry Tieman { 3688148beb61SHenry Tieman struct ice_aqc_alloc_free_res_elem *buf; 3689148beb61SHenry Tieman u16 buf_len; 36905518ac2aSTony Nguyen int status; 3691148beb61SHenry Tieman 3692148beb61SHenry Tieman /* Allocate resource */ 369366486d89SBruce Allan buf_len = struct_size(buf, elem, 1); 3694148beb61SHenry Tieman buf = kzalloc(buf_len, GFP_KERNEL); 3695148beb61SHenry Tieman if (!buf) 3696d54699e2STony Nguyen return -ENOMEM; 3697148beb61SHenry Tieman 3698148beb61SHenry Tieman buf->num_elems = cpu_to_le16(num_items); 3699148beb61SHenry Tieman buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & 3700148beb61SHenry Tieman ICE_AQC_RES_TYPE_M) | alloc_shared); 3701148beb61SHenry Tieman 3702148beb61SHenry Tieman status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, 3703148beb61SHenry Tieman ice_aqc_opc_alloc_res, NULL); 3704148beb61SHenry Tieman if (status) 3705148beb61SHenry Tieman goto exit; 3706148beb61SHenry Tieman 3707148beb61SHenry Tieman *counter_id = le16_to_cpu(buf->elem[0].e.sw_resp); 3708148beb61SHenry Tieman 3709148beb61SHenry Tieman exit: 3710148beb61SHenry Tieman kfree(buf); 3711148beb61SHenry Tieman return status; 3712148beb61SHenry Tieman } 3713148beb61SHenry Tieman 3714148beb61SHenry Tieman /** 3715148beb61SHenry Tieman * ice_free_res_cntr - free resource counter 3716148beb61SHenry Tieman * @hw: pointer to the hardware structure 3717148beb61SHenry Tieman * @type: type of resource 3718148beb61SHenry Tieman * @alloc_shared: if set it is shared else dedicated 3719148beb61SHenry Tieman * @num_items: number of entries to be freed for FD resource type 3720148beb61SHenry Tieman * @counter_id: counter ID resource which needs to be freed 3721148beb61SHenry Tieman */ 37225e24d598STony Nguyen int 3723148beb61SHenry Tieman ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, 3724148beb61SHenry Tieman u16 counter_id) 3725148beb61SHenry Tieman { 3726148beb61SHenry Tieman struct ice_aqc_alloc_free_res_elem *buf; 3727148beb61SHenry Tieman u16 buf_len; 37285518ac2aSTony Nguyen int status; 3729148beb61SHenry Tieman 3730148beb61SHenry Tieman /* Free resource */ 373166486d89SBruce Allan buf_len = struct_size(buf, elem, 1); 3732148beb61SHenry Tieman buf = kzalloc(buf_len, GFP_KERNEL); 3733148beb61SHenry Tieman if (!buf) 3734d54699e2STony Nguyen return -ENOMEM; 3735148beb61SHenry Tieman 3736148beb61SHenry Tieman buf->num_elems = cpu_to_le16(num_items); 3737148beb61SHenry Tieman buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & 3738148beb61SHenry Tieman ICE_AQC_RES_TYPE_M) | alloc_shared); 3739148beb61SHenry Tieman buf->elem[0].e.sw_resp = cpu_to_le16(counter_id); 3740148beb61SHenry Tieman 3741148beb61SHenry Tieman status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, 3742148beb61SHenry Tieman ice_aqc_opc_free_res, NULL); 3743148beb61SHenry Tieman if (status) 37449228d8b2SJacob Keller ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n"); 3745148beb61SHenry Tieman 3746148beb61SHenry Tieman kfree(buf); 3747148beb61SHenry Tieman return status; 3748148beb61SHenry Tieman } 3749148beb61SHenry Tieman 3750fd2a6b71SDan Nowlin /* This is mapping table entry that maps every word within a given protocol 3751fd2a6b71SDan Nowlin * structure to the real byte offset as per the specification of that 3752fd2a6b71SDan Nowlin * protocol header. 3753fd2a6b71SDan Nowlin * for example dst address is 3 words in ethertype header and corresponding 3754fd2a6b71SDan Nowlin * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8 3755fd2a6b71SDan Nowlin * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a 3756fd2a6b71SDan Nowlin * matching entry describing its field. This needs to be updated if new 3757fd2a6b71SDan Nowlin * structure is added to that union. 3758fd2a6b71SDan Nowlin */ 3759fd2a6b71SDan Nowlin static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { 3760fd2a6b71SDan Nowlin { ICE_MAC_OFOS, { 0, 2, 4, 6, 8, 10, 12 } }, 3761fd2a6b71SDan Nowlin { ICE_MAC_IL, { 0, 2, 4, 6, 8, 10, 12 } }, 3762fd2a6b71SDan Nowlin { ICE_ETYPE_OL, { 0 } }, 3763fd2a6b71SDan Nowlin { ICE_VLAN_OFOS, { 2, 0 } }, 3764fd2a6b71SDan Nowlin { ICE_IPV4_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, 3765fd2a6b71SDan Nowlin { ICE_IPV4_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, 3766fd2a6b71SDan Nowlin { ICE_IPV6_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 3767fd2a6b71SDan Nowlin 26, 28, 30, 32, 34, 36, 38 } }, 3768fd2a6b71SDan Nowlin { ICE_IPV6_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 3769fd2a6b71SDan Nowlin 26, 28, 30, 32, 34, 36, 38 } }, 3770fd2a6b71SDan Nowlin { ICE_TCP_IL, { 0, 2 } }, 3771fd2a6b71SDan Nowlin { ICE_UDP_OF, { 0, 2 } }, 3772fd2a6b71SDan Nowlin { ICE_UDP_ILOS, { 0, 2 } }, 37738b032a55SMichal Swiatkowski { ICE_VXLAN, { 8, 10, 12, 14 } }, 37748b032a55SMichal Swiatkowski { ICE_GENEVE, { 8, 10, 12, 14 } }, 3775f0a35040SMichal Swiatkowski { ICE_NVGRE, { 0, 2, 4, 6 } }, 3776fd2a6b71SDan Nowlin }; 3777fd2a6b71SDan Nowlin 3778fd2a6b71SDan Nowlin static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { 3779fd2a6b71SDan Nowlin { ICE_MAC_OFOS, ICE_MAC_OFOS_HW }, 3780fd2a6b71SDan Nowlin { ICE_MAC_IL, ICE_MAC_IL_HW }, 3781fd2a6b71SDan Nowlin { ICE_ETYPE_OL, ICE_ETYPE_OL_HW }, 3782fd2a6b71SDan Nowlin { ICE_VLAN_OFOS, ICE_VLAN_OL_HW }, 3783fd2a6b71SDan Nowlin { ICE_IPV4_OFOS, ICE_IPV4_OFOS_HW }, 3784fd2a6b71SDan Nowlin { ICE_IPV4_IL, ICE_IPV4_IL_HW }, 3785fd2a6b71SDan Nowlin { ICE_IPV6_OFOS, ICE_IPV6_OFOS_HW }, 3786fd2a6b71SDan Nowlin { ICE_IPV6_IL, ICE_IPV6_IL_HW }, 3787fd2a6b71SDan Nowlin { ICE_TCP_IL, ICE_TCP_IL_HW }, 3788fd2a6b71SDan Nowlin { ICE_UDP_OF, ICE_UDP_OF_HW }, 3789fd2a6b71SDan Nowlin { ICE_UDP_ILOS, ICE_UDP_ILOS_HW }, 37908b032a55SMichal Swiatkowski { ICE_VXLAN, ICE_UDP_OF_HW }, 37918b032a55SMichal Swiatkowski { ICE_GENEVE, ICE_UDP_OF_HW }, 3792f0a35040SMichal Swiatkowski { ICE_NVGRE, ICE_GRE_OF_HW }, 3793fd2a6b71SDan Nowlin }; 3794fd2a6b71SDan Nowlin 3795fd2a6b71SDan Nowlin /** 3796fd2a6b71SDan Nowlin * ice_find_recp - find a recipe 3797fd2a6b71SDan Nowlin * @hw: pointer to the hardware structure 3798fd2a6b71SDan Nowlin * @lkup_exts: extension sequence to match 3799de6acd1cSMichal Swiatkowski * @tun_type: type of recipe tunnel 3800fd2a6b71SDan Nowlin * 3801fd2a6b71SDan Nowlin * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found. 3802fd2a6b71SDan Nowlin */ 3803de6acd1cSMichal Swiatkowski static u16 3804de6acd1cSMichal Swiatkowski ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts, 3805de6acd1cSMichal Swiatkowski enum ice_sw_tunnel_type tun_type) 3806fd2a6b71SDan Nowlin { 3807fd2a6b71SDan Nowlin bool refresh_required = true; 3808fd2a6b71SDan Nowlin struct ice_sw_recipe *recp; 3809fd2a6b71SDan Nowlin u8 i; 3810fd2a6b71SDan Nowlin 3811fd2a6b71SDan Nowlin /* Walk through existing recipes to find a match */ 3812fd2a6b71SDan Nowlin recp = hw->switch_info->recp_list; 3813fd2a6b71SDan Nowlin for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { 3814fd2a6b71SDan Nowlin /* If recipe was not created for this ID, in SW bookkeeping, 3815fd2a6b71SDan Nowlin * check if FW has an entry for this recipe. If the FW has an 3816fd2a6b71SDan Nowlin * entry update it in our SW bookkeeping and continue with the 3817fd2a6b71SDan Nowlin * matching. 3818fd2a6b71SDan Nowlin */ 3819fd2a6b71SDan Nowlin if (!recp[i].recp_created) 3820fd2a6b71SDan Nowlin if (ice_get_recp_frm_fw(hw, 3821fd2a6b71SDan Nowlin hw->switch_info->recp_list, i, 3822fd2a6b71SDan Nowlin &refresh_required)) 3823fd2a6b71SDan Nowlin continue; 3824fd2a6b71SDan Nowlin 3825fd2a6b71SDan Nowlin /* Skip inverse action recipes */ 3826fd2a6b71SDan Nowlin if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl & 3827fd2a6b71SDan Nowlin ICE_AQ_RECIPE_ACT_INV_ACT) 3828fd2a6b71SDan Nowlin continue; 3829fd2a6b71SDan Nowlin 3830fd2a6b71SDan Nowlin /* if number of words we are looking for match */ 3831fd2a6b71SDan Nowlin if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) { 3832fd2a6b71SDan Nowlin struct ice_fv_word *ar = recp[i].lkup_exts.fv_words; 3833fd2a6b71SDan Nowlin struct ice_fv_word *be = lkup_exts->fv_words; 3834fd2a6b71SDan Nowlin u16 *cr = recp[i].lkup_exts.field_mask; 3835fd2a6b71SDan Nowlin u16 *de = lkup_exts->field_mask; 3836fd2a6b71SDan Nowlin bool found = true; 3837fd2a6b71SDan Nowlin u8 pe, qr; 3838fd2a6b71SDan Nowlin 3839fd2a6b71SDan Nowlin /* ar, cr, and qr are related to the recipe words, while 3840fd2a6b71SDan Nowlin * be, de, and pe are related to the lookup words 3841fd2a6b71SDan Nowlin */ 3842fd2a6b71SDan Nowlin for (pe = 0; pe < lkup_exts->n_val_words; pe++) { 3843fd2a6b71SDan Nowlin for (qr = 0; qr < recp[i].lkup_exts.n_val_words; 3844fd2a6b71SDan Nowlin qr++) { 3845fd2a6b71SDan Nowlin if (ar[qr].off == be[pe].off && 3846fd2a6b71SDan Nowlin ar[qr].prot_id == be[pe].prot_id && 3847fd2a6b71SDan Nowlin cr[qr] == de[pe]) 3848fd2a6b71SDan Nowlin /* Found the "pe"th word in the 3849fd2a6b71SDan Nowlin * given recipe 3850fd2a6b71SDan Nowlin */ 3851fd2a6b71SDan Nowlin break; 3852fd2a6b71SDan Nowlin } 3853fd2a6b71SDan Nowlin /* After walking through all the words in the 3854fd2a6b71SDan Nowlin * "i"th recipe if "p"th word was not found then 3855fd2a6b71SDan Nowlin * this recipe is not what we are looking for. 3856fd2a6b71SDan Nowlin * So break out from this loop and try the next 3857fd2a6b71SDan Nowlin * recipe 3858fd2a6b71SDan Nowlin */ 3859fd2a6b71SDan Nowlin if (qr >= recp[i].lkup_exts.n_val_words) { 3860fd2a6b71SDan Nowlin found = false; 3861fd2a6b71SDan Nowlin break; 3862fd2a6b71SDan Nowlin } 3863fd2a6b71SDan Nowlin } 3864fd2a6b71SDan Nowlin /* If for "i"th recipe the found was never set to false 3865fd2a6b71SDan Nowlin * then it means we found our match 3866de6acd1cSMichal Swiatkowski * Also tun type of recipe needs to be checked 3867fd2a6b71SDan Nowlin */ 3868de6acd1cSMichal Swiatkowski if (found && recp[i].tun_type == tun_type) 3869fd2a6b71SDan Nowlin return i; /* Return the recipe ID */ 3870fd2a6b71SDan Nowlin } 3871fd2a6b71SDan Nowlin } 3872fd2a6b71SDan Nowlin return ICE_MAX_NUM_RECIPES; 3873fd2a6b71SDan Nowlin } 3874fd2a6b71SDan Nowlin 3875fd2a6b71SDan Nowlin /** 3876fd2a6b71SDan Nowlin * ice_prot_type_to_id - get protocol ID from protocol type 3877fd2a6b71SDan Nowlin * @type: protocol type 3878fd2a6b71SDan Nowlin * @id: pointer to variable that will receive the ID 3879fd2a6b71SDan Nowlin * 3880fd2a6b71SDan Nowlin * Returns true if found, false otherwise 3881fd2a6b71SDan Nowlin */ 3882fd2a6b71SDan Nowlin static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id) 3883fd2a6b71SDan Nowlin { 3884fd2a6b71SDan Nowlin u8 i; 3885fd2a6b71SDan Nowlin 3886fd2a6b71SDan Nowlin for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) 3887fd2a6b71SDan Nowlin if (ice_prot_id_tbl[i].type == type) { 3888fd2a6b71SDan Nowlin *id = ice_prot_id_tbl[i].protocol_id; 3889fd2a6b71SDan Nowlin return true; 3890fd2a6b71SDan Nowlin } 3891fd2a6b71SDan Nowlin return false; 3892fd2a6b71SDan Nowlin } 3893fd2a6b71SDan Nowlin 3894fd2a6b71SDan Nowlin /** 3895fd2a6b71SDan Nowlin * ice_fill_valid_words - count valid words 3896fd2a6b71SDan Nowlin * @rule: advanced rule with lookup information 3897fd2a6b71SDan Nowlin * @lkup_exts: byte offset extractions of the words that are valid 3898fd2a6b71SDan Nowlin * 3899fd2a6b71SDan Nowlin * calculate valid words in a lookup rule using mask value 3900fd2a6b71SDan Nowlin */ 3901fd2a6b71SDan Nowlin static u8 3902fd2a6b71SDan Nowlin ice_fill_valid_words(struct ice_adv_lkup_elem *rule, 3903fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts) 3904fd2a6b71SDan Nowlin { 3905fd2a6b71SDan Nowlin u8 j, word, prot_id, ret_val; 3906fd2a6b71SDan Nowlin 3907fd2a6b71SDan Nowlin if (!ice_prot_type_to_id(rule->type, &prot_id)) 3908fd2a6b71SDan Nowlin return 0; 3909fd2a6b71SDan Nowlin 3910fd2a6b71SDan Nowlin word = lkup_exts->n_val_words; 3911fd2a6b71SDan Nowlin 3912fd2a6b71SDan Nowlin for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++) 3913fd2a6b71SDan Nowlin if (((u16 *)&rule->m_u)[j] && 3914fd2a6b71SDan Nowlin rule->type < ARRAY_SIZE(ice_prot_ext)) { 3915fd2a6b71SDan Nowlin /* No more space to accommodate */ 3916fd2a6b71SDan Nowlin if (word >= ICE_MAX_CHAIN_WORDS) 3917fd2a6b71SDan Nowlin return 0; 3918fd2a6b71SDan Nowlin lkup_exts->fv_words[word].off = 3919fd2a6b71SDan Nowlin ice_prot_ext[rule->type].offs[j]; 3920fd2a6b71SDan Nowlin lkup_exts->fv_words[word].prot_id = 3921fd2a6b71SDan Nowlin ice_prot_id_tbl[rule->type].protocol_id; 3922fd2a6b71SDan Nowlin lkup_exts->field_mask[word] = 3923fd2a6b71SDan Nowlin be16_to_cpu(((__force __be16 *)&rule->m_u)[j]); 3924fd2a6b71SDan Nowlin word++; 3925fd2a6b71SDan Nowlin } 3926fd2a6b71SDan Nowlin 3927fd2a6b71SDan Nowlin ret_val = word - lkup_exts->n_val_words; 3928fd2a6b71SDan Nowlin lkup_exts->n_val_words = word; 3929fd2a6b71SDan Nowlin 3930fd2a6b71SDan Nowlin return ret_val; 3931fd2a6b71SDan Nowlin } 3932fd2a6b71SDan Nowlin 3933fd2a6b71SDan Nowlin /** 3934fd2a6b71SDan Nowlin * ice_create_first_fit_recp_def - Create a recipe grouping 3935fd2a6b71SDan Nowlin * @hw: pointer to the hardware structure 3936fd2a6b71SDan Nowlin * @lkup_exts: an array of protocol header extractions 3937fd2a6b71SDan Nowlin * @rg_list: pointer to a list that stores new recipe groups 3938fd2a6b71SDan Nowlin * @recp_cnt: pointer to a variable that stores returned number of recipe groups 3939fd2a6b71SDan Nowlin * 3940fd2a6b71SDan Nowlin * Using first fit algorithm, take all the words that are still not done 3941fd2a6b71SDan Nowlin * and start grouping them in 4-word groups. Each group makes up one 3942fd2a6b71SDan Nowlin * recipe. 3943fd2a6b71SDan Nowlin */ 39445e24d598STony Nguyen static int 3945fd2a6b71SDan Nowlin ice_create_first_fit_recp_def(struct ice_hw *hw, 3946fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts, 3947fd2a6b71SDan Nowlin struct list_head *rg_list, 3948fd2a6b71SDan Nowlin u8 *recp_cnt) 3949fd2a6b71SDan Nowlin { 3950fd2a6b71SDan Nowlin struct ice_pref_recipe_group *grp = NULL; 3951fd2a6b71SDan Nowlin u8 j; 3952fd2a6b71SDan Nowlin 3953fd2a6b71SDan Nowlin *recp_cnt = 0; 3954fd2a6b71SDan Nowlin 3955fd2a6b71SDan Nowlin /* Walk through every word in the rule to check if it is not done. If so 3956fd2a6b71SDan Nowlin * then this word needs to be part of a new recipe. 3957fd2a6b71SDan Nowlin */ 3958fd2a6b71SDan Nowlin for (j = 0; j < lkup_exts->n_val_words; j++) 3959fd2a6b71SDan Nowlin if (!test_bit(j, lkup_exts->done)) { 3960fd2a6b71SDan Nowlin if (!grp || 3961fd2a6b71SDan Nowlin grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) { 3962fd2a6b71SDan Nowlin struct ice_recp_grp_entry *entry; 3963fd2a6b71SDan Nowlin 3964fd2a6b71SDan Nowlin entry = devm_kzalloc(ice_hw_to_dev(hw), 3965fd2a6b71SDan Nowlin sizeof(*entry), 3966fd2a6b71SDan Nowlin GFP_KERNEL); 3967fd2a6b71SDan Nowlin if (!entry) 3968d54699e2STony Nguyen return -ENOMEM; 3969fd2a6b71SDan Nowlin list_add(&entry->l_entry, rg_list); 3970fd2a6b71SDan Nowlin grp = &entry->r_group; 3971fd2a6b71SDan Nowlin (*recp_cnt)++; 3972fd2a6b71SDan Nowlin } 3973fd2a6b71SDan Nowlin 3974fd2a6b71SDan Nowlin grp->pairs[grp->n_val_pairs].prot_id = 3975fd2a6b71SDan Nowlin lkup_exts->fv_words[j].prot_id; 3976fd2a6b71SDan Nowlin grp->pairs[grp->n_val_pairs].off = 3977fd2a6b71SDan Nowlin lkup_exts->fv_words[j].off; 3978fd2a6b71SDan Nowlin grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j]; 3979fd2a6b71SDan Nowlin grp->n_val_pairs++; 3980fd2a6b71SDan Nowlin } 3981fd2a6b71SDan Nowlin 3982fd2a6b71SDan Nowlin return 0; 3983fd2a6b71SDan Nowlin } 3984fd2a6b71SDan Nowlin 3985fd2a6b71SDan Nowlin /** 3986fd2a6b71SDan Nowlin * ice_fill_fv_word_index - fill in the field vector indices for a recipe group 3987fd2a6b71SDan Nowlin * @hw: pointer to the hardware structure 3988fd2a6b71SDan Nowlin * @fv_list: field vector with the extraction sequence information 3989fd2a6b71SDan Nowlin * @rg_list: recipe groupings with protocol-offset pairs 3990fd2a6b71SDan Nowlin * 3991fd2a6b71SDan Nowlin * Helper function to fill in the field vector indices for protocol-offset 3992fd2a6b71SDan Nowlin * pairs. These indexes are then ultimately programmed into a recipe. 3993fd2a6b71SDan Nowlin */ 39945e24d598STony Nguyen static int 3995fd2a6b71SDan Nowlin ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list, 3996fd2a6b71SDan Nowlin struct list_head *rg_list) 3997fd2a6b71SDan Nowlin { 3998fd2a6b71SDan Nowlin struct ice_sw_fv_list_entry *fv; 3999fd2a6b71SDan Nowlin struct ice_recp_grp_entry *rg; 4000fd2a6b71SDan Nowlin struct ice_fv_word *fv_ext; 4001fd2a6b71SDan Nowlin 4002fd2a6b71SDan Nowlin if (list_empty(fv_list)) 4003fd2a6b71SDan Nowlin return 0; 4004fd2a6b71SDan Nowlin 4005fd2a6b71SDan Nowlin fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry, 4006fd2a6b71SDan Nowlin list_entry); 4007fd2a6b71SDan Nowlin fv_ext = fv->fv_ptr->ew; 4008fd2a6b71SDan Nowlin 4009fd2a6b71SDan Nowlin list_for_each_entry(rg, rg_list, l_entry) { 4010fd2a6b71SDan Nowlin u8 i; 4011fd2a6b71SDan Nowlin 4012fd2a6b71SDan Nowlin for (i = 0; i < rg->r_group.n_val_pairs; i++) { 4013fd2a6b71SDan Nowlin struct ice_fv_word *pr; 4014fd2a6b71SDan Nowlin bool found = false; 4015fd2a6b71SDan Nowlin u16 mask; 4016fd2a6b71SDan Nowlin u8 j; 4017fd2a6b71SDan Nowlin 4018fd2a6b71SDan Nowlin pr = &rg->r_group.pairs[i]; 4019fd2a6b71SDan Nowlin mask = rg->r_group.mask[i]; 4020fd2a6b71SDan Nowlin 4021fd2a6b71SDan Nowlin for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 4022fd2a6b71SDan Nowlin if (fv_ext[j].prot_id == pr->prot_id && 4023fd2a6b71SDan Nowlin fv_ext[j].off == pr->off) { 4024fd2a6b71SDan Nowlin found = true; 4025fd2a6b71SDan Nowlin 4026fd2a6b71SDan Nowlin /* Store index of field vector */ 4027fd2a6b71SDan Nowlin rg->fv_idx[i] = j; 4028fd2a6b71SDan Nowlin rg->fv_mask[i] = mask; 4029fd2a6b71SDan Nowlin break; 4030fd2a6b71SDan Nowlin } 4031fd2a6b71SDan Nowlin 4032fd2a6b71SDan Nowlin /* Protocol/offset could not be found, caller gave an 4033fd2a6b71SDan Nowlin * invalid pair 4034fd2a6b71SDan Nowlin */ 4035fd2a6b71SDan Nowlin if (!found) 4036d54699e2STony Nguyen return -EINVAL; 4037fd2a6b71SDan Nowlin } 4038fd2a6b71SDan Nowlin } 4039fd2a6b71SDan Nowlin 4040fd2a6b71SDan Nowlin return 0; 4041fd2a6b71SDan Nowlin } 4042fd2a6b71SDan Nowlin 4043fd2a6b71SDan Nowlin /** 4044fd2a6b71SDan Nowlin * ice_find_free_recp_res_idx - find free result indexes for recipe 4045fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4046fd2a6b71SDan Nowlin * @profiles: bitmap of profiles that will be associated with the new recipe 4047fd2a6b71SDan Nowlin * @free_idx: pointer to variable to receive the free index bitmap 4048fd2a6b71SDan Nowlin * 4049fd2a6b71SDan Nowlin * The algorithm used here is: 4050fd2a6b71SDan Nowlin * 1. When creating a new recipe, create a set P which contains all 4051fd2a6b71SDan Nowlin * Profiles that will be associated with our new recipe 4052fd2a6b71SDan Nowlin * 4053fd2a6b71SDan Nowlin * 2. For each Profile p in set P: 4054fd2a6b71SDan Nowlin * a. Add all recipes associated with Profile p into set R 4055fd2a6b71SDan Nowlin * b. Optional : PossibleIndexes &= profile[p].possibleIndexes 4056fd2a6b71SDan Nowlin * [initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF] 4057fd2a6b71SDan Nowlin * i. Or just assume they all have the same possible indexes: 4058fd2a6b71SDan Nowlin * 44, 45, 46, 47 4059fd2a6b71SDan Nowlin * i.e., PossibleIndexes = 0x0000F00000000000 4060fd2a6b71SDan Nowlin * 4061fd2a6b71SDan Nowlin * 3. For each Recipe r in set R: 4062fd2a6b71SDan Nowlin * a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes 4063fd2a6b71SDan Nowlin * b. FreeIndexes = UsedIndexes ^ PossibleIndexes 4064fd2a6b71SDan Nowlin * 4065fd2a6b71SDan Nowlin * FreeIndexes will contain the bits indicating the indexes free for use, 4066fd2a6b71SDan Nowlin * then the code needs to update the recipe[r].used_result_idx_bits to 4067fd2a6b71SDan Nowlin * indicate which indexes were selected for use by this recipe. 4068fd2a6b71SDan Nowlin */ 4069fd2a6b71SDan Nowlin static u16 4070fd2a6b71SDan Nowlin ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles, 4071fd2a6b71SDan Nowlin unsigned long *free_idx) 4072fd2a6b71SDan Nowlin { 4073fd2a6b71SDan Nowlin DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS); 4074fd2a6b71SDan Nowlin DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES); 4075fd2a6b71SDan Nowlin DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS); 4076fd2a6b71SDan Nowlin u16 bit; 4077fd2a6b71SDan Nowlin 4078fd2a6b71SDan Nowlin bitmap_zero(recipes, ICE_MAX_NUM_RECIPES); 4079fd2a6b71SDan Nowlin bitmap_zero(used_idx, ICE_MAX_FV_WORDS); 4080fd2a6b71SDan Nowlin 4081fd2a6b71SDan Nowlin bitmap_set(possible_idx, 0, ICE_MAX_FV_WORDS); 4082fd2a6b71SDan Nowlin 4083fd2a6b71SDan Nowlin /* For each profile we are going to associate the recipe with, add the 4084fd2a6b71SDan Nowlin * recipes that are associated with that profile. This will give us 4085fd2a6b71SDan Nowlin * the set of recipes that our recipe may collide with. Also, determine 4086fd2a6b71SDan Nowlin * what possible result indexes are usable given this set of profiles. 4087fd2a6b71SDan Nowlin */ 4088fd2a6b71SDan Nowlin for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) { 4089fd2a6b71SDan Nowlin bitmap_or(recipes, recipes, profile_to_recipe[bit], 4090fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 4091fd2a6b71SDan Nowlin bitmap_and(possible_idx, possible_idx, 4092fd2a6b71SDan Nowlin hw->switch_info->prof_res_bm[bit], 4093fd2a6b71SDan Nowlin ICE_MAX_FV_WORDS); 4094fd2a6b71SDan Nowlin } 4095fd2a6b71SDan Nowlin 4096fd2a6b71SDan Nowlin /* For each recipe that our new recipe may collide with, determine 4097fd2a6b71SDan Nowlin * which indexes have been used. 4098fd2a6b71SDan Nowlin */ 4099fd2a6b71SDan Nowlin for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES) 4100fd2a6b71SDan Nowlin bitmap_or(used_idx, used_idx, 4101fd2a6b71SDan Nowlin hw->switch_info->recp_list[bit].res_idxs, 4102fd2a6b71SDan Nowlin ICE_MAX_FV_WORDS); 4103fd2a6b71SDan Nowlin 4104fd2a6b71SDan Nowlin bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS); 4105fd2a6b71SDan Nowlin 4106fd2a6b71SDan Nowlin /* return number of free indexes */ 4107fd2a6b71SDan Nowlin return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS); 4108fd2a6b71SDan Nowlin } 4109fd2a6b71SDan Nowlin 4110fd2a6b71SDan Nowlin /** 4111fd2a6b71SDan Nowlin * ice_add_sw_recipe - function to call AQ calls to create switch recipe 4112fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4113fd2a6b71SDan Nowlin * @rm: recipe management list entry 4114fd2a6b71SDan Nowlin * @profiles: bitmap of profiles that will be associated. 4115fd2a6b71SDan Nowlin */ 41165e24d598STony Nguyen static int 4117fd2a6b71SDan Nowlin ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm, 41188b032a55SMichal Swiatkowski unsigned long *profiles) 4119fd2a6b71SDan Nowlin { 4120fd2a6b71SDan Nowlin DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS); 4121fd2a6b71SDan Nowlin struct ice_aqc_recipe_data_elem *tmp; 4122fd2a6b71SDan Nowlin struct ice_aqc_recipe_data_elem *buf; 4123fd2a6b71SDan Nowlin struct ice_recp_grp_entry *entry; 4124fd2a6b71SDan Nowlin u16 free_res_idx; 4125fd2a6b71SDan Nowlin u16 recipe_count; 4126fd2a6b71SDan Nowlin u8 chain_idx; 4127fd2a6b71SDan Nowlin u8 recps = 0; 41285518ac2aSTony Nguyen int status; 4129fd2a6b71SDan Nowlin 4130fd2a6b71SDan Nowlin /* When more than one recipe are required, another recipe is needed to 4131fd2a6b71SDan Nowlin * chain them together. Matching a tunnel metadata ID takes up one of 4132fd2a6b71SDan Nowlin * the match fields in the chaining recipe reducing the number of 4133fd2a6b71SDan Nowlin * chained recipes by one. 4134fd2a6b71SDan Nowlin */ 4135fd2a6b71SDan Nowlin /* check number of free result indices */ 4136fd2a6b71SDan Nowlin bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS); 4137fd2a6b71SDan Nowlin free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm); 4138fd2a6b71SDan Nowlin 4139fd2a6b71SDan Nowlin ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n", 4140fd2a6b71SDan Nowlin free_res_idx, rm->n_grp_count); 4141fd2a6b71SDan Nowlin 4142fd2a6b71SDan Nowlin if (rm->n_grp_count > 1) { 4143fd2a6b71SDan Nowlin if (rm->n_grp_count > free_res_idx) 4144d54699e2STony Nguyen return -ENOSPC; 4145fd2a6b71SDan Nowlin 4146fd2a6b71SDan Nowlin rm->n_grp_count++; 4147fd2a6b71SDan Nowlin } 4148fd2a6b71SDan Nowlin 4149fd2a6b71SDan Nowlin if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE) 4150d54699e2STony Nguyen return -ENOSPC; 4151fd2a6b71SDan Nowlin 4152fd2a6b71SDan Nowlin tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL); 4153fd2a6b71SDan Nowlin if (!tmp) 4154d54699e2STony Nguyen return -ENOMEM; 4155fd2a6b71SDan Nowlin 4156fd2a6b71SDan Nowlin buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf), 4157fd2a6b71SDan Nowlin GFP_KERNEL); 4158fd2a6b71SDan Nowlin if (!buf) { 4159d54699e2STony Nguyen status = -ENOMEM; 4160fd2a6b71SDan Nowlin goto err_mem; 4161fd2a6b71SDan Nowlin } 4162fd2a6b71SDan Nowlin 4163fd2a6b71SDan Nowlin bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES); 4164fd2a6b71SDan Nowlin recipe_count = ICE_MAX_NUM_RECIPES; 4165fd2a6b71SDan Nowlin status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC, 4166fd2a6b71SDan Nowlin NULL); 4167fd2a6b71SDan Nowlin if (status || recipe_count == 0) 4168fd2a6b71SDan Nowlin goto err_unroll; 4169fd2a6b71SDan Nowlin 4170fd2a6b71SDan Nowlin /* Allocate the recipe resources, and configure them according to the 4171fd2a6b71SDan Nowlin * match fields from protocol headers and extracted field vectors. 4172fd2a6b71SDan Nowlin */ 4173fd2a6b71SDan Nowlin chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS); 4174fd2a6b71SDan Nowlin list_for_each_entry(entry, &rm->rg_list, l_entry) { 4175fd2a6b71SDan Nowlin u8 i; 4176fd2a6b71SDan Nowlin 4177fd2a6b71SDan Nowlin status = ice_alloc_recipe(hw, &entry->rid); 4178fd2a6b71SDan Nowlin if (status) 4179fd2a6b71SDan Nowlin goto err_unroll; 4180fd2a6b71SDan Nowlin 4181fd2a6b71SDan Nowlin /* Clear the result index of the located recipe, as this will be 4182fd2a6b71SDan Nowlin * updated, if needed, later in the recipe creation process. 4183fd2a6b71SDan Nowlin */ 4184fd2a6b71SDan Nowlin tmp[0].content.result_indx = 0; 4185fd2a6b71SDan Nowlin 4186fd2a6b71SDan Nowlin buf[recps] = tmp[0]; 4187fd2a6b71SDan Nowlin buf[recps].recipe_indx = (u8)entry->rid; 4188fd2a6b71SDan Nowlin /* if the recipe is a non-root recipe RID should be programmed 4189fd2a6b71SDan Nowlin * as 0 for the rules to be applied correctly. 4190fd2a6b71SDan Nowlin */ 4191fd2a6b71SDan Nowlin buf[recps].content.rid = 0; 4192fd2a6b71SDan Nowlin memset(&buf[recps].content.lkup_indx, 0, 4193fd2a6b71SDan Nowlin sizeof(buf[recps].content.lkup_indx)); 4194fd2a6b71SDan Nowlin 4195fd2a6b71SDan Nowlin /* All recipes use look-up index 0 to match switch ID. */ 4196fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; 4197fd2a6b71SDan Nowlin buf[recps].content.mask[0] = 4198fd2a6b71SDan Nowlin cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); 4199fd2a6b71SDan Nowlin /* Setup lkup_indx 1..4 to INVALID/ignore and set the mask 4200fd2a6b71SDan Nowlin * to be 0 4201fd2a6b71SDan Nowlin */ 4202fd2a6b71SDan Nowlin for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { 4203fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = 0x80; 4204fd2a6b71SDan Nowlin buf[recps].content.mask[i] = 0; 4205fd2a6b71SDan Nowlin } 4206fd2a6b71SDan Nowlin 4207fd2a6b71SDan Nowlin for (i = 0; i < entry->r_group.n_val_pairs; i++) { 4208fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i]; 4209fd2a6b71SDan Nowlin buf[recps].content.mask[i + 1] = 4210fd2a6b71SDan Nowlin cpu_to_le16(entry->fv_mask[i]); 4211fd2a6b71SDan Nowlin } 4212fd2a6b71SDan Nowlin 4213fd2a6b71SDan Nowlin if (rm->n_grp_count > 1) { 4214fd2a6b71SDan Nowlin /* Checks to see if there really is a valid result index 4215fd2a6b71SDan Nowlin * that can be used. 4216fd2a6b71SDan Nowlin */ 4217fd2a6b71SDan Nowlin if (chain_idx >= ICE_MAX_FV_WORDS) { 4218fd2a6b71SDan Nowlin ice_debug(hw, ICE_DBG_SW, "No chain index available\n"); 4219d54699e2STony Nguyen status = -ENOSPC; 4220fd2a6b71SDan Nowlin goto err_unroll; 4221fd2a6b71SDan Nowlin } 4222fd2a6b71SDan Nowlin 4223fd2a6b71SDan Nowlin entry->chain_idx = chain_idx; 4224fd2a6b71SDan Nowlin buf[recps].content.result_indx = 4225fd2a6b71SDan Nowlin ICE_AQ_RECIPE_RESULT_EN | 4226fd2a6b71SDan Nowlin ((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) & 4227fd2a6b71SDan Nowlin ICE_AQ_RECIPE_RESULT_DATA_M); 4228fd2a6b71SDan Nowlin clear_bit(chain_idx, result_idx_bm); 4229fd2a6b71SDan Nowlin chain_idx = find_first_bit(result_idx_bm, 4230fd2a6b71SDan Nowlin ICE_MAX_FV_WORDS); 4231fd2a6b71SDan Nowlin } 4232fd2a6b71SDan Nowlin 4233fd2a6b71SDan Nowlin /* fill recipe dependencies */ 4234fd2a6b71SDan Nowlin bitmap_zero((unsigned long *)buf[recps].recipe_bitmap, 4235fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 4236fd2a6b71SDan Nowlin set_bit(buf[recps].recipe_indx, 4237fd2a6b71SDan Nowlin (unsigned long *)buf[recps].recipe_bitmap); 4238fd2a6b71SDan Nowlin buf[recps].content.act_ctrl_fwd_priority = rm->priority; 4239fd2a6b71SDan Nowlin recps++; 4240fd2a6b71SDan Nowlin } 4241fd2a6b71SDan Nowlin 4242fd2a6b71SDan Nowlin if (rm->n_grp_count == 1) { 4243fd2a6b71SDan Nowlin rm->root_rid = buf[0].recipe_indx; 4244fd2a6b71SDan Nowlin set_bit(buf[0].recipe_indx, rm->r_bitmap); 4245fd2a6b71SDan Nowlin buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT; 4246fd2a6b71SDan Nowlin if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) { 4247fd2a6b71SDan Nowlin memcpy(buf[0].recipe_bitmap, rm->r_bitmap, 4248fd2a6b71SDan Nowlin sizeof(buf[0].recipe_bitmap)); 4249fd2a6b71SDan Nowlin } else { 4250d54699e2STony Nguyen status = -EINVAL; 4251fd2a6b71SDan Nowlin goto err_unroll; 4252fd2a6b71SDan Nowlin } 4253fd2a6b71SDan Nowlin /* Applicable only for ROOT_RECIPE, set the fwd_priority for 4254fd2a6b71SDan Nowlin * the recipe which is getting created if specified 4255fd2a6b71SDan Nowlin * by user. Usually any advanced switch filter, which results 4256fd2a6b71SDan Nowlin * into new extraction sequence, ended up creating a new recipe 4257fd2a6b71SDan Nowlin * of type ROOT and usually recipes are associated with profiles 4258fd2a6b71SDan Nowlin * Switch rule referreing newly created recipe, needs to have 4259fd2a6b71SDan Nowlin * either/or 'fwd' or 'join' priority, otherwise switch rule 4260fd2a6b71SDan Nowlin * evaluation will not happen correctly. In other words, if 4261fd2a6b71SDan Nowlin * switch rule to be evaluated on priority basis, then recipe 4262fd2a6b71SDan Nowlin * needs to have priority, otherwise it will be evaluated last. 4263fd2a6b71SDan Nowlin */ 4264fd2a6b71SDan Nowlin buf[0].content.act_ctrl_fwd_priority = rm->priority; 4265fd2a6b71SDan Nowlin } else { 4266fd2a6b71SDan Nowlin struct ice_recp_grp_entry *last_chain_entry; 4267fd2a6b71SDan Nowlin u16 rid, i; 4268fd2a6b71SDan Nowlin 4269fd2a6b71SDan Nowlin /* Allocate the last recipe that will chain the outcomes of the 4270fd2a6b71SDan Nowlin * other recipes together 4271fd2a6b71SDan Nowlin */ 4272fd2a6b71SDan Nowlin status = ice_alloc_recipe(hw, &rid); 4273fd2a6b71SDan Nowlin if (status) 4274fd2a6b71SDan Nowlin goto err_unroll; 4275fd2a6b71SDan Nowlin 4276fd2a6b71SDan Nowlin buf[recps].recipe_indx = (u8)rid; 4277fd2a6b71SDan Nowlin buf[recps].content.rid = (u8)rid; 4278fd2a6b71SDan Nowlin buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT; 4279fd2a6b71SDan Nowlin /* the new entry created should also be part of rg_list to 4280fd2a6b71SDan Nowlin * make sure we have complete recipe 4281fd2a6b71SDan Nowlin */ 4282fd2a6b71SDan Nowlin last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw), 4283fd2a6b71SDan Nowlin sizeof(*last_chain_entry), 4284fd2a6b71SDan Nowlin GFP_KERNEL); 4285fd2a6b71SDan Nowlin if (!last_chain_entry) { 4286d54699e2STony Nguyen status = -ENOMEM; 4287fd2a6b71SDan Nowlin goto err_unroll; 4288fd2a6b71SDan Nowlin } 4289fd2a6b71SDan Nowlin last_chain_entry->rid = rid; 4290fd2a6b71SDan Nowlin memset(&buf[recps].content.lkup_indx, 0, 4291fd2a6b71SDan Nowlin sizeof(buf[recps].content.lkup_indx)); 4292fd2a6b71SDan Nowlin /* All recipes use look-up index 0 to match switch ID. */ 4293fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; 4294fd2a6b71SDan Nowlin buf[recps].content.mask[0] = 4295fd2a6b71SDan Nowlin cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); 4296fd2a6b71SDan Nowlin for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { 4297fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = 4298fd2a6b71SDan Nowlin ICE_AQ_RECIPE_LKUP_IGNORE; 4299fd2a6b71SDan Nowlin buf[recps].content.mask[i] = 0; 4300fd2a6b71SDan Nowlin } 4301fd2a6b71SDan Nowlin 4302fd2a6b71SDan Nowlin i = 1; 4303fd2a6b71SDan Nowlin /* update r_bitmap with the recp that is used for chaining */ 4304fd2a6b71SDan Nowlin set_bit(rid, rm->r_bitmap); 4305fd2a6b71SDan Nowlin /* this is the recipe that chains all the other recipes so it 4306fd2a6b71SDan Nowlin * should not have a chaining ID to indicate the same 4307fd2a6b71SDan Nowlin */ 4308fd2a6b71SDan Nowlin last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND; 4309fd2a6b71SDan Nowlin list_for_each_entry(entry, &rm->rg_list, l_entry) { 4310fd2a6b71SDan Nowlin last_chain_entry->fv_idx[i] = entry->chain_idx; 4311fd2a6b71SDan Nowlin buf[recps].content.lkup_indx[i] = entry->chain_idx; 4312fd2a6b71SDan Nowlin buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF); 4313fd2a6b71SDan Nowlin set_bit(entry->rid, rm->r_bitmap); 4314fd2a6b71SDan Nowlin } 4315fd2a6b71SDan Nowlin list_add(&last_chain_entry->l_entry, &rm->rg_list); 4316fd2a6b71SDan Nowlin if (sizeof(buf[recps].recipe_bitmap) >= 4317fd2a6b71SDan Nowlin sizeof(rm->r_bitmap)) { 4318fd2a6b71SDan Nowlin memcpy(buf[recps].recipe_bitmap, rm->r_bitmap, 4319fd2a6b71SDan Nowlin sizeof(buf[recps].recipe_bitmap)); 4320fd2a6b71SDan Nowlin } else { 4321d54699e2STony Nguyen status = -EINVAL; 4322fd2a6b71SDan Nowlin goto err_unroll; 4323fd2a6b71SDan Nowlin } 4324fd2a6b71SDan Nowlin buf[recps].content.act_ctrl_fwd_priority = rm->priority; 4325fd2a6b71SDan Nowlin 4326fd2a6b71SDan Nowlin recps++; 4327fd2a6b71SDan Nowlin rm->root_rid = (u8)rid; 4328fd2a6b71SDan Nowlin } 4329fd2a6b71SDan Nowlin status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 4330fd2a6b71SDan Nowlin if (status) 4331fd2a6b71SDan Nowlin goto err_unroll; 4332fd2a6b71SDan Nowlin 4333fd2a6b71SDan Nowlin status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL); 4334fd2a6b71SDan Nowlin ice_release_change_lock(hw); 4335fd2a6b71SDan Nowlin if (status) 4336fd2a6b71SDan Nowlin goto err_unroll; 4337fd2a6b71SDan Nowlin 4338fd2a6b71SDan Nowlin /* Every recipe that just got created add it to the recipe 4339fd2a6b71SDan Nowlin * book keeping list 4340fd2a6b71SDan Nowlin */ 4341fd2a6b71SDan Nowlin list_for_each_entry(entry, &rm->rg_list, l_entry) { 4342fd2a6b71SDan Nowlin struct ice_switch_info *sw = hw->switch_info; 4343fd2a6b71SDan Nowlin bool is_root, idx_found = false; 4344fd2a6b71SDan Nowlin struct ice_sw_recipe *recp; 4345fd2a6b71SDan Nowlin u16 idx, buf_idx = 0; 4346fd2a6b71SDan Nowlin 4347fd2a6b71SDan Nowlin /* find buffer index for copying some data */ 4348fd2a6b71SDan Nowlin for (idx = 0; idx < rm->n_grp_count; idx++) 4349fd2a6b71SDan Nowlin if (buf[idx].recipe_indx == entry->rid) { 4350fd2a6b71SDan Nowlin buf_idx = idx; 4351fd2a6b71SDan Nowlin idx_found = true; 4352fd2a6b71SDan Nowlin } 4353fd2a6b71SDan Nowlin 4354fd2a6b71SDan Nowlin if (!idx_found) { 4355d54699e2STony Nguyen status = -EIO; 4356fd2a6b71SDan Nowlin goto err_unroll; 4357fd2a6b71SDan Nowlin } 4358fd2a6b71SDan Nowlin 4359fd2a6b71SDan Nowlin recp = &sw->recp_list[entry->rid]; 4360fd2a6b71SDan Nowlin is_root = (rm->root_rid == entry->rid); 4361fd2a6b71SDan Nowlin recp->is_root = is_root; 4362fd2a6b71SDan Nowlin 4363fd2a6b71SDan Nowlin recp->root_rid = entry->rid; 4364fd2a6b71SDan Nowlin recp->big_recp = (is_root && rm->n_grp_count > 1); 4365fd2a6b71SDan Nowlin 4366fd2a6b71SDan Nowlin memcpy(&recp->ext_words, entry->r_group.pairs, 4367fd2a6b71SDan Nowlin entry->r_group.n_val_pairs * sizeof(struct ice_fv_word)); 4368fd2a6b71SDan Nowlin 4369fd2a6b71SDan Nowlin memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap, 4370fd2a6b71SDan Nowlin sizeof(recp->r_bitmap)); 4371fd2a6b71SDan Nowlin 4372fd2a6b71SDan Nowlin /* Copy non-result fv index values and masks to recipe. This 4373fd2a6b71SDan Nowlin * call will also update the result recipe bitmask. 4374fd2a6b71SDan Nowlin */ 4375fd2a6b71SDan Nowlin ice_collect_result_idx(&buf[buf_idx], recp); 4376fd2a6b71SDan Nowlin 4377fd2a6b71SDan Nowlin /* for non-root recipes, also copy to the root, this allows 4378fd2a6b71SDan Nowlin * easier matching of a complete chained recipe 4379fd2a6b71SDan Nowlin */ 4380fd2a6b71SDan Nowlin if (!is_root) 4381fd2a6b71SDan Nowlin ice_collect_result_idx(&buf[buf_idx], 4382fd2a6b71SDan Nowlin &sw->recp_list[rm->root_rid]); 4383fd2a6b71SDan Nowlin 4384fd2a6b71SDan Nowlin recp->n_ext_words = entry->r_group.n_val_pairs; 4385fd2a6b71SDan Nowlin recp->chain_idx = entry->chain_idx; 4386fd2a6b71SDan Nowlin recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority; 4387fd2a6b71SDan Nowlin recp->n_grp_count = rm->n_grp_count; 43888b032a55SMichal Swiatkowski recp->tun_type = rm->tun_type; 4389fd2a6b71SDan Nowlin recp->recp_created = true; 4390fd2a6b71SDan Nowlin } 4391fd2a6b71SDan Nowlin rm->root_buf = buf; 4392fd2a6b71SDan Nowlin kfree(tmp); 4393fd2a6b71SDan Nowlin return status; 4394fd2a6b71SDan Nowlin 4395fd2a6b71SDan Nowlin err_unroll: 4396fd2a6b71SDan Nowlin err_mem: 4397fd2a6b71SDan Nowlin kfree(tmp); 4398fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), buf); 4399fd2a6b71SDan Nowlin return status; 4400fd2a6b71SDan Nowlin } 4401fd2a6b71SDan Nowlin 4402fd2a6b71SDan Nowlin /** 4403fd2a6b71SDan Nowlin * ice_create_recipe_group - creates recipe group 4404fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4405fd2a6b71SDan Nowlin * @rm: recipe management list entry 4406fd2a6b71SDan Nowlin * @lkup_exts: lookup elements 4407fd2a6b71SDan Nowlin */ 44085e24d598STony Nguyen static int 4409fd2a6b71SDan Nowlin ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm, 4410fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts) 4411fd2a6b71SDan Nowlin { 4412fd2a6b71SDan Nowlin u8 recp_count = 0; 44135518ac2aSTony Nguyen int status; 4414fd2a6b71SDan Nowlin 4415fd2a6b71SDan Nowlin rm->n_grp_count = 0; 4416fd2a6b71SDan Nowlin 4417fd2a6b71SDan Nowlin /* Create recipes for words that are marked not done by packing them 4418fd2a6b71SDan Nowlin * as best fit. 4419fd2a6b71SDan Nowlin */ 4420fd2a6b71SDan Nowlin status = ice_create_first_fit_recp_def(hw, lkup_exts, 4421fd2a6b71SDan Nowlin &rm->rg_list, &recp_count); 4422fd2a6b71SDan Nowlin if (!status) { 4423fd2a6b71SDan Nowlin rm->n_grp_count += recp_count; 4424fd2a6b71SDan Nowlin rm->n_ext_words = lkup_exts->n_val_words; 4425fd2a6b71SDan Nowlin memcpy(&rm->ext_words, lkup_exts->fv_words, 4426fd2a6b71SDan Nowlin sizeof(rm->ext_words)); 4427fd2a6b71SDan Nowlin memcpy(rm->word_masks, lkup_exts->field_mask, 4428fd2a6b71SDan Nowlin sizeof(rm->word_masks)); 4429fd2a6b71SDan Nowlin } 4430fd2a6b71SDan Nowlin 4431fd2a6b71SDan Nowlin return status; 4432fd2a6b71SDan Nowlin } 4433fd2a6b71SDan Nowlin 4434fd2a6b71SDan Nowlin /** 4435fd2a6b71SDan Nowlin * ice_get_fv - get field vectors/extraction sequences for spec. lookup types 4436fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4437fd2a6b71SDan Nowlin * @lkups: lookup elements or match criteria for the advanced recipe, one 4438fd2a6b71SDan Nowlin * structure per protocol header 4439fd2a6b71SDan Nowlin * @lkups_cnt: number of protocols 4440fd2a6b71SDan Nowlin * @bm: bitmap of field vectors to consider 4441fd2a6b71SDan Nowlin * @fv_list: pointer to a list that holds the returned field vectors 4442fd2a6b71SDan Nowlin */ 44435e24d598STony Nguyen static int 4444fd2a6b71SDan Nowlin ice_get_fv(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, 4445fd2a6b71SDan Nowlin unsigned long *bm, struct list_head *fv_list) 4446fd2a6b71SDan Nowlin { 4447fd2a6b71SDan Nowlin u8 *prot_ids; 44485518ac2aSTony Nguyen int status; 4449fd2a6b71SDan Nowlin u16 i; 4450fd2a6b71SDan Nowlin 4451fd2a6b71SDan Nowlin prot_ids = kcalloc(lkups_cnt, sizeof(*prot_ids), GFP_KERNEL); 4452fd2a6b71SDan Nowlin if (!prot_ids) 4453d54699e2STony Nguyen return -ENOMEM; 4454fd2a6b71SDan Nowlin 4455fd2a6b71SDan Nowlin for (i = 0; i < lkups_cnt; i++) 4456fd2a6b71SDan Nowlin if (!ice_prot_type_to_id(lkups[i].type, &prot_ids[i])) { 4457d54699e2STony Nguyen status = -EIO; 4458fd2a6b71SDan Nowlin goto free_mem; 4459fd2a6b71SDan Nowlin } 4460fd2a6b71SDan Nowlin 4461fd2a6b71SDan Nowlin /* Find field vectors that include all specified protocol types */ 4462fd2a6b71SDan Nowlin status = ice_get_sw_fv_list(hw, prot_ids, lkups_cnt, bm, fv_list); 4463fd2a6b71SDan Nowlin 4464fd2a6b71SDan Nowlin free_mem: 4465fd2a6b71SDan Nowlin kfree(prot_ids); 4466fd2a6b71SDan Nowlin return status; 4467fd2a6b71SDan Nowlin } 4468fd2a6b71SDan Nowlin 44698b032a55SMichal Swiatkowski /** 44708b032a55SMichal Swiatkowski * ice_tun_type_match_word - determine if tun type needs a match mask 44718b032a55SMichal Swiatkowski * @tun_type: tunnel type 44728b032a55SMichal Swiatkowski * @mask: mask to be used for the tunnel 44738b032a55SMichal Swiatkowski */ 44748b032a55SMichal Swiatkowski static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask) 44758b032a55SMichal Swiatkowski { 44768b032a55SMichal Swiatkowski switch (tun_type) { 44778b032a55SMichal Swiatkowski case ICE_SW_TUN_GENEVE: 44788b032a55SMichal Swiatkowski case ICE_SW_TUN_VXLAN: 4479f0a35040SMichal Swiatkowski case ICE_SW_TUN_NVGRE: 44808b032a55SMichal Swiatkowski *mask = ICE_TUN_FLAG_MASK; 44818b032a55SMichal Swiatkowski return true; 44828b032a55SMichal Swiatkowski 44838b032a55SMichal Swiatkowski default: 44848b032a55SMichal Swiatkowski *mask = 0; 44858b032a55SMichal Swiatkowski return false; 44868b032a55SMichal Swiatkowski } 44878b032a55SMichal Swiatkowski } 44888b032a55SMichal Swiatkowski 44898b032a55SMichal Swiatkowski /** 44908b032a55SMichal Swiatkowski * ice_add_special_words - Add words that are not protocols, such as metadata 44918b032a55SMichal Swiatkowski * @rinfo: other information regarding the rule e.g. priority and action info 44928b032a55SMichal Swiatkowski * @lkup_exts: lookup word structure 44938b032a55SMichal Swiatkowski */ 4494d54699e2STony Nguyen static int 44958b032a55SMichal Swiatkowski ice_add_special_words(struct ice_adv_rule_info *rinfo, 44968b032a55SMichal Swiatkowski struct ice_prot_lkup_ext *lkup_exts) 44978b032a55SMichal Swiatkowski { 44988b032a55SMichal Swiatkowski u16 mask; 44998b032a55SMichal Swiatkowski 45008b032a55SMichal Swiatkowski /* If this is a tunneled packet, then add recipe index to match the 45018b032a55SMichal Swiatkowski * tunnel bit in the packet metadata flags. 45028b032a55SMichal Swiatkowski */ 45038b032a55SMichal Swiatkowski if (ice_tun_type_match_word(rinfo->tun_type, &mask)) { 45048b032a55SMichal Swiatkowski if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) { 45058b032a55SMichal Swiatkowski u8 word = lkup_exts->n_val_words++; 45068b032a55SMichal Swiatkowski 45078b032a55SMichal Swiatkowski lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; 45088b032a55SMichal Swiatkowski lkup_exts->fv_words[word].off = ICE_TUN_FLAG_MDID_OFF; 45098b032a55SMichal Swiatkowski lkup_exts->field_mask[word] = mask; 45108b032a55SMichal Swiatkowski } else { 4511d54699e2STony Nguyen return -ENOSPC; 45128b032a55SMichal Swiatkowski } 45138b032a55SMichal Swiatkowski } 45148b032a55SMichal Swiatkowski 45158b032a55SMichal Swiatkowski return 0; 45168b032a55SMichal Swiatkowski } 45178b032a55SMichal Swiatkowski 4518fd2a6b71SDan Nowlin /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule 4519fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4520fd2a6b71SDan Nowlin * @rinfo: other information regarding the rule e.g. priority and action info 4521fd2a6b71SDan Nowlin * @bm: pointer to memory for returning the bitmap of field vectors 4522fd2a6b71SDan Nowlin */ 4523fd2a6b71SDan Nowlin static void 4524fd2a6b71SDan Nowlin ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo, 4525fd2a6b71SDan Nowlin unsigned long *bm) 4526fd2a6b71SDan Nowlin { 45278b032a55SMichal Swiatkowski enum ice_prof_type prof_type; 45288b032a55SMichal Swiatkowski 4529fd2a6b71SDan Nowlin bitmap_zero(bm, ICE_MAX_NUM_PROFILES); 4530fd2a6b71SDan Nowlin 45318b032a55SMichal Swiatkowski switch (rinfo->tun_type) { 45328b032a55SMichal Swiatkowski case ICE_NON_TUN: 45338b032a55SMichal Swiatkowski prof_type = ICE_PROF_NON_TUN; 45348b032a55SMichal Swiatkowski break; 45358b032a55SMichal Swiatkowski case ICE_ALL_TUNNELS: 45368b032a55SMichal Swiatkowski prof_type = ICE_PROF_TUN_ALL; 45378b032a55SMichal Swiatkowski break; 45388b032a55SMichal Swiatkowski case ICE_SW_TUN_GENEVE: 45398b032a55SMichal Swiatkowski case ICE_SW_TUN_VXLAN: 45408b032a55SMichal Swiatkowski prof_type = ICE_PROF_TUN_UDP; 45418b032a55SMichal Swiatkowski break; 4542f0a35040SMichal Swiatkowski case ICE_SW_TUN_NVGRE: 4543f0a35040SMichal Swiatkowski prof_type = ICE_PROF_TUN_GRE; 4544f0a35040SMichal Swiatkowski break; 45458b032a55SMichal Swiatkowski default: 45468b032a55SMichal Swiatkowski prof_type = ICE_PROF_ALL; 45478b032a55SMichal Swiatkowski break; 45488b032a55SMichal Swiatkowski } 45498b032a55SMichal Swiatkowski 45508b032a55SMichal Swiatkowski ice_get_sw_fv_bitmap(hw, prof_type, bm); 4551fd2a6b71SDan Nowlin } 4552fd2a6b71SDan Nowlin 4553fd2a6b71SDan Nowlin /** 4554fd2a6b71SDan Nowlin * ice_add_adv_recipe - Add an advanced recipe that is not part of the default 4555fd2a6b71SDan Nowlin * @hw: pointer to hardware structure 4556fd2a6b71SDan Nowlin * @lkups: lookup elements or match criteria for the advanced recipe, one 4557fd2a6b71SDan Nowlin * structure per protocol header 4558fd2a6b71SDan Nowlin * @lkups_cnt: number of protocols 4559fd2a6b71SDan Nowlin * @rinfo: other information regarding the rule e.g. priority and action info 4560fd2a6b71SDan Nowlin * @rid: return the recipe ID of the recipe created 4561fd2a6b71SDan Nowlin */ 45625e24d598STony Nguyen static int 4563fd2a6b71SDan Nowlin ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 4564fd2a6b71SDan Nowlin u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid) 4565fd2a6b71SDan Nowlin { 4566fd2a6b71SDan Nowlin DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES); 4567fd2a6b71SDan Nowlin DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES); 4568fd2a6b71SDan Nowlin struct ice_prot_lkup_ext *lkup_exts; 4569fd2a6b71SDan Nowlin struct ice_recp_grp_entry *r_entry; 4570fd2a6b71SDan Nowlin struct ice_sw_fv_list_entry *fvit; 4571fd2a6b71SDan Nowlin struct ice_recp_grp_entry *r_tmp; 4572fd2a6b71SDan Nowlin struct ice_sw_fv_list_entry *tmp; 4573fd2a6b71SDan Nowlin struct ice_sw_recipe *rm; 45745518ac2aSTony Nguyen int status = 0; 4575fd2a6b71SDan Nowlin u8 i; 4576fd2a6b71SDan Nowlin 4577fd2a6b71SDan Nowlin if (!lkups_cnt) 4578d54699e2STony Nguyen return -EINVAL; 4579fd2a6b71SDan Nowlin 4580fd2a6b71SDan Nowlin lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL); 4581fd2a6b71SDan Nowlin if (!lkup_exts) 4582d54699e2STony Nguyen return -ENOMEM; 4583fd2a6b71SDan Nowlin 4584fd2a6b71SDan Nowlin /* Determine the number of words to be matched and if it exceeds a 4585fd2a6b71SDan Nowlin * recipe's restrictions 4586fd2a6b71SDan Nowlin */ 4587fd2a6b71SDan Nowlin for (i = 0; i < lkups_cnt; i++) { 4588fd2a6b71SDan Nowlin u16 count; 4589fd2a6b71SDan Nowlin 4590fd2a6b71SDan Nowlin if (lkups[i].type >= ICE_PROTOCOL_LAST) { 4591d54699e2STony Nguyen status = -EIO; 4592fd2a6b71SDan Nowlin goto err_free_lkup_exts; 4593fd2a6b71SDan Nowlin } 4594fd2a6b71SDan Nowlin 4595fd2a6b71SDan Nowlin count = ice_fill_valid_words(&lkups[i], lkup_exts); 4596fd2a6b71SDan Nowlin if (!count) { 4597d54699e2STony Nguyen status = -EIO; 4598fd2a6b71SDan Nowlin goto err_free_lkup_exts; 4599fd2a6b71SDan Nowlin } 4600fd2a6b71SDan Nowlin } 4601fd2a6b71SDan Nowlin 4602fd2a6b71SDan Nowlin rm = kzalloc(sizeof(*rm), GFP_KERNEL); 4603fd2a6b71SDan Nowlin if (!rm) { 4604d54699e2STony Nguyen status = -ENOMEM; 4605fd2a6b71SDan Nowlin goto err_free_lkup_exts; 4606fd2a6b71SDan Nowlin } 4607fd2a6b71SDan Nowlin 4608fd2a6b71SDan Nowlin /* Get field vectors that contain fields extracted from all the protocol 4609fd2a6b71SDan Nowlin * headers being programmed. 4610fd2a6b71SDan Nowlin */ 4611fd2a6b71SDan Nowlin INIT_LIST_HEAD(&rm->fv_list); 4612fd2a6b71SDan Nowlin INIT_LIST_HEAD(&rm->rg_list); 4613fd2a6b71SDan Nowlin 4614fd2a6b71SDan Nowlin /* Get bitmap of field vectors (profiles) that are compatible with the 4615fd2a6b71SDan Nowlin * rule request; only these will be searched in the subsequent call to 4616fd2a6b71SDan Nowlin * ice_get_fv. 4617fd2a6b71SDan Nowlin */ 4618fd2a6b71SDan Nowlin ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap); 4619fd2a6b71SDan Nowlin 4620fd2a6b71SDan Nowlin status = ice_get_fv(hw, lkups, lkups_cnt, fv_bitmap, &rm->fv_list); 4621fd2a6b71SDan Nowlin if (status) 4622fd2a6b71SDan Nowlin goto err_unroll; 4623fd2a6b71SDan Nowlin 46248b032a55SMichal Swiatkowski /* Create any special protocol/offset pairs, such as looking at tunnel 46258b032a55SMichal Swiatkowski * bits by extracting metadata 46268b032a55SMichal Swiatkowski */ 46278b032a55SMichal Swiatkowski status = ice_add_special_words(rinfo, lkup_exts); 46288b032a55SMichal Swiatkowski if (status) 46298b032a55SMichal Swiatkowski goto err_free_lkup_exts; 46308b032a55SMichal Swiatkowski 4631fd2a6b71SDan Nowlin /* Group match words into recipes using preferred recipe grouping 4632fd2a6b71SDan Nowlin * criteria. 4633fd2a6b71SDan Nowlin */ 4634fd2a6b71SDan Nowlin status = ice_create_recipe_group(hw, rm, lkup_exts); 4635fd2a6b71SDan Nowlin if (status) 4636fd2a6b71SDan Nowlin goto err_unroll; 4637fd2a6b71SDan Nowlin 4638fd2a6b71SDan Nowlin /* set the recipe priority if specified */ 4639fd2a6b71SDan Nowlin rm->priority = (u8)rinfo->priority; 4640fd2a6b71SDan Nowlin 4641fd2a6b71SDan Nowlin /* Find offsets from the field vector. Pick the first one for all the 4642fd2a6b71SDan Nowlin * recipes. 4643fd2a6b71SDan Nowlin */ 4644fd2a6b71SDan Nowlin status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list); 4645fd2a6b71SDan Nowlin if (status) 4646fd2a6b71SDan Nowlin goto err_unroll; 4647fd2a6b71SDan Nowlin 4648fd2a6b71SDan Nowlin /* get bitmap of all profiles the recipe will be associated with */ 4649fd2a6b71SDan Nowlin bitmap_zero(profiles, ICE_MAX_NUM_PROFILES); 4650fd2a6b71SDan Nowlin list_for_each_entry(fvit, &rm->fv_list, list_entry) { 4651fd2a6b71SDan Nowlin ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id); 4652fd2a6b71SDan Nowlin set_bit((u16)fvit->profile_id, profiles); 4653fd2a6b71SDan Nowlin } 4654fd2a6b71SDan Nowlin 4655fd2a6b71SDan Nowlin /* Look for a recipe which matches our requested fv / mask list */ 4656de6acd1cSMichal Swiatkowski *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type); 4657fd2a6b71SDan Nowlin if (*rid < ICE_MAX_NUM_RECIPES) 4658fd2a6b71SDan Nowlin /* Success if found a recipe that match the existing criteria */ 4659fd2a6b71SDan Nowlin goto err_unroll; 4660fd2a6b71SDan Nowlin 4661de6acd1cSMichal Swiatkowski rm->tun_type = rinfo->tun_type; 4662fd2a6b71SDan Nowlin /* Recipe we need does not exist, add a recipe */ 46638b032a55SMichal Swiatkowski status = ice_add_sw_recipe(hw, rm, profiles); 4664fd2a6b71SDan Nowlin if (status) 4665fd2a6b71SDan Nowlin goto err_unroll; 4666fd2a6b71SDan Nowlin 4667fd2a6b71SDan Nowlin /* Associate all the recipes created with all the profiles in the 4668fd2a6b71SDan Nowlin * common field vector. 4669fd2a6b71SDan Nowlin */ 4670fd2a6b71SDan Nowlin list_for_each_entry(fvit, &rm->fv_list, list_entry) { 4671fd2a6b71SDan Nowlin DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); 4672fd2a6b71SDan Nowlin u16 j; 4673fd2a6b71SDan Nowlin 4674fd2a6b71SDan Nowlin status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id, 4675fd2a6b71SDan Nowlin (u8 *)r_bitmap, NULL); 4676fd2a6b71SDan Nowlin if (status) 4677fd2a6b71SDan Nowlin goto err_unroll; 4678fd2a6b71SDan Nowlin 4679fd2a6b71SDan Nowlin bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap, 4680fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 4681fd2a6b71SDan Nowlin status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 4682fd2a6b71SDan Nowlin if (status) 4683fd2a6b71SDan Nowlin goto err_unroll; 4684fd2a6b71SDan Nowlin 4685fd2a6b71SDan Nowlin status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id, 4686fd2a6b71SDan Nowlin (u8 *)r_bitmap, 4687fd2a6b71SDan Nowlin NULL); 4688fd2a6b71SDan Nowlin ice_release_change_lock(hw); 4689fd2a6b71SDan Nowlin 4690fd2a6b71SDan Nowlin if (status) 4691fd2a6b71SDan Nowlin goto err_unroll; 4692fd2a6b71SDan Nowlin 4693fd2a6b71SDan Nowlin /* Update profile to recipe bitmap array */ 4694fd2a6b71SDan Nowlin bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap, 4695fd2a6b71SDan Nowlin ICE_MAX_NUM_RECIPES); 4696fd2a6b71SDan Nowlin 4697fd2a6b71SDan Nowlin /* Update recipe to profile bitmap array */ 4698fd2a6b71SDan Nowlin for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES) 4699fd2a6b71SDan Nowlin set_bit((u16)fvit->profile_id, recipe_to_profile[j]); 4700fd2a6b71SDan Nowlin } 4701fd2a6b71SDan Nowlin 4702fd2a6b71SDan Nowlin *rid = rm->root_rid; 4703fd2a6b71SDan Nowlin memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts, 4704fd2a6b71SDan Nowlin sizeof(*lkup_exts)); 4705fd2a6b71SDan Nowlin err_unroll: 4706fd2a6b71SDan Nowlin list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) { 4707fd2a6b71SDan Nowlin list_del(&r_entry->l_entry); 4708fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), r_entry); 4709fd2a6b71SDan Nowlin } 4710fd2a6b71SDan Nowlin 4711fd2a6b71SDan Nowlin list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) { 4712fd2a6b71SDan Nowlin list_del(&fvit->list_entry); 4713fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), fvit); 4714fd2a6b71SDan Nowlin } 4715fd2a6b71SDan Nowlin 4716fd2a6b71SDan Nowlin if (rm->root_buf) 4717fd2a6b71SDan Nowlin devm_kfree(ice_hw_to_dev(hw), rm->root_buf); 4718fd2a6b71SDan Nowlin 4719fd2a6b71SDan Nowlin kfree(rm); 4720fd2a6b71SDan Nowlin 4721fd2a6b71SDan Nowlin err_free_lkup_exts: 4722fd2a6b71SDan Nowlin kfree(lkup_exts); 4723fd2a6b71SDan Nowlin 4724fd2a6b71SDan Nowlin return status; 4725fd2a6b71SDan Nowlin } 4726fd2a6b71SDan Nowlin 4727148beb61SHenry Tieman /** 47280f94570dSGrishma Kotecha * ice_find_dummy_packet - find dummy packet 47290f94570dSGrishma Kotecha * 47300f94570dSGrishma Kotecha * @lkups: lookup elements or match criteria for the advanced recipe, one 47310f94570dSGrishma Kotecha * structure per protocol header 47320f94570dSGrishma Kotecha * @lkups_cnt: number of protocols 47338b032a55SMichal Swiatkowski * @tun_type: tunnel type 47340f94570dSGrishma Kotecha * @pkt: dummy packet to fill according to filter match criteria 47350f94570dSGrishma Kotecha * @pkt_len: packet length of dummy packet 47360f94570dSGrishma Kotecha * @offsets: pointer to receive the pointer to the offsets for the packet 47370f94570dSGrishma Kotecha */ 47380f94570dSGrishma Kotecha static void 47390f94570dSGrishma Kotecha ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, 47408b032a55SMichal Swiatkowski enum ice_sw_tunnel_type tun_type, 47410f94570dSGrishma Kotecha const u8 **pkt, u16 *pkt_len, 47420f94570dSGrishma Kotecha const struct ice_dummy_pkt_offsets **offsets) 47430f94570dSGrishma Kotecha { 47440f94570dSGrishma Kotecha bool tcp = false, udp = false, ipv6 = false, vlan = false; 47450f94570dSGrishma Kotecha u16 i; 47460f94570dSGrishma Kotecha 47470f94570dSGrishma Kotecha for (i = 0; i < lkups_cnt; i++) { 47480f94570dSGrishma Kotecha if (lkups[i].type == ICE_UDP_ILOS) 47490f94570dSGrishma Kotecha udp = true; 47500f94570dSGrishma Kotecha else if (lkups[i].type == ICE_TCP_IL) 47510f94570dSGrishma Kotecha tcp = true; 47520f94570dSGrishma Kotecha else if (lkups[i].type == ICE_IPV6_OFOS) 47530f94570dSGrishma Kotecha ipv6 = true; 47540f94570dSGrishma Kotecha else if (lkups[i].type == ICE_VLAN_OFOS) 47550f94570dSGrishma Kotecha vlan = true; 47560f94570dSGrishma Kotecha else if (lkups[i].type == ICE_ETYPE_OL && 47570f94570dSGrishma Kotecha lkups[i].h_u.ethertype.ethtype_id == 47580f94570dSGrishma Kotecha cpu_to_be16(ICE_IPV6_ETHER_ID) && 47590f94570dSGrishma Kotecha lkups[i].m_u.ethertype.ethtype_id == 47600f94570dSGrishma Kotecha cpu_to_be16(0xFFFF)) 47610f94570dSGrishma Kotecha ipv6 = true; 47620f94570dSGrishma Kotecha } 47630f94570dSGrishma Kotecha 4764f0a35040SMichal Swiatkowski if (tun_type == ICE_SW_TUN_NVGRE) { 4765f0a35040SMichal Swiatkowski if (tcp) { 4766f0a35040SMichal Swiatkowski *pkt = dummy_gre_tcp_packet; 4767f0a35040SMichal Swiatkowski *pkt_len = sizeof(dummy_gre_tcp_packet); 4768f0a35040SMichal Swiatkowski *offsets = dummy_gre_tcp_packet_offsets; 4769f0a35040SMichal Swiatkowski return; 4770f0a35040SMichal Swiatkowski } 4771f0a35040SMichal Swiatkowski 4772f0a35040SMichal Swiatkowski *pkt = dummy_gre_udp_packet; 4773f0a35040SMichal Swiatkowski *pkt_len = sizeof(dummy_gre_udp_packet); 4774f0a35040SMichal Swiatkowski *offsets = dummy_gre_udp_packet_offsets; 4775f0a35040SMichal Swiatkowski return; 4776f0a35040SMichal Swiatkowski } 4777f0a35040SMichal Swiatkowski 47788b032a55SMichal Swiatkowski if (tun_type == ICE_SW_TUN_VXLAN || 47798b032a55SMichal Swiatkowski tun_type == ICE_SW_TUN_GENEVE) { 47808b032a55SMichal Swiatkowski if (tcp) { 47818b032a55SMichal Swiatkowski *pkt = dummy_udp_tun_tcp_packet; 47828b032a55SMichal Swiatkowski *pkt_len = sizeof(dummy_udp_tun_tcp_packet); 47838b032a55SMichal Swiatkowski *offsets = dummy_udp_tun_tcp_packet_offsets; 47848b032a55SMichal Swiatkowski return; 47858b032a55SMichal Swiatkowski } 47868b032a55SMichal Swiatkowski 47878b032a55SMichal Swiatkowski *pkt = dummy_udp_tun_udp_packet; 47888b032a55SMichal Swiatkowski *pkt_len = sizeof(dummy_udp_tun_udp_packet); 47898b032a55SMichal Swiatkowski *offsets = dummy_udp_tun_udp_packet_offsets; 47908b032a55SMichal Swiatkowski return; 47918b032a55SMichal Swiatkowski } 47928b032a55SMichal Swiatkowski 47930f94570dSGrishma Kotecha if (udp && !ipv6) { 47940f94570dSGrishma Kotecha if (vlan) { 47950f94570dSGrishma Kotecha *pkt = dummy_vlan_udp_packet; 47960f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_udp_packet); 47970f94570dSGrishma Kotecha *offsets = dummy_vlan_udp_packet_offsets; 47980f94570dSGrishma Kotecha return; 47990f94570dSGrishma Kotecha } 48000f94570dSGrishma Kotecha *pkt = dummy_udp_packet; 48010f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_udp_packet); 48020f94570dSGrishma Kotecha *offsets = dummy_udp_packet_offsets; 48030f94570dSGrishma Kotecha return; 48040f94570dSGrishma Kotecha } else if (udp && ipv6) { 48050f94570dSGrishma Kotecha if (vlan) { 48060f94570dSGrishma Kotecha *pkt = dummy_vlan_udp_ipv6_packet; 48070f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_udp_ipv6_packet); 48080f94570dSGrishma Kotecha *offsets = dummy_vlan_udp_ipv6_packet_offsets; 48090f94570dSGrishma Kotecha return; 48100f94570dSGrishma Kotecha } 48110f94570dSGrishma Kotecha *pkt = dummy_udp_ipv6_packet; 48120f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_udp_ipv6_packet); 48130f94570dSGrishma Kotecha *offsets = dummy_udp_ipv6_packet_offsets; 48140f94570dSGrishma Kotecha return; 48150f94570dSGrishma Kotecha } else if ((tcp && ipv6) || ipv6) { 48160f94570dSGrishma Kotecha if (vlan) { 48170f94570dSGrishma Kotecha *pkt = dummy_vlan_tcp_ipv6_packet; 48180f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_tcp_ipv6_packet); 48190f94570dSGrishma Kotecha *offsets = dummy_vlan_tcp_ipv6_packet_offsets; 48200f94570dSGrishma Kotecha return; 48210f94570dSGrishma Kotecha } 48220f94570dSGrishma Kotecha *pkt = dummy_tcp_ipv6_packet; 48230f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_tcp_ipv6_packet); 48240f94570dSGrishma Kotecha *offsets = dummy_tcp_ipv6_packet_offsets; 48250f94570dSGrishma Kotecha return; 48260f94570dSGrishma Kotecha } 48270f94570dSGrishma Kotecha 48280f94570dSGrishma Kotecha if (vlan) { 48290f94570dSGrishma Kotecha *pkt = dummy_vlan_tcp_packet; 48300f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_vlan_tcp_packet); 48310f94570dSGrishma Kotecha *offsets = dummy_vlan_tcp_packet_offsets; 48320f94570dSGrishma Kotecha } else { 48330f94570dSGrishma Kotecha *pkt = dummy_tcp_packet; 48340f94570dSGrishma Kotecha *pkt_len = sizeof(dummy_tcp_packet); 48350f94570dSGrishma Kotecha *offsets = dummy_tcp_packet_offsets; 48360f94570dSGrishma Kotecha } 48370f94570dSGrishma Kotecha } 48380f94570dSGrishma Kotecha 48390f94570dSGrishma Kotecha /** 48400f94570dSGrishma Kotecha * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria 48410f94570dSGrishma Kotecha * 48420f94570dSGrishma Kotecha * @lkups: lookup elements or match criteria for the advanced recipe, one 48430f94570dSGrishma Kotecha * structure per protocol header 48440f94570dSGrishma Kotecha * @lkups_cnt: number of protocols 48450f94570dSGrishma Kotecha * @s_rule: stores rule information from the match criteria 48460f94570dSGrishma Kotecha * @dummy_pkt: dummy packet to fill according to filter match criteria 48470f94570dSGrishma Kotecha * @pkt_len: packet length of dummy packet 48480f94570dSGrishma Kotecha * @offsets: offset info for the dummy packet 48490f94570dSGrishma Kotecha */ 48505e24d598STony Nguyen static int 48510f94570dSGrishma Kotecha ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, 48520f94570dSGrishma Kotecha struct ice_aqc_sw_rules_elem *s_rule, 48530f94570dSGrishma Kotecha const u8 *dummy_pkt, u16 pkt_len, 48540f94570dSGrishma Kotecha const struct ice_dummy_pkt_offsets *offsets) 48550f94570dSGrishma Kotecha { 48560f94570dSGrishma Kotecha u8 *pkt; 48570f94570dSGrishma Kotecha u16 i; 48580f94570dSGrishma Kotecha 48590f94570dSGrishma Kotecha /* Start with a packet with a pre-defined/dummy content. Then, fill 48600f94570dSGrishma Kotecha * in the header values to be looked up or matched. 48610f94570dSGrishma Kotecha */ 48620f94570dSGrishma Kotecha pkt = s_rule->pdata.lkup_tx_rx.hdr; 48630f94570dSGrishma Kotecha 48640f94570dSGrishma Kotecha memcpy(pkt, dummy_pkt, pkt_len); 48650f94570dSGrishma Kotecha 48660f94570dSGrishma Kotecha for (i = 0; i < lkups_cnt; i++) { 48670f94570dSGrishma Kotecha enum ice_protocol_type type; 48680f94570dSGrishma Kotecha u16 offset = 0, len = 0, j; 48690f94570dSGrishma Kotecha bool found = false; 48700f94570dSGrishma Kotecha 48710f94570dSGrishma Kotecha /* find the start of this layer; it should be found since this 48720f94570dSGrishma Kotecha * was already checked when search for the dummy packet 48730f94570dSGrishma Kotecha */ 48740f94570dSGrishma Kotecha type = lkups[i].type; 48750f94570dSGrishma Kotecha for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) { 48760f94570dSGrishma Kotecha if (type == offsets[j].type) { 48770f94570dSGrishma Kotecha offset = offsets[j].offset; 48780f94570dSGrishma Kotecha found = true; 48790f94570dSGrishma Kotecha break; 48800f94570dSGrishma Kotecha } 48810f94570dSGrishma Kotecha } 48820f94570dSGrishma Kotecha /* this should never happen in a correct calling sequence */ 48830f94570dSGrishma Kotecha if (!found) 4884d54699e2STony Nguyen return -EINVAL; 48850f94570dSGrishma Kotecha 48860f94570dSGrishma Kotecha switch (lkups[i].type) { 48870f94570dSGrishma Kotecha case ICE_MAC_OFOS: 48880f94570dSGrishma Kotecha case ICE_MAC_IL: 48890f94570dSGrishma Kotecha len = sizeof(struct ice_ether_hdr); 48900f94570dSGrishma Kotecha break; 48910f94570dSGrishma Kotecha case ICE_ETYPE_OL: 48920f94570dSGrishma Kotecha len = sizeof(struct ice_ethtype_hdr); 48930f94570dSGrishma Kotecha break; 48940f94570dSGrishma Kotecha case ICE_VLAN_OFOS: 48950f94570dSGrishma Kotecha len = sizeof(struct ice_vlan_hdr); 48960f94570dSGrishma Kotecha break; 48970f94570dSGrishma Kotecha case ICE_IPV4_OFOS: 48980f94570dSGrishma Kotecha case ICE_IPV4_IL: 48990f94570dSGrishma Kotecha len = sizeof(struct ice_ipv4_hdr); 49000f94570dSGrishma Kotecha break; 49010f94570dSGrishma Kotecha case ICE_IPV6_OFOS: 49020f94570dSGrishma Kotecha case ICE_IPV6_IL: 49030f94570dSGrishma Kotecha len = sizeof(struct ice_ipv6_hdr); 49040f94570dSGrishma Kotecha break; 49050f94570dSGrishma Kotecha case ICE_TCP_IL: 49060f94570dSGrishma Kotecha case ICE_UDP_OF: 49070f94570dSGrishma Kotecha case ICE_UDP_ILOS: 49080f94570dSGrishma Kotecha len = sizeof(struct ice_l4_hdr); 49090f94570dSGrishma Kotecha break; 49100f94570dSGrishma Kotecha case ICE_SCTP_IL: 49110f94570dSGrishma Kotecha len = sizeof(struct ice_sctp_hdr); 49120f94570dSGrishma Kotecha break; 4913f0a35040SMichal Swiatkowski case ICE_NVGRE: 4914f0a35040SMichal Swiatkowski len = sizeof(struct ice_nvgre_hdr); 4915f0a35040SMichal Swiatkowski break; 49168b032a55SMichal Swiatkowski case ICE_VXLAN: 49178b032a55SMichal Swiatkowski case ICE_GENEVE: 49188b032a55SMichal Swiatkowski len = sizeof(struct ice_udp_tnl_hdr); 49198b032a55SMichal Swiatkowski break; 49200f94570dSGrishma Kotecha default: 4921d54699e2STony Nguyen return -EINVAL; 49220f94570dSGrishma Kotecha } 49230f94570dSGrishma Kotecha 49240f94570dSGrishma Kotecha /* the length should be a word multiple */ 49250f94570dSGrishma Kotecha if (len % ICE_BYTES_PER_WORD) 4926d54699e2STony Nguyen return -EIO; 49270f94570dSGrishma Kotecha 49280f94570dSGrishma Kotecha /* We have the offset to the header start, the length, the 49290f94570dSGrishma Kotecha * caller's header values and mask. Use this information to 49300f94570dSGrishma Kotecha * copy the data into the dummy packet appropriately based on 49310f94570dSGrishma Kotecha * the mask. Note that we need to only write the bits as 49320f94570dSGrishma Kotecha * indicated by the mask to make sure we don't improperly write 49330f94570dSGrishma Kotecha * over any significant packet data. 49340f94570dSGrishma Kotecha */ 49350f94570dSGrishma Kotecha for (j = 0; j < len / sizeof(u16); j++) 49360f94570dSGrishma Kotecha if (((u16 *)&lkups[i].m_u)[j]) 49370f94570dSGrishma Kotecha ((u16 *)(pkt + offset))[j] = 49380f94570dSGrishma Kotecha (((u16 *)(pkt + offset))[j] & 49390f94570dSGrishma Kotecha ~((u16 *)&lkups[i].m_u)[j]) | 49400f94570dSGrishma Kotecha (((u16 *)&lkups[i].h_u)[j] & 49410f94570dSGrishma Kotecha ((u16 *)&lkups[i].m_u)[j]); 49420f94570dSGrishma Kotecha } 49430f94570dSGrishma Kotecha 49440f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(pkt_len); 49450f94570dSGrishma Kotecha 49460f94570dSGrishma Kotecha return 0; 49470f94570dSGrishma Kotecha } 49480f94570dSGrishma Kotecha 49490f94570dSGrishma Kotecha /** 49508b032a55SMichal Swiatkowski * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port 49518b032a55SMichal Swiatkowski * @hw: pointer to the hardware structure 49528b032a55SMichal Swiatkowski * @tun_type: tunnel type 49538b032a55SMichal Swiatkowski * @pkt: dummy packet to fill in 49548b032a55SMichal Swiatkowski * @offsets: offset info for the dummy packet 49558b032a55SMichal Swiatkowski */ 4956d54699e2STony Nguyen static int 49578b032a55SMichal Swiatkowski ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type, 49588b032a55SMichal Swiatkowski u8 *pkt, const struct ice_dummy_pkt_offsets *offsets) 49598b032a55SMichal Swiatkowski { 49608b032a55SMichal Swiatkowski u16 open_port, i; 49618b032a55SMichal Swiatkowski 49628b032a55SMichal Swiatkowski switch (tun_type) { 49638b032a55SMichal Swiatkowski case ICE_SW_TUN_VXLAN: 4964de6acd1cSMichal Swiatkowski if (!ice_get_open_tunnel_port(hw, &open_port, TNL_VXLAN)) 4965d54699e2STony Nguyen return -EIO; 49668b032a55SMichal Swiatkowski break; 4967de6acd1cSMichal Swiatkowski case ICE_SW_TUN_GENEVE: 4968de6acd1cSMichal Swiatkowski if (!ice_get_open_tunnel_port(hw, &open_port, TNL_GENEVE)) 4969d54699e2STony Nguyen return -EIO; 4970de6acd1cSMichal Swiatkowski break; 49718b032a55SMichal Swiatkowski default: 49728b032a55SMichal Swiatkowski /* Nothing needs to be done for this tunnel type */ 49738b032a55SMichal Swiatkowski return 0; 49748b032a55SMichal Swiatkowski } 49758b032a55SMichal Swiatkowski 49768b032a55SMichal Swiatkowski /* Find the outer UDP protocol header and insert the port number */ 49778b032a55SMichal Swiatkowski for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { 49788b032a55SMichal Swiatkowski if (offsets[i].type == ICE_UDP_OF) { 49798b032a55SMichal Swiatkowski struct ice_l4_hdr *hdr; 49808b032a55SMichal Swiatkowski u16 offset; 49818b032a55SMichal Swiatkowski 49828b032a55SMichal Swiatkowski offset = offsets[i].offset; 49838b032a55SMichal Swiatkowski hdr = (struct ice_l4_hdr *)&pkt[offset]; 49848b032a55SMichal Swiatkowski hdr->dst_port = cpu_to_be16(open_port); 49858b032a55SMichal Swiatkowski 49868b032a55SMichal Swiatkowski return 0; 49878b032a55SMichal Swiatkowski } 49888b032a55SMichal Swiatkowski } 49898b032a55SMichal Swiatkowski 4990d54699e2STony Nguyen return -EIO; 49918b032a55SMichal Swiatkowski } 49928b032a55SMichal Swiatkowski 49938b032a55SMichal Swiatkowski /** 49940f94570dSGrishma Kotecha * ice_find_adv_rule_entry - Search a rule entry 49950f94570dSGrishma Kotecha * @hw: pointer to the hardware structure 49960f94570dSGrishma Kotecha * @lkups: lookup elements or match criteria for the advanced recipe, one 49970f94570dSGrishma Kotecha * structure per protocol header 49980f94570dSGrishma Kotecha * @lkups_cnt: number of protocols 49990f94570dSGrishma Kotecha * @recp_id: recipe ID for which we are finding the rule 50000f94570dSGrishma Kotecha * @rinfo: other information regarding the rule e.g. priority and action info 50010f94570dSGrishma Kotecha * 50020f94570dSGrishma Kotecha * Helper function to search for a given advance rule entry 50030f94570dSGrishma Kotecha * Returns pointer to entry storing the rule if found 50040f94570dSGrishma Kotecha */ 50050f94570dSGrishma Kotecha static struct ice_adv_fltr_mgmt_list_entry * 50060f94570dSGrishma Kotecha ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 50070f94570dSGrishma Kotecha u16 lkups_cnt, u16 recp_id, 50080f94570dSGrishma Kotecha struct ice_adv_rule_info *rinfo) 50090f94570dSGrishma Kotecha { 50100f94570dSGrishma Kotecha struct ice_adv_fltr_mgmt_list_entry *list_itr; 50110f94570dSGrishma Kotecha struct ice_switch_info *sw = hw->switch_info; 50120f94570dSGrishma Kotecha int i; 50130f94570dSGrishma Kotecha 50140f94570dSGrishma Kotecha list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules, 50150f94570dSGrishma Kotecha list_entry) { 50160f94570dSGrishma Kotecha bool lkups_matched = true; 50170f94570dSGrishma Kotecha 50180f94570dSGrishma Kotecha if (lkups_cnt != list_itr->lkups_cnt) 50190f94570dSGrishma Kotecha continue; 50200f94570dSGrishma Kotecha for (i = 0; i < list_itr->lkups_cnt; i++) 50210f94570dSGrishma Kotecha if (memcmp(&list_itr->lkups[i], &lkups[i], 50220f94570dSGrishma Kotecha sizeof(*lkups))) { 50230f94570dSGrishma Kotecha lkups_matched = false; 50240f94570dSGrishma Kotecha break; 50250f94570dSGrishma Kotecha } 50260f94570dSGrishma Kotecha if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag && 50278b032a55SMichal Swiatkowski rinfo->tun_type == list_itr->rule_info.tun_type && 50280f94570dSGrishma Kotecha lkups_matched) 50290f94570dSGrishma Kotecha return list_itr; 50300f94570dSGrishma Kotecha } 50310f94570dSGrishma Kotecha return NULL; 50320f94570dSGrishma Kotecha } 50330f94570dSGrishma Kotecha 50340f94570dSGrishma Kotecha /** 50350f94570dSGrishma Kotecha * ice_adv_add_update_vsi_list 50360f94570dSGrishma Kotecha * @hw: pointer to the hardware structure 50370f94570dSGrishma Kotecha * @m_entry: pointer to current adv filter management list entry 50380f94570dSGrishma Kotecha * @cur_fltr: filter information from the book keeping entry 50390f94570dSGrishma Kotecha * @new_fltr: filter information with the new VSI to be added 50400f94570dSGrishma Kotecha * 50410f94570dSGrishma Kotecha * Call AQ command to add or update previously created VSI list with new VSI. 50420f94570dSGrishma Kotecha * 50430f94570dSGrishma Kotecha * Helper function to do book keeping associated with adding filter information 50440f94570dSGrishma Kotecha * The algorithm to do the booking keeping is described below : 50450f94570dSGrishma Kotecha * When a VSI needs to subscribe to a given advanced filter 50460f94570dSGrishma Kotecha * if only one VSI has been added till now 50470f94570dSGrishma Kotecha * Allocate a new VSI list and add two VSIs 50480f94570dSGrishma Kotecha * to this list using switch rule command 50490f94570dSGrishma Kotecha * Update the previously created switch rule with the 50500f94570dSGrishma Kotecha * newly created VSI list ID 50510f94570dSGrishma Kotecha * if a VSI list was previously created 50520f94570dSGrishma Kotecha * Add the new VSI to the previously created VSI list set 50530f94570dSGrishma Kotecha * using the update switch rule command 50540f94570dSGrishma Kotecha */ 50555e24d598STony Nguyen static int 50560f94570dSGrishma Kotecha ice_adv_add_update_vsi_list(struct ice_hw *hw, 50570f94570dSGrishma Kotecha struct ice_adv_fltr_mgmt_list_entry *m_entry, 50580f94570dSGrishma Kotecha struct ice_adv_rule_info *cur_fltr, 50590f94570dSGrishma Kotecha struct ice_adv_rule_info *new_fltr) 50600f94570dSGrishma Kotecha { 50610f94570dSGrishma Kotecha u16 vsi_list_id = 0; 50625518ac2aSTony Nguyen int status; 50630f94570dSGrishma Kotecha 50640f94570dSGrishma Kotecha if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || 50650f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP || 50660f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET) 5067d54699e2STony Nguyen return -EOPNOTSUPP; 50680f94570dSGrishma Kotecha 50690f94570dSGrishma Kotecha if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || 50700f94570dSGrishma Kotecha new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) && 50710f94570dSGrishma Kotecha (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI || 50720f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST)) 5073d54699e2STony Nguyen return -EOPNOTSUPP; 50740f94570dSGrishma Kotecha 50750f94570dSGrishma Kotecha if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { 50760f94570dSGrishma Kotecha /* Only one entry existed in the mapping and it was not already 50770f94570dSGrishma Kotecha * a part of a VSI list. So, create a VSI list with the old and 50780f94570dSGrishma Kotecha * new VSIs. 50790f94570dSGrishma Kotecha */ 50800f94570dSGrishma Kotecha struct ice_fltr_info tmp_fltr; 50810f94570dSGrishma Kotecha u16 vsi_handle_arr[2]; 50820f94570dSGrishma Kotecha 50830f94570dSGrishma Kotecha /* A rule already exists with the new VSI being added */ 50840f94570dSGrishma Kotecha if (cur_fltr->sw_act.fwd_id.hw_vsi_id == 50850f94570dSGrishma Kotecha new_fltr->sw_act.fwd_id.hw_vsi_id) 5086d54699e2STony Nguyen return -EEXIST; 50870f94570dSGrishma Kotecha 50880f94570dSGrishma Kotecha vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle; 50890f94570dSGrishma Kotecha vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle; 50900f94570dSGrishma Kotecha status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, 50910f94570dSGrishma Kotecha &vsi_list_id, 50920f94570dSGrishma Kotecha ICE_SW_LKUP_LAST); 50930f94570dSGrishma Kotecha if (status) 50940f94570dSGrishma Kotecha return status; 50950f94570dSGrishma Kotecha 50960f94570dSGrishma Kotecha memset(&tmp_fltr, 0, sizeof(tmp_fltr)); 50970f94570dSGrishma Kotecha tmp_fltr.flag = m_entry->rule_info.sw_act.flag; 50980f94570dSGrishma Kotecha tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; 50990f94570dSGrishma Kotecha tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; 51000f94570dSGrishma Kotecha tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; 51010f94570dSGrishma Kotecha tmp_fltr.lkup_type = ICE_SW_LKUP_LAST; 51020f94570dSGrishma Kotecha 51030f94570dSGrishma Kotecha /* Update the previous switch rule of "forward to VSI" to 51040f94570dSGrishma Kotecha * "fwd to VSI list" 51050f94570dSGrishma Kotecha */ 51060f94570dSGrishma Kotecha status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 51070f94570dSGrishma Kotecha if (status) 51080f94570dSGrishma Kotecha return status; 51090f94570dSGrishma Kotecha 51100f94570dSGrishma Kotecha cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id; 51110f94570dSGrishma Kotecha cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST; 51120f94570dSGrishma Kotecha m_entry->vsi_list_info = 51130f94570dSGrishma Kotecha ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, 51140f94570dSGrishma Kotecha vsi_list_id); 51150f94570dSGrishma Kotecha } else { 51160f94570dSGrishma Kotecha u16 vsi_handle = new_fltr->sw_act.vsi_handle; 51170f94570dSGrishma Kotecha 51180f94570dSGrishma Kotecha if (!m_entry->vsi_list_info) 5119d54699e2STony Nguyen return -EIO; 51200f94570dSGrishma Kotecha 51210f94570dSGrishma Kotecha /* A rule already exists with the new VSI being added */ 51220f94570dSGrishma Kotecha if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) 51230f94570dSGrishma Kotecha return 0; 51240f94570dSGrishma Kotecha 51250f94570dSGrishma Kotecha /* Update the previously created VSI list set with 51260f94570dSGrishma Kotecha * the new VSI ID passed in 51270f94570dSGrishma Kotecha */ 51280f94570dSGrishma Kotecha vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id; 51290f94570dSGrishma Kotecha 51300f94570dSGrishma Kotecha status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, 51310f94570dSGrishma Kotecha vsi_list_id, false, 51320f94570dSGrishma Kotecha ice_aqc_opc_update_sw_rules, 51330f94570dSGrishma Kotecha ICE_SW_LKUP_LAST); 51340f94570dSGrishma Kotecha /* update VSI list mapping info with new VSI ID */ 51350f94570dSGrishma Kotecha if (!status) 51360f94570dSGrishma Kotecha set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); 51370f94570dSGrishma Kotecha } 51380f94570dSGrishma Kotecha if (!status) 51390f94570dSGrishma Kotecha m_entry->vsi_count++; 51400f94570dSGrishma Kotecha return status; 51410f94570dSGrishma Kotecha } 51420f94570dSGrishma Kotecha 51430f94570dSGrishma Kotecha /** 51440f94570dSGrishma Kotecha * ice_add_adv_rule - helper function to create an advanced switch rule 51450f94570dSGrishma Kotecha * @hw: pointer to the hardware structure 51460f94570dSGrishma Kotecha * @lkups: information on the words that needs to be looked up. All words 51470f94570dSGrishma Kotecha * together makes one recipe 51480f94570dSGrishma Kotecha * @lkups_cnt: num of entries in the lkups array 51490f94570dSGrishma Kotecha * @rinfo: other information related to the rule that needs to be programmed 51500f94570dSGrishma Kotecha * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be 51510f94570dSGrishma Kotecha * ignored is case of error. 51520f94570dSGrishma Kotecha * 51530f94570dSGrishma Kotecha * This function can program only 1 rule at a time. The lkups is used to 51540f94570dSGrishma Kotecha * describe the all the words that forms the "lookup" portion of the recipe. 51550f94570dSGrishma Kotecha * These words can span multiple protocols. Callers to this function need to 51560f94570dSGrishma Kotecha * pass in a list of protocol headers with lookup information along and mask 51570f94570dSGrishma Kotecha * that determines which words are valid from the given protocol header. 51580f94570dSGrishma Kotecha * rinfo describes other information related to this rule such as forwarding 51590f94570dSGrishma Kotecha * IDs, priority of this rule, etc. 51600f94570dSGrishma Kotecha */ 51615e24d598STony Nguyen int 51620f94570dSGrishma Kotecha ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 51630f94570dSGrishma Kotecha u16 lkups_cnt, struct ice_adv_rule_info *rinfo, 51640f94570dSGrishma Kotecha struct ice_rule_query_data *added_entry) 51650f94570dSGrishma Kotecha { 51660f94570dSGrishma Kotecha struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL; 51670f94570dSGrishma Kotecha u16 rid = 0, i, pkt_len, rule_buf_sz, vsi_handle; 51680f94570dSGrishma Kotecha const struct ice_dummy_pkt_offsets *pkt_offsets; 51690f94570dSGrishma Kotecha struct ice_aqc_sw_rules_elem *s_rule = NULL; 51700f94570dSGrishma Kotecha struct list_head *rule_head; 51710f94570dSGrishma Kotecha struct ice_switch_info *sw; 51720f94570dSGrishma Kotecha const u8 *pkt = NULL; 51730f94570dSGrishma Kotecha u16 word_cnt; 51740f94570dSGrishma Kotecha u32 act = 0; 51755518ac2aSTony Nguyen int status; 51760f94570dSGrishma Kotecha u8 q_rgn; 51770f94570dSGrishma Kotecha 51780f94570dSGrishma Kotecha /* Initialize profile to result index bitmap */ 51790f94570dSGrishma Kotecha if (!hw->switch_info->prof_res_bm_init) { 51800f94570dSGrishma Kotecha hw->switch_info->prof_res_bm_init = 1; 51810f94570dSGrishma Kotecha ice_init_prof_result_bm(hw); 51820f94570dSGrishma Kotecha } 51830f94570dSGrishma Kotecha 51840f94570dSGrishma Kotecha if (!lkups_cnt) 5185d54699e2STony Nguyen return -EINVAL; 51860f94570dSGrishma Kotecha 51870f94570dSGrishma Kotecha /* get # of words we need to match */ 51880f94570dSGrishma Kotecha word_cnt = 0; 51890f94570dSGrishma Kotecha for (i = 0; i < lkups_cnt; i++) { 51900f94570dSGrishma Kotecha u16 j, *ptr; 51910f94570dSGrishma Kotecha 51920f94570dSGrishma Kotecha ptr = (u16 *)&lkups[i].m_u; 51930f94570dSGrishma Kotecha for (j = 0; j < sizeof(lkups->m_u) / sizeof(u16); j++) 51940f94570dSGrishma Kotecha if (ptr[j] != 0) 51950f94570dSGrishma Kotecha word_cnt++; 51960f94570dSGrishma Kotecha } 51970f94570dSGrishma Kotecha 51980f94570dSGrishma Kotecha if (!word_cnt || word_cnt > ICE_MAX_CHAIN_WORDS) 5199d54699e2STony Nguyen return -EINVAL; 52000f94570dSGrishma Kotecha 52010f94570dSGrishma Kotecha /* make sure that we can locate a dummy packet */ 52028b032a55SMichal Swiatkowski ice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type, &pkt, &pkt_len, 52030f94570dSGrishma Kotecha &pkt_offsets); 52040f94570dSGrishma Kotecha if (!pkt) { 5205d54699e2STony Nguyen status = -EINVAL; 52060f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 52070f94570dSGrishma Kotecha } 52080f94570dSGrishma Kotecha 52090f94570dSGrishma Kotecha if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || 52100f94570dSGrishma Kotecha rinfo->sw_act.fltr_act == ICE_FWD_TO_Q || 52110f94570dSGrishma Kotecha rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP || 52120f94570dSGrishma Kotecha rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) 5213d54699e2STony Nguyen return -EIO; 52140f94570dSGrishma Kotecha 52150f94570dSGrishma Kotecha vsi_handle = rinfo->sw_act.vsi_handle; 52160f94570dSGrishma Kotecha if (!ice_is_vsi_valid(hw, vsi_handle)) 5217d54699e2STony Nguyen return -EINVAL; 52180f94570dSGrishma Kotecha 52190f94570dSGrishma Kotecha if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) 52200f94570dSGrishma Kotecha rinfo->sw_act.fwd_id.hw_vsi_id = 52210f94570dSGrishma Kotecha ice_get_hw_vsi_num(hw, vsi_handle); 52220f94570dSGrishma Kotecha if (rinfo->sw_act.flag & ICE_FLTR_TX) 52230f94570dSGrishma Kotecha rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); 52240f94570dSGrishma Kotecha 52250f94570dSGrishma Kotecha status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid); 52260f94570dSGrishma Kotecha if (status) 52270f94570dSGrishma Kotecha return status; 52280f94570dSGrishma Kotecha m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo); 52290f94570dSGrishma Kotecha if (m_entry) { 52300f94570dSGrishma Kotecha /* we have to add VSI to VSI_LIST and increment vsi_count. 52310f94570dSGrishma Kotecha * Also Update VSI list so that we can change forwarding rule 52320f94570dSGrishma Kotecha * if the rule already exists, we will check if it exists with 52330f94570dSGrishma Kotecha * same vsi_id, if not then add it to the VSI list if it already 52340f94570dSGrishma Kotecha * exists if not then create a VSI list and add the existing VSI 52350f94570dSGrishma Kotecha * ID and the new VSI ID to the list 52360f94570dSGrishma Kotecha * We will add that VSI to the list 52370f94570dSGrishma Kotecha */ 52380f94570dSGrishma Kotecha status = ice_adv_add_update_vsi_list(hw, m_entry, 52390f94570dSGrishma Kotecha &m_entry->rule_info, 52400f94570dSGrishma Kotecha rinfo); 52410f94570dSGrishma Kotecha if (added_entry) { 52420f94570dSGrishma Kotecha added_entry->rid = rid; 52430f94570dSGrishma Kotecha added_entry->rule_id = m_entry->rule_info.fltr_rule_id; 52440f94570dSGrishma Kotecha added_entry->vsi_handle = rinfo->sw_act.vsi_handle; 52450f94570dSGrishma Kotecha } 52460f94570dSGrishma Kotecha return status; 52470f94570dSGrishma Kotecha } 52480f94570dSGrishma Kotecha rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE + pkt_len; 52490f94570dSGrishma Kotecha s_rule = kzalloc(rule_buf_sz, GFP_KERNEL); 52500f94570dSGrishma Kotecha if (!s_rule) 5251d54699e2STony Nguyen return -ENOMEM; 525273b483b7SWojciech Drewek if (!rinfo->flags_info.act_valid) { 525373b483b7SWojciech Drewek act |= ICE_SINGLE_ACT_LAN_ENABLE; 525473b483b7SWojciech Drewek act |= ICE_SINGLE_ACT_LB_ENABLE; 525573b483b7SWojciech Drewek } else { 525673b483b7SWojciech Drewek act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE | 525773b483b7SWojciech Drewek ICE_SINGLE_ACT_LB_ENABLE); 525873b483b7SWojciech Drewek } 525973b483b7SWojciech Drewek 52600f94570dSGrishma Kotecha switch (rinfo->sw_act.fltr_act) { 52610f94570dSGrishma Kotecha case ICE_FWD_TO_VSI: 52620f94570dSGrishma Kotecha act |= (rinfo->sw_act.fwd_id.hw_vsi_id << 52630f94570dSGrishma Kotecha ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M; 52640f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT; 52650f94570dSGrishma Kotecha break; 52660f94570dSGrishma Kotecha case ICE_FWD_TO_Q: 52670f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_TO_Q; 52680f94570dSGrishma Kotecha act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & 52690f94570dSGrishma Kotecha ICE_SINGLE_ACT_Q_INDEX_M; 52700f94570dSGrishma Kotecha break; 52710f94570dSGrishma Kotecha case ICE_FWD_TO_QGRP: 52720f94570dSGrishma Kotecha q_rgn = rinfo->sw_act.qgrp_size > 0 ? 52730f94570dSGrishma Kotecha (u8)ilog2(rinfo->sw_act.qgrp_size) : 0; 52740f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_TO_Q; 52750f94570dSGrishma Kotecha act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & 52760f94570dSGrishma Kotecha ICE_SINGLE_ACT_Q_INDEX_M; 52770f94570dSGrishma Kotecha act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & 52780f94570dSGrishma Kotecha ICE_SINGLE_ACT_Q_REGION_M; 52790f94570dSGrishma Kotecha break; 52800f94570dSGrishma Kotecha case ICE_DROP_PACKET: 52810f94570dSGrishma Kotecha act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | 52820f94570dSGrishma Kotecha ICE_SINGLE_ACT_VALID_BIT; 52830f94570dSGrishma Kotecha break; 52840f94570dSGrishma Kotecha default: 5285d54699e2STony Nguyen status = -EIO; 52860f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 52870f94570dSGrishma Kotecha } 52880f94570dSGrishma Kotecha 52890f94570dSGrishma Kotecha /* set the rule LOOKUP type based on caller specified 'Rx' 52900f94570dSGrishma Kotecha * instead of hardcoding it to be either LOOKUP_TX/RX 52910f94570dSGrishma Kotecha * 52920f94570dSGrishma Kotecha * for 'Rx' set the source to be the port number 52930f94570dSGrishma Kotecha * for 'Tx' set the source to be the source HW VSI number (determined 52940f94570dSGrishma Kotecha * by caller) 52950f94570dSGrishma Kotecha */ 52960f94570dSGrishma Kotecha if (rinfo->rx) { 52970f94570dSGrishma Kotecha s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); 52980f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.src = 52990f94570dSGrishma Kotecha cpu_to_le16(hw->port_info->lport); 53000f94570dSGrishma Kotecha } else { 53010f94570dSGrishma Kotecha s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); 53020f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(rinfo->sw_act.src); 53030f94570dSGrishma Kotecha } 53040f94570dSGrishma Kotecha 53050f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(rid); 53060f94570dSGrishma Kotecha s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act); 53070f94570dSGrishma Kotecha 53080f94570dSGrishma Kotecha status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, pkt, 53090f94570dSGrishma Kotecha pkt_len, pkt_offsets); 53100f94570dSGrishma Kotecha if (status) 53110f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 53120f94570dSGrishma Kotecha 53138b032a55SMichal Swiatkowski if (rinfo->tun_type != ICE_NON_TUN) { 53148b032a55SMichal Swiatkowski status = ice_fill_adv_packet_tun(hw, rinfo->tun_type, 53158b032a55SMichal Swiatkowski s_rule->pdata.lkup_tx_rx.hdr, 53168b032a55SMichal Swiatkowski pkt_offsets); 53178b032a55SMichal Swiatkowski if (status) 53188b032a55SMichal Swiatkowski goto err_ice_add_adv_rule; 53198b032a55SMichal Swiatkowski } 53208b032a55SMichal Swiatkowski 53210f94570dSGrishma Kotecha status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, 53220f94570dSGrishma Kotecha rule_buf_sz, 1, ice_aqc_opc_add_sw_rules, 53230f94570dSGrishma Kotecha NULL); 53240f94570dSGrishma Kotecha if (status) 53250f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 53260f94570dSGrishma Kotecha adv_fltr = devm_kzalloc(ice_hw_to_dev(hw), 53270f94570dSGrishma Kotecha sizeof(struct ice_adv_fltr_mgmt_list_entry), 53280f94570dSGrishma Kotecha GFP_KERNEL); 53290f94570dSGrishma Kotecha if (!adv_fltr) { 5330d54699e2STony Nguyen status = -ENOMEM; 53310f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 53320f94570dSGrishma Kotecha } 53330f94570dSGrishma Kotecha 53340f94570dSGrishma Kotecha adv_fltr->lkups = devm_kmemdup(ice_hw_to_dev(hw), lkups, 53350f94570dSGrishma Kotecha lkups_cnt * sizeof(*lkups), GFP_KERNEL); 53360f94570dSGrishma Kotecha if (!adv_fltr->lkups) { 5337d54699e2STony Nguyen status = -ENOMEM; 53380f94570dSGrishma Kotecha goto err_ice_add_adv_rule; 53390f94570dSGrishma Kotecha } 53400f94570dSGrishma Kotecha 53410f94570dSGrishma Kotecha adv_fltr->lkups_cnt = lkups_cnt; 53420f94570dSGrishma Kotecha adv_fltr->rule_info = *rinfo; 53430f94570dSGrishma Kotecha adv_fltr->rule_info.fltr_rule_id = 53440f94570dSGrishma Kotecha le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); 53450f94570dSGrishma Kotecha sw = hw->switch_info; 53460f94570dSGrishma Kotecha sw->recp_list[rid].adv_rule = true; 53470f94570dSGrishma Kotecha rule_head = &sw->recp_list[rid].filt_rules; 53480f94570dSGrishma Kotecha 53490f94570dSGrishma Kotecha if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) 53500f94570dSGrishma Kotecha adv_fltr->vsi_count = 1; 53510f94570dSGrishma Kotecha 53520f94570dSGrishma Kotecha /* Add rule entry to book keeping list */ 53530f94570dSGrishma Kotecha list_add(&adv_fltr->list_entry, rule_head); 53540f94570dSGrishma Kotecha if (added_entry) { 53550f94570dSGrishma Kotecha added_entry->rid = rid; 53560f94570dSGrishma Kotecha added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id; 53570f94570dSGrishma Kotecha added_entry->vsi_handle = rinfo->sw_act.vsi_handle; 53580f94570dSGrishma Kotecha } 53590f94570dSGrishma Kotecha err_ice_add_adv_rule: 53600f94570dSGrishma Kotecha if (status && adv_fltr) { 53610f94570dSGrishma Kotecha devm_kfree(ice_hw_to_dev(hw), adv_fltr->lkups); 53620f94570dSGrishma Kotecha devm_kfree(ice_hw_to_dev(hw), adv_fltr); 53630f94570dSGrishma Kotecha } 53640f94570dSGrishma Kotecha 53650f94570dSGrishma Kotecha kfree(s_rule); 53660f94570dSGrishma Kotecha 53670f94570dSGrishma Kotecha return status; 53680f94570dSGrishma Kotecha } 53690f94570dSGrishma Kotecha 53700f94570dSGrishma Kotecha /** 5371334cb062SAnirudh Venkataramanan * ice_replay_vsi_fltr - Replay filters for requested VSI 53720f9d5027SAnirudh Venkataramanan * @hw: pointer to the hardware structure 5373334cb062SAnirudh Venkataramanan * @vsi_handle: driver VSI handle 5374f9867df6SAnirudh Venkataramanan * @recp_id: Recipe ID for which rules need to be replayed 5375334cb062SAnirudh Venkataramanan * @list_head: list for which filters need to be replayed 5376334cb062SAnirudh Venkataramanan * 5377334cb062SAnirudh Venkataramanan * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. 5378334cb062SAnirudh Venkataramanan * It is required to pass valid VSI handle. 53790f9d5027SAnirudh Venkataramanan */ 53805e24d598STony Nguyen static int 5381334cb062SAnirudh Venkataramanan ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, 5382334cb062SAnirudh Venkataramanan struct list_head *list_head) 53830f9d5027SAnirudh Venkataramanan { 53840f9d5027SAnirudh Venkataramanan struct ice_fltr_mgmt_list_entry *itr; 53855e24d598STony Nguyen int status = 0; 5386334cb062SAnirudh Venkataramanan u16 hw_vsi_id; 53870f9d5027SAnirudh Venkataramanan 53880f9d5027SAnirudh Venkataramanan if (list_empty(list_head)) 53890f9d5027SAnirudh Venkataramanan return status; 5390334cb062SAnirudh Venkataramanan hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); 53910f9d5027SAnirudh Venkataramanan 5392334cb062SAnirudh Venkataramanan list_for_each_entry(itr, list_head, list_entry) { 53930f9d5027SAnirudh Venkataramanan struct ice_fltr_list_entry f_entry; 53940f9d5027SAnirudh Venkataramanan 53950f9d5027SAnirudh Venkataramanan f_entry.fltr_info = itr->fltr_info; 5396334cb062SAnirudh Venkataramanan if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && 5397334cb062SAnirudh Venkataramanan itr->fltr_info.vsi_handle == vsi_handle) { 5398f9867df6SAnirudh Venkataramanan /* update the src in case it is VSI num */ 5399334cb062SAnirudh Venkataramanan if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) 5400334cb062SAnirudh Venkataramanan f_entry.fltr_info.src = hw_vsi_id; 54010f9d5027SAnirudh Venkataramanan status = ice_add_rule_internal(hw, recp_id, &f_entry); 54020f9d5027SAnirudh Venkataramanan if (status) 54030f9d5027SAnirudh Venkataramanan goto end; 54040f9d5027SAnirudh Venkataramanan continue; 54050f9d5027SAnirudh Venkataramanan } 5406072f0c3dSDave Ertman if (!itr->vsi_list_info || 5407072f0c3dSDave Ertman !test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) 5408334cb062SAnirudh Venkataramanan continue; 5409334cb062SAnirudh Venkataramanan /* Clearing it so that the logic can add it back */ 5410334cb062SAnirudh Venkataramanan clear_bit(vsi_handle, itr->vsi_list_info->vsi_map); 5411334cb062SAnirudh Venkataramanan f_entry.fltr_info.vsi_handle = vsi_handle; 54120f9d5027SAnirudh Venkataramanan f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; 5413f9867df6SAnirudh Venkataramanan /* update the src in case it is VSI num */ 5414334cb062SAnirudh Venkataramanan if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) 5415334cb062SAnirudh Venkataramanan f_entry.fltr_info.src = hw_vsi_id; 54160f9d5027SAnirudh Venkataramanan if (recp_id == ICE_SW_LKUP_VLAN) 54170f9d5027SAnirudh Venkataramanan status = ice_add_vlan_internal(hw, &f_entry); 54180f9d5027SAnirudh Venkataramanan else 5419334cb062SAnirudh Venkataramanan status = ice_add_rule_internal(hw, recp_id, &f_entry); 54200f9d5027SAnirudh Venkataramanan if (status) 54210f9d5027SAnirudh Venkataramanan goto end; 54220f9d5027SAnirudh Venkataramanan } 54230f9d5027SAnirudh Venkataramanan end: 54240f9d5027SAnirudh Venkataramanan return status; 54250f9d5027SAnirudh Venkataramanan } 54260f9d5027SAnirudh Venkataramanan 54270f9d5027SAnirudh Venkataramanan /** 54288bb98f33SShivanshu Shukla * ice_adv_rem_update_vsi_list 54298bb98f33SShivanshu Shukla * @hw: pointer to the hardware structure 54308bb98f33SShivanshu Shukla * @vsi_handle: VSI handle of the VSI to remove 54318bb98f33SShivanshu Shukla * @fm_list: filter management entry for which the VSI list management needs to 54328bb98f33SShivanshu Shukla * be done 54338bb98f33SShivanshu Shukla */ 54345e24d598STony Nguyen static int 54358bb98f33SShivanshu Shukla ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, 54368bb98f33SShivanshu Shukla struct ice_adv_fltr_mgmt_list_entry *fm_list) 54378bb98f33SShivanshu Shukla { 54388bb98f33SShivanshu Shukla struct ice_vsi_list_map_info *vsi_list_info; 54398bb98f33SShivanshu Shukla enum ice_sw_lkup_type lkup_type; 54408bb98f33SShivanshu Shukla u16 vsi_list_id; 54415518ac2aSTony Nguyen int status; 54428bb98f33SShivanshu Shukla 54438bb98f33SShivanshu Shukla if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST || 54448bb98f33SShivanshu Shukla fm_list->vsi_count == 0) 5445d54699e2STony Nguyen return -EINVAL; 54468bb98f33SShivanshu Shukla 54478bb98f33SShivanshu Shukla /* A rule with the VSI being removed does not exist */ 54488bb98f33SShivanshu Shukla if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) 5449d54699e2STony Nguyen return -ENOENT; 54508bb98f33SShivanshu Shukla 54518bb98f33SShivanshu Shukla lkup_type = ICE_SW_LKUP_LAST; 54528bb98f33SShivanshu Shukla vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id; 54538bb98f33SShivanshu Shukla status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, 54548bb98f33SShivanshu Shukla ice_aqc_opc_update_sw_rules, 54558bb98f33SShivanshu Shukla lkup_type); 54568bb98f33SShivanshu Shukla if (status) 54578bb98f33SShivanshu Shukla return status; 54588bb98f33SShivanshu Shukla 54598bb98f33SShivanshu Shukla fm_list->vsi_count--; 54608bb98f33SShivanshu Shukla clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); 54618bb98f33SShivanshu Shukla vsi_list_info = fm_list->vsi_list_info; 54628bb98f33SShivanshu Shukla if (fm_list->vsi_count == 1) { 54638bb98f33SShivanshu Shukla struct ice_fltr_info tmp_fltr; 54648bb98f33SShivanshu Shukla u16 rem_vsi_handle; 54658bb98f33SShivanshu Shukla 54668bb98f33SShivanshu Shukla rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, 54678bb98f33SShivanshu Shukla ICE_MAX_VSI); 54688bb98f33SShivanshu Shukla if (!ice_is_vsi_valid(hw, rem_vsi_handle)) 5469d54699e2STony Nguyen return -EIO; 54708bb98f33SShivanshu Shukla 54718bb98f33SShivanshu Shukla /* Make sure VSI list is empty before removing it below */ 54728bb98f33SShivanshu Shukla status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, 54738bb98f33SShivanshu Shukla vsi_list_id, true, 54748bb98f33SShivanshu Shukla ice_aqc_opc_update_sw_rules, 54758bb98f33SShivanshu Shukla lkup_type); 54768bb98f33SShivanshu Shukla if (status) 54778bb98f33SShivanshu Shukla return status; 54788bb98f33SShivanshu Shukla 54798bb98f33SShivanshu Shukla memset(&tmp_fltr, 0, sizeof(tmp_fltr)); 54808bb98f33SShivanshu Shukla tmp_fltr.flag = fm_list->rule_info.sw_act.flag; 54818bb98f33SShivanshu Shukla tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id; 54828bb98f33SShivanshu Shukla fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI; 54838bb98f33SShivanshu Shukla tmp_fltr.fltr_act = ICE_FWD_TO_VSI; 54848bb98f33SShivanshu Shukla tmp_fltr.fwd_id.hw_vsi_id = 54858bb98f33SShivanshu Shukla ice_get_hw_vsi_num(hw, rem_vsi_handle); 54868bb98f33SShivanshu Shukla fm_list->rule_info.sw_act.fwd_id.hw_vsi_id = 54878bb98f33SShivanshu Shukla ice_get_hw_vsi_num(hw, rem_vsi_handle); 54888bb98f33SShivanshu Shukla fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle; 54898bb98f33SShivanshu Shukla 54908bb98f33SShivanshu Shukla /* Update the previous switch rule of "MAC forward to VSI" to 54918bb98f33SShivanshu Shukla * "MAC fwd to VSI list" 54928bb98f33SShivanshu Shukla */ 54938bb98f33SShivanshu Shukla status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); 54948bb98f33SShivanshu Shukla if (status) { 54958bb98f33SShivanshu Shukla ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n", 54968bb98f33SShivanshu Shukla tmp_fltr.fwd_id.hw_vsi_id, status); 54978bb98f33SShivanshu Shukla return status; 54988bb98f33SShivanshu Shukla } 54998bb98f33SShivanshu Shukla fm_list->vsi_list_info->ref_cnt--; 55008bb98f33SShivanshu Shukla 55018bb98f33SShivanshu Shukla /* Remove the VSI list since it is no longer used */ 55028bb98f33SShivanshu Shukla status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); 55038bb98f33SShivanshu Shukla if (status) { 55048bb98f33SShivanshu Shukla ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n", 55058bb98f33SShivanshu Shukla vsi_list_id, status); 55068bb98f33SShivanshu Shukla return status; 55078bb98f33SShivanshu Shukla } 55088bb98f33SShivanshu Shukla 55098bb98f33SShivanshu Shukla list_del(&vsi_list_info->list_entry); 55108bb98f33SShivanshu Shukla devm_kfree(ice_hw_to_dev(hw), vsi_list_info); 55118bb98f33SShivanshu Shukla fm_list->vsi_list_info = NULL; 55128bb98f33SShivanshu Shukla } 55138bb98f33SShivanshu Shukla 55148bb98f33SShivanshu Shukla return status; 55158bb98f33SShivanshu Shukla } 55168bb98f33SShivanshu Shukla 55178bb98f33SShivanshu Shukla /** 55188bb98f33SShivanshu Shukla * ice_rem_adv_rule - removes existing advanced switch rule 55198bb98f33SShivanshu Shukla * @hw: pointer to the hardware structure 55208bb98f33SShivanshu Shukla * @lkups: information on the words that needs to be looked up. All words 55218bb98f33SShivanshu Shukla * together makes one recipe 55228bb98f33SShivanshu Shukla * @lkups_cnt: num of entries in the lkups array 55238bb98f33SShivanshu Shukla * @rinfo: Its the pointer to the rule information for the rule 55248bb98f33SShivanshu Shukla * 55258bb98f33SShivanshu Shukla * This function can be used to remove 1 rule at a time. The lkups is 55268bb98f33SShivanshu Shukla * used to describe all the words that forms the "lookup" portion of the 55278bb98f33SShivanshu Shukla * rule. These words can span multiple protocols. Callers to this function 55288bb98f33SShivanshu Shukla * need to pass in a list of protocol headers with lookup information along 55298bb98f33SShivanshu Shukla * and mask that determines which words are valid from the given protocol 55308bb98f33SShivanshu Shukla * header. rinfo describes other information related to this rule such as 55318bb98f33SShivanshu Shukla * forwarding IDs, priority of this rule, etc. 55328bb98f33SShivanshu Shukla */ 55335e24d598STony Nguyen static int 55348bb98f33SShivanshu Shukla ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, 55358bb98f33SShivanshu Shukla u16 lkups_cnt, struct ice_adv_rule_info *rinfo) 55368bb98f33SShivanshu Shukla { 55378bb98f33SShivanshu Shukla struct ice_adv_fltr_mgmt_list_entry *list_elem; 55388bb98f33SShivanshu Shukla struct ice_prot_lkup_ext lkup_exts; 55398bb98f33SShivanshu Shukla bool remove_rule = false; 55408bb98f33SShivanshu Shukla struct mutex *rule_lock; /* Lock to protect filter rule list */ 55418bb98f33SShivanshu Shukla u16 i, rid, vsi_handle; 55425518ac2aSTony Nguyen int status = 0; 55438bb98f33SShivanshu Shukla 55448bb98f33SShivanshu Shukla memset(&lkup_exts, 0, sizeof(lkup_exts)); 55458bb98f33SShivanshu Shukla for (i = 0; i < lkups_cnt; i++) { 55468bb98f33SShivanshu Shukla u16 count; 55478bb98f33SShivanshu Shukla 55488bb98f33SShivanshu Shukla if (lkups[i].type >= ICE_PROTOCOL_LAST) 5549d54699e2STony Nguyen return -EIO; 55508bb98f33SShivanshu Shukla 55518bb98f33SShivanshu Shukla count = ice_fill_valid_words(&lkups[i], &lkup_exts); 55528bb98f33SShivanshu Shukla if (!count) 5553d54699e2STony Nguyen return -EIO; 55548bb98f33SShivanshu Shukla } 55558bb98f33SShivanshu Shukla 55568b032a55SMichal Swiatkowski /* Create any special protocol/offset pairs, such as looking at tunnel 55578b032a55SMichal Swiatkowski * bits by extracting metadata 55588b032a55SMichal Swiatkowski */ 55598b032a55SMichal Swiatkowski status = ice_add_special_words(rinfo, &lkup_exts); 55608b032a55SMichal Swiatkowski if (status) 55618b032a55SMichal Swiatkowski return status; 55628b032a55SMichal Swiatkowski 5563de6acd1cSMichal Swiatkowski rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type); 55648bb98f33SShivanshu Shukla /* If did not find a recipe that match the existing criteria */ 55658bb98f33SShivanshu Shukla if (rid == ICE_MAX_NUM_RECIPES) 5566d54699e2STony Nguyen return -EINVAL; 55678bb98f33SShivanshu Shukla 55688bb98f33SShivanshu Shukla rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock; 55698bb98f33SShivanshu Shukla list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo); 55708bb98f33SShivanshu Shukla /* the rule is already removed */ 55718bb98f33SShivanshu Shukla if (!list_elem) 55728bb98f33SShivanshu Shukla return 0; 55738bb98f33SShivanshu Shukla mutex_lock(rule_lock); 55748bb98f33SShivanshu Shukla if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) { 55758bb98f33SShivanshu Shukla remove_rule = true; 55768bb98f33SShivanshu Shukla } else if (list_elem->vsi_count > 1) { 55778bb98f33SShivanshu Shukla remove_rule = false; 55788bb98f33SShivanshu Shukla vsi_handle = rinfo->sw_act.vsi_handle; 55798bb98f33SShivanshu Shukla status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem); 55808bb98f33SShivanshu Shukla } else { 55818bb98f33SShivanshu Shukla vsi_handle = rinfo->sw_act.vsi_handle; 55828bb98f33SShivanshu Shukla status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem); 55838bb98f33SShivanshu Shukla if (status) { 55848bb98f33SShivanshu Shukla mutex_unlock(rule_lock); 55858bb98f33SShivanshu Shukla return status; 55868bb98f33SShivanshu Shukla } 55878bb98f33SShivanshu Shukla if (list_elem->vsi_count == 0) 55888bb98f33SShivanshu Shukla remove_rule = true; 55898bb98f33SShivanshu Shukla } 55908bb98f33SShivanshu Shukla mutex_unlock(rule_lock); 55918bb98f33SShivanshu Shukla if (remove_rule) { 55928bb98f33SShivanshu Shukla struct ice_aqc_sw_rules_elem *s_rule; 55938bb98f33SShivanshu Shukla u16 rule_buf_sz; 55948bb98f33SShivanshu Shukla 55958bb98f33SShivanshu Shukla rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE; 55968bb98f33SShivanshu Shukla s_rule = kzalloc(rule_buf_sz, GFP_KERNEL); 55978bb98f33SShivanshu Shukla if (!s_rule) 5598d54699e2STony Nguyen return -ENOMEM; 55998bb98f33SShivanshu Shukla s_rule->pdata.lkup_tx_rx.act = 0; 56008bb98f33SShivanshu Shukla s_rule->pdata.lkup_tx_rx.index = 56018bb98f33SShivanshu Shukla cpu_to_le16(list_elem->rule_info.fltr_rule_id); 56028bb98f33SShivanshu Shukla s_rule->pdata.lkup_tx_rx.hdr_len = 0; 56038bb98f33SShivanshu Shukla status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, 56048bb98f33SShivanshu Shukla rule_buf_sz, 1, 56058bb98f33SShivanshu Shukla ice_aqc_opc_remove_sw_rules, NULL); 5606d54699e2STony Nguyen if (!status || status == -ENOENT) { 56078bb98f33SShivanshu Shukla struct ice_switch_info *sw = hw->switch_info; 56088bb98f33SShivanshu Shukla 56098bb98f33SShivanshu Shukla mutex_lock(rule_lock); 56108bb98f33SShivanshu Shukla list_del(&list_elem->list_entry); 56118bb98f33SShivanshu Shukla devm_kfree(ice_hw_to_dev(hw), list_elem->lkups); 56128bb98f33SShivanshu Shukla devm_kfree(ice_hw_to_dev(hw), list_elem); 56138bb98f33SShivanshu Shukla mutex_unlock(rule_lock); 56148bb98f33SShivanshu Shukla if (list_empty(&sw->recp_list[rid].filt_rules)) 56158bb98f33SShivanshu Shukla sw->recp_list[rid].adv_rule = false; 56168bb98f33SShivanshu Shukla } 56178bb98f33SShivanshu Shukla kfree(s_rule); 56188bb98f33SShivanshu Shukla } 56198bb98f33SShivanshu Shukla return status; 56208bb98f33SShivanshu Shukla } 56218bb98f33SShivanshu Shukla 56228bb98f33SShivanshu Shukla /** 56238bb98f33SShivanshu Shukla * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID 56248bb98f33SShivanshu Shukla * @hw: pointer to the hardware structure 56258bb98f33SShivanshu Shukla * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID 56268bb98f33SShivanshu Shukla * 56278bb98f33SShivanshu Shukla * This function is used to remove 1 rule at a time. The removal is based on 56288bb98f33SShivanshu Shukla * the remove_entry parameter. This function will remove rule for a given 56298bb98f33SShivanshu Shukla * vsi_handle with a given rule_id which is passed as parameter in remove_entry 56308bb98f33SShivanshu Shukla */ 56315e24d598STony Nguyen int 56328bb98f33SShivanshu Shukla ice_rem_adv_rule_by_id(struct ice_hw *hw, 56338bb98f33SShivanshu Shukla struct ice_rule_query_data *remove_entry) 56348bb98f33SShivanshu Shukla { 56358bb98f33SShivanshu Shukla struct ice_adv_fltr_mgmt_list_entry *list_itr; 56368bb98f33SShivanshu Shukla struct list_head *list_head; 56378bb98f33SShivanshu Shukla struct ice_adv_rule_info rinfo; 56388bb98f33SShivanshu Shukla struct ice_switch_info *sw; 56398bb98f33SShivanshu Shukla 56408bb98f33SShivanshu Shukla sw = hw->switch_info; 56418bb98f33SShivanshu Shukla if (!sw->recp_list[remove_entry->rid].recp_created) 5642d54699e2STony Nguyen return -EINVAL; 56438bb98f33SShivanshu Shukla list_head = &sw->recp_list[remove_entry->rid].filt_rules; 56448bb98f33SShivanshu Shukla list_for_each_entry(list_itr, list_head, list_entry) { 56458bb98f33SShivanshu Shukla if (list_itr->rule_info.fltr_rule_id == 56468bb98f33SShivanshu Shukla remove_entry->rule_id) { 56478bb98f33SShivanshu Shukla rinfo = list_itr->rule_info; 56488bb98f33SShivanshu Shukla rinfo.sw_act.vsi_handle = remove_entry->vsi_handle; 56498bb98f33SShivanshu Shukla return ice_rem_adv_rule(hw, list_itr->lkups, 56508bb98f33SShivanshu Shukla list_itr->lkups_cnt, &rinfo); 56518bb98f33SShivanshu Shukla } 56528bb98f33SShivanshu Shukla } 56538bb98f33SShivanshu Shukla /* either list is empty or unable to find rule */ 5654d54699e2STony Nguyen return -ENOENT; 56558bb98f33SShivanshu Shukla } 56568bb98f33SShivanshu Shukla 56578bb98f33SShivanshu Shukla /** 5658c1e5da5dSWojciech Drewek * ice_rem_adv_rule_for_vsi - removes existing advanced switch rules for a 5659c1e5da5dSWojciech Drewek * given VSI handle 5660c1e5da5dSWojciech Drewek * @hw: pointer to the hardware structure 5661c1e5da5dSWojciech Drewek * @vsi_handle: VSI handle for which we are supposed to remove all the rules. 5662c1e5da5dSWojciech Drewek * 5663c1e5da5dSWojciech Drewek * This function is used to remove all the rules for a given VSI and as soon 5664c1e5da5dSWojciech Drewek * as removing a rule fails, it will return immediately with the error code, 5665c1e5da5dSWojciech Drewek * else it will return success. 5666c1e5da5dSWojciech Drewek */ 5667c1e5da5dSWojciech Drewek int ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle) 5668c1e5da5dSWojciech Drewek { 5669c1e5da5dSWojciech Drewek struct ice_adv_fltr_mgmt_list_entry *list_itr, *tmp_entry; 5670c1e5da5dSWojciech Drewek struct ice_vsi_list_map_info *map_info; 5671c1e5da5dSWojciech Drewek struct ice_adv_rule_info rinfo; 5672c1e5da5dSWojciech Drewek struct list_head *list_head; 5673c1e5da5dSWojciech Drewek struct ice_switch_info *sw; 5674c1e5da5dSWojciech Drewek int status; 5675c1e5da5dSWojciech Drewek u8 rid; 5676c1e5da5dSWojciech Drewek 5677c1e5da5dSWojciech Drewek sw = hw->switch_info; 5678c1e5da5dSWojciech Drewek for (rid = 0; rid < ICE_MAX_NUM_RECIPES; rid++) { 5679c1e5da5dSWojciech Drewek if (!sw->recp_list[rid].recp_created) 5680c1e5da5dSWojciech Drewek continue; 5681c1e5da5dSWojciech Drewek if (!sw->recp_list[rid].adv_rule) 5682c1e5da5dSWojciech Drewek continue; 5683c1e5da5dSWojciech Drewek 5684c1e5da5dSWojciech Drewek list_head = &sw->recp_list[rid].filt_rules; 5685c1e5da5dSWojciech Drewek list_for_each_entry_safe(list_itr, tmp_entry, list_head, 5686c1e5da5dSWojciech Drewek list_entry) { 5687c1e5da5dSWojciech Drewek rinfo = list_itr->rule_info; 5688c1e5da5dSWojciech Drewek 5689c1e5da5dSWojciech Drewek if (rinfo.sw_act.fltr_act == ICE_FWD_TO_VSI_LIST) { 5690c1e5da5dSWojciech Drewek map_info = list_itr->vsi_list_info; 5691c1e5da5dSWojciech Drewek if (!map_info) 5692c1e5da5dSWojciech Drewek continue; 5693c1e5da5dSWojciech Drewek 5694c1e5da5dSWojciech Drewek if (!test_bit(vsi_handle, map_info->vsi_map)) 5695c1e5da5dSWojciech Drewek continue; 5696c1e5da5dSWojciech Drewek } else if (rinfo.sw_act.vsi_handle != vsi_handle) { 5697c1e5da5dSWojciech Drewek continue; 5698c1e5da5dSWojciech Drewek } 5699c1e5da5dSWojciech Drewek 5700c1e5da5dSWojciech Drewek rinfo.sw_act.vsi_handle = vsi_handle; 5701c1e5da5dSWojciech Drewek status = ice_rem_adv_rule(hw, list_itr->lkups, 5702c1e5da5dSWojciech Drewek list_itr->lkups_cnt, &rinfo); 5703c1e5da5dSWojciech Drewek if (status) 5704c1e5da5dSWojciech Drewek return status; 5705c1e5da5dSWojciech Drewek } 5706c1e5da5dSWojciech Drewek } 5707c1e5da5dSWojciech Drewek return 0; 5708c1e5da5dSWojciech Drewek } 5709c1e5da5dSWojciech Drewek 5710c1e5da5dSWojciech Drewek /** 5711c36a2b97SVictor Raj * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI 5712c36a2b97SVictor Raj * @hw: pointer to the hardware structure 5713c36a2b97SVictor Raj * @vsi_handle: driver VSI handle 5714c36a2b97SVictor Raj * @list_head: list for which filters need to be replayed 5715c36a2b97SVictor Raj * 5716c36a2b97SVictor Raj * Replay the advanced rule for the given VSI. 5717c36a2b97SVictor Raj */ 5718c36a2b97SVictor Raj static int 5719c36a2b97SVictor Raj ice_replay_vsi_adv_rule(struct ice_hw *hw, u16 vsi_handle, 5720c36a2b97SVictor Raj struct list_head *list_head) 5721c36a2b97SVictor Raj { 5722c36a2b97SVictor Raj struct ice_rule_query_data added_entry = { 0 }; 5723c36a2b97SVictor Raj struct ice_adv_fltr_mgmt_list_entry *adv_fltr; 5724c36a2b97SVictor Raj int status = 0; 5725c36a2b97SVictor Raj 5726c36a2b97SVictor Raj if (list_empty(list_head)) 5727c36a2b97SVictor Raj return status; 5728c36a2b97SVictor Raj list_for_each_entry(adv_fltr, list_head, list_entry) { 5729c36a2b97SVictor Raj struct ice_adv_rule_info *rinfo = &adv_fltr->rule_info; 5730c36a2b97SVictor Raj u16 lk_cnt = adv_fltr->lkups_cnt; 5731c36a2b97SVictor Raj 5732c36a2b97SVictor Raj if (vsi_handle != rinfo->sw_act.vsi_handle) 5733c36a2b97SVictor Raj continue; 5734c36a2b97SVictor Raj status = ice_add_adv_rule(hw, adv_fltr->lkups, lk_cnt, rinfo, 5735c36a2b97SVictor Raj &added_entry); 5736c36a2b97SVictor Raj if (status) 5737c36a2b97SVictor Raj break; 5738c36a2b97SVictor Raj } 5739c36a2b97SVictor Raj return status; 5740c36a2b97SVictor Raj } 5741c36a2b97SVictor Raj 5742c36a2b97SVictor Raj /** 5743334cb062SAnirudh Venkataramanan * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists 57440f9d5027SAnirudh Venkataramanan * @hw: pointer to the hardware structure 5745334cb062SAnirudh Venkataramanan * @vsi_handle: driver VSI handle 57460f9d5027SAnirudh Venkataramanan * 5747334cb062SAnirudh Venkataramanan * Replays filters for requested VSI via vsi_handle. 57480f9d5027SAnirudh Venkataramanan */ 57495e24d598STony Nguyen int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) 57500f9d5027SAnirudh Venkataramanan { 57510f9d5027SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 5752c36a2b97SVictor Raj int status; 57530f9d5027SAnirudh Venkataramanan u8 i; 57540f9d5027SAnirudh Venkataramanan 5755c36a2b97SVictor Raj for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { 5756334cb062SAnirudh Venkataramanan struct list_head *head; 57570f9d5027SAnirudh Venkataramanan 5758334cb062SAnirudh Venkataramanan head = &sw->recp_list[i].filt_replay_rules; 5759c36a2b97SVictor Raj if (!sw->recp_list[i].adv_rule) 5760334cb062SAnirudh Venkataramanan status = ice_replay_vsi_fltr(hw, vsi_handle, i, head); 5761c36a2b97SVictor Raj else 5762c36a2b97SVictor Raj status = ice_replay_vsi_adv_rule(hw, vsi_handle, head); 57630f9d5027SAnirudh Venkataramanan if (status) 57640f9d5027SAnirudh Venkataramanan return status; 57650f9d5027SAnirudh Venkataramanan } 57660f9d5027SAnirudh Venkataramanan return status; 57670f9d5027SAnirudh Venkataramanan } 5768334cb062SAnirudh Venkataramanan 5769334cb062SAnirudh Venkataramanan /** 5770334cb062SAnirudh Venkataramanan * ice_rm_all_sw_replay_rule_info - deletes filter replay rules 5771f9867df6SAnirudh Venkataramanan * @hw: pointer to the HW struct 5772334cb062SAnirudh Venkataramanan * 5773334cb062SAnirudh Venkataramanan * Deletes the filter replay rules. 5774334cb062SAnirudh Venkataramanan */ 5775334cb062SAnirudh Venkataramanan void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) 5776334cb062SAnirudh Venkataramanan { 5777334cb062SAnirudh Venkataramanan struct ice_switch_info *sw = hw->switch_info; 5778334cb062SAnirudh Venkataramanan u8 i; 5779334cb062SAnirudh Venkataramanan 5780334cb062SAnirudh Venkataramanan if (!sw) 5781334cb062SAnirudh Venkataramanan return; 5782334cb062SAnirudh Venkataramanan 57838b8ef05bSVictor Raj for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { 5784334cb062SAnirudh Venkataramanan if (!list_empty(&sw->recp_list[i].filt_replay_rules)) { 5785334cb062SAnirudh Venkataramanan struct list_head *l_head; 5786334cb062SAnirudh Venkataramanan 5787334cb062SAnirudh Venkataramanan l_head = &sw->recp_list[i].filt_replay_rules; 57888b8ef05bSVictor Raj if (!sw->recp_list[i].adv_rule) 5789334cb062SAnirudh Venkataramanan ice_rem_sw_rule_info(hw, l_head); 57908b8ef05bSVictor Raj else 57918b8ef05bSVictor Raj ice_rem_adv_rule_info(hw, l_head); 5792334cb062SAnirudh Venkataramanan } 5793334cb062SAnirudh Venkataramanan } 5794334cb062SAnirudh Venkataramanan } 5795