Wenzhuo,
Please could you have a look?
Thanks

2015-09-24 20:44, Tim Shearer:
> I encountered an issue with DPDK 2.1.0  which occasionally causes the link 
> status interrupt callback not to be called after the interface is started for 
> the first time. I traced the problem back to the function 
> eth_igb_link_update(), which is used to determine if the link has changed 
> state since the previous time it was called. It appears that this function 
> can be called simultaneously from two different threads:
> 
> (1) From the main application/configuration thread, via rte_eth_dev_start() - 
> pointed to by (*dev->dev_ops->link_update)
> (2) From the eal interrupt thread, via eth_igb_interrupt_action(), to check 
> if the link state has transitioned up or down. The user callback is only 
> executed if the link has changed state.
> 
> The race condition manifests itself as follows:
>  - Main thread configures the interface with link status interrupt (LSI) 
> enabled, sets up the queues etc.
>  - Main thread calls rte_eth_dev_start. The interface is started and then we 
> call eth_igb_link_update()
>  - While in this call, the link goes up. Accordingly, we  detect the 
> transition, and write the new link state (up) into the global rte_eth_dev 
> struct
>  - The interrupt fires, which also drops into the eth_igb_link_update 
> function, finds that the global link status has already been set to up (no 
> change)
>  - Therefore, the handler thinks the interrupt was spurious, and the callback 
> doesn't get called.
> 
> I suspect that rte_eth_dev_start shouldn't be checking the link state if 
> interrupts are enabled. Would someone mind taking a quick look at the patch 
> below?
> 
> Thanks!
> Tim
> 
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -1300,7 +1300,7 @@ rte_eth_dev_start(uint8_t port_id)
>  
>         rte_eth_dev_config_restore(port_id);
>  
> -       if (dev->data->dev_conf.intr_conf.lsc != 0) {
> +       if (dev->data->dev_conf.intr_conf.lsc == 0) {
>                 FUNC_PTR_OR_ERR_RET(*dev->dev_ops->link_update, -ENOTSUP);
>                 (*dev->dev_ops->link_update)(dev, 0);
>         }
> 
> 


Reply via email to