net/virtio: setup Rx queue interrupts
This patch mainly allocates structure to store queue/irq mapping, and configure queue/irq mapping down through PCI ops. It also creates eventfds for each Rx queue and tell the kernel about the eventfd/intr binding. Note: So far, we hard-code 1:1 queue/irq mapping (each rx queue has one exclusive interrupt), like this: vec 0 -> config irq vec 1 -> rxq0 vec 2 -> rxq1 ... which means, the "vectors" option of QEMU should be configured with a value >= N+1 (N is the number of the queue pairs). Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com> Tested-by: Lei Yao <lei.a.yao@intel.com> Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
This commit is contained in:
parent
c056be239d
commit
26b683b4f7
@ -5,6 +5,7 @@
|
||||
;
|
||||
[Features]
|
||||
Link status = Y
|
||||
Rx interrupt = Y
|
||||
Queue start/stop = Y
|
||||
Scattered Rx = Y
|
||||
Promiscuous mode = Y
|
||||
|
@ -5,6 +5,7 @@
|
||||
;
|
||||
[Features]
|
||||
Link status = Y
|
||||
Rx interrupt = Y
|
||||
Queue start/stop = Y
|
||||
Promiscuous mode = Y
|
||||
Allmulticast mode = Y
|
||||
|
@ -87,6 +87,8 @@ In this release, the virtio PMD driver provides the basic functionality of packe
|
||||
|
||||
* Virtio supports Link State interrupt.
|
||||
|
||||
* Virtio supports Rx interrupt (so far, only support 1:1 mapping for queue/interrupt).
|
||||
|
||||
* Virtio supports software vlan stripping and inserting.
|
||||
|
||||
* Virtio supports using port IO to get PCI resource when uio/igb_uio module is not available.
|
||||
@ -274,3 +276,61 @@ Example of using the vector version of the virtio poll mode driver in
|
||||
``testpmd``::
|
||||
|
||||
testpmd -c 0x7 -n 4 -- -i --txqflags=0xF01 --rxq=1 --txq=1 --nb-cores=1
|
||||
|
||||
|
||||
Interrupt mode
|
||||
--------------
|
||||
|
||||
.. _virtio_interrupt_mode:
|
||||
|
||||
There are three kinds of interrupts from a virtio device over PCI bus: config
|
||||
interrupt, Rx interrupts, and Tx interrupts. Config interrupt is used for
|
||||
notification of device configuration changes, especially link status (lsc).
|
||||
Interrupt mode is translated into Rx interrupts in the context of DPDK.
|
||||
|
||||
Prerequisites for Rx interrupts
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To support Rx interrupts,
|
||||
#. Check if guest kernel supports VFIO-NOIOMMU:
|
||||
|
||||
Linux started to support VFIO-NOIOMMU since 4.8.0. Make sure the guest
|
||||
kernel is compiled with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
CONFIG_VFIO_NOIOMMU=y
|
||||
|
||||
#. Properly set msix vectors when starting VM:
|
||||
|
||||
Enable multi-queue when starting VM, and specify msix vectors in qemu
|
||||
cmdline. (N+1) is the minimum, and (2N+2) is mostly recommended.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$(QEMU) ... -device virtio-net-pci,mq=on,vectors=2N+2 ...
|
||||
|
||||
#. In VM, insert vfio module in NOIOMMU mode:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
modprobe vfio enable_unsafe_noiommu_mode=1
|
||||
modprobe vfio-pci
|
||||
|
||||
#. In VM, bind the virtio device with vfio-pci:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python tools/dpdk-devbind.py -b vfio-pci 00:03.0
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Here we use l3fwd-power as an example to show how to get started.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ l3fwd-power -c 0x3 -- -p 1 -P --config="(0,0,1)" \
|
||||
--no-numa --parse-ptype
|
||||
|
@ -78,6 +78,19 @@ New Features
|
||||
it might enter into kernel space to wake up those kthreads if
|
||||
necessary).
|
||||
|
||||
* **Added virtio Rx interrupt suppprt.**
|
||||
|
||||
This feature enables Rx interrupt mode for virtio pci net devices as
|
||||
binded to VFIO (noiommu mode) and drived by virtio PMD.
|
||||
|
||||
With this feature, virtio PMD can switch between polling mode and
|
||||
interrupt mode, to achieve best performance, and at the same time save
|
||||
power. It can work on both legacy and modern virtio devices. At this mode,
|
||||
each rxq is mapped with an exluded MSIx interrupt.
|
||||
|
||||
See the :ref:`Virtio Interrupt Mode <virtio_interrupt_mode>` documentation
|
||||
for more information.
|
||||
|
||||
|
||||
Resolved Issues
|
||||
---------------
|
||||
|
@ -1210,6 +1210,82 @@ rx_func_get(struct rte_eth_dev *eth_dev)
|
||||
eth_dev->rx_pkt_burst = &virtio_recv_pkts;
|
||||
}
|
||||
|
||||
/* Only support 1:1 queue/interrupt mapping so far.
|
||||
* TODO: support n:1 queue/interrupt mapping when there are limited number of
|
||||
* interrupt vectors (<N+1).
|
||||
*/
|
||||
static int
|
||||
virtio_queues_bind_intr(struct rte_eth_dev *dev)
|
||||
{
|
||||
uint32_t i;
|
||||
struct virtio_hw *hw = dev->data->dev_private;
|
||||
|
||||
PMD_INIT_LOG(INFO, "queue/interrupt binding\n");
|
||||
for (i = 0; i < dev->data->nb_rx_queues; ++i) {
|
||||
dev->intr_handle->intr_vec[i] = i + 1;
|
||||
if (VTPCI_OPS(hw)->set_queue_irq(hw, hw->vqs[i * 2], i + 1) ==
|
||||
VIRTIO_MSI_NO_VECTOR) {
|
||||
PMD_DRV_LOG(ERR, "failed to set queue vector");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virtio_configure_intr(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct virtio_hw *hw = dev->data->dev_private;
|
||||
|
||||
if (!rte_intr_cap_multiple(dev->intr_handle)) {
|
||||
PMD_INIT_LOG(ERR, "Multiple intr vector not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (rte_intr_efd_enable(dev->intr_handle, dev->data->nb_rx_queues)) {
|
||||
PMD_INIT_LOG(ERR, "Fail to create eventfd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* DO NOT try to remove this! This function will enable msix, or QEMU
|
||||
* will encounter SIGSEGV when DRIVER_OK is sent.
|
||||
* And for legacy devices, this should be done before queue/vec binding
|
||||
* to change the config size from 20 to 24, or VIRTIO_MSI_QUEUE_VECTOR
|
||||
* (22) will be ignored.
|
||||
*/
|
||||
if (rte_intr_enable(dev->intr_handle) < 0) {
|
||||
PMD_DRV_LOG(ERR, "interrupt enable failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1306,6 +1382,14 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
|
||||
ret = virtio_alloc_queues(eth_dev);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
vtpci_reinit_complete(hw);
|
||||
|
||||
if (pci_dev)
|
||||
|
Loading…
x
Reference in New Issue
Block a user