net: hns3: add support for set_rxnfc
authorLipeng <lipeng321@huawei.com>
Tue, 10 Oct 2017 08:42:05 +0000 (16:42 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 10 Oct 2017 20:09:14 +0000 (13:09 -0700)
This patch supports the ethtool's set_rxnfc().

Signed-off-by: Lipeng <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c

index c677530841cf65f3abfca639cbc102f94e1a9834..d952d6213024e99aa03344843a7ce801c034ef48 100644 (file)
@@ -339,6 +339,8 @@ struct hnae3_ae_ops {
                       u8 *hfunc);
        int (*set_rss)(struct hnae3_handle *handle, const u32 *indir,
                       const u8 *key, const u8 hfunc);
+       int (*set_rss_tuple)(struct hnae3_handle *handle,
+                            struct ethtool_rxnfc *cmd);
 
        int (*get_tc_size)(struct hnae3_handle *handle);
 
index 8ecd807447674eaa031379729a5055ac85bb9e81..60960e588b5fc586d60e9a61edd429807cf1ceab 100644 (file)
@@ -85,6 +85,15 @@ static int hclge_init_cmd_queue(struct hclge_dev *hdev, int ring_type)
        return 0;
 }
 
+void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read)
+{
+       desc->flag = cpu_to_le16(HCLGE_CMD_FLAG_NO_INTR | HCLGE_CMD_FLAG_IN);
+       if (is_read)
+               desc->flag |= cpu_to_le16(HCLGE_CMD_FLAG_WR);
+       else
+               desc->flag &= cpu_to_le16(~HCLGE_CMD_FLAG_WR);
+}
+
 void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
                                enum hclge_opcode_type opcode, bool is_read)
 {
index 8f3ba02aea3ce8cb9b48ef07bfb5c3e7e7030264..b4373345c2b4d3558af8e7cbf2880253a59c6704 100644 (file)
@@ -739,6 +739,7 @@ struct hclge_hw;
 int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num);
 void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
                                enum hclge_opcode_type opcode, bool is_read);
+void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read);
 
 int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
                               struct hclge_promisc_param *param);
index c91c779aeeed1990149d730fbbfb2edfeadf7a18..5b5e52c7fde0ff932e10701338ffe208f5443625 100644 (file)
@@ -2595,8 +2595,6 @@ static int hclge_set_rss_tc_mode(struct hclge_dev *hdev, u16 *tc_valid,
 
 static int hclge_set_rss_input_tuple(struct hclge_dev *hdev)
 {
-#define HCLGE_RSS_INPUT_TUPLE_OTHER            0xf
-#define HCLGE_RSS_INPUT_TUPLE_SCTP             0x1f
        struct hclge_rss_input_tuple_cmd *req;
        struct hclge_desc desc;
        int ret;
@@ -2677,6 +2675,98 @@ static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir,
        return ret;
 }
 
+static u8 hclge_get_rss_hash_bits(struct ethtool_rxnfc *nfc)
+{
+       u8 hash_sets = nfc->data & RXH_L4_B_0_1 ? HCLGE_S_PORT_BIT : 0;
+
+       if (nfc->data & RXH_L4_B_2_3)
+               hash_sets |= HCLGE_D_PORT_BIT;
+       else
+               hash_sets &= ~HCLGE_D_PORT_BIT;
+
+       if (nfc->data & RXH_IP_SRC)
+               hash_sets |= HCLGE_S_IP_BIT;
+       else
+               hash_sets &= ~HCLGE_S_IP_BIT;
+
+       if (nfc->data & RXH_IP_DST)
+               hash_sets |= HCLGE_D_IP_BIT;
+       else
+               hash_sets &= ~HCLGE_D_IP_BIT;
+
+       if (nfc->flow_type == SCTP_V4_FLOW || nfc->flow_type == SCTP_V6_FLOW)
+               hash_sets |= HCLGE_V_TAG_BIT;
+
+       return hash_sets;
+}
+
+static int hclge_set_rss_tuple(struct hnae3_handle *handle,
+                              struct ethtool_rxnfc *nfc)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       struct hclge_rss_input_tuple_cmd *req;
+       struct hclge_desc desc;
+       u8 tuple_sets;
+       int ret;
+
+       if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
+                         RXH_L4_B_0_1 | RXH_L4_B_2_3))
+               return -EINVAL;
+
+       req = (struct hclge_rss_input_tuple_cmd *)desc.data;
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_INPUT_TUPLE, true);
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Read rss tuple fail, status = %d\n", ret);
+               return ret;
+       }
+
+       hclge_cmd_reuse_desc(&desc, false);
+
+       tuple_sets = hclge_get_rss_hash_bits(nfc);
+       switch (nfc->flow_type) {
+       case TCP_V4_FLOW:
+               req->ipv4_tcp_en = tuple_sets;
+               break;
+       case TCP_V6_FLOW:
+               req->ipv6_tcp_en = tuple_sets;
+               break;
+       case UDP_V4_FLOW:
+               req->ipv4_udp_en = tuple_sets;
+               break;
+       case UDP_V6_FLOW:
+               req->ipv6_udp_en = tuple_sets;
+               break;
+       case SCTP_V4_FLOW:
+               req->ipv4_sctp_en = tuple_sets;
+               break;
+       case SCTP_V6_FLOW:
+               if ((nfc->data & RXH_L4_B_0_1) ||
+                   (nfc->data & RXH_L4_B_2_3))
+                       return -EINVAL;
+
+               req->ipv6_sctp_en = tuple_sets;
+               break;
+       case IPV4_FLOW:
+               req->ipv4_fragment_en = HCLGE_RSS_INPUT_TUPLE_OTHER;
+               break;
+       case IPV6_FLOW:
+               req->ipv6_fragment_en = HCLGE_RSS_INPUT_TUPLE_OTHER;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "Set rss tuple fail, status = %d\n", ret);
+
+       return ret;
+}
+
 static int hclge_get_tc_size(struct hnae3_handle *handle)
 {
        struct hclge_vport *vport = hclge_get_vport(handle);
@@ -4344,6 +4434,7 @@ static const struct hnae3_ae_ops hclge_ops = {
        .get_rss_indir_size = hclge_get_rss_indir_size,
        .get_rss = hclge_get_rss,
        .set_rss = hclge_set_rss,
+       .set_rss_tuple = hclge_set_rss_tuple,
        .get_tc_size = hclge_get_tc_size,
        .get_mac_addr = hclge_get_mac_addr,
        .set_mac_addr = hclge_set_mac_addr,
index 79c1a06cb941b630fa6e0d2536b9e7608e63937d..a7c018c7b0eca66987cd9febe6b0941e90bb820d 100644 (file)
 #define HCLGE_RSS_CFG_TBL_NUM \
        (HCLGE_RSS_IND_TBL_SIZE / HCLGE_RSS_CFG_TBL_SIZE)
 
+#define HCLGE_RSS_INPUT_TUPLE_OTHER    GENMASK(3, 0)
+#define HCLGE_RSS_INPUT_TUPLE_SCTP     GENMASK(4, 0)
+#define HCLGE_D_PORT_BIT               BIT(0)
+#define HCLGE_S_PORT_BIT               BIT(1)
+#define HCLGE_D_IP_BIT                 BIT(2)
+#define HCLGE_S_IP_BIT                 BIT(3)
+#define HCLGE_V_TAG_BIT                        BIT(4)
+
 #define HCLGE_RSS_TC_SIZE_0            1
 #define HCLGE_RSS_TC_SIZE_1            2
 #define HCLGE_RSS_TC_SIZE_2            4
index 1c5d003ecf294f7907c89ad683c941e29265b0a4..f0e88e00a1f6f71aaf47582079bda634e7232729 100644 (file)
@@ -533,6 +533,21 @@ int hns3_set_ringparam(struct net_device *ndev, struct ethtool_ringparam *param)
        return ret;
 }
 
+static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+       struct hnae3_handle *h = hns3_get_handle(netdev);
+
+       if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss_tuple)
+               return -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_SRXFH:
+               return h->ae_algo->ops->set_rss_tuple(h, cmd);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static const struct ethtool_ops hns3_ethtool_ops = {
        .get_drvinfo = hns3_get_drvinfo,
        .get_link = hns3_get_link,
@@ -543,6 +558,7 @@ static const struct ethtool_ops hns3_ethtool_ops = {
        .get_ethtool_stats = hns3_get_stats,
        .get_sset_count = hns3_get_sset_count,
        .get_rxnfc = hns3_get_rxnfc,
+       .set_rxnfc = hns3_set_rxnfc,
        .get_rxfh_key_size = hns3_get_rss_key_size,
        .get_rxfh_indir_size = hns3_get_rss_indir_size,
        .get_rxfh = hns3_get_rss,