blob: 24e8a4fe404e6658c49c7ddb02e375960a4d4e19 [file] [log] [blame]
/*
* 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:
*/