bnx2x: Add support for 4-tupple UDP RSS
authorMerav Sicron <meravs@broadcom.com>
Tue, 19 Jun 2012 07:48:24 +0000 (07:48 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 Jun 2012 21:34:34 +0000 (14:34 -0700)
This change enables to control via ethtool whether to do UDP RSS on 2-tupple
(IP source / destination only) or on 4-tupple (include UDP source / destination
port). It also enables to read back the RSS configuration.

Signed-off-by: Merav Sicron <meravs@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h

index 9370f5ffaf4ad04def8dc1f6215c187a0ea925e2..f4366f79c1173ff9ba27bd340861d59eddee74c5 100644 (file)
@@ -1666,14 +1666,13 @@ static void bnx2x_set_rx_buf_size(struct bnx2x *bp)
 static int bnx2x_init_rss_pf(struct bnx2x *bp)
 {
        int i;
-       u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
        u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp);
 
        /* Prepare the initial contents fo the indirection table if RSS is
         * enabled
         */
-       for (i = 0; i < sizeof(ind_table); i++)
-               ind_table[i] =
+       for (i = 0; i < sizeof(bp->rss_conf_obj.ind_table); i++)
+               bp->rss_conf_obj.ind_table[i] =
                        bp->fp->cl_id +
                        ethtool_rxfh_indir_default(i, num_eth_queues);
 
@@ -1685,12 +1684,11 @@ static int bnx2x_init_rss_pf(struct bnx2x *bp)
         * For 57712 and newer on the other hand it's a per-function
         * configuration.
         */
-       return bnx2x_config_rss_eth(bp, ind_table,
-                                   bp->port.pmf || !CHIP_IS_E1x(bp));
+       return bnx2x_config_rss_eth(bp, bp->port.pmf || !CHIP_IS_E1x(bp));
 }
 
 int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
-                       u8 *ind_table, bool config_hash)
+                       bool config_hash)
 {
        struct bnx2x_config_rss_params params = {NULL};
        int i;
@@ -1713,11 +1711,15 @@ int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
        __set_bit(BNX2X_RSS_IPV4_TCP, &params.rss_flags);
        __set_bit(BNX2X_RSS_IPV6, &params.rss_flags);
        __set_bit(BNX2X_RSS_IPV6_TCP, &params.rss_flags);
+       if (rss_obj->udp_rss_v4)
+               __set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
+       if (rss_obj->udp_rss_v6)
+               __set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);
 
        /* Hash bits */
        params.rss_result_mask = MULTI_MASK;
 
-       memcpy(params.ind_table, ind_table, sizeof(params.ind_table));
+       memcpy(params.ind_table, rss_obj->ind_table, sizeof(params.ind_table));
 
        if (config_hash) {
                /* RSS keys */
index 7cd99b75347a162467af239599c1a16274fecca5..bb479843d59c9a0adff90343a7e888e0b3684609 100644 (file)
@@ -94,7 +94,7 @@ void bnx2x_send_unload_done(struct bnx2x *bp);
  * @config_hash:       re-configure RSS hash keys configuration
  */
 int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
-                       u8 *ind_table, bool config_hash);
+                       bool config_hash);
 
 /**
  * bnx2x__init_func_obj - init function object
@@ -865,11 +865,9 @@ static inline int func_by_vn(struct bnx2x *bp, int vn)
        return 2 * vn + BP_PORT(bp);
 }
 
-static inline int bnx2x_config_rss_eth(struct bnx2x *bp, u8 *ind_table,
-                                      bool config_hash)
+static inline int bnx2x_config_rss_eth(struct bnx2x *bp, bool config_hash)
 {
-       return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, ind_table,
-                                  config_hash);
+       return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, config_hash);
 }
 
 /**
index ed2b49a0c5a540332f17daea3a0ca6bc815e8cca..d096813994b2661ea95affe1da7598619f382fa6 100644 (file)
@@ -2600,6 +2600,41 @@ static int bnx2x_set_phys_id(struct net_device *dev,
        return 0;
 }
 
+static int bnx2x_get_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
+{
+
+       switch (info->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               info->data = RXH_IP_SRC | RXH_IP_DST |
+                            RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case UDP_V4_FLOW:
+               if (bp->rss_conf_obj.udp_rss_v4)
+                       info->data = RXH_IP_SRC | RXH_IP_DST |
+                                    RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               else
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               break;
+       case UDP_V6_FLOW:
+               if (bp->rss_conf_obj.udp_rss_v6)
+                       info->data = RXH_IP_SRC | RXH_IP_DST |
+                                    RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               else
+                       info->data = RXH_IP_SRC | RXH_IP_DST;
+               break;
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               info->data = RXH_IP_SRC | RXH_IP_DST;
+               break;
+       default:
+               info->data = 0;
+               break;
+       }
+
+       return 0;
+}
+
 static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
                           u32 *rules __always_unused)
 {
@@ -2609,7 +2644,102 @@ static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
        case ETHTOOL_GRXRINGS:
                info->data = BNX2X_NUM_ETH_QUEUES(bp);
                return 0;
+       case ETHTOOL_GRXFH:
+               return bnx2x_get_rss_flags(bp, info);
+       default:
+               DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
+{
+       int udp_rss_requested;
+
+       DP(BNX2X_MSG_ETHTOOL,
+          "Set rss flags command parameters: flow type = %d, data = %llu\n",
+          info->flow_type, info->data);
+
+       switch (info->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               /* For TCP only 4-tupple hash is supported */
+               if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
+                                 RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+                       DP(BNX2X_MSG_ETHTOOL,
+                          "Command parameters not supported\n");
+                       return -EINVAL;
+               } else {
+                       return 0;
+               }
+
+       case UDP_V4_FLOW:
+       case UDP_V6_FLOW:
+               /* For UDP either 2-tupple hash or 4-tupple hash is supported */
+               if (info->data == (RXH_IP_SRC | RXH_IP_DST |
+                                RXH_L4_B_0_1 | RXH_L4_B_2_3))
+                       udp_rss_requested = 1;
+               else if (info->data == (RXH_IP_SRC | RXH_IP_DST))
+                       udp_rss_requested = 0;
+               else
+                       return -EINVAL;
+               if ((info->flow_type == UDP_V4_FLOW) &&
+                   (bp->rss_conf_obj.udp_rss_v4 != udp_rss_requested)) {
+                       bp->rss_conf_obj.udp_rss_v4 = udp_rss_requested;
+                       DP(BNX2X_MSG_ETHTOOL,
+                          "rss re-configured, UDP 4-tupple %s\n",
+                          udp_rss_requested ? "enabled" : "disabled");
+                       return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
+               } else if ((info->flow_type == UDP_V6_FLOW) &&
+                          (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) {
+                       bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested;
+                       return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
+                       DP(BNX2X_MSG_ETHTOOL,
+                          "rss re-configured, UDP 4-tupple %s\n",
+                          udp_rss_requested ? "enabled" : "disabled");
+               } else {
+                       return 0;
+               }
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               /* For IP only 2-tupple hash is supported */
+               if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
+                       DP(BNX2X_MSG_ETHTOOL,
+                          "Command parameters not supported\n");
+                       return -EINVAL;
+               } else {
+                       return 0;
+               }
+       case SCTP_V4_FLOW:
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case SCTP_V6_FLOW:
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case IP_USER_FLOW:
+       case ETHER_FLOW:
+               /* RSS is not supported for these protocols */
+               if (info->data) {
+                       DP(BNX2X_MSG_ETHTOOL,
+                          "Command parameters not supported\n");
+                       return -EINVAL;
+               } else {
+                       return 0;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bnx2x_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+{
+       struct bnx2x *bp = netdev_priv(dev);
 
+       switch (info->cmd) {
+       case ETHTOOL_SRXFH:
+               return bnx2x_set_rss_flags(bp, info);
        default:
                DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
                return -EOPNOTSUPP;
@@ -2649,7 +2779,6 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
 {
        struct bnx2x *bp = netdev_priv(dev);
        size_t i;
-       u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
 
        for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
                /*
@@ -2661,10 +2790,10 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
                 * align the received table to the Client ID of the leading RSS
                 * queue
                 */
-               ind_table[i] = indir[i] + bp->fp->cl_id;
+               bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id;
        }
 
-       return bnx2x_config_rss_eth(bp, ind_table, false);
+       return bnx2x_config_rss_eth(bp, false);
 }
 
 static const struct ethtool_ops bnx2x_ethtool_ops = {
@@ -2694,6 +2823,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
        .set_phys_id            = bnx2x_set_phys_id,
        .get_ethtool_stats      = bnx2x_get_ethtool_stats,
        .get_rxnfc              = bnx2x_get_rxnfc,
+       .set_rxnfc              = bnx2x_set_rxnfc,
        .get_rxfh_indir_size    = bnx2x_get_rxfh_indir_size,
        .get_rxfh_indir         = bnx2x_get_rxfh_indir,
        .set_rxfh_indir         = bnx2x_set_rxfh_indir,
index 6c14b4a4e82cef8af70d34b812f7af46873484a0..734fd87cd99093e0d30899006cb12cacd10a027c 100644 (file)
@@ -4107,6 +4107,10 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
                data->capabilities |=
                        ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
 
+       if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags))
+               data->capabilities |=
+                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
+
        if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags))
                data->capabilities |=
                        ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
@@ -4115,6 +4119,10 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
                data->capabilities |=
                        ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
 
+       if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags))
+               data->capabilities |=
+                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
+
        /* Hashing mask */
        data->rss_result_mask = p->rss_result_mask;
 
index efd80bdd0dfe2c906697edf7a821eadfd87b80b2..76818ef08f9b578ee3a4a5fe1a203a771bfb1bfe 100644 (file)
@@ -694,8 +694,10 @@ enum {
 
        BNX2X_RSS_IPV4,
        BNX2X_RSS_IPV4_TCP,
+       BNX2X_RSS_IPV4_UDP,
        BNX2X_RSS_IPV6,
        BNX2X_RSS_IPV6_TCP,
+       BNX2X_RSS_IPV6_UDP,
 };
 
 struct bnx2x_config_rss_params {
@@ -729,6 +731,10 @@ struct bnx2x_rss_config_obj {
        /* Last configured indirection table */
        u8                      ind_table[T_ETH_INDIRECTION_TABLE_SIZE];
 
+       /* flags for enabling 4-tupple hash on UDP */
+       u8                      udp_rss_v4;
+       u8                      udp_rss_v6;
+
        int (*config_rss)(struct bnx2x *bp,
                          struct bnx2x_config_rss_params *p);
 };