aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-10-26 19:33:28 -0400
committerBen Hutchings <bhutchings@solarflare.com>2013-08-22 14:25:53 -0400
commit7c460d9be6109834da86052c4d4a9bb0be9cd407 (patch)
tree8f93ef9333fed351a9fea98719d010f52e9ebc91 /drivers/net/ethernet/sfc
parentf26e958cfce0522832a5d593943948e6b61c3126 (diff)
sfc: Extend and abstract efx_filter_spec to cover Huntington/EF10
Replace type field with match_flags. Add rss_context and match values covering of most of what is now in the MCDI protocol. Change some fields into bitfields so that the structure size doesn't grow beyond 64 bytes. Ditch the filter decoding functions as it is now easier to pick apart the abstract structure. Rewrite ethtool NFC rule functions to set/get filter match flags and values directly. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c211
-rw-r--r--drivers/net/ethernet/sfc/filter.c455
-rw-r--r--drivers/net/ethernet/sfc/filter.h220
3 files changed, 494 insertions, 392 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index ec5cacd427ec..58ae28b8820d 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -799,11 +799,12 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
799 return efx_reset(efx, rc); 799 return efx_reset(efx, rc);
800} 800}
801 801
802/* MAC address mask including only MC flag */ 802/* MAC address mask including only I/G bit */
803static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; 803static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
804 804
805#define IP4_ADDR_FULL_MASK ((__force __be32)~0) 805#define IP4_ADDR_FULL_MASK ((__force __be32)~0)
806#define PORT_FULL_MASK ((__force __be16)~0) 806#define PORT_FULL_MASK ((__force __be16)~0)
807#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
807 808
808static int efx_ethtool_get_class_rule(struct efx_nic *efx, 809static int efx_ethtool_get_class_rule(struct efx_nic *efx,
809 struct ethtool_rx_flow_spec *rule) 810 struct ethtool_rx_flow_spec *rule)
@@ -813,8 +814,6 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
813 struct ethhdr *mac_entry = &rule->h_u.ether_spec; 814 struct ethhdr *mac_entry = &rule->h_u.ether_spec;
814 struct ethhdr *mac_mask = &rule->m_u.ether_spec; 815 struct ethhdr *mac_mask = &rule->m_u.ether_spec;
815 struct efx_filter_spec spec; 816 struct efx_filter_spec spec;
816 u16 vid;
817 u8 proto;
818 int rc; 817 int rc;
819 818
820 rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL, 819 rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL,
@@ -827,39 +826,67 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
827 else 826 else
828 rule->ring_cookie = spec.dmaq_id; 827 rule->ring_cookie = spec.dmaq_id;
829 828
830 if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) { 829 if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) &&
831 rule->flow_type = ETHER_FLOW; 830 spec.ether_type == htons(ETH_P_IP) &&
832 memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN); 831 (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) &&
833 if (spec.type == EFX_FILTER_MC_DEF) 832 (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) &&
834 memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN); 833 !(spec.match_flags &
835 return 0; 834 ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID |
836 } 835 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST |
837 836 EFX_FILTER_MATCH_IP_PROTO |
838 rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest); 837 EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) {
839 if (rc == 0) { 838 rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ?
839 TCP_V4_FLOW : UDP_V4_FLOW);
840 if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) {
841 ip_entry->ip4dst = spec.loc_host[0];
842 ip_mask->ip4dst = IP4_ADDR_FULL_MASK;
843 }
844 if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) {
845 ip_entry->ip4src = spec.rem_host[0];
846 ip_mask->ip4src = IP4_ADDR_FULL_MASK;
847 }
848 if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) {
849 ip_entry->pdst = spec.loc_port;
850 ip_mask->pdst = PORT_FULL_MASK;
851 }
852 if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) {
853 ip_entry->psrc = spec.rem_port;
854 ip_mask->psrc = PORT_FULL_MASK;
855 }
856 } else if (!(spec.match_flags &
857 ~(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG |
858 EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_ETHER_TYPE |
859 EFX_FILTER_MATCH_OUTER_VID))) {
840 rule->flow_type = ETHER_FLOW; 860 rule->flow_type = ETHER_FLOW;
841 memset(mac_mask->h_dest, ~0, ETH_ALEN); 861 if (spec.match_flags &
842 if (vid != EFX_FILTER_VID_UNSPEC) { 862 (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) {
843 rule->flow_type |= FLOW_EXT; 863 memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN);
844 rule->h_ext.vlan_tci = htons(vid); 864 if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC)
845 rule->m_ext.vlan_tci = htons(0xfff); 865 memset(mac_mask->h_dest, ~0, ETH_ALEN);
866 else
867 memcpy(mac_mask->h_dest, mac_addr_ig_mask,
868 ETH_ALEN);
846 } 869 }
847 return 0; 870 if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) {
871 memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN);
872 memset(mac_mask->h_source, ~0, ETH_ALEN);
873 }
874 if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {
875 mac_entry->h_proto = spec.ether_type;
876 mac_mask->h_proto = ETHER_TYPE_FULL_MASK;
877 }
878 } else {
879 /* The above should handle all filters that we insert */
880 WARN_ON(1);
881 return -EINVAL;
848 } 882 }
849 883
850 rc = efx_filter_get_ipv4_local(&spec, &proto, 884 if (spec.match_flags & EFX_FILTER_MATCH_OUTER_VID) {
851 &ip_entry->ip4dst, &ip_entry->pdst); 885 rule->flow_type |= FLOW_EXT;
852 if (rc != 0) { 886 rule->h_ext.vlan_tci = spec.outer_vid;
853 rc = efx_filter_get_ipv4_full( 887 rule->m_ext.vlan_tci = htons(0xfff);
854 &spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst,
855 &ip_entry->ip4src, &ip_entry->psrc);
856 EFX_WARN_ON_PARANOID(rc);
857 ip_mask->ip4src = IP4_ADDR_FULL_MASK;
858 ip_mask->psrc = PORT_FULL_MASK;
859 } 888 }
860 rule->flow_type = (proto == IPPROTO_TCP) ? TCP_V4_FLOW : UDP_V4_FLOW; 889
861 ip_mask->ip4dst = IP4_ADDR_FULL_MASK;
862 ip_mask->pdst = PORT_FULL_MASK;
863 return rc; 890 return rc;
864} 891}
865 892
@@ -969,80 +996,78 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
969 (rule->ring_cookie == RX_CLS_FLOW_DISC) ? 996 (rule->ring_cookie == RX_CLS_FLOW_DISC) ?
970 EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie); 997 EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie);
971 998
972 switch (rule->flow_type) { 999 switch (rule->flow_type & ~FLOW_EXT) {
973 case TCP_V4_FLOW: 1000 case TCP_V4_FLOW:
974 case UDP_V4_FLOW: { 1001 case UDP_V4_FLOW:
975 u8 proto = (rule->flow_type == TCP_V4_FLOW ? 1002 spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE |
976 IPPROTO_TCP : IPPROTO_UDP); 1003 EFX_FILTER_MATCH_IP_PROTO);
977 1004 spec.ether_type = htons(ETH_P_IP);
978 /* Must match all of destination, */ 1005 spec.ip_proto = ((rule->flow_type & ~FLOW_EXT) == TCP_V4_FLOW ?
979 if (!(ip_mask->ip4dst == IP4_ADDR_FULL_MASK && 1006 IPPROTO_TCP : IPPROTO_UDP);
980 ip_mask->pdst == PORT_FULL_MASK)) 1007 if (ip_mask->ip4dst) {
981 return -EINVAL; 1008 if (ip_mask->ip4dst != IP4_ADDR_FULL_MASK)
982 /* all or none of source, */ 1009 return -EINVAL;
983 if ((ip_mask->ip4src || ip_mask->psrc) && 1010 spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST;
984 !(ip_mask->ip4src == IP4_ADDR_FULL_MASK && 1011 spec.loc_host[0] = ip_entry->ip4dst;
985 ip_mask->psrc == PORT_FULL_MASK)) 1012 }
986 return -EINVAL; 1013 if (ip_mask->ip4src) {
987 /* and nothing else */ 1014 if (ip_mask->ip4src != IP4_ADDR_FULL_MASK)
988 if (ip_mask->tos || rule->m_ext.vlan_tci) 1015 return -EINVAL;
1016 spec.match_flags |= EFX_FILTER_MATCH_REM_HOST;
1017 spec.rem_host[0] = ip_entry->ip4src;
1018 }
1019 if (ip_mask->pdst) {
1020 if (ip_mask->pdst != PORT_FULL_MASK)
1021 return -EINVAL;
1022 spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT;
1023 spec.loc_port = ip_entry->pdst;
1024 }
1025 if (ip_mask->psrc) {
1026 if (ip_mask->psrc != PORT_FULL_MASK)
1027 return -EINVAL;
1028 spec.match_flags |= EFX_FILTER_MATCH_REM_PORT;
1029 spec.rem_port = ip_entry->psrc;
1030 }
1031 if (ip_mask->tos)
989 return -EINVAL; 1032 return -EINVAL;
990
991 if (ip_mask->ip4src)
992 rc = efx_filter_set_ipv4_full(&spec, proto,
993 ip_entry->ip4dst,
994 ip_entry->pdst,
995 ip_entry->ip4src,
996 ip_entry->psrc);
997 else
998 rc = efx_filter_set_ipv4_local(&spec, proto,
999 ip_entry->ip4dst,
1000 ip_entry->pdst);
1001 if (rc)
1002 return rc;
1003 break; 1033 break;
1004 }
1005
1006 case ETHER_FLOW | FLOW_EXT:
1007 case ETHER_FLOW: {
1008 u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ?
1009 ntohs(rule->m_ext.vlan_tci) : 0);
1010 1034
1011 /* Must not match on source address or Ethertype */ 1035 case ETHER_FLOW:
1012 if (!is_zero_ether_addr(mac_mask->h_source) || 1036 if (!is_zero_ether_addr(mac_mask->h_dest)) {
1013 mac_mask->h_proto) 1037 if (ether_addr_equal(mac_mask->h_dest,
1014 return -EINVAL; 1038 mac_addr_ig_mask))
1015 1039 spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
1016 /* Is it a default UC or MC filter? */ 1040 else if (is_broadcast_ether_addr(mac_mask->h_dest))
1017 if (ether_addr_equal(mac_mask->h_dest, mac_addr_mc_mask) && 1041 spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC;
1018 vlan_tag_mask == 0) {
1019 if (is_multicast_ether_addr(mac_entry->h_dest))
1020 rc = efx_filter_set_mc_def(&spec);
1021 else 1042 else
1022 rc = efx_filter_set_uc_def(&spec); 1043 return -EINVAL;
1044 memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN);
1023 } 1045 }
1024 /* Otherwise, it must match all of destination and all 1046 if (!is_zero_ether_addr(mac_mask->h_source)) {
1025 * or none of VID. 1047 if (!is_broadcast_ether_addr(mac_mask->h_source))
1026 */ 1048 return -EINVAL;
1027 else if (is_broadcast_ether_addr(mac_mask->h_dest) && 1049 spec.match_flags |= EFX_FILTER_MATCH_REM_MAC;
1028 (vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) { 1050 memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN);
1029 rc = efx_filter_set_eth_local( 1051 }
1030 &spec, 1052 if (mac_mask->h_proto) {
1031 vlan_tag_mask ? 1053 if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK)
1032 ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, 1054 return -EINVAL;
1033 mac_entry->h_dest); 1055 spec.match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
1034 } else { 1056 spec.ether_type = mac_entry->h_proto;
1035 rc = -EINVAL;
1036 } 1057 }
1037 if (rc)
1038 return rc;
1039 break; 1058 break;
1040 }
1041 1059
1042 default: 1060 default:
1043 return -EINVAL; 1061 return -EINVAL;
1044 } 1062 }
1045 1063
1064 if ((rule->flow_type & FLOW_EXT) && rule->m_ext.vlan_tci) {
1065 if (rule->m_ext.vlan_tci != htons(0xfff))
1066 return -EINVAL;
1067 spec.match_flags |= EFX_FILTER_MATCH_OUTER_VID;
1068 spec.outer_vid = rule->h_ext.vlan_tci;
1069 }
1070
1046 rc = efx_filter_insert_filter(efx, &spec, true); 1071 rc = efx_filter_insert_filter(efx, &spec, true);
1047 if (rc < 0) 1072 if (rc < 0)
1048 return rc; 1073 return rc;
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index c547630cfee4..96f8f2e34403 100644
--- a/drivers/net/ethernet/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
@@ -32,6 +32,18 @@
32 * counter-productive. */ 32 * counter-productive. */
33#define EFX_FARCH_FILTER_CTL_SRCH_HINT_MAX 5 33#define EFX_FARCH_FILTER_CTL_SRCH_HINT_MAX 5
34 34
35enum efx_farch_filter_type {
36 EFX_FARCH_FILTER_TCP_FULL = 0,
37 EFX_FARCH_FILTER_TCP_WILD,
38 EFX_FARCH_FILTER_UDP_FULL,
39 EFX_FARCH_FILTER_UDP_WILD,
40 EFX_FARCH_FILTER_MAC_FULL = 4,
41 EFX_FARCH_FILTER_MAC_WILD,
42 EFX_FARCH_FILTER_UC_DEF = 8,
43 EFX_FARCH_FILTER_MC_DEF,
44 EFX_FARCH_FILTER_TYPE_COUNT, /* number of specific types */
45};
46
35enum efx_farch_filter_table_id { 47enum efx_farch_filter_table_id {
36 EFX_FARCH_FILTER_TABLE_RX_IP = 0, 48 EFX_FARCH_FILTER_TABLE_RX_IP = 0,
37 EFX_FARCH_FILTER_TABLE_RX_MAC, 49 EFX_FARCH_FILTER_TABLE_RX_MAC,
@@ -62,7 +74,7 @@ struct efx_farch_filter_table {
62 unsigned used; /* number currently used */ 74 unsigned used; /* number currently used */
63 unsigned long *used_bitmap; 75 unsigned long *used_bitmap;
64 struct efx_farch_filter_spec *spec; 76 struct efx_farch_filter_spec *spec;
65 unsigned search_depth[EFX_FILTER_TYPE_COUNT]; 77 unsigned search_depth[EFX_FARCH_FILTER_TYPE_COUNT];
66}; 78};
67 79
68struct efx_filter_state { 80struct efx_filter_state {
@@ -106,33 +118,22 @@ static enum efx_farch_filter_table_id
106efx_farch_filter_spec_table_id(const struct efx_farch_filter_spec *spec) 118efx_farch_filter_spec_table_id(const struct efx_farch_filter_spec *spec)
107{ 119{
108 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != 120 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP !=
109 (EFX_FILTER_TCP_FULL >> 2)); 121 (EFX_FARCH_FILTER_TCP_FULL >> 2));
110 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != 122 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP !=
111 (EFX_FILTER_TCP_WILD >> 2)); 123 (EFX_FARCH_FILTER_TCP_WILD >> 2));
112 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != 124 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP !=
113 (EFX_FILTER_UDP_FULL >> 2)); 125 (EFX_FARCH_FILTER_UDP_FULL >> 2));
114 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != 126 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP !=
115 (EFX_FILTER_UDP_WILD >> 2)); 127 (EFX_FARCH_FILTER_UDP_WILD >> 2));
116 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC != 128 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC !=
117 (EFX_FILTER_MAC_FULL >> 2)); 129 (EFX_FARCH_FILTER_MAC_FULL >> 2));
118 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC != 130 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC !=
119 (EFX_FILTER_MAC_WILD >> 2)); 131 (EFX_FARCH_FILTER_MAC_WILD >> 2));
120 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_TX_MAC != 132 BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_TX_MAC !=
121 EFX_FARCH_FILTER_TABLE_RX_MAC + 2); 133 EFX_FARCH_FILTER_TABLE_RX_MAC + 2);
122 EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC);
123 return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0); 134 return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0);
124} 135}
125 136
126static struct efx_farch_filter_table *
127efx_farch_filter_spec_table(struct efx_filter_state *state,
128 const struct efx_farch_filter_spec *spec)
129{
130 if (spec->type == EFX_FILTER_UNSPEC)
131 return NULL;
132 else
133 return &state->table[efx_farch_filter_spec_table_id(spec)];
134}
135
136static void 137static void
137efx_farch_filter_table_reset_search_depth(struct efx_farch_filter_table *table) 138efx_farch_filter_table_reset_search_depth(struct efx_farch_filter_table *table)
138{ 139{
@@ -149,27 +150,27 @@ static void efx_farch_filter_push_rx_config(struct efx_nic *efx)
149 150
150 table = &state->table[EFX_FARCH_FILTER_TABLE_RX_IP]; 151 table = &state->table[EFX_FARCH_FILTER_TABLE_RX_IP];
151 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT, 152 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT,
152 table->search_depth[EFX_FILTER_TCP_FULL] + 153 table->search_depth[EFX_FARCH_FILTER_TCP_FULL] +
153 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); 154 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL);
154 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT, 155 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT,
155 table->search_depth[EFX_FILTER_TCP_WILD] + 156 table->search_depth[EFX_FARCH_FILTER_TCP_WILD] +
156 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); 157 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD);
157 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT, 158 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT,
158 table->search_depth[EFX_FILTER_UDP_FULL] + 159 table->search_depth[EFX_FARCH_FILTER_UDP_FULL] +
159 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); 160 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL);
160 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT, 161 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT,
161 table->search_depth[EFX_FILTER_UDP_WILD] + 162 table->search_depth[EFX_FARCH_FILTER_UDP_WILD] +
162 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); 163 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD);
163 164
164 table = &state->table[EFX_FARCH_FILTER_TABLE_RX_MAC]; 165 table = &state->table[EFX_FARCH_FILTER_TABLE_RX_MAC];
165 if (table->size) { 166 if (table->size) {
166 EFX_SET_OWORD_FIELD( 167 EFX_SET_OWORD_FIELD(
167 filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, 168 filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
168 table->search_depth[EFX_FILTER_MAC_FULL] + 169 table->search_depth[EFX_FARCH_FILTER_MAC_FULL] +
169 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); 170 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL);
170 EFX_SET_OWORD_FIELD( 171 EFX_SET_OWORD_FIELD(
171 filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, 172 filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
172 table->search_depth[EFX_FILTER_MAC_WILD] + 173 table->search_depth[EFX_FARCH_FILTER_MAC_WILD] +
173 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); 174 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD);
174 } 175 }
175 176
@@ -225,223 +226,202 @@ static void efx_farch_filter_push_tx_limits(struct efx_nic *efx)
225 if (table->size) { 226 if (table->size) {
226 EFX_SET_OWORD_FIELD( 227 EFX_SET_OWORD_FIELD(
227 tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, 228 tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
228 table->search_depth[EFX_FILTER_MAC_FULL] + 229 table->search_depth[EFX_FARCH_FILTER_MAC_FULL] +
229 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); 230 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL);
230 EFX_SET_OWORD_FIELD( 231 EFX_SET_OWORD_FIELD(
231 tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, 232 tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
232 table->search_depth[EFX_FILTER_MAC_WILD] + 233 table->search_depth[EFX_FARCH_FILTER_MAC_WILD] +
233 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); 234 EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD);
234 } 235 }
235 236
236 efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG); 237 efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG);
237} 238}
238 239
239static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec, 240static int
240 __be32 host1, __be16 port1, 241efx_farch_filter_from_gen_spec(struct efx_farch_filter_spec *spec,
241 __be32 host2, __be16 port2) 242 const struct efx_filter_spec *gen_spec)
242{
243 spec->data[0] = ntohl(host1) << 16 | ntohs(port1);
244 spec->data[1] = ntohs(port2) << 16 | ntohl(host1) >> 16;
245 spec->data[2] = ntohl(host2);
246}
247
248static inline void __efx_filter_get_ipv4(const struct efx_filter_spec *spec,
249 __be32 *host1, __be16 *port1,
250 __be32 *host2, __be16 *port2)
251{
252 *host1 = htonl(spec->data[0] >> 16 | spec->data[1] << 16);
253 *port1 = htons(spec->data[0]);
254 *host2 = htonl(spec->data[2]);
255 *port2 = htons(spec->data[1] >> 16);
256}
257
258/**
259 * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port
260 * @spec: Specification to initialise
261 * @proto: Transport layer protocol number
262 * @host: Local host address (network byte order)
263 * @port: Local port (network byte order)
264 */
265int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
266 __be32 host, __be16 port)
267{ 243{
268 __be32 host1; 244 bool is_full = false;
269 __be16 port1;
270
271 EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
272
273 /* This cannot currently be combined with other filtering */
274 if (spec->type != EFX_FILTER_UNSPEC)
275 return -EPROTONOSUPPORT;
276 245
277 if (port == 0) 246 if ((gen_spec->flags & EFX_FILTER_FLAG_RX_RSS) &&
247 gen_spec->rss_context != EFX_FILTER_RSS_CONTEXT_DEFAULT)
278 return -EINVAL; 248 return -EINVAL;
279 249
280 switch (proto) { 250 spec->priority = gen_spec->priority;
281 case IPPROTO_TCP: 251 spec->flags = gen_spec->flags;
282 spec->type = EFX_FILTER_TCP_WILD; 252 spec->dmaq_id = gen_spec->dmaq_id;
283 break;
284 case IPPROTO_UDP:
285 spec->type = EFX_FILTER_UDP_WILD;
286 break;
287 default:
288 return -EPROTONOSUPPORT;
289 }
290
291 /* Filter is constructed in terms of source and destination,
292 * with the odd wrinkle that the ports are swapped in a UDP
293 * wildcard filter. We need to convert from local and remote
294 * (= zero for wildcard) addresses.
295 */
296 host1 = 0;
297 if (proto != IPPROTO_UDP) {
298 port1 = 0;
299 } else {
300 port1 = port;
301 port = 0;
302 }
303
304 __efx_filter_set_ipv4(spec, host1, port1, host, port);
305 return 0;
306}
307 253
308int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, 254 switch (gen_spec->match_flags) {
309 u8 *proto, __be32 *host, __be16 *port) 255 case (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
310{ 256 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
311 __be32 host1; 257 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT):
312 __be16 port1; 258 is_full = true;
259 /* fall through */
260 case (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
261 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT): {
262 __be32 rhost, host1, host2;
263 __be16 rport, port1, port2;
313 264
314 switch (spec->type) { 265 EFX_BUG_ON_PARANOID(!(gen_spec->flags & EFX_FILTER_FLAG_RX));
315 case EFX_FILTER_TCP_WILD:
316 *proto = IPPROTO_TCP;
317 __efx_filter_get_ipv4(spec, &host1, &port1, host, port);
318 return 0;
319 case EFX_FILTER_UDP_WILD:
320 *proto = IPPROTO_UDP;
321 __efx_filter_get_ipv4(spec, &host1, port, host, &port1);
322 return 0;
323 default:
324 return -EINVAL;
325 }
326}
327
328/**
329 * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports
330 * @spec: Specification to initialise
331 * @proto: Transport layer protocol number
332 * @host: Local host address (network byte order)
333 * @port: Local port (network byte order)
334 * @rhost: Remote host address (network byte order)
335 * @rport: Remote port (network byte order)
336 */
337int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto,
338 __be32 host, __be16 port,
339 __be32 rhost, __be16 rport)
340{
341 EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
342 266
343 /* This cannot currently be combined with other filtering */ 267 if (gen_spec->ether_type != htons(ETH_P_IP))
344 if (spec->type != EFX_FILTER_UNSPEC) 268 return -EPROTONOSUPPORT;
345 return -EPROTONOSUPPORT; 269 if (gen_spec->loc_port == 0 ||
270 (is_full && gen_spec->rem_port == 0))
271 return -EADDRNOTAVAIL;
272 switch (gen_spec->ip_proto) {
273 case IPPROTO_TCP:
274 spec->type = (is_full ? EFX_FARCH_FILTER_TCP_FULL :
275 EFX_FARCH_FILTER_TCP_WILD);
276 break;
277 case IPPROTO_UDP:
278 spec->type = (is_full ? EFX_FARCH_FILTER_UDP_FULL :
279 EFX_FARCH_FILTER_UDP_WILD);
280 break;
281 default:
282 return -EPROTONOSUPPORT;
283 }
346 284
347 if (port == 0 || rport == 0) 285 /* Filter is constructed in terms of source and destination,
348 return -EINVAL; 286 * with the odd wrinkle that the ports are swapped in a UDP
287 * wildcard filter. We need to convert from local and remote
288 * (= zero for wildcard) addresses.
289 */
290 rhost = is_full ? gen_spec->rem_host[0] : 0;
291 rport = is_full ? gen_spec->rem_port : 0;
292 host1 = rhost;
293 host2 = gen_spec->loc_host[0];
294 if (!is_full && gen_spec->ip_proto == IPPROTO_UDP) {
295 port1 = gen_spec->loc_port;
296 port2 = rport;
297 } else {
298 port1 = rport;
299 port2 = gen_spec->loc_port;
300 }
301 spec->data[0] = ntohl(host1) << 16 | ntohs(port1);
302 spec->data[1] = ntohs(port2) << 16 | ntohl(host1) >> 16;
303 spec->data[2] = ntohl(host2);
349 304
350 switch (proto) {
351 case IPPROTO_TCP:
352 spec->type = EFX_FILTER_TCP_FULL;
353 break; 305 break;
354 case IPPROTO_UDP:
355 spec->type = EFX_FILTER_UDP_FULL;
356 break;
357 default:
358 return -EPROTONOSUPPORT;
359 } 306 }
360 307
361 __efx_filter_set_ipv4(spec, rhost, rport, host, port); 308 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
362 return 0; 309 is_full = true;
363} 310 /* fall through */
364 311 case EFX_FILTER_MATCH_LOC_MAC:
365int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, 312 spec->type = (is_full ? EFX_FARCH_FILTER_MAC_FULL :
366 u8 *proto, __be32 *host, __be16 *port, 313 EFX_FARCH_FILTER_MAC_WILD);
367 __be32 *rhost, __be16 *rport) 314 spec->data[0] = is_full ? ntohs(gen_spec->outer_vid) : 0;
368{ 315 spec->data[1] = (gen_spec->loc_mac[2] << 24 |
369 switch (spec->type) { 316 gen_spec->loc_mac[3] << 16 |
370 case EFX_FILTER_TCP_FULL: 317 gen_spec->loc_mac[4] << 8 |
371 *proto = IPPROTO_TCP; 318 gen_spec->loc_mac[5]);
319 spec->data[2] = (gen_spec->loc_mac[0] << 8 |
320 gen_spec->loc_mac[1]);
372 break; 321 break;
373 case EFX_FILTER_UDP_FULL: 322
374 *proto = IPPROTO_UDP; 323 case EFX_FILTER_MATCH_LOC_MAC_IG:
324 spec->type = (is_multicast_ether_addr(gen_spec->loc_mac) ?
325 EFX_FARCH_FILTER_MC_DEF :
326 EFX_FARCH_FILTER_UC_DEF);
327 memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
375 break; 328 break;
329
376 default: 330 default:
377 return -EINVAL; 331 return -EPROTONOSUPPORT;
378 } 332 }
379 333
380 __efx_filter_get_ipv4(spec, rhost, rport, host, port);
381 return 0; 334 return 0;
382} 335}
383 336
384/** 337static void
385 * efx_filter_set_eth_local - specify local Ethernet address and optional VID 338efx_farch_filter_to_gen_spec(struct efx_filter_spec *gen_spec,
386 * @spec: Specification to initialise 339 const struct efx_farch_filter_spec *spec)
387 * @vid: VLAN ID to match, or %EFX_FILTER_VID_UNSPEC
388 * @addr: Local Ethernet MAC address
389 */
390int efx_filter_set_eth_local(struct efx_filter_spec *spec,
391 u16 vid, const u8 *addr)
392{ 340{
393 EFX_BUG_ON_PARANOID(!(spec->flags & 341 bool is_full = false;
394 (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
395
396 /* This cannot currently be combined with other filtering */
397 if (spec->type != EFX_FILTER_UNSPEC)
398 return -EPROTONOSUPPORT;
399
400 if (vid == EFX_FILTER_VID_UNSPEC) {
401 spec->type = EFX_FILTER_MAC_WILD;
402 spec->data[0] = 0;
403 } else {
404 spec->type = EFX_FILTER_MAC_FULL;
405 spec->data[0] = vid;
406 }
407 342
408 spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; 343 /* *gen_spec should be completely initialised, to be consistent
409 spec->data[2] = addr[0] << 8 | addr[1]; 344 * with efx_filter_init_{rx,tx}() and in case we want to copy
410 return 0; 345 * it back to userland.
411} 346 */
347 memset(gen_spec, 0, sizeof(*gen_spec));
412 348
413/** 349 gen_spec->priority = spec->priority;
414 * efx_filter_set_uc_def - specify matching otherwise-unmatched unicast 350 gen_spec->flags = spec->flags;
415 * @spec: Specification to initialise 351 gen_spec->dmaq_id = spec->dmaq_id;
416 */
417int efx_filter_set_uc_def(struct efx_filter_spec *spec)
418{
419 EFX_BUG_ON_PARANOID(!(spec->flags &
420 (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
421 352
422 if (spec->type != EFX_FILTER_UNSPEC) 353 switch (spec->type) {
423 return -EINVAL; 354 case EFX_FARCH_FILTER_TCP_FULL:
355 case EFX_FARCH_FILTER_UDP_FULL:
356 is_full = true;
357 /* fall through */
358 case EFX_FARCH_FILTER_TCP_WILD:
359 case EFX_FARCH_FILTER_UDP_WILD: {
360 __be32 host1, host2;
361 __be16 port1, port2;
362
363 gen_spec->match_flags =
364 EFX_FILTER_MATCH_ETHER_TYPE |
365 EFX_FILTER_MATCH_IP_PROTO |
366 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
367 if (is_full)
368 gen_spec->match_flags |= (EFX_FILTER_MATCH_REM_HOST |
369 EFX_FILTER_MATCH_REM_PORT);
370 gen_spec->ether_type = htons(ETH_P_IP);
371 gen_spec->ip_proto =
372 (spec->type == EFX_FARCH_FILTER_TCP_FULL ||
373 spec->type == EFX_FARCH_FILTER_TCP_WILD) ?
374 IPPROTO_TCP : IPPROTO_UDP;
375
376 host1 = htonl(spec->data[0] >> 16 | spec->data[1] << 16);
377 port1 = htons(spec->data[0]);
378 host2 = htonl(spec->data[2]);
379 port2 = htons(spec->data[1] >> 16);
380 if (spec->flags & EFX_FILTER_FLAG_TX) {
381 gen_spec->loc_host[0] = host1;
382 gen_spec->rem_host[0] = host2;
383 } else {
384 gen_spec->loc_host[0] = host2;
385 gen_spec->rem_host[0] = host1;
386 }
387 if (!!(gen_spec->flags & EFX_FILTER_FLAG_TX) ^
388 (!is_full && gen_spec->ip_proto == IPPROTO_UDP)) {
389 gen_spec->loc_port = port1;
390 gen_spec->rem_port = port2;
391 } else {
392 gen_spec->loc_port = port2;
393 gen_spec->rem_port = port1;
394 }
424 395
425 spec->type = EFX_FILTER_UC_DEF; 396 break;
426 memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */ 397 }
427 return 0;
428}
429 398
430/** 399 case EFX_FARCH_FILTER_MAC_FULL:
431 * efx_filter_set_mc_def - specify matching otherwise-unmatched multicast 400 is_full = true;
432 * @spec: Specification to initialise 401 /* fall through */
433 */ 402 case EFX_FARCH_FILTER_MAC_WILD:
434int efx_filter_set_mc_def(struct efx_filter_spec *spec) 403 gen_spec->match_flags = EFX_FILTER_MATCH_LOC_MAC;
435{ 404 if (is_full)
436 EFX_BUG_ON_PARANOID(!(spec->flags & 405 gen_spec->match_flags |= EFX_FILTER_MATCH_OUTER_VID;
437 (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX))); 406 gen_spec->loc_mac[0] = spec->data[2] >> 8;
407 gen_spec->loc_mac[1] = spec->data[2];
408 gen_spec->loc_mac[2] = spec->data[1] >> 24;
409 gen_spec->loc_mac[3] = spec->data[1] >> 16;
410 gen_spec->loc_mac[4] = spec->data[1] >> 8;
411 gen_spec->loc_mac[5] = spec->data[1];
412 gen_spec->outer_vid = htons(spec->data[0]);
413 break;
438 414
439 if (spec->type != EFX_FILTER_UNSPEC) 415 case EFX_FARCH_FILTER_UC_DEF:
440 return -EINVAL; 416 case EFX_FARCH_FILTER_MC_DEF:
417 gen_spec->match_flags = EFX_FILTER_MATCH_LOC_MAC_IG;
418 gen_spec->loc_mac[0] = spec->type == EFX_FARCH_FILTER_MC_DEF;
419 break;
441 420
442 spec->type = EFX_FILTER_MC_DEF; 421 default:
443 memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */ 422 WARN_ON(1);
444 return 0; 423 break;
424 }
445} 425}
446 426
447static void 427static void
@@ -455,7 +435,7 @@ efx_farch_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx)
455 /* If there's only one channel then disable RSS for non VF 435 /* If there's only one channel then disable RSS for non VF
456 * traffic, thereby allowing VFs to use RSS when the PF can't. 436 * traffic, thereby allowing VFs to use RSS when the PF can't.
457 */ 437 */
458 spec->type = EFX_FILTER_UC_DEF + filter_idx; 438 spec->type = EFX_FARCH_FILTER_UC_DEF + filter_idx;
459 spec->priority = EFX_FILTER_PRI_MANUAL; 439 spec->priority = EFX_FILTER_PRI_MANUAL;
460 spec->flags = (EFX_FILTER_FLAG_RX | 440 spec->flags = (EFX_FILTER_FLAG_RX |
461 (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) | 441 (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) |
@@ -464,29 +444,6 @@ efx_farch_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx)
464 table->used_bitmap[0] |= 1 << filter_idx; 444 table->used_bitmap[0] |= 1 << filter_idx;
465} 445}
466 446
467int efx_filter_get_eth_local(const struct efx_filter_spec *spec,
468 u16 *vid, u8 *addr)
469{
470 switch (spec->type) {
471 case EFX_FILTER_MAC_WILD:
472 *vid = EFX_FILTER_VID_UNSPEC;
473 break;
474 case EFX_FILTER_MAC_FULL:
475 *vid = spec->data[0];
476 break;
477 default:
478 return -EINVAL;
479 }
480
481 addr[0] = spec->data[2] >> 8;
482 addr[1] = spec->data[2];
483 addr[2] = spec->data[1] >> 24;
484 addr[3] = spec->data[1] >> 16;
485 addr[4] = spec->data[1] >> 8;
486 addr[5] = spec->data[1];
487 return 0;
488}
489
490/* Build a filter entry and return its n-tuple key. */ 447/* Build a filter entry and return its n-tuple key. */
491static u32 efx_farch_filter_build(efx_oword_t *filter, 448static u32 efx_farch_filter_build(efx_oword_t *filter,
492 struct efx_farch_filter_spec *spec) 449 struct efx_farch_filter_spec *spec)
@@ -495,8 +452,8 @@ static u32 efx_farch_filter_build(efx_oword_t *filter,
495 452
496 switch (efx_farch_filter_spec_table_id(spec)) { 453 switch (efx_farch_filter_spec_table_id(spec)) {
497 case EFX_FARCH_FILTER_TABLE_RX_IP: { 454 case EFX_FARCH_FILTER_TABLE_RX_IP: {
498 bool is_udp = (spec->type == EFX_FILTER_UDP_FULL || 455 bool is_udp = (spec->type == EFX_FARCH_FILTER_UDP_FULL ||
499 spec->type == EFX_FILTER_UDP_WILD); 456 spec->type == EFX_FARCH_FILTER_UDP_WILD);
500 EFX_POPULATE_OWORD_7( 457 EFX_POPULATE_OWORD_7(
501 *filter, 458 *filter,
502 FRF_BZ_RSS_EN, 459 FRF_BZ_RSS_EN,
@@ -513,7 +470,7 @@ static u32 efx_farch_filter_build(efx_oword_t *filter,
513 } 470 }
514 471
515 case EFX_FARCH_FILTER_TABLE_RX_MAC: { 472 case EFX_FARCH_FILTER_TABLE_RX_MAC: {
516 bool is_wild = spec->type == EFX_FILTER_MAC_WILD; 473 bool is_wild = spec->type == EFX_FARCH_FILTER_MAC_WILD;
517 EFX_POPULATE_OWORD_7( 474 EFX_POPULATE_OWORD_7(
518 *filter, 475 *filter,
519 FRF_CZ_RMFT_RSS_EN, 476 FRF_CZ_RMFT_RSS_EN,
@@ -530,7 +487,7 @@ static u32 efx_farch_filter_build(efx_oword_t *filter,
530 } 487 }
531 488
532 case EFX_FARCH_FILTER_TABLE_TX_MAC: { 489 case EFX_FARCH_FILTER_TABLE_TX_MAC: {
533 bool is_wild = spec->type == EFX_FILTER_MAC_WILD; 490 bool is_wild = spec->type == EFX_FARCH_FILTER_MAC_WILD;
534 EFX_POPULATE_OWORD_5(*filter, 491 EFX_POPULATE_OWORD_5(*filter,
535 FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id, 492 FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id,
536 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, 493 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
@@ -573,15 +530,15 @@ static bool efx_farch_filter_equal(const struct efx_farch_filter_spec *left,
573 530
574#define EFX_FARCH_FILTER_MATCH_PRI_COUNT 5 531#define EFX_FARCH_FILTER_MATCH_PRI_COUNT 5
575 532
576static const u8 efx_farch_filter_type_match_pri[EFX_FILTER_TYPE_COUNT] = { 533static const u8 efx_farch_filter_type_match_pri[EFX_FARCH_FILTER_TYPE_COUNT] = {
577 [EFX_FILTER_TCP_FULL] = 0, 534 [EFX_FARCH_FILTER_TCP_FULL] = 0,
578 [EFX_FILTER_UDP_FULL] = 0, 535 [EFX_FARCH_FILTER_UDP_FULL] = 0,
579 [EFX_FILTER_TCP_WILD] = 1, 536 [EFX_FARCH_FILTER_TCP_WILD] = 1,
580 [EFX_FILTER_UDP_WILD] = 1, 537 [EFX_FARCH_FILTER_UDP_WILD] = 1,
581 [EFX_FILTER_MAC_FULL] = 2, 538 [EFX_FARCH_FILTER_MAC_FULL] = 2,
582 [EFX_FILTER_MAC_WILD] = 3, 539 [EFX_FARCH_FILTER_MAC_WILD] = 3,
583 [EFX_FILTER_UC_DEF] = 4, 540 [EFX_FARCH_FILTER_UC_DEF] = 4,
584 [EFX_FILTER_MC_DEF] = 4, 541 [EFX_FARCH_FILTER_MC_DEF] = 4,
585}; 542};
586 543
587static const enum efx_farch_filter_table_id efx_farch_filter_range_table[] = { 544static const enum efx_farch_filter_table_id efx_farch_filter_range_table[] = {
@@ -672,11 +629,12 @@ s32 efx_filter_insert_filter(struct efx_nic *efx,
672 unsigned int depth = 0; 629 unsigned int depth = 0;
673 int rc; 630 int rc;
674 631
675 /* XXX efx_farch_filter_spec and efx_filter_spec will diverge in future */ 632 rc = efx_farch_filter_from_gen_spec(&spec, gen_spec);
676 memcpy(&spec, gen_spec, sizeof(*gen_spec)); 633 if (rc)
634 return rc;
677 635
678 table = efx_farch_filter_spec_table(state, &spec); 636 table = &state->table[efx_farch_filter_spec_table_id(&spec)];
679 if (!table || table->size == 0) 637 if (table->size == 0)
680 return -EINVAL; 638 return -EINVAL;
681 639
682 netif_vdbg(efx, hw, efx->net_dev, 640 netif_vdbg(efx, hw, efx->net_dev,
@@ -687,8 +645,8 @@ s32 efx_filter_insert_filter(struct efx_nic *efx,
687 /* One filter spec per type */ 645 /* One filter spec per type */
688 BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_UC_DEF != 0); 646 BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_UC_DEF != 0);
689 BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_MC_DEF != 647 BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_MC_DEF !=
690 EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF); 648 EFX_FARCH_FILTER_MC_DEF - EFX_FARCH_FILTER_UC_DEF);
691 rep_index = spec.type - EFX_FILTER_UC_DEF; 649 rep_index = spec.type - EFX_FARCH_FILTER_UC_DEF;
692 ins_index = rep_index; 650 ins_index = rep_index;
693 651
694 spin_lock_bh(&state->lock); 652 spin_lock_bh(&state->lock);
@@ -911,8 +869,7 @@ int efx_filter_get_filter_safe(struct efx_nic *efx,
911 869
912 if (test_bit(filter_idx, table->used_bitmap) && 870 if (test_bit(filter_idx, table->used_bitmap) &&
913 spec->priority == priority) { 871 spec->priority == priority) {
914 /* XXX efx_farch_filter_spec and efx_filter_spec will diverge */ 872 efx_farch_filter_to_gen_spec(spec_buf, spec);
915 memcpy(spec_buf, spec, sizeof(*spec));
916 rc = 0; 873 rc = 0;
917 } else { 874 } else {
918 rc = -ENOENT; 875 rc = -ENOENT;
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index b1170d44171e..1b410defccec 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -11,32 +11,49 @@
11#define EFX_FILTER_H 11#define EFX_FILTER_H
12 12
13#include <linux/types.h> 13#include <linux/types.h>
14#include <linux/if_ether.h>
15#include <asm/byteorder.h>
14 16
15/** 17/**
16 * enum efx_filter_type - type of hardware filter 18 * enum efx_filter_match_flags - Flags for hardware filter match type
17 * @EFX_FILTER_TCP_FULL: Matching TCP/IPv4 4-tuple 19 * @EFX_FILTER_MATCH_REM_HOST: Match by remote IP host address
18 * @EFX_FILTER_TCP_WILD: Matching TCP/IPv4 destination (host, port) 20 * @EFX_FILTER_MATCH_LOC_HOST: Match by local IP host address
19 * @EFX_FILTER_UDP_FULL: Matching UDP/IPv4 4-tuple 21 * @EFX_FILTER_MATCH_REM_MAC: Match by remote MAC address
20 * @EFX_FILTER_UDP_WILD: Matching UDP/IPv4 destination (host, port) 22 * @EFX_FILTER_MATCH_REM_PORT: Match by remote TCP/UDP port
21 * @EFX_FILTER_MAC_FULL: Matching Ethernet destination MAC address, VID 23 * @EFX_FILTER_MATCH_LOC_MAC: Match by local MAC address
22 * @EFX_FILTER_MAC_WILD: Matching Ethernet destination MAC address 24 * @EFX_FILTER_MATCH_LOC_PORT: Match by local TCP/UDP port
23 * @EFX_FILTER_UC_DEF: Matching all otherwise unmatched unicast 25 * @EFX_FILTER_MATCH_ETHER_TYPE: Match by Ether-type
24 * @EFX_FILTER_MC_DEF: Matching all otherwise unmatched multicast 26 * @EFX_FILTER_MATCH_INNER_VID: Match by inner VLAN ID
25 * @EFX_FILTER_UNSPEC: Match type is unspecified 27 * @EFX_FILTER_MATCH_OUTER_VID: Match by outer VLAN ID
28 * @EFX_FILTER_MATCH_IP_PROTO: Match by IP transport protocol
29 * @EFX_FILTER_MATCH_LOC_MAC_IG: Match by local MAC address I/G bit.
30 * Used for RX default unicast and multicast/broadcast filters.
26 * 31 *
27 * Falcon NICs only support the TCP/IPv4 and UDP/IPv4 filter types. 32 * Only some combinations are supported, depending on NIC type:
33 *
34 * - Falcon supports RX filters matching by {TCP,UDP}/IPv4 4-tuple or
35 * local 2-tuple (only implemented for Falcon B0)
36 *
37 * - Siena supports RX and TX filters matching by {TCP,UDP}/IPv4 4-tuple
38 * or local 2-tuple, or local MAC with or without outer VID, and RX
39 * default filters
40 *
41 * - Huntington supports filter matching controlled by firmware, potentially
42 * using {TCP,UDP}/IPv{4,6} 4-tuple or local 2-tuple, local MAC or I/G bit,
43 * with or without outer and inner VID
28 */ 44 */
29enum efx_filter_type { 45enum efx_filter_match_flags {
30 EFX_FILTER_TCP_FULL = 0, 46 EFX_FILTER_MATCH_REM_HOST = 0x0001,
31 EFX_FILTER_TCP_WILD, 47 EFX_FILTER_MATCH_LOC_HOST = 0x0002,
32 EFX_FILTER_UDP_FULL, 48 EFX_FILTER_MATCH_REM_MAC = 0x0004,
33 EFX_FILTER_UDP_WILD, 49 EFX_FILTER_MATCH_REM_PORT = 0x0008,
34 EFX_FILTER_MAC_FULL = 4, 50 EFX_FILTER_MATCH_LOC_MAC = 0x0010,
35 EFX_FILTER_MAC_WILD, 51 EFX_FILTER_MATCH_LOC_PORT = 0x0020,
36 EFX_FILTER_UC_DEF = 8, 52 EFX_FILTER_MATCH_ETHER_TYPE = 0x0040,
37 EFX_FILTER_MC_DEF, 53 EFX_FILTER_MATCH_INNER_VID = 0x0080,
38 EFX_FILTER_TYPE_COUNT, /* number of specific types */ 54 EFX_FILTER_MATCH_OUTER_VID = 0x0100,
39 EFX_FILTER_UNSPEC = 0xf, 55 EFX_FILTER_MATCH_IP_PROTO = 0x0200,
56 EFX_FILTER_MATCH_LOC_MAC_IG = 0x0400,
40}; 57};
41 58
42/** 59/**
@@ -73,29 +90,55 @@ enum efx_filter_flags {
73 90
74/** 91/**
75 * struct efx_filter_spec - specification for a hardware filter 92 * struct efx_filter_spec - specification for a hardware filter
76 * @type: Type of match to be performed, from &enum efx_filter_type 93 * @match_flags: Match type flags, from &enum efx_filter_match_flags
77 * @priority: Priority of the filter, from &enum efx_filter_priority 94 * @priority: Priority of the filter, from &enum efx_filter_priority
78 * @flags: Miscellaneous flags, from &enum efx_filter_flags 95 * @flags: Miscellaneous flags, from &enum efx_filter_flags
96 * @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set
79 * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for 97 * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for
80 * an RX drop filter 98 * an RX drop filter
81 * @data: Match data (type-dependent) 99 * @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set
100 * @inner_vid: Inner VLAN ID to match, if %EFX_FILTER_MATCH_INNER_VID is set
101 * @loc_mac: Local MAC address to match, if %EFX_FILTER_MATCH_LOC_MAC or
102 * %EFX_FILTER_MATCH_LOC_MAC_IG is set
103 * @rem_mac: Remote MAC address to match, if %EFX_FILTER_MATCH_REM_MAC is set
104 * @ether_type: Ether-type to match, if %EFX_FILTER_MATCH_ETHER_TYPE is set
105 * @ip_proto: IP transport protocol to match, if %EFX_FILTER_MATCH_IP_PROTO
106 * is set
107 * @loc_host: Local IP host to match, if %EFX_FILTER_MATCH_LOC_HOST is set
108 * @rem_host: Remote IP host to match, if %EFX_FILTER_MATCH_REM_HOST is set
109 * @loc_port: Local TCP/UDP port to match, if %EFX_FILTER_MATCH_LOC_PORT is set
110 * @rem_port: Remote TCP/UDP port to match, if %EFX_FILTER_MATCH_REM_PORT is set
82 * 111 *
83 * Use the efx_filter_set_*() functions to initialise the @type and 112 * The efx_filter_init_rx() or efx_filter_init_tx() function *must* be
84 * @data fields. 113 * used to initialise the structure. The efx_filter_set_*() functions
114 * may then be used to set @rss_context, @match_flags and related
115 * fields.
85 * 116 *
86 * The @priority field is used by software to determine whether a new 117 * The @priority field is used by software to determine whether a new
87 * filter may replace an old one. The hardware priority of a filter 118 * filter may replace an old one. The hardware priority of a filter
88 * depends on the filter type. 119 * depends on which fields are matched.
89 */ 120 */
90struct efx_filter_spec { 121struct efx_filter_spec {
91 u8 type:4; 122 u32 match_flags:12;
92 u8 priority:4; 123 u32 priority:2;
93 u8 flags; 124 u32 flags:6;
94 u16 dmaq_id; 125 u32 dmaq_id:12;
95 u32 data[3]; 126 u32 rss_context;
127 __be16 outer_vid __aligned(4); /* allow jhash2() of match values */
128 __be16 inner_vid;
129 u8 loc_mac[ETH_ALEN];
130 u8 rem_mac[ETH_ALEN];
131 __be16 ether_type;
132 u8 ip_proto;
133 __be32 loc_host[4];
134 __be32 rem_host[4];
135 __be16 loc_port;
136 __be16 rem_port;
137 /* total 64 bytes */
96}; 138};
97 139
98enum { 140enum {
141 EFX_FILTER_RSS_CONTEXT_DEFAULT = 0xffffffff,
99 EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff 142 EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff
100}; 143};
101 144
@@ -104,39 +147,116 @@ static inline void efx_filter_init_rx(struct efx_filter_spec *spec,
104 enum efx_filter_flags flags, 147 enum efx_filter_flags flags,
105 unsigned rxq_id) 148 unsigned rxq_id)
106{ 149{
107 spec->type = EFX_FILTER_UNSPEC; 150 memset(spec, 0, sizeof(*spec));
108 spec->priority = priority; 151 spec->priority = priority;
109 spec->flags = EFX_FILTER_FLAG_RX | flags; 152 spec->flags = EFX_FILTER_FLAG_RX | flags;
153 spec->rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT;
110 spec->dmaq_id = rxq_id; 154 spec->dmaq_id = rxq_id;
111} 155}
112 156
113static inline void efx_filter_init_tx(struct efx_filter_spec *spec, 157static inline void efx_filter_init_tx(struct efx_filter_spec *spec,
114 unsigned txq_id) 158 unsigned txq_id)
115{ 159{
116 spec->type = EFX_FILTER_UNSPEC; 160 memset(spec, 0, sizeof(*spec));
117 spec->priority = EFX_FILTER_PRI_REQUIRED; 161 spec->priority = EFX_FILTER_PRI_REQUIRED;
118 spec->flags = EFX_FILTER_FLAG_TX; 162 spec->flags = EFX_FILTER_FLAG_TX;
119 spec->dmaq_id = txq_id; 163 spec->dmaq_id = txq_id;
120} 164}
121 165
122extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, 166/**
123 __be32 host, __be16 port); 167 * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port
124extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, 168 * @spec: Specification to initialise
125 u8 *proto, __be32 *host, __be16 *port); 169 * @proto: Transport layer protocol number
126extern int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, 170 * @host: Local host address (network byte order)
127 __be32 host, __be16 port, 171 * @port: Local port (network byte order)
128 __be32 rhost, __be16 rport); 172 */
129extern int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, 173static inline int
130 u8 *proto, __be32 *host, __be16 *port, 174efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
131 __be32 *rhost, __be16 *rport); 175 __be32 host, __be16 port)
132extern int efx_filter_set_eth_local(struct efx_filter_spec *spec, 176{
133 u16 vid, const u8 *addr); 177 spec->match_flags |=
134extern int efx_filter_get_eth_local(const struct efx_filter_spec *spec, 178 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
135 u16 *vid, u8 *addr); 179 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
136extern int efx_filter_set_uc_def(struct efx_filter_spec *spec); 180 spec->ether_type = htons(ETH_P_IP);
137extern int efx_filter_set_mc_def(struct efx_filter_spec *spec); 181 spec->ip_proto = proto;
182 spec->loc_host[0] = host;
183 spec->loc_port = port;
184 return 0;
185}
186
187/**
188 * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports
189 * @spec: Specification to initialise
190 * @proto: Transport layer protocol number
191 * @lhost: Local host address (network byte order)
192 * @lport: Local port (network byte order)
193 * @rhost: Remote host address (network byte order)
194 * @rport: Remote port (network byte order)
195 */
196static inline int
197efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto,
198 __be32 lhost, __be16 lport,
199 __be32 rhost, __be16 rport)
200{
201 spec->match_flags |=
202 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
203 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
204 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
205 spec->ether_type = htons(ETH_P_IP);
206 spec->ip_proto = proto;
207 spec->loc_host[0] = lhost;
208 spec->loc_port = lport;
209 spec->rem_host[0] = rhost;
210 spec->rem_port = rport;
211 return 0;
212}
213
138enum { 214enum {
139 EFX_FILTER_VID_UNSPEC = 0xffff, 215 EFX_FILTER_VID_UNSPEC = 0xffff,
140}; 216};
141 217
218/**
219 * efx_filter_set_eth_local - specify local Ethernet address and/or VID
220 * @spec: Specification to initialise
221 * @vid: Outer VLAN ID to match, or %EFX_FILTER_VID_UNSPEC
222 * @addr: Local Ethernet MAC address, or %NULL
223 */
224static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec,
225 u16 vid, const u8 *addr)
226{
227 if (vid == EFX_FILTER_VID_UNSPEC && addr == NULL)
228 return -EINVAL;
229
230 if (vid != EFX_FILTER_VID_UNSPEC) {
231 spec->match_flags |= EFX_FILTER_MATCH_OUTER_VID;
232 spec->outer_vid = htons(vid);
233 }
234 if (addr != NULL) {
235 spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC;
236 memcpy(spec->loc_mac, addr, ETH_ALEN);
237 }
238 return 0;
239}
240
241/**
242 * efx_filter_set_uc_def - specify matching otherwise-unmatched unicast
243 * @spec: Specification to initialise
244 */
245static inline int efx_filter_set_uc_def(struct efx_filter_spec *spec)
246{
247 spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
248 return 0;
249}
250
251/**
252 * efx_filter_set_mc_def - specify matching otherwise-unmatched multicast
253 * @spec: Specification to initialise
254 */
255static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec)
256{
257 spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
258 spec->loc_mac[0] = 1;
259 return 0;
260}
261
142#endif /* EFX_FILTER_H */ 262#endif /* EFX_FILTER_H */