]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
net: hns3: Add mac loopback selftest support in hns3 driver
[mirror_ubuntu-bionic-kernel.git] / drivers / net / ethernet / hisilicon / hns3 / hns3pf / hclge_main.c
index c91c779aeeed1990149d730fbbfb2edfeadf7a18..8508521c26e8ff7790d2881ef8d47d01c85b5c39 100644 (file)
@@ -2350,11 +2350,11 @@ static int hclge_get_status(struct hnae3_handle *handle)
        return hdev->hw.mac.link;
 }
 
-static void hclge_service_timer(unsigned long data)
+static void hclge_service_timer(struct timer_list *t)
 {
-       struct hclge_dev *hdev = (struct hclge_dev *)data;
-       (void)mod_timer(&hdev->service_timer, jiffies + HZ);
+       struct hclge_dev *hdev = from_timer(hdev, t, service_timer);
 
+       mod_timer(&hdev->service_timer, jiffies + HZ);
        hclge_task_schedule(hdev);
 }
 
@@ -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,161 @@ 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_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;
+
+       nfc->data = 0;
+
+       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;
+       }
+
+       switch (nfc->flow_type) {
+       case TCP_V4_FLOW:
+               tuple_sets = req->ipv4_tcp_en;
+               break;
+       case UDP_V4_FLOW:
+               tuple_sets = req->ipv4_udp_en;
+               break;
+       case TCP_V6_FLOW:
+               tuple_sets = req->ipv6_tcp_en;
+               break;
+       case UDP_V6_FLOW:
+               tuple_sets = req->ipv6_udp_en;
+               break;
+       case SCTP_V4_FLOW:
+               tuple_sets = req->ipv4_sctp_en;
+               break;
+       case SCTP_V6_FLOW:
+               tuple_sets = req->ipv6_sctp_en;
+               break;
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               tuple_sets = HCLGE_S_IP_BIT | HCLGE_D_IP_BIT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!tuple_sets)
+               return 0;
+
+       if (tuple_sets & HCLGE_D_PORT_BIT)
+               nfc->data |= RXH_L4_B_2_3;
+       if (tuple_sets & HCLGE_S_PORT_BIT)
+               nfc->data |= RXH_L4_B_0_1;
+       if (tuple_sets & HCLGE_D_IP_BIT)
+               nfc->data |= RXH_IP_DST;
+       if (tuple_sets & HCLGE_S_IP_BIT)
+               nfc->data |= RXH_IP_SRC;
+
+       return 0;
+}
+
 static int hclge_get_tc_size(struct hnae3_handle *handle)
 {
        struct hclge_vport *vport = hclge_get_vport(handle);
@@ -2996,6 +3149,59 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
                        "mac enable fail, ret =%d.\n", ret);
 }
 
+static int hclge_set_loopback(struct hnae3_handle *handle,
+                             enum hnae3_loop loop_mode, bool en)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_config_mac_mode_cmd *req;
+       struct hclge_dev *hdev = vport->back;
+       struct hclge_desc desc;
+       u32 loop_en;
+       int ret;
+
+       switch (loop_mode) {
+       case HNAE3_MAC_INTER_LOOP_MAC:
+               req = (struct hclge_config_mac_mode_cmd *)&desc.data[0];
+               /* 1 Read out the MAC mode config at first */
+               hclge_cmd_setup_basic_desc(&desc,
+                                          HCLGE_OPC_CONFIG_MAC_MODE,
+                                          true);
+               ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+               if (ret) {
+                       dev_err(&hdev->pdev->dev,
+                               "mac loopback get fail, ret =%d.\n",
+                               ret);
+                       return ret;
+               }
+
+               /* 2 Then setup the loopback flag */
+               loop_en = le32_to_cpu(req->txrx_pad_fcs_loop_en);
+               if (en)
+                       hnae_set_bit(loop_en, HCLGE_MAC_APP_LP_B, 1);
+               else
+                       hnae_set_bit(loop_en, HCLGE_MAC_APP_LP_B, 0);
+
+               req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en);
+
+               /* 3 Config mac work mode with loopback flag
+                * and its original configure parameters
+                */
+               hclge_cmd_reuse_desc(&desc, false);
+               ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+               if (ret)
+                       dev_err(&hdev->pdev->dev,
+                               "mac loopback set fail, ret =%d.\n", ret);
+               break;
+       default:
+               ret = -ENOTSUPP;
+               dev_err(&hdev->pdev->dev,
+                       "loop_mode %d is not supported\n", loop_mode);
+               break;
+       }
+
+       return ret;
+}
+
 static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id,
                            int stream_id, bool enable)
 {
@@ -3051,7 +3257,7 @@ static int hclge_ae_start(struct hnae3_handle *handle)
        /* mac enable */
        hclge_cfg_mac_mode(hdev, true);
        clear_bit(HCLGE_STATE_DOWN, &hdev->state);
-       (void)mod_timer(&hdev->service_timer, jiffies + HZ);
+       mod_timer(&hdev->service_timer, jiffies + HZ);
 
        ret = hclge_mac_start_phy(hdev);
        if (ret)
@@ -4283,8 +4489,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
 
        hclge_dcb_ops_set(hdev);
 
-       setup_timer(&hdev->service_timer, hclge_service_timer,
-                   (unsigned long)hdev);
+       timer_setup(&hdev->service_timer, hclge_service_timer, 0);
        INIT_WORK(&hdev->service_task, hclge_service_task);
 
        set_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state);
@@ -4311,7 +4516,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
        if (IS_ENABLED(CONFIG_PCI_IOV))
                hclge_disable_sriov(hdev);
 
-       if (hdev->service_timer.data)
+       if (hdev->service_timer.function)
                del_timer_sync(&hdev->service_timer);
        if (hdev->service_task.func)
                cancel_work_sync(&hdev->service_task);
@@ -4333,6 +4538,7 @@ static const struct hnae3_ae_ops hclge_ops = {
        .unmap_ring_from_vector = hclge_unmap_ring_from_vector,
        .get_vector = hclge_get_vector,
        .set_promisc_mode = hclge_set_promisc_mode,
+       .set_loopback = hclge_set_loopback,
        .start = hclge_ae_start,
        .stop = hclge_ae_stop,
        .get_status = hclge_get_status,
@@ -4344,6 +4550,8 @@ 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_rss_tuple = hclge_get_rss_tuple,
        .get_tc_size = hclge_get_tc_size,
        .get_mac_addr = hclge_get_mac_addr,
        .set_mac_addr = hclge_set_mac_addr,