> -----Original Message----- > From: Pei, Andy <andy....@intel.com> > Sent: Wednesday, May 18, 2022 8:14 PM > To: dev@dpdk.org > Cc: Xia, Chenbo <chenbo....@intel.com>; maxime.coque...@redhat.com; Cao, > Gang <gang....@intel.com>; Liu, Changpeng <changpeng....@intel.com>; Xu, > Rosen <rosen...@intel.com>; Xiao, QimaiX <qimaix.x...@intel.com> > Subject: [PATCH v8 12/13] vdpa/ifc: add interrupt handling for config > space > > Create a thread to poll and relay config space change interrupt. > Use VHOST_USER_SLAVE_CONFIG_CHANGE_MSG to inform QEMU. > > Signed-off-by: Andy Pei <andy....@intel.com> > --- > drivers/vdpa/ifc/ifcvf_vdpa.c | 118 > +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 117 insertions(+), 1 deletion(-) > > diff --git a/drivers/vdpa/ifc/ifcvf_vdpa.c b/drivers/vdpa/ifc/ifcvf_vdpa.c > index 376a1af..8a49622 100644 > --- a/drivers/vdpa/ifc/ifcvf_vdpa.c > +++ b/drivers/vdpa/ifc/ifcvf_vdpa.c > @@ -53,7 +53,9 @@ struct ifcvf_internal { > int vfio_group_fd; > int vfio_dev_fd; > pthread_t tid; /* thread for notify relay */ > + pthread_t intr_tid; /* thread for config space change interrupt > relay */ > int epfd; > + int csc_epfd; > int vid; > struct rte_vdpa_device *vdev; > uint16_t max_queues; > @@ -566,6 +568,111 @@ struct rte_vdpa_dev_info { > return 0; > } > > +static void > +virtio_interrupt_handler(struct ifcvf_internal *internal) > +{ > + int vid = internal->vid; > + int ret; > + > + ret = rte_vhost_slave_config_change(vid, 1); > + if (ret) > + DRV_LOG(ERR, "failed to notify the guest about configuration > space change."); > +} > + > +static void * > +intr_relay(void *arg) > +{ > + struct ifcvf_internal *internal = (struct ifcvf_internal *)arg; > + struct epoll_event csc_event; > + struct epoll_event ev; > + uint64_t buf; > + int nbytes; > + int csc_epfd, csc_val = 0; > + > + csc_epfd = epoll_create(1); > + if (csc_epfd < 0) { > + DRV_LOG(ERR, "failed to create epoll for config space > change."); > + return NULL; > + } > + > + ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP; > + ev.data.fd = rte_intr_fd_get(internal->pdev->intr_handle); > + if (epoll_ctl(csc_epfd, EPOLL_CTL_ADD, > + rte_intr_fd_get(internal->pdev->intr_handle), &ev) < 0) { > + DRV_LOG(ERR, "epoll add error: %s", strerror(errno)); > + return NULL; > + } > + > + internal->csc_epfd = csc_epfd; > + > + for (;;) { > + csc_val = epoll_wait(csc_epfd, &csc_event, 1, -1); > + if (csc_val < 0) { > + if (errno == EINTR) > + continue; > + DRV_LOG(ERR, "epoll_wait return fail."); > + return NULL; > + } else if (csc_val == 0) { > + continue; > + } else { > + /* csc_val > 0 */ > + nbytes = read(csc_event.data.fd, &buf, 8); > + if (nbytes < 0) { > + if (errno == EINTR || > + errno == EWOULDBLOCK || > + errno == EAGAIN) > + continue; > + DRV_LOG(ERR, "Error reading from file > descriptor %d: %s\n", > + csc_event.data.fd, > + strerror(errno)); > + return NULL; > + } else if (nbytes == 0) { > + DRV_LOG(ERR, "Read nothing from file > descriptor %d\n", > + csc_event.data.fd); > + continue; > + } else { > + virtio_interrupt_handler(internal); > + } > + } > + } > + > + return NULL; > +}
I think we should not assume unset_intr_relay will help us close epfd when Error happens, so just close it when there's some error. > + > +static int > +setup_intr_relay(struct ifcvf_internal *internal) > +{ > + char name[THREAD_NAME_LEN]; > + int ret; > + > + snprintf(name, sizeof(name), "ifc-intr-%d", internal->vid); > + ret = rte_ctrl_thread_create(&internal->intr_tid, name, NULL, > + intr_relay, (void *)internal); > + if (ret) { > + DRV_LOG(ERR, "failed to create notify relay pthread."); > + return -1; > + } > + return 0; > +} > + > +static int > +unset_intr_relay(struct ifcvf_internal *internal) > +{ > + void *status; > + > + if (internal->intr_tid) { > + pthread_cancel(internal->intr_tid); > + pthread_join(internal->intr_tid, &status); > + } > + internal->intr_tid = 0; > + > + if (internal->csc_epfd >= 0) > + close(internal->csc_epfd); > + internal->csc_epfd = -1; > + > + return 0; > +} It will always return 0, so return type should be void > + > static int > update_datapath(struct ifcvf_internal *internal) > { > @@ -592,10 +699,16 @@ struct rte_vdpa_dev_info { > if (ret) > goto err; > > + ret = setup_intr_relay(internal); > + if (ret) > + goto err; > + > rte_atomic32_set(&internal->running, 1); > } else if (rte_atomic32_read(&internal->running) && > (!rte_atomic32_read(&internal->started) || > !rte_atomic32_read(&internal->dev_attached))) { > + ret = unset_intr_relay(internal); This will be changed accordingly. Thanks, Chenbo > + > ret = unset_notify_relay(internal); > if (ret) > goto err; > @@ -812,7 +925,7 @@ struct rte_vdpa_dev_info { > if (nfds < 0) { > if (errno == EINTR) > continue; > - DRV_LOG(ERR, "epoll_wait return fail\n"); > + DRV_LOG(ERR, "epoll_wait return fail."); > return NULL; > } > > @@ -888,6 +1001,9 @@ struct rte_vdpa_dev_info { > /* stop the direct IO data path */ > unset_notify_relay(internal); > vdpa_ifcvf_stop(internal); > + > + unset_intr_relay(internal); > + > vdpa_disable_vfio_intr(internal); > > ret = rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, false); > -- > 1.8.3.1