net/hns3: support LSC event report
authorChengwen Feng <fengchengwen@huawei.com>
Fri, 22 Jan 2021 10:18:52 +0000 (18:18 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 2 Feb 2021 23:48:11 +0000 (00:48 +0100)
This patch support LSC (Link Status Change) event report.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
Signed-off-by: Lijun Ou <oulijun@huawei.com>
drivers/net/hns3/hns3_ethdev.c
drivers/net/hns3/hns3_ethdev.h
drivers/net/hns3/hns3_ethdev_vf.c
drivers/net/hns3/hns3_mbx.c

index d9dd8e1..221e008 100644 (file)
@@ -19,6 +19,7 @@
 #define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM      1
 
 #define HNS3_SERVICE_INTERVAL          1000000 /* us */
+#define HNS3_SERVICE_QUICK_INTERVAL    10
 #define HNS3_INVALID_PVID              0xFFFF
 
 #define HNS3_FILTER_TYPE_VF            0
@@ -93,6 +94,7 @@ static int hns3_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
 static int hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid,
                                    int on);
 static int hns3_update_speed_duplex(struct rte_eth_dev *eth_dev);
+static bool hns3_update_link_status(struct hns3_hw *hw);
 
 static int hns3_add_mc_addr(struct hns3_hw *hw,
                            struct rte_ether_addr *mac_addr);
@@ -4458,7 +4460,7 @@ hns3_get_mac_link_status(struct hns3_hw *hw)
        return !!link_status;
 }
 
-void
+static bool
 hns3_update_link_status(struct hns3_hw *hw)
 {
        int state;
@@ -4467,7 +4469,36 @@ hns3_update_link_status(struct hns3_hw *hw)
        if (state != hw->mac.link_status) {
                hw->mac.link_status = state;
                hns3_warn(hw, "Link status change to %s!", state ? "up" : "down");
+               return true;
        }
+
+       return false;
+}
+
+/*
+ * Current, the PF driver get link status by two ways:
+ * 1) Periodic polling in the intr thread context, driver call
+ *    hns3_update_link_status to update link status.
+ * 2) Firmware report async interrupt, driver process the event in the intr
+ *    thread context, and call hns3_update_link_status to update link status.
+ *
+ * If detect link status changed, driver need report LSE. One method is add the
+ * report LSE logic in hns3_update_link_status.
+ *
+ * But the PF driver ops(link_update) also call hns3_update_link_status to
+ * update link status.
+ * If we report LSE in hns3_update_link_status, it may lead to deadlock in the
+ * bonding application.
+ *
+ * So add the one new API which used only in intr thread context.
+ */
+void
+hns3_update_link_status_and_event(struct hns3_hw *hw)
+{
+       struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+       bool changed = hns3_update_link_status(hw);
+       if (changed)
+               rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 }
 
 static void
@@ -4479,9 +4510,10 @@ hns3_service_handler(void *param)
 
        if (!hns3_is_reset_pending(hns)) {
                hns3_update_speed_duplex(eth_dev);
-               hns3_update_link_status(hw);
-       } else
+               hns3_update_link_status_and_event(hw);
+       } else {
                hns3_warn(hw, "Cancel the query when reset is pending");
+       }
 
        rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev);
 }
@@ -5557,8 +5589,10 @@ hns3_stop_service(struct hns3_adapter *hns)
        struct rte_eth_dev *eth_dev;
 
        eth_dev = &rte_eth_devices[hw->data->port_id];
-       if (hw->adapter_state == HNS3_NIC_STARTED)
+       if (hw->adapter_state == HNS3_NIC_STARTED) {
                rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
+               hns3_update_link_status_and_event(hw);
+       }
        hw->mac.link_status = ETH_LINK_DOWN;
 
        hns3_set_rxtx_function(eth_dev);
@@ -5601,7 +5635,15 @@ hns3_start_service(struct hns3_adapter *hns)
        hns3_set_rxtx_function(eth_dev);
        hns3_mp_req_start_rxtx(eth_dev);
        if (hw->adapter_state == HNS3_NIC_STARTED) {
-               hns3_service_handler(eth_dev);
+               /*
+                * This API parent function already hold the hns3_hw.lock, the
+                * hns3_service_handler may report lse, in bonding application
+                * it will call driver's ops which may acquire the hns3_hw.lock
+                * again, thus lead to deadlock.
+                * We defer calls hns3_service_handler to avoid the deadlock.
+                */
+               rte_eal_alarm_set(HNS3_SERVICE_QUICK_INTERVAL,
+                                 hns3_service_handler, eth_dev);
 
                /* Enable interrupt of all rx queues before enabling queues */
                hns3_dev_all_rx_queue_intr_enable(hw, true);
index 6374a76..e72f3e1 100644 (file)
@@ -946,11 +946,13 @@ int hns3_dev_filter_ctrl(struct rte_eth_dev *dev,
                         enum rte_filter_op filter_op, void *arg);
 bool hns3_is_reset_pending(struct hns3_adapter *hns);
 bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
-void hns3_update_link_status(struct hns3_hw *hw);
+void hns3_update_link_status_and_event(struct hns3_hw *hw);
 void hns3_ether_format_addr(char *buf, uint16_t size,
                        const struct rte_ether_addr *ether_addr);
 int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
                       struct rte_eth_dev_info *info);
+void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
+                         uint32_t link_speed, uint8_t link_duplex);
 
 static inline bool
 is_reset_pending(struct hns3_adapter *hns)
index 0ee06bf..faf7e01 100644 (file)
@@ -1440,6 +1440,41 @@ hns3vf_request_link_info(struct hns3_hw *hw)
                hns3_err(hw, "Failed to fetch link status from PF: %d", ret);
 }
 
+void
+hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
+                         uint32_t link_speed, uint8_t link_duplex)
+{
+       struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+       struct hns3_mac *mac = &hw->mac;
+       bool report_lse;
+       bool changed;
+
+       changed = mac->link_status != link_status ||
+                 mac->link_speed != link_speed ||
+                 mac->link_duplex != link_duplex;
+       if (!changed)
+               return;
+
+       /*
+        * VF's link status/speed/duplex were updated by polling from PF driver,
+        * because the link status/speed/duplex may be changed in the polling
+        * interval, so driver will report lse (lsc event) once any of the above
+        * thress variables changed.
+        * But if the PF's link status is down and driver saved link status is
+        * also down, there are no need to report lse.
+        */
+       report_lse = true;
+       if (link_status == ETH_LINK_DOWN && link_status == mac->link_status)
+               report_lse = false;
+
+       mac->link_status = link_status;
+       mac->link_speed = link_speed;
+       mac->link_duplex = link_duplex;
+
+       if (report_lse)
+               rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+}
+
 static int
 hns3vf_vlan_filter_configure(struct hns3_adapter *hns, uint16_t vlan_id, int on)
 {
@@ -2373,8 +2408,11 @@ hns3vf_stop_service(struct hns3_adapter *hns)
        struct rte_eth_dev *eth_dev;
 
        eth_dev = &rte_eth_devices[hw->data->port_id];
-       if (hw->adapter_state == HNS3_NIC_STARTED)
+       if (hw->adapter_state == HNS3_NIC_STARTED) {
                rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
+               hns3vf_update_link_status(hw, ETH_LINK_DOWN, hw->mac.link_speed,
+                       hw->mac.link_duplex);
+       }
        hw->mac.link_status = ETH_LINK_DOWN;
 
        hns3_set_rxtx_function(eth_dev);
index 1d500b9..925cfca 100644 (file)
@@ -203,8 +203,9 @@ hns3_cmd_crq_empty(struct hns3_hw *hw)
 static void
 hns3_mbx_handler(struct hns3_hw *hw)
 {
-       struct hns3_mac *mac = &hw->mac;
        enum hns3_reset_level reset_level;
+       uint8_t link_status, link_duplex;
+       uint32_t link_speed;
        uint16_t *msg_q;
        uint8_t opcode;
        uint32_t tail;
@@ -218,10 +219,11 @@ hns3_mbx_handler(struct hns3_hw *hw)
                opcode = msg_q[0] & 0xff;
                switch (opcode) {
                case HNS3_MBX_LINK_STAT_CHANGE:
-                       memcpy(&mac->link_speed, &msg_q[2],
-                                  sizeof(mac->link_speed));
-                       mac->link_status = rte_le_to_cpu_16(msg_q[1]);
-                       mac->link_duplex = (uint8_t)rte_le_to_cpu_16(msg_q[4]);
+                       memcpy(&link_speed, &msg_q[2], sizeof(link_speed));
+                       link_status = rte_le_to_cpu_16(msg_q[1]);
+                       link_duplex = (uint8_t)rte_le_to_cpu_16(msg_q[4]);
+                       hns3vf_update_link_status(hw, link_status, link_speed,
+                                                 link_duplex);
                        break;
                case HNS3_MBX_ASSERTING_RESET:
                        /* PF has asserted reset hence VF should go in pending
@@ -310,7 +312,7 @@ hns3_handle_link_change_event(struct hns3_hw *hw,
        if (!req->msg[LINK_STATUS_OFFSET])
                hns3_link_fail_parse(hw, req->msg[LINK_FAIL_CODE_OFFSET]);
 
-       hns3_update_link_status(hw);
+       hns3_update_link_status_and_event(hw);
 }
 
 static void