Skip to content

Commit

Permalink
net/iavf: add thread for event callbacks
Browse files Browse the repository at this point in the history
[ upstream commit cb5c1b9 ]

All callbacks registered for ethdev events are called in
eal-intr-thread, and some of them execute virtchnl commands.
Because interrupts are disabled in the intr thread, no response
will be received for these commands. So all callbacks should
be called in a new context.

When the device is bonded, the bond pmd registers a callback for
the LSC event to execute virtchnl commands to reinitialize the
device, and it would also raise the above issue.

This commit adds a new thread to call all event callbacks.

Fixes: 48de41c ("net/avf: enable link status update")
Fixes: 8410842 ("net/iavf: support asynchronous virtual channel message")

Signed-off-by: Yiding Zhou <yidingx.zhou@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
  • Loading branch information
yiding-zhou authored and kevintraynor committed Nov 7, 2022
1 parent 4ff81b5 commit c346009
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 6 deletions.
2 changes: 2 additions & 0 deletions drivers/net/iavf/iavf.h
Expand Up @@ -400,6 +400,8 @@ _atomic_set_async_response_cmd(struct iavf_info *vf, enum virtchnl_ops ops)
}
int iavf_check_api_version(struct iavf_adapter *adapter);
int iavf_get_vf_resource(struct iavf_adapter *adapter);
void iavf_dev_event_handler_fini(void);
int iavf_dev_event_handler_init(void);
void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
int iavf_enable_vlan_strip(struct iavf_adapter *adapter);
int iavf_disable_vlan_strip(struct iavf_adapter *adapter);
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/iavf/iavf_ethdev.c
Expand Up @@ -2561,6 +2561,9 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
&eth_dev->data->mac_addrs[0]);

if (iavf_dev_event_handler_init())
goto init_vf_err;

if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) {
/* register callback func to eal lib */
rte_intr_callback_register(pci_dev->intr_handle,
Expand Down Expand Up @@ -2715,6 +2718,8 @@ iavf_dev_uninit(struct rte_eth_dev *dev)

iavf_dev_close(dev);

iavf_dev_event_handler_fini();

return 0;
}

Expand Down
153 changes: 147 additions & 6 deletions drivers/net/iavf/iavf_vchnl.c
Expand Up @@ -2,6 +2,7 @@
* Copyright(c) 2017 Intel Corporation
*/

#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
Expand All @@ -11,6 +12,7 @@
#include <inttypes.h>
#include <rte_byteorder.h>
#include <rte_common.h>
#include <rte_os_shim.h>

#include <rte_debug.h>
#include <rte_alarm.h>
Expand All @@ -27,6 +29,146 @@
#define MAX_TRY_TIMES 2000
#define ASQ_DELAY_MS 1

#define MAX_EVENT_PENDING 16

struct iavf_event_element {
TAILQ_ENTRY(iavf_event_element) next;
struct rte_eth_dev *dev;
enum rte_eth_event_type event;
void *param;
size_t param_alloc_size;
uint8_t param_alloc_data[0];
};

struct iavf_event_handler {
uint32_t ndev;
pthread_t tid;
int fd[2];
pthread_mutex_t lock;
TAILQ_HEAD(event_list, iavf_event_element) pending;
};

static struct iavf_event_handler event_handler = {
.fd = {-1, -1},
};

#ifndef TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif

static void *
iavf_dev_event_handle(void *param __rte_unused)
{
struct iavf_event_handler *handler = &event_handler;
TAILQ_HEAD(event_list, iavf_event_element) pending;

while (true) {
char unused[MAX_EVENT_PENDING];
ssize_t nr = read(handler->fd[0], &unused, sizeof(unused));
if (nr <= 0)
break;

TAILQ_INIT(&pending);
pthread_mutex_lock(&handler->lock);
TAILQ_CONCAT(&pending, &handler->pending, next);
pthread_mutex_unlock(&handler->lock);

struct iavf_event_element *pos, *save_next;
TAILQ_FOREACH_SAFE(pos, &pending, next, save_next) {
TAILQ_REMOVE(&pending, pos, next);
rte_eth_dev_callback_process(pos->dev, pos->event, pos->param);
rte_free(pos);
}
}

return NULL;
}

static void
iavf_dev_event_post(struct rte_eth_dev *dev,
enum rte_eth_event_type event,
void *param, size_t param_alloc_size)
{
struct iavf_event_handler *handler = &event_handler;
char notify_byte;
struct iavf_event_element *elem = rte_malloc(NULL, sizeof(*elem) + param_alloc_size, 0);
if (!elem)
return;

elem->dev = dev;
elem->event = event;
elem->param = param;
elem->param_alloc_size = param_alloc_size;
if (param && param_alloc_size) {
rte_memcpy(elem->param_alloc_data, param, param_alloc_size);
elem->param = elem->param_alloc_data;
}

pthread_mutex_lock(&handler->lock);
TAILQ_INSERT_TAIL(&handler->pending, elem, next);
pthread_mutex_unlock(&handler->lock);

ssize_t nw = write(handler->fd[1], &notify_byte, 1);
RTE_SET_USED(nw);
}

int
iavf_dev_event_handler_init(void)
{
struct iavf_event_handler *handler = &event_handler;

if (__atomic_add_fetch(&handler->ndev, 1, __ATOMIC_RELAXED) != 1)
return 0;
#if defined(RTE_EXEC_ENV_IS_WINDOWS) && RTE_EXEC_ENV_IS_WINDOWS != 0
int err = _pipe(handler->fd, MAX_EVENT_PENDING, O_BINARY);
#else
int err = pipe(handler->fd);
#endif
if (err != 0) {
__atomic_sub_fetch(&handler->ndev, 1, __ATOMIC_RELAXED);
return -1;
}

TAILQ_INIT(&handler->pending);
pthread_mutex_init(&handler->lock, NULL);

if (rte_ctrl_thread_create(&handler->tid, "iavf-event-thread",
NULL, iavf_dev_event_handle, NULL)) {
__atomic_sub_fetch(&handler->ndev, 1, __ATOMIC_RELAXED);
return -1;
}

return 0;
}

void
iavf_dev_event_handler_fini(void)
{
struct iavf_event_handler *handler = &event_handler;

if (__atomic_sub_fetch(&handler->ndev, 1, __ATOMIC_RELAXED) != 0)
return;

int unused = pthread_cancel(handler->tid);
RTE_SET_USED(unused);
close(handler->fd[0]);
close(handler->fd[1]);
handler->fd[0] = -1;
handler->fd[1] = -1;

pthread_join(handler->tid, NULL);
pthread_mutex_destroy(&handler->lock);

struct iavf_event_element *pos, *save_next;
TAILQ_FOREACH_SAFE(pos, &handler->pending, next, save_next) {
TAILQ_REMOVE(&handler->pending, pos, next);
rte_free(pos);
}
}

static uint32_t
iavf_convert_link_speed(enum virtchnl_link_speed virt_link_speed)
{
Expand Down Expand Up @@ -278,8 +420,8 @@ iavf_handle_pf_event_msg(struct rte_eth_dev *dev, uint8_t *msg,
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
vf->vf_reset = true;
rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
NULL);
iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_RESET,
NULL, 0);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
Expand All @@ -293,7 +435,7 @@ iavf_handle_pf_event_msg(struct rte_eth_dev *dev, uint8_t *msg,
vf->link_speed = iavf_convert_link_speed(speed);
}
iavf_dev_link_update(dev, 0);
rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0);
break;
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
Expand Down Expand Up @@ -359,9 +501,8 @@ iavf_handle_virtchnl_msg(struct rte_eth_dev *dev)
desc.subtype =
RTE_ETH_EVENT_IPSEC_UNKNOWN;
desc.metadata = ev->ipsec_event_data;
rte_eth_dev_callback_process(dev,
RTE_ETH_EVENT_IPSEC,
&desc);
iavf_dev_event_post(dev, RTE_ETH_EVENT_IPSEC,
&desc, sizeof(desc));
return;
}

Expand Down

0 comments on commit c346009

Please sign in to comment.