For virtio PCI devices, interrupt should be configured before setting
VIRTIO_CONFIG_STATUS_DRIVER_OK so that QEMU can properly set eventfds
in the host.

For virtio virtual devices, VIRTIO_CONFIG_STATUS_DRIVER_OK should be
set firstly, so that intr_handle is initialized in
virtio_user_start_device().

To accommodate both requirements, we rearrange the sequence like this:
  a. set interrupt configure for PCI devices.
  b. set VIRTIO_CONFIG_STATUS_DRIVER_OK.
  c. set interrupt configure for virtual devices.

Signed-off-by: Jianfeng Tan <jianfeng....@intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 57 ++++++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 6 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c 
b/drivers/net/virtio/virtio_ethdev.c
index d9986ab..f0213ba 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1275,7 +1275,7 @@ virtio_queues_unbind_intr(struct rte_eth_dev *dev)
 }
 
 static int
-virtio_configure_intr(struct rte_eth_dev *dev)
+virtio_configure_intr_pci(struct rte_eth_dev *dev)
 {
        struct virtio_hw *hw = dev->data->dev_private;
 
@@ -1327,6 +1327,37 @@ virtio_configure_intr(struct rte_eth_dev *dev)
        return 0;
 }
 
+static int
+virtio_configure_intr_vdev(struct rte_eth_dev *dev)
+{
+       struct virtio_hw *hw = dev->data->dev_private;
+
+       if (!dev->intr_handle->intr_vec) {
+               dev->intr_handle->intr_vec =
+                       rte_zmalloc("intr_vec",
+                                   hw->max_queue_pairs * sizeof(int), 0);
+               if (!dev->intr_handle->intr_vec) {
+                       PMD_INIT_LOG(ERR, "Failed to allocate %u rxq vectors",
+                                    hw->max_queue_pairs);
+                       return -ENOMEM;
+               }
+       }
+
+       /* Re-register callback to update max_intr */
+       rte_intr_callback_unregister(dev->intr_handle,
+                                    virtio_interrupt_handler,
+                                    dev);
+       rte_intr_callback_register(dev->intr_handle,
+                                  virtio_interrupt_handler,
+                                  dev);
+
+       if (virtio_queues_bind_intr(dev) < 0) {
+               PMD_INIT_LOG(ERR, "Failed to bind queue/interrupt");
+               return -1;
+       }
+
+       return 0;
+}
 /* reset device and renegotiate features if needed */
 static int
 virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
@@ -1450,15 +1481,29 @@ virtio_init_device(struct rte_eth_dev *eth_dev, 
uint64_t req_features)
        if (ret < 0)
                return ret;
 
-       if (eth_dev->data->dev_conf.intr_conf.rxq) {
-               if (virtio_configure_intr(eth_dev) < 0) {
-                       PMD_INIT_LOG(ERR, "failed to configure interrupt");
-                       return -1;
-               }
+       /* For virtio PCI devices, setup interrupt configuration before
+        * setting VIRTIO_CONFIG_STATUS_DRIVER_OK, required by QEMU.
+        */
+       if (pci_dev &&
+           eth_dev->data->dev_conf.intr_conf.rxq &&
+           virtio_configure_intr_pci(eth_dev) < 0) {
+               PMD_INIT_LOG(ERR, "failed to configure interrupt");
+               return -1;
        }
 
        vtpci_reinit_complete(hw);
 
+       /* For virtio vdev, setup interrupt configuration after
+        * setting VIRTIO_CONFIG_STATUS_DRIVER_OK, so that intr_handle
+        * is initialized in virtio_user_start_device().
+        */
+       if (!pci_dev &&
+           eth_dev->data->dev_conf.intr_conf.rxq &&
+           virtio_configure_intr_vdev(eth_dev) < 0) {
+               PMD_INIT_LOG(ERR, "failed to configure interrupt");
+               return -1;
+       }
+
        if (pci_dev)
                PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
                        eth_dev->data->port_id, pci_dev->id.vendor_id,
-- 
2.7.4

Reply via email to