virtio: add modern device support
Type: feature
Change-Id: I205f7c146a213d603d9d1e46fcf5195a876608dc
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
diff --git a/src/vnet/devices/virtio/virtio_pci_modern.c b/src/vnet/devices/virtio/virtio_pci_modern.c
new file mode 100644
index 0000000..24e8a4f
--- /dev/null
+++ b/src/vnet/devices/virtio/virtio_pci_modern.c
@@ -0,0 +1,440 @@
+/*
+ * 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 <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <vppinfra/types.h>
+#include <vlib/vlib.h>
+#include <vlib/pci/pci.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/devices/virtio/virtio.h>
+#include <vnet/devices/virtio/virtio_pci_modern.h>
+#include <vnet/devices/virtio/pci.h>
+
+
+static u64
+virtio_pci_modern_get_device_features (vlib_main_t * vm, virtio_if_t * vif)
+{
+ u64 features_lo, features_hi;
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DEVICE_FEATURE_SELECT_OFFSET (vif),
+ VIRTIO_FEATURE_SELECT_LO);
+ features_lo =
+ virtio_pci_reg_read_u32 (vif, VIRTIO_DEVICE_FEATURE_OFFSET (vif));
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DEVICE_FEATURE_SELECT_OFFSET (vif),
+ VIRTIO_FEATURE_SELECT_HI);
+ features_hi =
+ virtio_pci_reg_read_u32 (vif, VIRTIO_DEVICE_FEATURE_OFFSET (vif));
+ u64 features = ((features_hi << 32) | features_lo);
+ return features;
+}
+
+static u64
+virtio_pci_modern_get_driver_features (vlib_main_t * vm, virtio_if_t * vif)
+{
+ u64 features_lo, features_hi;
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
+ VIRTIO_FEATURE_SELECT_LO);
+ features_lo =
+ virtio_pci_reg_read_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif));
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
+ VIRTIO_FEATURE_SELECT_HI);
+ features_hi =
+ virtio_pci_reg_read_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif));
+
+ vif->features = ((features_hi << 32) | features_lo);
+ return vif->features;
+}
+
+static void
+virtio_pci_modern_set_driver_features (vlib_main_t * vm, virtio_if_t * vif,
+ u64 features)
+{
+ u32 features_lo = (u32) features, features_hi = (u32) (features >> 32);
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
+ VIRTIO_FEATURE_SELECT_LO);
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif),
+ features_lo);
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
+ VIRTIO_FEATURE_SELECT_HI);
+ virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif),
+ features_hi);
+
+ if (features != virtio_pci_modern_get_driver_features (vm, vif))
+ {
+ clib_warning ("modern set guest features failed!");
+ }
+}
+
+static u16
+virtio_pci_modern_get_msix_config (virtio_if_t * vif)
+{
+ u16 msix_config;
+ msix_config =
+ virtio_pci_reg_read_u16 (vif, VIRTIO_MSIX_CONFIG_VECTOR_OFFSET (vif));
+ return msix_config;
+}
+
+static u16
+virtio_pci_modern_set_msix_config (vlib_main_t * vm, virtio_if_t * vif,
+ u16 msix_config)
+{
+ virtio_pci_reg_write_u16 (vif, VIRTIO_MSIX_CONFIG_VECTOR_OFFSET (vif),
+ msix_config);
+ return virtio_pci_modern_get_msix_config (vif);
+}
+
+static u16
+virtio_pci_modern_get_num_queues (virtio_if_t * vif)
+{
+ u16 num_queues = 0;
+ num_queues = virtio_pci_reg_read_u16 (vif, VIRTIO_NUM_QUEUES_OFFSET (vif));
+ return num_queues;
+}
+
+static u8
+virtio_pci_modern_get_status (vlib_main_t * vm, virtio_if_t * vif)
+{
+ u8 status = 0;
+ status = virtio_pci_reg_read_u8 (vif, VIRTIO_DEVICE_STATUS_OFFSET (vif));
+ return status;
+}
+
+static void
+virtio_pci_modern_set_status (vlib_main_t * vm, virtio_if_t * vif, u8 status)
+{
+ if (status != VIRTIO_CONFIG_STATUS_RESET)
+ status |= virtio_pci_modern_get_status (vm, vif);
+ virtio_pci_reg_write_u8 (vif, VIRTIO_DEVICE_STATUS_OFFSET (vif), status);
+}
+
+static u8
+virtio_pci_modern_reset (vlib_main_t * vm, virtio_if_t * vif)
+{
+ virtio_pci_modern_set_status (vm, vif, VIRTIO_CONFIG_STATUS_RESET);
+ return virtio_pci_modern_get_status (vm, vif);
+}
+
+static u8
+virtio_pci_modern_get_config_generation (virtio_if_t * vif)
+{
+ u8 config_generation = 0;
+ config_generation =
+ virtio_pci_reg_read_u8 (vif, VIRTIO_CONFIG_GENERATION_OFFSET (vif));
+ return config_generation;
+}
+
+static void
+virtio_pci_modern_set_queue_select (virtio_if_t * vif, u16 queue_select)
+{
+ virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_SELECT_OFFSET (vif),
+ queue_select);
+}
+
+static u16
+virtio_pci_modern_get_queue_size (vlib_main_t * vm, virtio_if_t * vif,
+ u16 queue_id)
+{
+ u16 queue_size = 0;
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ queue_size = virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_SIZE_OFFSET (vif));
+ return queue_size;
+}
+
+static void
+virtio_pci_modern_set_queue_size (vlib_main_t * vm, virtio_if_t * vif,
+ u16 queue_id, u16 queue_size)
+{
+ if (!is_pow2 (queue_size))
+ {
+ return;
+ }
+
+ if (virtio_pci_modern_get_queue_size (vm, vif, queue_id) > queue_size)
+ virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_SIZE_OFFSET (vif),
+ queue_size);
+}
+
+static u16
+virtio_pci_modern_get_queue_msix_vector (virtio_if_t * vif)
+{
+ u16 queue_msix_vector = 0;
+ queue_msix_vector =
+ virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_MSIX_VECTOR_OFFSET (vif));
+ return queue_msix_vector;
+}
+
+static u16
+virtio_pci_modern_set_queue_msix_vector (vlib_main_t * vm, virtio_if_t * vif,
+ u16 queue_msix_vector, u16 queue_id)
+{
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_MSIX_VECTOR_OFFSET (vif),
+ queue_msix_vector);
+ return virtio_pci_modern_get_queue_msix_vector (vif);
+}
+
+static u16
+virtio_pci_modern_get_queue_enable (virtio_if_t * vif, u16 queue_id)
+{
+ u16 queue_enable = 0;
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ queue_enable =
+ virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_ENABLE_OFFSET (vif));
+ return queue_enable;
+}
+
+static void
+virtio_pci_modern_set_queue_enable (virtio_if_t * vif, u16 queue_id,
+ u16 queue_enable)
+{
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_ENABLE_OFFSET (vif),
+ queue_enable);
+}
+
+static u16
+virtio_pci_modern_get_queue_notify_off (virtio_if_t * vif, u16 queue_id)
+{
+ u16 queue_notify_off = 0;
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ queue_notify_off =
+ virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_NOTIFY_OFF_OFFSET (vif));
+ return queue_notify_off;
+}
+
+static u64
+virtio_pci_modern_get_queue_desc (virtio_if_t * vif)
+{
+ u64 queue_desc = 0;
+ queue_desc = virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif));
+ return queue_desc;
+}
+
+static void
+virtio_pci_modern_set_queue_desc (virtio_if_t * vif, u64 queue_desc)
+{
+ virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif), queue_desc);
+}
+
+static u64
+virtio_pci_modern_get_queue_driver (virtio_if_t * vif)
+{
+ u64 queue_driver = 0;
+ queue_driver =
+ virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif));
+ return queue_driver;
+}
+
+static void
+virtio_pci_modern_set_queue_driver (virtio_if_t * vif, u64 queue_driver)
+{
+ virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif),
+ queue_driver);
+}
+
+static u64
+virtio_pci_modern_get_queue_device (virtio_if_t * vif)
+{
+ u64 queue_device = 0;
+ queue_device =
+ virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif));
+ return queue_device;
+}
+
+static void
+virtio_pci_modern_set_queue_device (virtio_if_t * vif, u64 queue_device)
+{
+ virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif),
+ queue_device);
+}
+
+static u8
+virtio_pci_modern_setup_queue (vlib_main_t * vm, virtio_if_t * vif,
+ u16 queue_id, void *p)
+{
+ struct vring vr;
+ u16 queue_size = 0;
+
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ queue_size = virtio_pci_modern_get_queue_size (vm, vif, queue_id);
+ vring_init (&vr, queue_size, p, VIRTIO_PCI_VRING_ALIGN);
+
+ u64 desc = vlib_physmem_get_pa (vm, vr.desc);
+ virtio_pci_modern_set_queue_desc (vif, desc);
+ if (desc != virtio_pci_modern_get_queue_desc (vif))
+ return 1;
+
+ u64 avail = vlib_physmem_get_pa (vm, vr.avail);
+ virtio_pci_modern_set_queue_driver (vif, avail);
+ if (avail != virtio_pci_modern_get_queue_driver (vif))
+ return 1;
+
+ u64 used = vlib_physmem_get_pa (vm, vr.used);
+ virtio_pci_modern_set_queue_device (vif, used);
+ if (used != virtio_pci_modern_get_queue_device (vif))
+ return 1;
+
+ virtio_pci_modern_set_queue_enable (vif, queue_id, 1);
+
+ if (virtio_pci_modern_get_queue_enable (vif, queue_id))
+ return 0;
+
+ return 1;
+}
+
+static void
+virtio_pci_modern_del_queue (vlib_main_t * vm, virtio_if_t * vif,
+ u16 queue_id)
+{
+ virtio_pci_modern_set_queue_select (vif, queue_id);
+ virtio_pci_modern_set_queue_enable (vif, queue_id, 0);
+ virtio_pci_modern_set_queue_desc (vif, 0);
+ virtio_pci_modern_set_queue_driver (vif, 0);
+ virtio_pci_modern_set_queue_device (vif, 0);
+}
+
+static void
+virtio_pci_modern_get_device_mac (vlib_main_t * vm, virtio_if_t * vif)
+{
+ *((u32 *) vif->mac_addr) =
+ virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif));
+ *((u16 *) (vif->mac_addr + 4)) =
+ virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4);
+}
+
+static void
+virtio_pci_modern_set_device_mac (vlib_main_t * vm, virtio_if_t * vif)
+{
+ virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif),
+ *((u32 *) vif->mac_addr));
+ virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4,
+ *((u16 *) (vif->mac_addr + 4)));
+}
+
+static u16
+virtio_pci_modern_get_device_status (vlib_main_t * vm, virtio_if_t * vif)
+{
+ u16 status = 0;
+ status = virtio_pci_reg_read_u16 (vif, VIRTIO_STATUS_OFFSET (vif));
+ return status;
+}
+
+static u16
+virtio_pci_modern_get_max_virtqueue_pairs (vlib_main_t * vm,
+ virtio_if_t * vif)
+{
+ u16 max_virtqueue_pairs = 0;
+ max_virtqueue_pairs =
+ virtio_pci_reg_read_u16 (vif, VIRTIO_MAX_VIRTQUEUE_PAIRS_OFFSET (vif));
+ u16 supported_queues = virtio_pci_modern_get_num_queues (vif);
+ virtio_log_debug (vif, "max-virtqueue-pairs %u, supported-queues %u",
+ max_virtqueue_pairs, supported_queues);
+ return max_virtqueue_pairs;
+}
+
+static u16
+virtio_pci_modern_get_device_mtu (vlib_main_t * vm, virtio_if_t * vif)
+{
+ u16 mtu = 0;
+ mtu = virtio_pci_reg_read_u16 (vif, VIRTIO_MTU_OFFSET (vif));
+ return mtu;
+}
+
+static void
+virtio_pci_modern_read_config (vlib_main_t * vm, virtio_if_t * vif, void *dst,
+ int len, u32 addr)
+{
+ u8 config_count;
+ do
+ {
+ config_count = virtio_pci_modern_get_config_generation (vif);
+ virtio_pci_modern_get_device_mac (vm, vif);
+ u16 status = virtio_pci_modern_get_device_status (vm, vif);
+ u16 max_queue_pairs =
+ virtio_pci_modern_get_max_virtqueue_pairs (vm, vif);
+ u16 mtu = virtio_pci_modern_get_device_mtu (vm, vif);
+ virtio_log_debug (vif, "status %u, max_queue_pairs %u, mtu %u", status,
+ max_queue_pairs, mtu);
+ }
+ while (config_count != virtio_pci_modern_get_config_generation (vif));
+}
+
+static void
+virtio_pci_modern_write_config (vlib_main_t * vm, virtio_if_t * vif,
+ void *src, int len, u32 addr)
+{
+ // do nothing
+}
+
+static u8
+virtio_pci_modern_get_isr (vlib_main_t * vm, virtio_if_t * vif)
+{
+ return virtio_pci_reg_read_u8 (vif, VIRTIO_ISR_OFFSET (vif));
+}
+
+inline void
+virtio_pci_modern_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
+ u16 queue_id)
+{
+ u16 queue_notify_off =
+ virtio_pci_modern_get_queue_notify_off (vif, queue_id);
+ virtio_pci_reg_write_u16 (vif,
+ VIRTIO_NOTIFICATION_OFFSET (vif) +
+ vif->notify_off_multiplier * queue_notify_off,
+ queue_id);
+}
+
+static void
+virtio_pci_modern_device_debug_config_space (vlib_main_t * vm,
+ virtio_if_t * vif)
+{
+ // do nothing for now
+}
+
+const virtio_pci_func_t virtio_pci_modern_func = {
+ .read_config = virtio_pci_modern_read_config,
+ .write_config = virtio_pci_modern_write_config,
+ .get_device_features = virtio_pci_modern_get_device_features,
+ .get_driver_features = virtio_pci_modern_get_driver_features,
+ .set_driver_features = virtio_pci_modern_set_driver_features,
+ .get_status = virtio_pci_modern_get_status,
+ .set_status = virtio_pci_modern_set_status,
+ .device_reset = virtio_pci_modern_reset,
+ .get_isr = virtio_pci_modern_get_isr,
+ .get_queue_size = virtio_pci_modern_get_queue_size,
+ .set_queue_size = virtio_pci_modern_set_queue_size,
+ .setup_queue = virtio_pci_modern_setup_queue,
+ .del_queue = virtio_pci_modern_del_queue,
+ .notify_queue = virtio_pci_modern_notify_queue,
+ .set_config_irq = virtio_pci_modern_set_msix_config,
+ .set_queue_irq = virtio_pci_modern_set_queue_msix_vector,
+ .get_mac = virtio_pci_modern_get_device_mac,
+ .set_mac = virtio_pci_modern_set_device_mac,
+ .get_device_status = virtio_pci_modern_get_device_status,
+ .get_max_queue_pairs = virtio_pci_modern_get_max_virtqueue_pairs,
+ .get_mtu = virtio_pci_modern_get_device_mtu,
+ .device_debug_config_space = virtio_pci_modern_device_debug_config_space,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */