Skip to content

Commit

Permalink
net/ngbe: fix missed link interrupt
Browse files Browse the repository at this point in the history
[ upstream commit 0360c23 ]

When the port is started and stopped continuously and quickly, one
interrupt cannot be handled in time, which will cause subsequent
interrupts to be lost, so that link status will cannot be updated.

Fixes: b9246b8 ("net/ngbe: support link update")

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
  • Loading branch information
Jiawen Wu authored and kevintraynor committed Feb 21, 2022
1 parent cacbd7e commit 3698c17
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 77 deletions.
115 changes: 38 additions & 77 deletions drivers/net/ngbe/ngbe_ethdev.c
Expand Up @@ -89,7 +89,6 @@ static int ngbe_dev_macsec_interrupt_setup(struct rte_eth_dev *dev);
static int ngbe_dev_misc_interrupt_setup(struct rte_eth_dev *dev);
static int ngbe_dev_rxq_interrupt_setup(struct rte_eth_dev *dev);
static void ngbe_dev_interrupt_handler(void *param);
static void ngbe_dev_interrupt_delayed_handler(void *param);
static void ngbe_configure_msix(struct rte_eth_dev *dev);

#define NGBE_SET_HWSTRIP(h, q) do {\
Expand Down Expand Up @@ -943,6 +942,9 @@ ngbe_dev_start(struct rte_eth_dev *dev)

PMD_INIT_FUNC_TRACE();

/* Stop the link setup handler before resetting the HW. */
rte_eal_alarm_cancel(ngbe_dev_setup_link_alarm_handler, dev);

/* disable uio/vfio intr/eventfd mapping */
rte_intr_disable(intr_handle);

Expand Down Expand Up @@ -1132,6 +1134,8 @@ ngbe_dev_stop(struct rte_eth_dev *dev)

PMD_INIT_FUNC_TRACE();

rte_eal_alarm_cancel(ngbe_dev_setup_link_alarm_handler, dev);

if ((hw->sub_system_id & NGBE_OEM_MASK) == NGBE_LY_M88E1512_SFP ||
(hw->sub_system_id & NGBE_OEM_MASK) == NGBE_LY_YT8521S_SFP) {
/* gpio0 is used to power on/off control*/
Expand Down Expand Up @@ -1801,6 +1805,24 @@ ngbe_dev_supported_ptypes_get(struct rte_eth_dev *dev)
return NULL;
}

void
ngbe_dev_setup_link_alarm_handler(void *param)
{
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
struct ngbe_hw *hw = ngbe_dev_hw(dev);
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
u32 speed;
bool autoneg = false;

speed = hw->phy.autoneg_advertised;
if (!speed)
hw->mac.get_link_capabilities(hw, &speed, &autoneg);

hw->mac.setup_link(hw, speed, true);

intr->flags &= ~NGBE_FLAG_NEED_LINK_CONFIG;
}

/* return 0 means link status changed, -1 means not changed */
int
ngbe_dev_link_update_share(struct rte_eth_dev *dev,
Expand Down Expand Up @@ -1838,8 +1860,16 @@ ngbe_dev_link_update_share(struct rte_eth_dev *dev,
return rte_eth_linkstatus_set(dev, &link);
}

if (!link_up)
if (!link_up) {
if (hw->phy.media_type == ngbe_media_type_fiber &&
hw->phy.type != ngbe_phy_mvl_sfi) {
intr->flags |= NGBE_FLAG_NEED_LINK_CONFIG;
rte_eal_alarm_set(10,
ngbe_dev_setup_link_alarm_handler, dev);
}

return rte_eth_linkstatus_set(dev, &link);
}

intr->flags &= ~NGBE_FLAG_NEED_LINK_CONFIG;
link.link_status = RTE_ETH_LINK_UP;
Expand Down Expand Up @@ -2062,9 +2092,6 @@ ngbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
struct ngbe_hw *hw = ngbe_dev_hw(dev);
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);

/* clear all cause mask */
ngbe_disable_intr(hw);

/* read-on-clear nic registers here */
eicr = ((u32 *)hw->isb_mem)[NGBE_ISB_MISC];
PMD_DRV_LOG(DEBUG, "eicr %x", eicr);
Expand All @@ -2084,6 +2111,8 @@ ngbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
if (eicr & NGBE_ICRMISC_GPIO)
intr->flags |= NGBE_FLAG_NEED_LINK_UPDATE;

((u32 *)hw->isb_mem)[NGBE_ISB_MISC] = 0;

return 0;
}

Expand Down Expand Up @@ -2136,7 +2165,6 @@ static int
ngbe_dev_interrupt_action(struct rte_eth_dev *dev)
{
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
int64_t timeout;

PMD_DRV_LOG(DEBUG, "intr action type %d", intr->flags);

Expand All @@ -2152,31 +2180,11 @@ ngbe_dev_interrupt_action(struct rte_eth_dev *dev)
rte_eth_linkstatus_get(dev, &link);

ngbe_dev_link_update(dev, 0);

/* likely to up */
if (link.link_status != RTE_ETH_LINK_UP)
/* handle it 1 sec later, wait it being stable */
timeout = NGBE_LINK_UP_CHECK_TIMEOUT;
/* likely to down */
else
/* handle it 4 sec later, wait it being stable */
timeout = NGBE_LINK_DOWN_CHECK_TIMEOUT;

intr->flags &= ~NGBE_FLAG_NEED_LINK_UPDATE;
ngbe_dev_link_status_print(dev);
if (rte_eal_alarm_set(timeout * 1000,
ngbe_dev_interrupt_delayed_handler,
(void *)dev) < 0) {
PMD_DRV_LOG(ERR, "Error setting alarm");
} else {
/* remember original mask */
intr->mask_misc_orig = intr->mask_misc;
/* only disable lsc interrupt */
intr->mask_misc &= ~NGBE_ICRMISC_PHY;

intr->mask_orig = intr->mask;
/* only disable all misc interrupts */
intr->mask &= ~(1ULL << NGBE_MISC_VEC_ID);
}
if (dev->data->dev_link.link_speed != link.link_speed)
rte_eth_dev_callback_process(dev,
RTE_ETH_EVENT_INTR_LSC, NULL);
}

PMD_DRV_LOG(DEBUG, "enable intr immediately");
Expand All @@ -2185,53 +2193,6 @@ ngbe_dev_interrupt_action(struct rte_eth_dev *dev)
return 0;
}

/**
* Interrupt handler which shall be registered for alarm callback for delayed
* handling specific interrupt to wait for the stable nic state. As the
* NIC interrupt state is not stable for ngbe after link is just down,
* it needs to wait 4 seconds to get the stable status.
*
* @param param
* The address of parameter (struct rte_eth_dev *) registered before.
*/
static void
ngbe_dev_interrupt_delayed_handler(void *param)
{
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
struct ngbe_hw *hw = ngbe_dev_hw(dev);
uint32_t eicr;

ngbe_disable_intr(hw);

eicr = ((u32 *)hw->isb_mem)[NGBE_ISB_MISC];
if (eicr & NGBE_ICRMISC_VFMBX)
ngbe_pf_mbx_process(dev);

if (intr->flags & NGBE_FLAG_NEED_LINK_UPDATE) {
ngbe_dev_link_update(dev, 0);
intr->flags &= ~NGBE_FLAG_NEED_LINK_UPDATE;
ngbe_dev_link_status_print(dev);
rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
NULL);
}

if (intr->flags & NGBE_FLAG_MACSEC) {
rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_MACSEC,
NULL);
intr->flags &= ~NGBE_FLAG_MACSEC;
}

/* restore original mask */
intr->mask_misc = intr->mask_misc_orig;
intr->mask_misc_orig = 0;
intr->mask = intr->mask_orig;
intr->mask_orig = 0;

PMD_DRV_LOG(DEBUG, "enable intr in delayed handler S[%08x]", eicr);
ngbe_enable_intr(dev);
}

/**
* Interrupt handler triggered by NIC for handling
* specific interrupt.
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ngbe/ngbe_ethdev.h
Expand Up @@ -341,6 +341,7 @@ void ngbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
uint16_t queue, bool on);
void ngbe_config_vlan_strip_on_all_queues(struct rte_eth_dev *dev,
int mask);
void ngbe_dev_setup_link_alarm_handler(void *param);
void ngbe_read_stats_registers(struct ngbe_hw *hw,
struct ngbe_hw_stats *hw_stats);

Expand Down

0 comments on commit 3698c17

Please sign in to comment.