ff1863f428
Virtio spec say that any IRQ requests are only hints. So try to limit number of interrupts generated by vhost by defining minimum interval between sending IRQ. Coalescing is disabled by default. Can be enabled using RPC command 'set_vhost_controller_coalescing'. Change-Id: I9b96014d004ea0ea022b4498c6b47d30d867091a Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com> Reviewed-on: https://review.gerrithub.io/378130 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
252 lines
8.2 KiB
C
252 lines
8.2 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright (c) Intel Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef SPDK_VHOST_INTERNAL_H
|
|
#define SPDK_VHOST_INTERNAL_H
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include <rte_vhost.h>
|
|
|
|
#include "spdk_internal/log.h"
|
|
#include "spdk/event.h"
|
|
#include "spdk/rpc.h"
|
|
|
|
#define SPDK_CACHE_LINE_SIZE RTE_CACHE_LINE_SIZE
|
|
|
|
#ifndef VHOST_USER_F_PROTOCOL_FEATURES
|
|
#define VHOST_USER_F_PROTOCOL_FEATURES 30
|
|
#endif
|
|
|
|
#ifndef VIRTIO_F_VERSION_1
|
|
#define VIRTIO_F_VERSION_1 32
|
|
#endif
|
|
|
|
#ifndef VIRTIO_BLK_F_MQ
|
|
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
|
|
#endif
|
|
|
|
#ifndef VIRTIO_BLK_F_CONFIG_WCE
|
|
#define VIRTIO_BLK_F_CONFIG_WCE 11
|
|
#endif
|
|
|
|
#define SPDK_VHOST_MAX_VQUEUES 256
|
|
#define SPDK_VHOST_MAX_VQ_SIZE 1024
|
|
|
|
#define SPDK_VHOST_SCSI_CTRLR_MAX_DEVS 8
|
|
|
|
#define SPDK_VHOST_IOVS_MAX 128
|
|
|
|
/*
|
|
* Rate at which stats are checked for interrupt coalescing.
|
|
*/
|
|
#define SPDK_VHOST_DEV_STATS_CHECK_INTERVAL_MS 10
|
|
/*
|
|
* Default threshold at which interrupts start to be coalesced.
|
|
*/
|
|
#define SPDK_VHOST_VQ_IOPS_COALESCING_THRESHOLD 60000
|
|
|
|
/*
|
|
* Currently coalescing is not used by default.
|
|
* Setting this to value > 0 here or by RPC will enable coalescing.
|
|
*/
|
|
#define SPDK_VHOST_COALESCING_DELAY_BASE_US 0
|
|
|
|
|
|
#define SPDK_VHOST_FEATURES ((1ULL << VHOST_F_LOG_ALL) | \
|
|
(1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \
|
|
(1ULL << VIRTIO_F_VERSION_1) | \
|
|
(1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \
|
|
(1ULL << VIRTIO_RING_F_EVENT_IDX) | \
|
|
(1ULL << VIRTIO_RING_F_INDIRECT_DESC))
|
|
|
|
#define SPDK_VHOST_DISABLED_FEATURES ((1ULL << VHOST_F_LOG_ALL) | \
|
|
(1ULL << VIRTIO_RING_F_EVENT_IDX) | \
|
|
(1ULL << VIRTIO_RING_F_INDIRECT_DESC))
|
|
|
|
enum spdk_vhost_dev_type {
|
|
SPDK_VHOST_DEV_T_SCSI,//!< SPDK_VHOST_DEV_T_SCSI
|
|
SPDK_VHOST_DEV_T_BLK, //!< SPDK_VHOST_DEV_T_BLK
|
|
};
|
|
|
|
struct spdk_vhost_virtqueue {
|
|
struct rte_vhost_vring vring;
|
|
void *tasks;
|
|
|
|
/* Request count from last stats check */
|
|
uint32_t req_cnt;
|
|
|
|
/* Request count from last event */
|
|
uint16_t used_req_cnt;
|
|
|
|
/* How long interrupt is delayed */
|
|
uint32_t irq_delay_time;
|
|
|
|
/* Next time when we need to send event */
|
|
uint64_t next_event_time;
|
|
|
|
} __attribute((aligned(SPDK_CACHE_LINE_SIZE)));
|
|
|
|
struct spdk_vhost_dev_backend {
|
|
uint64_t virtio_features;
|
|
uint64_t disabled_features;
|
|
|
|
/**
|
|
* Callbacks for starting and pausing the device.
|
|
* The first param is struct spdk_vhost_dev *.
|
|
* The second one is event context that has to be
|
|
* passed to spdk_vhost_dev_backend_event_done().
|
|
*/
|
|
spdk_vhost_event_fn start_device;
|
|
spdk_vhost_event_fn stop_device;
|
|
|
|
void (*dump_config_json)(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w);
|
|
int (*vhost_remove_controller)(struct spdk_vhost_dev *vdev);
|
|
};
|
|
|
|
struct spdk_vhost_dev {
|
|
struct rte_vhost_memory *mem;
|
|
char *name;
|
|
char *path;
|
|
|
|
int vid;
|
|
int task_cnt;
|
|
int32_t lcore;
|
|
uint64_t cpumask;
|
|
|
|
enum spdk_vhost_dev_type type;
|
|
const struct spdk_vhost_dev_backend *backend;
|
|
|
|
uint32_t coalescing_delay_time_base;
|
|
|
|
/* Threshold when event coalescing for virtqueue will be turned on. */
|
|
uint32_t coalescing_io_rate_threshold;
|
|
|
|
/* Next time when stats for event coalescing will be checked. */
|
|
uint64_t next_stats_check_time;
|
|
|
|
/* Interval used for event coalescing checking. */
|
|
uint64_t stats_check_interval;
|
|
|
|
uint16_t num_queues;
|
|
|
|
uint64_t negotiated_features;
|
|
|
|
struct spdk_vhost_virtqueue virtqueue[SPDK_VHOST_MAX_VQUEUES];
|
|
};
|
|
|
|
struct spdk_vhost_dev *spdk_vhost_dev_find(const char *ctrlr_name);
|
|
void spdk_vhost_dev_mem_register(struct spdk_vhost_dev *vdev);
|
|
void spdk_vhost_dev_mem_unregister(struct spdk_vhost_dev *vdev);
|
|
|
|
void *spdk_vhost_gpa_to_vva(struct spdk_vhost_dev *vdev, uint64_t addr);
|
|
|
|
uint16_t spdk_vhost_vq_avail_ring_get(struct spdk_vhost_virtqueue *vq, uint16_t *reqs,
|
|
uint16_t reqs_len);
|
|
bool spdk_vhost_vq_should_notify(struct spdk_vhost_dev *vdev, struct spdk_vhost_virtqueue *vq);
|
|
|
|
/**
|
|
* Get a virtio descriptor at given index in given virtqueue.
|
|
* The descriptor will provide access to the entire descriptor
|
|
* chain. The subsequent descriptors are accesible via
|
|
* \c spdk_vhost_vring_desc_get_next.
|
|
* \param vdev vhost device
|
|
* \param vq virtqueue
|
|
* \param req_idx descriptor index
|
|
* \param desc pointer to be set to the descriptor
|
|
* \param desc_table descriptor table to be used with
|
|
* \c spdk_vhost_vring_desc_get_next. This might be either
|
|
* default virtqueue descriptor table or per-chain indirect
|
|
* table.
|
|
* \param desc_table_size size of the *desc_table*
|
|
* \return 0 on success, -1 if given index is invalid.
|
|
* If -1 is returned, the content of params is undefined.
|
|
*/
|
|
int spdk_vhost_vq_get_desc(struct spdk_vhost_dev *vdev, struct spdk_vhost_virtqueue *vq,
|
|
uint16_t req_idx, struct vring_desc **desc, struct vring_desc **desc_table,
|
|
uint32_t *desc_table_size);
|
|
|
|
/**
|
|
* Send IRQ/call client (if pending) for \c vq.
|
|
* \param vdev vhost device
|
|
* \param vq virtqueue
|
|
* \return
|
|
* 0 - if no interrupt was signalled
|
|
* 1 - if interrupt was signalled
|
|
*/
|
|
int spdk_vhost_vq_used_signal(struct spdk_vhost_dev *vdev, struct spdk_vhost_virtqueue *vq);
|
|
|
|
|
|
/**
|
|
* Send IRQs for all queues that need to be signaled.
|
|
* \param vdev vhost device
|
|
* \param vq virtqueue
|
|
*/
|
|
void spdk_vhost_dev_used_signal(struct spdk_vhost_dev *vdev);
|
|
|
|
void spdk_vhost_vq_used_ring_enqueue(struct spdk_vhost_dev *vdev, struct spdk_vhost_virtqueue *vq,
|
|
uint16_t id, uint32_t len);
|
|
|
|
/**
|
|
* Get subsequent descriptor from given table.
|
|
* \param desc current descriptor, will be set to the
|
|
* next descriptor (NULL in case this is the last
|
|
* descriptor in the chain or the next desc is invalid)
|
|
* \param desc_table descriptor table
|
|
* \param desc_table_size size of the *desc_table*
|
|
* \return 0 on success, -1 if given index is invalid
|
|
* The *desc* param will be set regardless of the
|
|
* return value.
|
|
*/
|
|
int spdk_vhost_vring_desc_get_next(struct vring_desc **desc,
|
|
struct vring_desc *desc_table, uint32_t desc_table_size);
|
|
bool spdk_vhost_vring_desc_is_wr(struct vring_desc *cur_desc);
|
|
|
|
int spdk_vhost_vring_desc_to_iov(struct spdk_vhost_dev *vdev, struct iovec *iov,
|
|
uint16_t *iov_index, const struct vring_desc *desc);
|
|
bool spdk_vhost_dev_has_feature(struct spdk_vhost_dev *vdev, unsigned feature_id);
|
|
|
|
int spdk_vhost_dev_construct(struct spdk_vhost_dev *vdev, const char *name, const char *mask_str,
|
|
enum spdk_vhost_dev_type type, const struct spdk_vhost_dev_backend *backend);
|
|
int spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev);
|
|
|
|
int spdk_vhost_scsi_controller_construct(void);
|
|
int spdk_vhost_blk_controller_construct(void);
|
|
void spdk_vhost_dump_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w);
|
|
void spdk_vhost_dev_backend_event_done(void *event_ctx, int response);
|
|
void spdk_vhost_lock(void);
|
|
void spdk_vhost_unlock(void);
|
|
int spdk_remove_vhost_controller(struct spdk_vhost_dev *vdev);
|
|
|
|
#endif /* SPDK_VHOST_INTERNAL_H */
|