DPDK patches and discussions
 help / color / mirror / Atom feed
From: Helin Zhang <helin.zhang@intel.com>
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH 3/3] i40e: fix of interrupt based link status change
Date: Wed, 17 Sep 2014 15:54:21 +0800
Message-ID: <1410940461-17509-4-git-send-email-helin.zhang@intel.com> (raw)
In-Reply-To: <1410940461-17509-1-git-send-email-helin.zhang@intel.com>

As driver flag of 'RTE_PCI_DRV_INTR_LSC' was introduced
recently, it must be added in i40e. One second waiting
is needed for link up event, to wait the hardware into a
stable state, so the interrupt could be processed in two
parts. In addition, it should finally call the callback
function registered by application.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Reviewed-by: Jing Chen <jing.d.chen@intel.com>
Reviewed-by: Jijiang Liu <jijiang.liu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 88 +++++++++++++++++++++++++++++++++++----
 1 file changed, 80 insertions(+), 8 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 6df41ea..e223d3a 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -47,6 +47,7 @@
 #include <rte_memzone.h>
 #include <rte_malloc.h>
 #include <rte_memcpy.h>
+#include <rte_alarm.h>
 #include <rte_dev.h>
 
 #include "i40e_logs.h"
@@ -275,7 +276,7 @@ static struct eth_driver rte_i40e_pmd = {
 	{
 		.name = "rte_i40e_pmd",
 		.id_table = pci_id_i40e_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	},
 	.eth_dev_init = eth_i40e_dev_init,
 	.dev_private_size = sizeof(struct i40e_adapter),
@@ -3371,6 +3372,58 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
 	rte_free(info.msg_buf);
 }
 
+/*
+ * Interrupt handler is registered as the alarm callback for handling LSC
+ * interrupt in a definite of time, in order to wait the NIC into a stable
+ * state. Currently it waits 1 sec in i40e for the link up interrupt, and
+ * no need for link down interrupt.
+ */
+static void
+i40e_dev_interrupt_delayed_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t icr0;
+
+	/* read interrupt causes again */
+	icr0 = I40E_READ_REG(hw, I40E_PFINT_ICR0);
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_DRIVER
+	if (icr0 & I40E_PFINT_ICR0_ECC_ERR_MASK)
+		PMD_DRV_LOG(ERR, "ICR0: unrecoverable ECC error\n");
+	if (icr0 & I40E_PFINT_ICR0_MAL_DETECT_MASK)
+		PMD_DRV_LOG(ERR, "ICR0: malicious programming detected\n");
+	if (icr0 & I40E_PFINT_ICR0_GRST_MASK)
+		PMD_DRV_LOG(INFO, "ICR0: global reset requested\n");
+	if (icr0 & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK)
+		PMD_DRV_LOG(INFO, "ICR0: PCI exception\n activated\n");
+	if (icr0 & I40E_PFINT_ICR0_STORM_DETECT_MASK)
+		PMD_DRV_LOG(INFO, "ICR0: a change in the storm control "
+								"state\n");
+	if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK)
+		PMD_DRV_LOG(ERR, "ICR0: HMC error\n");
+	if (icr0 & I40E_PFINT_ICR0_PE_CRITERR_MASK)
+		PMD_DRV_LOG(ERR, "ICR0: protocol engine critical error\n");
+#endif /* RTE_LIBRTE_I40E_DEBUG_DRIVER */
+
+	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
+		PMD_DRV_LOG(INFO, "INT:VF reset detected\n");
+		i40e_dev_handle_vfr_event(dev);
+	}
+	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
+		PMD_DRV_LOG(INFO, "INT:ADMINQ event\n");
+		i40e_dev_handle_aq_msg(dev);
+	}
+
+	/* handle the link up interrupt in an alarm callback */
+	i40e_dev_link_update(dev, 0);
+	_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC);
+
+	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, I40E_PFINT_ICR0_ENA_MASK);
+	i40e_pf_enable_irq0(hw);
+	rte_intr_enable(&(dev->pci_dev->intr_handle));
+}
+
 /**
  * Interrupt handler triggered by NIC  for handling
  * specific interrupt.
@@ -3389,19 +3442,20 @@ i40e_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t icr0, icr0_ena;
+	uint32_t icr0;
 
+	/* Disable interrupt */
 	i40e_pf_disable_irq0(hw);
+	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, 0);
 
+	/* read out interrupt causes */
 	icr0 = I40E_READ_REG(hw, I40E_PFINT_ICR0);
-	icr0_ena = I40E_READ_REG(hw, I40E_PFINT_ICR0_ENA);
 
 	/* No interrupt event indicated */
 	if (!(icr0 & I40E_PFINT_ICR0_INTEVENT_MASK)) {
 		PMD_DRV_LOG(INFO, "No interrupt event\n");
 		goto done;
 	}
-
 #ifdef RTE_LIBRTE_I40E_DEBUG_DRIVER
 	if (icr0 & I40E_PFINT_ICR0_ECC_ERR_MASK)
 		PMD_DRV_LOG(ERR, "ICR0: unrecoverable ECC error\n");
@@ -3429,16 +3483,34 @@ i40e_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
 		i40e_dev_handle_aq_msg(dev);
 	}
 
+	/* Link Status Change interrupt */
 	if (icr0 & I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK) {
-		PMD_DRV_LOG(INFO, "INT:Link status changed\n");
+#define I40E_US_PER_SECOND 1000000
+		struct rte_eth_link link;
+
+		PMD_DRV_LOG(INFO, "ICR0: link status changed\n");
+		memset(&link, 0, sizeof(link));
+		rte_i40e_dev_atomic_read_link_status(dev, &link);
 		i40e_dev_link_update(dev, 0);
+
+		/*
+		 * For link up interrupt, it needs to wait 1 second to let the
+		 * hardware be a stable state. Otherwise several consecutive
+		 * interrupts can be observed.
+		 * For link down interrupt, no need to wait.
+		 */
+		if (!link.link_status && rte_eal_alarm_set(I40E_US_PER_SECOND,
+			i40e_dev_interrupt_delayed_handler, (void *)dev) >= 0)
+			return;
+		else
+			_rte_eth_dev_callback_process(dev,
+				RTE_ETH_EVENT_INTR_LSC);
 	}
 
 done:
-	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, icr0_ena);
-	/* Re-enable interrupt from device side */
+	/* Enable interrupt */
+	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, I40E_PFINT_ICR0_ENA_MASK);
 	i40e_pf_enable_irq0(hw);
-	/* Re-enable interrupt from host side */
 	rte_intr_enable(&(dev->pci_dev->intr_handle));
 }
 
-- 
1.8.1.4

  parent reply	other threads:[~2014-09-17  7:48 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-17  7:54 [dpdk-dev] [PATCH 0/3] fix of lsc interrupt in i40e PF Helin Zhang
2014-09-17  7:54 ` [dpdk-dev] [PATCH 1/3] i40e: renaming some local variables Helin Zhang
2014-09-17  7:54 ` [dpdk-dev] [PATCH 2/3] i40e: rework of PF interrupt cause enable flags processing Helin Zhang
2014-09-17  7:54 ` Helin Zhang [this message]
2014-09-30  6:09 ` [dpdk-dev] [PATCH 0/3] fix of lsc interrupt in i40e PF Cao, Min
2014-10-10  1:48 ` Chen, Jing D
2014-11-03 17:19   ` Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1410940461-17509-4-git-send-email-helin.zhang@intel.com \
    --to=helin.zhang@intel.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

DPDK patches and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \
		dev@dpdk.org
	public-inbox-index dev

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git