diff options
-rw-r--r-- | src/vnet/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vnet/devices/virtio/device.c | 34 | ||||
-rw-r--r-- | src/vnet/devices/virtio/virtio.h | 6 | ||||
-rw-r--r-- | src/vnet/devices/virtio/virtio_process.c | 88 |
4 files changed, 112 insertions, 17 deletions
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index f8b034f5dfa..021e8604077 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -987,6 +987,7 @@ list(APPEND VNET_SOURCES devices/virtio/virtio_api.c devices/virtio/virtio_pci_legacy.c devices/virtio/virtio_pci_modern.c + devices/virtio/virtio_process.c devices/virtio/virtio_types_api.c ) diff --git a/src/vnet/devices/virtio/device.c b/src/vnet/devices/virtio/device.c index 084be962ed7..521d76a8da4 100644 --- a/src/vnet/devices/virtio/device.c +++ b/src/vnet/devices/virtio/device.c @@ -761,11 +761,11 @@ static clib_error_t * virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid, vnet_hw_if_rx_mode mode) { + vlib_main_t *vm = vnm->vlib_main; virtio_main_t *mm = &virtio_main; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance); virtio_vring_t *rx_vring = vec_elt_at_index (vif->rxq_vrings, qid); - virtio_vring_t *tx_vring = 0; if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode)) { @@ -775,32 +775,32 @@ virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid, if (mode == VNET_HW_IF_RX_MODE_POLLING) { - vec_foreach (tx_vring, vif->txq_vrings) - { - /* only enable packet coalesce in poll mode */ - gro_flow_table_set_is_enable (tx_vring->flow_table, 1); - /* only enable packet buffering in poll mode */ - virtio_vring_buffering_set_is_enable (tx_vring->buffering, 1); - } + if (vif->packet_coalesce || vif->packet_buffering) + { + if (mm->interrupt_queues_count > 0) + mm->interrupt_queues_count--; + if (mm->interrupt_queues_count == 0) + vlib_process_signal_event (vm, + virtio_send_interrupt_node.index, + VIRTIO_EVENT_STOP_TIMER, 0); + } rx_vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; } else { if (vif->packet_coalesce || vif->packet_buffering) { - virtio_log_warning (vif, - "interface %U is in interrupt mode, disabling packet coalescing or buffering", - format_vnet_sw_if_index_name, vnet_get_main (), - vif->sw_if_index); - vec_foreach (tx_vring, vif->txq_vrings) - { - gro_flow_table_set_is_enable (tx_vring->flow_table, 0); - virtio_vring_buffering_set_is_enable (tx_vring->buffering, 0); - } + mm->interrupt_queues_count++; + if (mm->interrupt_queues_count == 1) + vlib_process_signal_event (vm, + virtio_send_interrupt_node.index, + VIRTIO_EVENT_START_TIMER, 0); } rx_vring->avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; } + rx_vring->mode = mode; + return 0; } diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h index 1cca9f366a8..86660a1f933 100644 --- a/src/vnet/devices/virtio/virtio.h +++ b/src/vnet/devices/virtio/virtio.h @@ -57,6 +57,9 @@ typedef enum #define VIRTIO_RING_FLAG_MASK_INT 1 +#define VIRTIO_EVENT_START_TIMER 1 +#define VIRTIO_EVENT_STOP_TIMER 2 + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -84,6 +87,7 @@ typedef struct u16 last_used_idx; u16 last_kick_avail_idx; u32 call_file_index; + vnet_hw_if_rx_mode mode; virtio_vring_buffering_t *buffering; gro_flow_table_t *flow_table; } virtio_vring_t; @@ -189,6 +193,7 @@ typedef struct typedef struct { + u32 interrupt_queues_count; /* logging */ vlib_log_class_t log_default; @@ -198,6 +203,7 @@ typedef struct extern virtio_main_t virtio_main; extern vnet_device_class_t virtio_device_class; extern vlib_node_registration_t virtio_input_node; +extern vlib_node_registration_t virtio_send_interrupt_node; clib_error_t *virtio_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 idx, u16 sz); diff --git a/src/vnet/devices/virtio/virtio_process.c b/src/vnet/devices/virtio/virtio_process.c new file mode 100644 index 00000000000..7a25611bb95 --- /dev/null +++ b/src/vnet/devices/virtio/virtio_process.c @@ -0,0 +1,88 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <vlib/vlib.h> +#include <vnet/devices/virtio/virtio.h> +#include <vnet/gso/gro_func.h> + +static uword +virtio_send_interrupt_process (vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + virtio_if_t *vif; + f64 timeout = 3153600000.0 /* 100 years */ ; + uword event_type, *event_data = 0; + virtio_main_t *vim = &virtio_main; + + while (1) + { + vlib_process_wait_for_event_or_clock (vm, timeout); + event_type = vlib_process_get_events (vm, &event_data); + vec_reset_length (event_data); + + switch (event_type) + { + case VIRTIO_EVENT_STOP_TIMER: + timeout = 3153600000.0; + break; + + case VIRTIO_EVENT_START_TIMER: + timeout = 1e-3; /* 1 millisecond */ + break; + + case ~0: + /* *INDENT-OFF* */ + pool_foreach (vif, vim->interfaces, { + if (vif->packet_coalesce || vif->packet_buffering) + { + virtio_vring_t *vring; + vec_foreach (vring, vif->rxq_vrings) + { + if (vring->mode == VNET_HW_IF_RX_MODE_INTERRUPT || + vring->mode == VNET_HW_IF_RX_MODE_ADAPTIVE) + vnet_device_input_set_interrupt_pending ( + vnet_get_main (), vif->hw_if_index, + RX_QUEUE_ACCESS (vring->queue_id)); + } + } + }); + /* *INDENT-ON* */ + break; + + default: + clib_warning ("BUG: unhandled event type %d", event_type); + break; + } + } + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (virtio_send_interrupt_node) = { + .function = virtio_send_interrupt_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "virtio-send-interrupt-process", +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |