net: hns3: add link change event report
authorJian Shen <shenjian15@huawei.com>
Thu, 1 Aug 2019 03:55:34 +0000 (11:55 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Aug 2019 17:32:12 +0000 (13:32 -0400)
Previously, PF updates link status per second. For some scenario,
it requires link down event being reported more quickly.
To solve it, firmware pushes the link change event to PF with
CMDQ message, and driver updates the link status directly.

Signed-off-by: Jian Shen <shenjian15@huawei.com>
Reviewed-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.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/hclge_mbx.c

index 75329ab775a61efa04f4aca2952ebed56c8ec495..1564be5e148b03b852d18c49d79b4e72436da3d7 100644 (file)
@@ -47,6 +47,7 @@ enum HCLGE_MBX_OPCODE {
        HCLGE_MBX_GET_MEDIA_TYPE,       /* (VF -> PF) get media type */
 
        HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */
+       HCLGE_MBX_PUSH_LINK_STATUS,     /* (M7 -> PF) get port link status */
 };
 
 /* below are per-VF mac-vlan subcodes */
index d9858f285460e70300ec6f8c56107a4f390777c9..538d1017592a2a36846a79b648267418481b9e0c 100644 (file)
@@ -383,6 +383,22 @@ err_csq:
        return ret;
 }
 
+static int hclge_firmware_compat_config(struct hclge_dev *hdev)
+{
+       struct hclge_firmware_compat_cmd *req;
+       struct hclge_desc desc;
+       u32 compat = 0;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false);
+
+       req = (struct hclge_firmware_compat_cmd *)desc.data;
+
+       hnae3_set_bit(compat, HCLGE_LINK_EVENT_REPORT_EN_B, 1);
+       req->compat = cpu_to_le32(compat);
+
+       return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
 int hclge_cmd_init(struct hclge_dev *hdev)
 {
        u32 version;
@@ -429,6 +445,15 @@ int hclge_cmd_init(struct hclge_dev *hdev)
                 hnae3_get_field(version, HNAE3_FW_VERSION_BYTE0_MASK,
                                 HNAE3_FW_VERSION_BYTE0_SHIFT));
 
+       /* ask the firmware to enable some features, driver can work without
+        * it.
+        */
+       ret = hclge_firmware_compat_config(hdev);
+       if (ret)
+               dev_warn(&hdev->pdev->dev,
+                        "Firmware compatible features not enabled(%d).\n",
+                        ret);
+
        return 0;
 
 err_cmd_init:
index 96840d8f3e2423cf45f3cfe632e8b674556a8523..743c9f41c67ea2a9d2a41948e03762bc05b1482e 100644 (file)
@@ -257,6 +257,7 @@ enum hclge_opcode_type {
        /* M7 stats command */
        HCLGE_OPC_M7_STATS_BD           = 0x7012,
        HCLGE_OPC_M7_STATS_INFO         = 0x7013,
+       HCLGE_OPC_M7_COMPAT_CFG         = 0x701A,
 
        /* SFP command */
        HCLGE_OPC_GET_SFP_INFO          = 0x7104,
@@ -1009,6 +1010,12 @@ struct hclge_query_ppu_pf_other_int_dfx_cmd {
        u8 rsv[4];
 };
 
+#define HCLGE_LINK_EVENT_REPORT_EN_B   0
+struct hclge_firmware_compat_cmd {
+       __le32 compat;
+       u8 rsv[20];
+};
+
 int hclge_cmd_init(struct hclge_dev *hdev);
 static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
 {
index 4138780fca3920fdfaae779e24e955485cb152fa..855b65e8ebf6573ea79a8d0ba96c8faf5fbac1da 100644 (file)
@@ -2517,7 +2517,7 @@ static void hclge_reset_task_schedule(struct hclge_dev *hdev)
                              &hdev->rst_service_task);
 }
 
-static void hclge_task_schedule(struct hclge_dev *hdev)
+void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time)
 {
        if (!test_bit(HCLGE_STATE_DOWN, &hdev->state) &&
            !test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
@@ -2526,7 +2526,7 @@ static void hclge_task_schedule(struct hclge_dev *hdev)
                hdev->fd_arfs_expire_timer++;
                mod_delayed_work_on(cpumask_first(&hdev->affinity_mask),
                                    system_wq, &hdev->service_task,
-                                   round_jiffies_relative(HZ));
+                                   delay_time);
        }
 }
 
@@ -3636,7 +3636,7 @@ static void hclge_service_task(struct work_struct *work)
                hdev->fd_arfs_expire_timer = 0;
        }
 
-       hclge_task_schedule(hdev);
+       hclge_task_schedule(hdev, round_jiffies_relative(HZ));
 }
 
 struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle)
@@ -6175,7 +6175,7 @@ static void hclge_set_timer_task(struct hnae3_handle *handle, bool enable)
        struct hclge_dev *hdev = vport->back;
 
        if (enable) {
-               hclge_task_schedule(hdev);
+               hclge_task_schedule(hdev, round_jiffies_relative(HZ));
        } else {
                /* Set the DOWN flag here to disable the service to be
                 * scheduled again
@@ -6220,6 +6220,7 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
        if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) &&
            hdev->reset_type != HNAE3_FUNC_RESET) {
                hclge_mac_stop_phy(hdev);
+               hclge_update_link_status(hdev);
                return;
        }
 
index 688e4250491dd6f40518a34ef89ea305fd77a5bf..c9b9867fc226a6cf9f55dd1f5ec2684a84e6ca98 100644 (file)
@@ -302,6 +302,13 @@ enum hclge_fc_mode {
        HCLGE_FC_DEFAULT
 };
 
+enum hclge_link_fail_code {
+       HCLGE_LF_NORMAL,
+       HCLGE_LF_REF_CLOCK_LOST,
+       HCLGE_LF_XSFP_TX_DISABLE,
+       HCLGE_LF_XSFP_ABSENT,
+};
+
 #define HCLGE_PG_NUM           4
 #define HCLGE_SCH_MODE_SP      0
 #define HCLGE_SCH_MODE_DWRR    1
@@ -1021,4 +1028,5 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
 int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
                                      u16 state, u16 vlan_tag, u16 qos,
                                      u16 vlan_proto);
+void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time);
 #endif
index 690b9990215caf7aa3adf72b65a1d8b248c9a7f6..87de32dfa6c838d2045b03fa498760e4c1e1f6ce 100644 (file)
@@ -545,6 +545,36 @@ static int hclge_get_rss_key(struct hclge_vport *vport,
                                    HCLGE_RSS_MBX_RESP_LEN);
 }
 
+static void hclge_link_fail_parse(struct hclge_dev *hdev, u8 link_fail_code)
+{
+       switch (link_fail_code) {
+       case HCLGE_LF_REF_CLOCK_LOST:
+               dev_warn(&hdev->pdev->dev, "Reference clock lost!\n");
+               break;
+       case HCLGE_LF_XSFP_TX_DISABLE:
+               dev_warn(&hdev->pdev->dev, "SFP tx is disabled!\n");
+               break;
+       case HCLGE_LF_XSFP_ABSENT:
+               dev_warn(&hdev->pdev->dev, "SFP is absent!\n");
+               break;
+       default:
+               break;
+       }
+}
+
+static void hclge_handle_link_change_event(struct hclge_dev *hdev,
+                                          struct hclge_mbx_vf_to_pf_cmd *req)
+{
+#define LINK_STATUS_OFFSET     1
+#define LINK_FAIL_CODE_OFFSET  2
+
+       clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state);
+       hclge_task_schedule(hdev, 0);
+
+       if (!req->msg[LINK_STATUS_OFFSET])
+               hclge_link_fail_parse(hdev, req->msg[LINK_FAIL_CODE_OFFSET]);
+}
+
 static bool hclge_cmd_crq_empty(struct hclge_hw *hw)
 {
        u32 tail = hclge_read_dev(hw, HCLGE_NIC_CRQ_TAIL_REG);
@@ -707,6 +737,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
                                        "PF fail(%d) to media type for VF\n",
                                        ret);
                        break;
+               case HCLGE_MBX_PUSH_LINK_STATUS:
+                       hclge_handle_link_change_event(hdev, req);
+                       break;
                default:
                        dev_err(&hdev->pdev->dev,
                                "un-supported mailbox message, code = %d\n",