net/netvsc: process link change messages in alarm
The original code would deadlock itself if a link change event happened with link state interrupt enabled. The problem is that the link state changed message would be seen while reading the host to guest ring (under lock) and then the driver would send a query to the host to see the new link state. The response would never be seen (stuck in a while loop) waiting for the response. The solution is to use the link change indication to trigger a DPDK alarm. The alarm will happen in a different thread and in that context it can send request for new link state and also do interrupt callback. This is similar to how the bonding driver is handling the same thing. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
parent
a4f53bec7c
commit
501a7e5735
@ -17,6 +17,7 @@
|
||||
#include <rte_memzone.h>
|
||||
#include <rte_malloc.h>
|
||||
#include <rte_atomic.h>
|
||||
#include <rte_alarm.h>
|
||||
#include <rte_branch_prediction.h>
|
||||
#include <rte_ether.h>
|
||||
#include <rte_common.h>
|
||||
@ -281,6 +282,15 @@ static int hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
|
||||
&nvs_rndis, sizeof(nvs_rndis), 0U, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alarm callback to process link changed notifications.
|
||||
* Can not directly since link_status is discovered while reading ring
|
||||
*/
|
||||
static void hn_rndis_link_alarm(void *arg)
|
||||
{
|
||||
_rte_eth_dev_callback_process(arg, RTE_ETH_EVENT_INTR_LSC, NULL);
|
||||
}
|
||||
|
||||
void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg)
|
||||
{
|
||||
const struct rndis_status_msg *indicate = msg;
|
||||
@ -298,11 +308,8 @@ void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg)
|
||||
case RNDIS_STATUS_LINK_SPEED_CHANGE:
|
||||
case RNDIS_STATUS_MEDIA_CONNECT:
|
||||
case RNDIS_STATUS_MEDIA_DISCONNECT:
|
||||
if (dev->data->dev_conf.intr_conf.lsc &&
|
||||
hn_dev_link_update(dev, 0) == 0)
|
||||
_rte_eth_dev_callback_process(dev,
|
||||
RTE_ETH_EVENT_INTR_LSC,
|
||||
NULL);
|
||||
if (dev->data->dev_conf.intr_conf.lsc)
|
||||
rte_eal_alarm_set(10, hn_rndis_link_alarm, dev);
|
||||
break;
|
||||
default:
|
||||
PMD_DRV_LOG(NOTICE, "unknown RNDIS indication: %#x",
|
||||
@ -1101,6 +1108,10 @@ hn_rndis_attach(struct hn_data *hv)
|
||||
void
|
||||
hn_rndis_detach(struct hn_data *hv)
|
||||
{
|
||||
struct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];
|
||||
|
||||
rte_eal_alarm_cancel(hn_rndis_link_alarm, dev);
|
||||
|
||||
/* Halt the RNDIS. */
|
||||
hn_rndis_halt(hv);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user