X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvhost%2Frte_eth_vhost.c;h=e55278af696047359fcef7c7eb182dd2d2f5089f;hb=8716f9942a408a79a114ac0496e4e7d55bc9944c;hp=9fbf39f66b692a4c974f55672f8b8b6f52a01d8c;hpb=9c99878aa1b16de26fcce82c112b401766dd910e;p=dpdk.git diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c index 9fbf39f66b..e55278af69 100644 --- a/drivers/net/vhost/rte_eth_vhost.c +++ b/drivers/net/vhost/rte_eth_vhost.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,8 @@ struct vhost_queue { uint16_t port; uint16_t virtqueue_id; struct vhost_stats stats; + int intr_enable; + rte_spinlock_t intr_lock; }; struct pmd_internal { @@ -524,12 +527,58 @@ find_internal_resource(char *ifname) return list; } +static int +eth_vhost_update_intr(struct rte_eth_dev *eth_dev, uint16_t rxq_idx) +{ + struct rte_intr_handle *handle = eth_dev->intr_handle; + struct rte_epoll_event rev; + int epfd, ret; + + if (!handle) + return 0; + + if (handle->efds[rxq_idx] == handle->elist[rxq_idx].fd) + return 0; + + VHOST_LOG(INFO, "kickfd for rxq-%d was changed, updating handler.\n", + rxq_idx); + + if (handle->elist[rxq_idx].fd != -1) + VHOST_LOG(ERR, "Unexpected previous kickfd value (Got %d, expected -1).\n", + handle->elist[rxq_idx].fd); + + /* + * First remove invalid epoll event, and then install + * the new one. May be solved with a proper API in the + * future. + */ + epfd = handle->elist[rxq_idx].epfd; + rev = handle->elist[rxq_idx]; + ret = rte_epoll_ctl(epfd, EPOLL_CTL_DEL, rev.fd, + &handle->elist[rxq_idx]); + if (ret) { + VHOST_LOG(ERR, "Delete epoll event failed.\n"); + return ret; + } + + rev.fd = handle->efds[rxq_idx]; + handle->elist[rxq_idx] = rev; + ret = rte_epoll_ctl(epfd, EPOLL_CTL_ADD, rev.fd, + &handle->elist[rxq_idx]); + if (ret) { + VHOST_LOG(ERR, "Add epoll event failed.\n"); + return ret; + } + + return 0; +} + static int eth_rxq_intr_enable(struct rte_eth_dev *dev, uint16_t qid) { struct rte_vhost_vring vring; struct vhost_queue *vq; - int ret = 0; + int old_intr_enable, ret = 0; vq = dev->data->rx_queues[qid]; if (!vq) { @@ -537,6 +586,18 @@ eth_rxq_intr_enable(struct rte_eth_dev *dev, uint16_t qid) return -1; } + rte_spinlock_lock(&vq->intr_lock); + old_intr_enable = vq->intr_enable; + vq->intr_enable = 1; + ret = eth_vhost_update_intr(dev, qid); + rte_spinlock_unlock(&vq->intr_lock); + + if (ret < 0) { + VHOST_LOG(ERR, "Failed to update rxq%d's intr\n", qid); + vq->intr_enable = old_intr_enable; + return ret; + } + ret = rte_vhost_get_vhost_vring(vq->vid, (qid << 1) + 1, &vring); if (ret < 0) { VHOST_LOG(ERR, "Failed to get rxq%d's vring\n", qid); @@ -571,6 +632,8 @@ eth_rxq_intr_disable(struct rte_eth_dev *dev, uint16_t qid) rte_vhost_enable_guest_notification(vq->vid, (qid << 1) + 1, 0); rte_wmb(); + vq->intr_enable = 0; + return 0; } @@ -593,7 +656,6 @@ eth_vhost_install_intr(struct rte_eth_dev *dev) { struct rte_vhost_vring vring; struct vhost_queue *vq; - int count = 0; int nb_rxq = dev->data->nb_rx_queues; int i; int ret; @@ -623,6 +685,8 @@ eth_vhost_install_intr(struct rte_eth_dev *dev) VHOST_LOG(INFO, "Prepare intr vec\n"); for (i = 0; i < nb_rxq; i++) { + dev->intr_handle->intr_vec[i] = RTE_INTR_VEC_RXTX_OFFSET + i; + dev->intr_handle->efds[i] = -1; vq = dev->data->rx_queues[i]; if (!vq) { VHOST_LOG(INFO, "rxq-%d not setup yet, skip!\n", i); @@ -641,14 +705,12 @@ eth_vhost_install_intr(struct rte_eth_dev *dev) "rxq-%d's kickfd is invalid, skip!\n", i); continue; } - dev->intr_handle->intr_vec[i] = RTE_INTR_VEC_RXTX_OFFSET + i; dev->intr_handle->efds[i] = vring.kickfd; - count++; VHOST_LOG(INFO, "Installed intr vec for rxq-%d\n", i); } - dev->intr_handle->nb_efd = count; - dev->intr_handle->max_intr = count + 1; + dev->intr_handle->nb_efd = nb_rxq; + dev->intr_handle->max_intr = nb_rxq + 1; dev->intr_handle->type = RTE_INTR_HANDLE_VDEV; return 0; @@ -830,6 +892,47 @@ destroy_device(int vid) _rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL); } +static int +vring_conf_update(int vid, struct rte_eth_dev *eth_dev, uint16_t vring_id) +{ + struct rte_eth_conf *dev_conf = ð_dev->data->dev_conf; + struct pmd_internal *internal = eth_dev->data->dev_private; + struct vhost_queue *vq; + struct rte_vhost_vring vring; + int rx_idx = vring_id % 2 ? (vring_id - 1) >> 1 : -1; + int ret = 0; + + /* + * The vring kickfd may be changed after the new device notification. + * Update it when the vring state is updated. + */ + if (rx_idx >= 0 && rx_idx < eth_dev->data->nb_rx_queues && + rte_atomic32_read(&internal->dev_attached) && + rte_atomic32_read(&internal->started) && + dev_conf->intr_conf.rxq) { + ret = rte_vhost_get_vhost_vring(vid, vring_id, &vring); + if (ret) { + VHOST_LOG(ERR, "Failed to get vring %d information.\n", + vring_id); + return ret; + } + eth_dev->intr_handle->efds[rx_idx] = vring.kickfd; + + vq = eth_dev->data->rx_queues[rx_idx]; + if (!vq) { + VHOST_LOG(ERR, "rxq%d is not setup yet\n", rx_idx); + return -1; + } + + rte_spinlock_lock(&vq->intr_lock); + if (vq->intr_enable) + ret = eth_vhost_update_intr(eth_dev, rx_idx); + rte_spinlock_unlock(&vq->intr_lock); + } + + return ret; +} + static int vring_state_changed(int vid, uint16_t vring, int enable) { @@ -848,6 +951,11 @@ vring_state_changed(int vid, uint16_t vring, int enable) eth_dev = list->eth_dev; /* won't be NULL */ state = vring_states[eth_dev->data->port_id]; + + if (enable && vring_conf_update(vid, eth_dev, vring)) + VHOST_LOG(INFO, "Failed to update vring-%d configuration.\n", + (int)vring); + rte_spinlock_lock(&state->lock); if (state->cur[vring] == enable) { rte_spinlock_unlock(&state->lock); @@ -1113,6 +1221,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id, vq->mb_pool = mb_pool; vq->virtqueue_id = rx_queue_id * VIRTIO_QNUM + VIRTIO_TXQ; + rte_spinlock_init(&vq->intr_lock); dev->data->rx_queues[rx_queue_id] = vq; return 0; @@ -1134,6 +1243,7 @@ eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id, } vq->virtqueue_id = tx_queue_id * VIRTIO_QNUM + VIRTIO_RXQ; + rte_spinlock_init(&vq->intr_lock); dev->data->tx_queues[tx_queue_id] = vq; return 0;