sfc: Prepare for RX scatter on EF10
[deliverable/linux.git] / drivers / net / ethernet / sfc / ethtool.c
index 1fc21458413d50ade70be1ff1ee9481aca7cf987..63546930f954367af2fb6563f45de618f1cbae90 100644 (file)
 #include "filter.h"
 #include "nic.h"
 
-struct ethtool_string {
-       char name[ETH_GSTRING_LEN];
-};
-
-struct efx_ethtool_stat {
+struct efx_sw_stat_desc {
        const char *name;
        enum {
-               EFX_ETHTOOL_STAT_SOURCE_mac_stats,
                EFX_ETHTOOL_STAT_SOURCE_nic,
                EFX_ETHTOOL_STAT_SOURCE_channel,
                EFX_ETHTOOL_STAT_SOURCE_tx_queue
@@ -35,7 +30,7 @@ struct efx_ethtool_stat {
        u64(*get_stat) (void *field); /* Reader function */
 };
 
-/* Initialiser for a struct #efx_ethtool_stat with type-checking */
+/* Initialiser for a struct efx_sw_stat_desc with type-checking */
 #define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
                                get_stat_function) {                    \
        .name = #stat_name,                                             \
@@ -52,24 +47,11 @@ static u64 efx_get_uint_stat(void *field)
        return *(unsigned int *)field;
 }
 
-static u64 efx_get_u64_stat(void *field)
-{
-       return *(u64 *) field;
-}
-
 static u64 efx_get_atomic_stat(void *field)
 {
        return atomic_read((atomic_t *) field);
 }
 
-#define EFX_ETHTOOL_U64_MAC_STAT(field)                                \
-       EFX_ETHTOOL_STAT(field, mac_stats, field,               \
-                         u64, efx_get_u64_stat)
-
-#define EFX_ETHTOOL_UINT_NIC_STAT(name)                                \
-       EFX_ETHTOOL_STAT(name, nic, n_##name,                   \
-                        unsigned int, efx_get_uint_stat)
-
 #define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field)               \
        EFX_ETHTOOL_STAT(field, nic, field,                     \
                         atomic_t, efx_get_atomic_stat)
@@ -82,72 +64,12 @@ static u64 efx_get_atomic_stat(void *field)
        EFX_ETHTOOL_STAT(tx_##field, tx_queue, field,           \
                         unsigned int, efx_get_uint_stat)
 
-static const struct efx_ethtool_stat efx_ethtool_stats[] = {
-       EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_packets),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_bad),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_pause),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_control),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_unicast),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_multicast),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_broadcast),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_lt64),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_64),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_65_to_127),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_128_to_255),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_256_to_511),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_512_to_1023),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_1024_to_15xx),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_15xx_to_jumbo),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_gtjumbo),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_collision),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_single_collision),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_multiple_collision),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_excessive_collision),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_deferred),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_late_collision),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_excessive_deferred),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_non_tcpudp),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_mac_src_error),
-       EFX_ETHTOOL_U64_MAC_STAT(tx_ip_src_error),
+static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {
+       EFX_ETHTOOL_UINT_TXQ_STAT(merge_events),
        EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts),
        EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers),
        EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets),
        EFX_ETHTOOL_UINT_TXQ_STAT(pushes),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_packets),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_good),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bad),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_pause),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_control),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_unicast),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_multicast),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_broadcast),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_lt64),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_64),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_65_to_127),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_128_to_255),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_256_to_511),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_512_to_1023),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_1024_to_15xx),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_15xx_to_jumbo),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_gtjumbo),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bad_lt64),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bad_64_to_15xx),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bad_15xx_to_jumbo),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_bad_gtjumbo),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_overflow),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_missed),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_false_carrier),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_symbol_error),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_align_error),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_length_error),
-       EFX_ETHTOOL_U64_MAC_STAT(rx_internal_error),
-       EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
        EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
@@ -157,8 +79,7 @@ static const struct efx_ethtool_stat efx_ethtool_stats[] = {
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_nodesc_trunc),
 };
 
-/* Number of ethtool statistics */
-#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
+#define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc)
 
 #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
 
@@ -205,8 +126,6 @@ static int efx_ethtool_get_settings(struct net_device *net_dev,
        efx->phy_op->get_settings(efx, ecmd);
        mutex_unlock(&efx->mac_lock);
 
-       /* GMAC does not support 1000Mbps HD */
-       ecmd->supported &= ~SUPPORTED_1000baseT_Half;
        /* Both MACs support pause frames (bidirectional and respond-only) */
        ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
 
@@ -291,12 +210,11 @@ static void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable)
  *
  * Fill in an individual self-test entry.
  */
-static void efx_fill_test(unsigned int test_index,
-                         struct ethtool_string *strings, u64 *data,
+static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data,
                          int *test, const char *unit_format, int unit_id,
                          const char *test_format, const char *test_id)
 {
-       struct ethtool_string unit_str, test_str;
+       char unit_str[ETH_GSTRING_LEN], test_str[ETH_GSTRING_LEN];
 
        /* Fill data value, if applicable */
        if (data)
@@ -305,15 +223,14 @@ static void efx_fill_test(unsigned int test_index,
        /* Fill string, if applicable */
        if (strings) {
                if (strchr(unit_format, '%'))
-                       snprintf(unit_str.name, sizeof(unit_str.name),
+                       snprintf(unit_str, sizeof(unit_str),
                                 unit_format, unit_id);
                else
-                       strcpy(unit_str.name, unit_format);
-               snprintf(test_str.name, sizeof(test_str.name),
-                        test_format, test_id);
-               snprintf(strings[test_index].name,
-                        sizeof(strings[test_index].name),
-                        "%-6s %-24s", unit_str.name, test_str.name);
+                       strcpy(unit_str, unit_format);
+               snprintf(test_str, sizeof(test_str), test_format, test_id);
+               snprintf(strings + test_index * ETH_GSTRING_LEN,
+                        ETH_GSTRING_LEN,
+                        "%-6s %-24s", unit_str, test_str);
        }
 }
 
@@ -336,7 +253,7 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
                                  struct efx_loopback_self_tests *lb_tests,
                                  enum efx_loopback_mode mode,
                                  unsigned int test_index,
-                                 struct ethtool_string *strings, u64 *data)
+                                 u8 *strings, u64 *data)
 {
        struct efx_channel *channel =
                efx_get_channel(efx, efx->tx_channel_offset);
@@ -373,8 +290,7 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
  */
 static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
                                       struct efx_self_tests *tests,
-                                      struct ethtool_string *strings,
-                                      u64 *data)
+                                      u8 *strings, u64 *data)
 {
        struct efx_channel *channel;
        unsigned int n = 0, i;
@@ -433,12 +349,14 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
 static int efx_ethtool_get_sset_count(struct net_device *net_dev,
                                      int string_set)
 {
+       struct efx_nic *efx = netdev_priv(net_dev);
+
        switch (string_set) {
        case ETH_SS_STATS:
-               return EFX_ETHTOOL_NUM_STATS;
+               return efx->type->describe_stats(efx, NULL) +
+                       EFX_ETHTOOL_SW_STAT_COUNT;
        case ETH_SS_TEST:
-               return efx_ethtool_fill_self_tests(netdev_priv(net_dev),
-                                                  NULL, NULL, NULL);
+               return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
        default:
                return -EINVAL;
        }
@@ -448,20 +366,18 @@ static void efx_ethtool_get_strings(struct net_device *net_dev,
                                    u32 string_set, u8 *strings)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
-       struct ethtool_string *ethtool_strings =
-               (struct ethtool_string *)strings;
        int i;
 
        switch (string_set) {
        case ETH_SS_STATS:
-               for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
-                       strlcpy(ethtool_strings[i].name,
-                               efx_ethtool_stats[i].name,
-                               sizeof(ethtool_strings[i].name));
+               strings += (efx->type->describe_stats(efx, strings) *
+                           ETH_GSTRING_LEN);
+               for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++)
+                       strlcpy(strings + i * ETH_GSTRING_LEN,
+                               efx_sw_stat_desc[i].name, ETH_GSTRING_LEN);
                break;
        case ETH_SS_TEST:
-               efx_ethtool_fill_self_tests(efx, NULL,
-                                           ethtool_strings, NULL);
+               efx_ethtool_fill_self_tests(efx, NULL, strings, NULL);
                break;
        default:
                /* No other string sets */
@@ -474,27 +390,20 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
                                  u64 *data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
-       struct efx_mac_stats *mac_stats = &efx->mac_stats;
-       const struct efx_ethtool_stat *stat;
+       const struct efx_sw_stat_desc *stat;
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
        int i;
 
-       EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
-
        spin_lock_bh(&efx->stats_lock);
 
-       /* Update MAC and NIC statistics */
-       efx->type->update_stats(efx);
+       /* Get NIC statistics */
+       data += efx->type->update_stats(efx, data, NULL);
 
-       /* Fill detailed statistics buffer */
-       for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
-               stat = &efx_ethtool_stats[i];
+       /* Get software statistics */
+       for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) {
+               stat = &efx_sw_stat_desc[i];
                switch (stat->source) {
-               case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
-                       data[i] = stat->get_stat((void *)mac_stats +
-                                                stat->offset);
-                       break;
                case EFX_ETHTOOL_STAT_SOURCE_nic:
                        data[i] = stat->get_stat((void *)efx + stat->offset);
                        break;
@@ -709,7 +618,6 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
        struct efx_nic *efx = netdev_priv(net_dev);
        u8 wanted_fc, old_fc;
        u32 old_adv;
-       bool reset;
        int rc = 0;
 
        mutex_lock(&efx->mac_lock);
@@ -732,24 +640,10 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
                goto out;
        }
 
-       /* TX flow control may automatically turn itself off if the
-        * link partner (intermittently) stops responding to pause
-        * frames. There isn't any indication that this has happened,
-        * so the best we do is leave it up to the user to spot this
-        * and fix it be cycling transmit flow control on this end. */
-       reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX);
-       if (EFX_WORKAROUND_11482(efx) && reset) {
-               if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
-                       /* Recover by resetting the EM block */
-                       falcon_stop_nic_stats(efx);
-                       falcon_drain_tx_fifo(efx);
-                       falcon_reconfigure_xmac(efx);
-                       falcon_start_nic_stats(efx);
-               } else {
-                       /* Schedule a reset to recover */
-                       efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
-               }
-       }
+       /* Hook for Falcon bug 11482 workaround */
+       if (efx->type->prepare_enable_fc_tx &&
+           (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX))
+               efx->type->prepare_enable_fc_tx(efx);
 
        old_adv = efx->link_advertising;
        old_fc = efx->wanted_fc;
@@ -814,11 +708,12 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
        return efx_reset(efx, rc);
 }
 
-/* MAC address mask including only MC flag */
-static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
+/* MAC address mask including only I/G bit */
+static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
 
 #define IP4_ADDR_FULL_MASK     ((__force __be32)~0)
 #define PORT_FULL_MASK         ((__force __be16)~0)
+#define ETHER_TYPE_FULL_MASK   ((__force __be16)~0)
 
 static int efx_ethtool_get_class_rule(struct efx_nic *efx,
                                      struct ethtool_rx_flow_spec *rule)
@@ -828,8 +723,6 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
        struct ethhdr *mac_entry = &rule->h_u.ether_spec;
        struct ethhdr *mac_mask = &rule->m_u.ether_spec;
        struct efx_filter_spec spec;
-       u16 vid;
-       u8 proto;
        int rc;
 
        rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL,
@@ -837,44 +730,72 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
        if (rc)
                return rc;
 
-       if (spec.dmaq_id == 0xfff)
+       if (spec.dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP)
                rule->ring_cookie = RX_CLS_FLOW_DISC;
        else
                rule->ring_cookie = spec.dmaq_id;
 
-       if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) {
-               rule->flow_type = ETHER_FLOW;
-               memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN);
-               if (spec.type == EFX_FILTER_MC_DEF)
-                       memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN);
-               return 0;
-       }
-
-       rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest);
-       if (rc == 0) {
+       if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) &&
+           spec.ether_type == htons(ETH_P_IP) &&
+           (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) &&
+           (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) &&
+           !(spec.match_flags &
+             ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID |
+               EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST |
+               EFX_FILTER_MATCH_IP_PROTO |
+               EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) {
+               rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ?
+                                  TCP_V4_FLOW : UDP_V4_FLOW);
+               if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) {
+                       ip_entry->ip4dst = spec.loc_host[0];
+                       ip_mask->ip4dst = IP4_ADDR_FULL_MASK;
+               }
+               if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) {
+                       ip_entry->ip4src = spec.rem_host[0];
+                       ip_mask->ip4src = IP4_ADDR_FULL_MASK;
+               }
+               if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) {
+                       ip_entry->pdst = spec.loc_port;
+                       ip_mask->pdst = PORT_FULL_MASK;
+               }
+               if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) {
+                       ip_entry->psrc = spec.rem_port;
+                       ip_mask->psrc = PORT_FULL_MASK;
+               }
+       } else if (!(spec.match_flags &
+                    ~(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG |
+                      EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_ETHER_TYPE |
+                      EFX_FILTER_MATCH_OUTER_VID))) {
                rule->flow_type = ETHER_FLOW;
-               memset(mac_mask->h_dest, ~0, ETH_ALEN);
-               if (vid != EFX_FILTER_VID_UNSPEC) {
-                       rule->flow_type |= FLOW_EXT;
-                       rule->h_ext.vlan_tci = htons(vid);
-                       rule->m_ext.vlan_tci = htons(0xfff);
+               if (spec.match_flags &
+                   (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) {
+                       memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN);
+                       if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC)
+                               memset(mac_mask->h_dest, ~0, ETH_ALEN);
+                       else
+                               memcpy(mac_mask->h_dest, mac_addr_ig_mask,
+                                      ETH_ALEN);
                }
-               return 0;
+               if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) {
+                       memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN);
+                       memset(mac_mask->h_source, ~0, ETH_ALEN);
+               }
+               if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {
+                       mac_entry->h_proto = spec.ether_type;
+                       mac_mask->h_proto = ETHER_TYPE_FULL_MASK;
+               }
+       } else {
+               /* The above should handle all filters that we insert */
+               WARN_ON(1);
+               return -EINVAL;
        }
 
-       rc = efx_filter_get_ipv4_local(&spec, &proto,
-                                      &ip_entry->ip4dst, &ip_entry->pdst);
-       if (rc != 0) {
-               rc = efx_filter_get_ipv4_full(
-                       &spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst,
-                       &ip_entry->ip4src, &ip_entry->psrc);
-               EFX_WARN_ON_PARANOID(rc);
-               ip_mask->ip4src = IP4_ADDR_FULL_MASK;
-               ip_mask->psrc = PORT_FULL_MASK;
+       if (spec.match_flags & EFX_FILTER_MATCH_OUTER_VID) {
+               rule->flow_type |= FLOW_EXT;
+               rule->h_ext.vlan_tci = spec.outer_vid;
+               rule->m_ext.vlan_tci = htons(0xfff);
        }
-       rule->flow_type = (proto == IPPROTO_TCP) ? TCP_V4_FLOW : UDP_V4_FLOW;
-       ip_mask->ip4dst = IP4_ADDR_FULL_MASK;
-       ip_mask->pdst = PORT_FULL_MASK;
+
        return rc;
 }
 
@@ -982,82 +903,80 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
        efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL,
                           efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
                           (rule->ring_cookie == RX_CLS_FLOW_DISC) ?
-                          0xfff : rule->ring_cookie);
+                          EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie);
 
-       switch (rule->flow_type) {
+       switch (rule->flow_type & ~FLOW_EXT) {
        case TCP_V4_FLOW:
-       case UDP_V4_FLOW: {
-               u8 proto = (rule->flow_type == TCP_V4_FLOW ?
-                           IPPROTO_TCP : IPPROTO_UDP);
-
-               /* Must match all of destination, */
-               if (!(ip_mask->ip4dst == IP4_ADDR_FULL_MASK &&
-                     ip_mask->pdst == PORT_FULL_MASK))
-                       return -EINVAL;
-               /* all or none of source, */
-               if ((ip_mask->ip4src || ip_mask->psrc) &&
-                   !(ip_mask->ip4src == IP4_ADDR_FULL_MASK &&
-                     ip_mask->psrc == PORT_FULL_MASK))
-                       return -EINVAL;
-               /* and nothing else */
-               if (ip_mask->tos || rule->m_ext.vlan_tci)
+       case UDP_V4_FLOW:
+               spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE |
+                                   EFX_FILTER_MATCH_IP_PROTO);
+               spec.ether_type = htons(ETH_P_IP);
+               spec.ip_proto = ((rule->flow_type & ~FLOW_EXT) == TCP_V4_FLOW ?
+                                IPPROTO_TCP : IPPROTO_UDP);
+               if (ip_mask->ip4dst) {
+                       if (ip_mask->ip4dst != IP4_ADDR_FULL_MASK)
+                               return -EINVAL;
+                       spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST;
+                       spec.loc_host[0] = ip_entry->ip4dst;
+               }
+               if (ip_mask->ip4src) {
+                       if (ip_mask->ip4src != IP4_ADDR_FULL_MASK)
+                               return -EINVAL;
+                       spec.match_flags |= EFX_FILTER_MATCH_REM_HOST;
+                       spec.rem_host[0] = ip_entry->ip4src;
+               }
+               if (ip_mask->pdst) {
+                       if (ip_mask->pdst != PORT_FULL_MASK)
+                               return -EINVAL;
+                       spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT;
+                       spec.loc_port = ip_entry->pdst;
+               }
+               if (ip_mask->psrc) {
+                       if (ip_mask->psrc != PORT_FULL_MASK)
+                               return -EINVAL;
+                       spec.match_flags |= EFX_FILTER_MATCH_REM_PORT;
+                       spec.rem_port = ip_entry->psrc;
+               }
+               if (ip_mask->tos)
                        return -EINVAL;
-
-               if (ip_mask->ip4src)
-                       rc = efx_filter_set_ipv4_full(&spec, proto,
-                                                     ip_entry->ip4dst,
-                                                     ip_entry->pdst,
-                                                     ip_entry->ip4src,
-                                                     ip_entry->psrc);
-               else
-                       rc = efx_filter_set_ipv4_local(&spec, proto,
-                                                      ip_entry->ip4dst,
-                                                      ip_entry->pdst);
-               if (rc)
-                       return rc;
                break;
-       }
-
-       case ETHER_FLOW | FLOW_EXT:
-       case ETHER_FLOW: {
-               u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ?
-                                    ntohs(rule->m_ext.vlan_tci) : 0);
-
-               /* Must not match on source address or Ethertype */
-               if (!is_zero_ether_addr(mac_mask->h_source) ||
-                   mac_mask->h_proto)
-                       return -EINVAL;
 
-               /* Is it a default UC or MC filter? */
-               if (ether_addr_equal(mac_mask->h_dest, mac_addr_mc_mask) &&
-                   vlan_tag_mask == 0) {
-                       if (is_multicast_ether_addr(mac_entry->h_dest))
-                               rc = efx_filter_set_mc_def(&spec);
+       case ETHER_FLOW:
+               if (!is_zero_ether_addr(mac_mask->h_dest)) {
+                       if (ether_addr_equal(mac_mask->h_dest,
+                                            mac_addr_ig_mask))
+                               spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
+                       else if (is_broadcast_ether_addr(mac_mask->h_dest))
+                               spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC;
                        else
-                               rc = efx_filter_set_uc_def(&spec);
+                               return -EINVAL;
+                       memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN);
                }
-               /* Otherwise, it must match all of destination and all
-                * or none of VID.
-                */
-               else if (is_broadcast_ether_addr(mac_mask->h_dest) &&
-                        (vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) {
-                       rc = efx_filter_set_eth_local(
-                               &spec,
-                               vlan_tag_mask ?
-                               ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
-                               mac_entry->h_dest);
-               } else {
-                       rc = -EINVAL;
+               if (!is_zero_ether_addr(mac_mask->h_source)) {
+                       if (!is_broadcast_ether_addr(mac_mask->h_source))
+                               return -EINVAL;
+                       spec.match_flags |= EFX_FILTER_MATCH_REM_MAC;
+                       memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN);
+               }
+               if (mac_mask->h_proto) {
+                       if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK)
+                               return -EINVAL;
+                       spec.match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+                       spec.ether_type = mac_entry->h_proto;
                }
-               if (rc)
-                       return rc;
                break;
-       }
 
        default:
                return -EINVAL;
        }
 
+       if ((rule->flow_type & FLOW_EXT) && rule->m_ext.vlan_tci) {
+               if (rule->m_ext.vlan_tci != htons(0xfff))
+                       return -EINVAL;
+               spec.match_flags |= EFX_FILTER_MATCH_OUTER_VID;
+               spec.outer_vid = rule->h_ext.vlan_tci;
+       }
+
        rc = efx_filter_insert_filter(efx, &spec, true);
        if (rc < 0)
                return rc;
This page took 0.032463 seconds and 5 git commands to generate.