[14/14] net/hns3: support LSC event report

Message ID 1611310732-51975-15-git-send-email-oulijun@huawei.com (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series Misc updates for hns3 |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-mellanox-Functional success Functional Testing PASS
ci/iol-testing warning Testing issues

Commit Message

Lijun Ou Jan. 22, 2021, 10:18 a.m. UTC
  From: Chengwen Feng <fengchengwen@huawei.com>

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    | 52 +++++++++++++++++++++++++++++++++++----
 drivers/net/hns3/hns3_ethdev.h    |  4 ++-
 drivers/net/hns3/hns3_ethdev_vf.c | 40 +++++++++++++++++++++++++++++-
 drivers/net/hns3/hns3_mbx.c       | 14 ++++++-----
 4 files changed, 97 insertions(+), 13 deletions(-)
  

Comments

Ferruh Yigit Jan. 28, 2021, 11:41 p.m. UTC | #1
On 1/22/2021 10:18 AM, Lijun Ou wrote:
> From: Chengwen Feng <fengchengwen@huawei.com>
> 
> This patch support LSC(Link Status Change) event report.

There is a user config for lsc, 'dev->data->dev_conf.intr_conf.lsc', which seems 
not taken into account.

Also 'RTE_PCI_DRV_INTR_LSC' should be set in 'rte_pci_driver.drv_flags' to 
report this feature to higher levels.

And when the feature is fully implemented, can you please add "Link status 
event" feature to 'hns3.ini'?

> 
> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
> Signed-off-by: Lijun Ou <oulijun@huawei.com>

<...>
  
Lijun Ou Jan. 29, 2021, 1:49 a.m. UTC | #2
在 2021/1/29 7:41, Ferruh Yigit 写道:
> On 1/22/2021 10:18 AM, Lijun Ou wrote:
>> From: Chengwen Feng <fengchengwen@huawei.com>
>>
>> This patch support LSC(Link Status Change) event report.
> 
> There is a user config for lsc, 'dev->data->dev_conf.intr_conf.lsc', 
> which seems not taken into account.
> 
Frist of all, thank you for your review. Currently, the old firmware 
doest not support interrupt reporting. Therefore, the PF does not suport 
interrupt reporting through the mailbox. Therefore, the PF obtains 
interrupts in polling mode and then reports interrupts.


> Also 'RTE_PCI_DRV_INTR_LSC' should be set in 'rte_pci_driver.drv_flags' 
> to report this feature to higher levels.
> 
In the future, the new firmware + PF will support interrupt reporting. 
In that case, the LSC capability of dev_flag will be set.
In the future, we will enable the VF to support LSC. That is, we are 
developing the PF to report LSC interrupts through the mailbox.
> And when the feature is fully implemented, can you please add "Link 
> status event" feature to 'hns3.ini'?
> 
By then, we'll add it in hns3.ini.
>>
>> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
>> Signed-off-by: Lijun Ou <oulijun@huawei.com>
> 
> <...>
> .
>
  
Ferruh Yigit Feb. 2, 2021, 12:06 p.m. UTC | #3
On 1/29/2021 1:49 AM, oulijun wrote:
> 
> 
> 在 2021/1/29 7:41, Ferruh Yigit 写道:
>> On 1/22/2021 10:18 AM, Lijun Ou wrote:
>>> From: Chengwen Feng <fengchengwen@huawei.com>
>>>
>>> This patch support LSC(Link Status Change) event report.
>>
>> There is a user config for lsc, 'dev->data->dev_conf.intr_conf.lsc', which 
>> seems not taken into account.
>>
> Frist of all, thank you for your review. Currently, the old firmware doest not 
> support interrupt reporting. Therefore, the PF does not suport interrupt 
> reporting through the mailbox. Therefore, the PF obtains interrupts in polling 
> mode and then reports interrupts.
> 
> 
>> Also 'RTE_PCI_DRV_INTR_LSC' should be set in 'rte_pci_driver.drv_flags' to 
>> report this feature to higher levels.
>>
> In the future, the new firmware + PF will support interrupt reporting. In that 
> case, the LSC capability of dev_flag will be set.
> In the future, we will enable the VF to support LSC. That is, we are developing 
> the PF to report LSC interrupts through the mailbox.
>> And when the feature is fully implemented, can you please add "Link status 
>> event" feature to 'hns3.ini'?
>>
> By then, we'll add it in hns3.ini.

Got it, so for now only LSC event report (even callbacks call) support added, I 
am proceeding with the patch.

>>>
>>> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
>>> Signed-off-by: Lijun Ou <oulijun@huawei.com>
>>
>> <...>
>> .
>>
  
Ferruh Yigit Feb. 2, 2021, 12:12 p.m. UTC | #4
On 1/22/2021 10:18 AM, Lijun Ou wrote:
> From: Chengwen Feng <fengchengwen@huawei.com>
> 
> 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>

<...>

> @@ -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);

indentation fixed while merging.



Applied to dpdk-next-net/main, thanks.
  

Patch

diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 94b6e44..bc77608 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -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);
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 0d17170..547e991 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -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)
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 7eb0b11..470aaee 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -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);
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index d2a5db8..3e44e3b 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -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