virtio/pci: add user callback for creating PCI vdevs

Added virtio_pci_dev_init, an equivalent to
virtio_user_dev_init. It takes an opaque pci
context pointer that is provided via virtio
PCI enumerate API.

virtio_pci will do only PCI-related
initialization. The virtio_dev creation
and SCSI-specific logic now belong to upper
layers

Change-Id: I7ad450591f893c4ab953c09cfb6441b186736751
Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/388302
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2017-11-20 23:22:02 +01:00 committed by Jim Harris
parent 56f61c8feb
commit aa0c1a699a
5 changed files with 125 additions and 58 deletions

View File

@ -57,6 +57,9 @@
#define CTRLQ_RING_SIZE 16
#define SCAN_REQUEST_RETRIES 5
/* Number of non-request queues - eventq and controlq */
#define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2
#define VIRTIO_SCSI_CONTROLQ 0
#define VIRTIO_SCSI_EVENTQ 1
#define VIRTIO_SCSI_REQUESTQ 2
@ -123,6 +126,42 @@ struct bdev_virtio_io_channel {
struct virtqueue *vq;
};
static int
virtio_pci_scsi_dev_create_cb(struct virtio_pci_ctx *pci_ctx)
{
static int pci_dev_counter = 0;
struct virtio_dev *vdev;
char *name;
uint32_t num_queues;
int rc;
vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL) {
SPDK_ERRLOG("virtio device calloc failed\n");
return -1;
}
name = spdk_sprintf_alloc("VirtioScsi%"PRIu32, ++pci_dev_counter);
if (name == NULL) {
free(vdev);
return -1;
}
rc = virtio_pci_dev_init(vdev, name, pci_ctx);
free(name);
if (rc != 0) {
free(vdev);
return -1;
}
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues),
&num_queues, sizeof(num_queues));
vdev->max_queues = SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED + num_queues;
return 0;
}
static int scan_target(struct virtio_scsi_scan_base *base);
static int
@ -1179,7 +1218,7 @@ bdev_virtio_process_config(void)
enable_pci = spdk_conf_section_get_boolval(sp, "Enable", false);
if (enable_pci) {
rc = virtio_enumerate_pci();
rc = virtio_pci_scsi_dev_enumerate(virtio_pci_scsi_dev_create_cb);
}
out:

View File

@ -54,8 +54,7 @@
*/
#define VQ_RING_DESC_CHAIN_END 32768
/* Number of non-request queues - eventq and controlq */
#define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2
#define SPDK_VIRTIO_MAX_VIRTQUEUES 0x100
/* Extra status define for readability */
#define VIRTIO_CONFIG_S_RESET 0
@ -189,6 +188,16 @@ struct virtio_driver {
extern struct virtio_driver g_virtio_driver;
/** Context for creating PCI virtio_devs */
struct virtio_pci_ctx;
/**
* Callback for creating virtio_dev from a PCI device.
* The first param is the PCI context to be associated with virtio_dev.
* \return 0 on success, -1 on error.
*/
typedef int (*virtio_pci_create_cb)(struct virtio_pci_ctx *pci_ctx);
/* Features desired/implemented by this driver. */
#define VIRTIO_SCSI_DEV_SUPPORTED_FEATURES \
(1ULL << VIRTIO_SCSI_F_INOUT | \
@ -374,9 +383,14 @@ virtio_dev_has_feature(struct virtio_dev *vdev, uint64_t bit)
void virtio_dev_dump_json_config(struct virtio_dev *vdev, struct spdk_json_write_ctx *w);
/**
* Init all compatible Virtio PCI devices.
* Enumerate all PCI Virtio devices on the system.
*
* \param enum_cb a function to be called for each valid PCI device.
* \return if a virtio_dev is has been created, the callback should return 0.
* Returning any other value will cause the PCI context to be freed,
* making it unusable.
*/
int virtio_enumerate_pci(void);
int virtio_pci_scsi_dev_enumerate(virtio_pci_create_cb enum_cb);
/**
* Connect to a vhost-user device and init corresponding virtio_dev struct.
@ -397,4 +411,19 @@ int virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *
uint16_t requested_queues, uint32_t queue_size,
uint16_t fixed_queue_num);
/**
* Initialize a virtio_dev for the given PCI device.
* The virtio_dev will try to use \c SPDK_VIRTIO_MAX_VIRTQUEUES queues by
* default and might fail to start. It is advised to overwrite the
* `virtio_dev->max_queues` field manually starting the device.
* The virtio_dev has to be freed with \c virtio_dev_destruct.
*
* \param vdev preallocated vhost device struct to operate on
* \param name name of this virtio device
* \param pci_ctx context of the PCI device
* \return 0 on success, -1 on error.
*/
int virtio_pci_dev_init(struct virtio_dev *vdev, const char *name,
struct virtio_pci_ctx *pci_ctx);
#endif /* SPDK_VIRTIO_H */

View File

@ -33,11 +33,10 @@
#include "spdk/stdinc.h"
#include <linux/virtio_scsi.h>
#include "spdk/mmio.h"
#include "spdk/string.h"
#include "spdk/env.h"
#include "spdk/pci_ids.h"
#include "virtio.h"
@ -57,7 +56,9 @@ struct virtio_hw {
struct virtio_pci_common_cfg *common_cfg;
struct spdk_pci_device *pci_dev;
struct virtio_scsi_config *dev_cfg;
/** Device-specific PCI config space */
void *dev_cfg;
};
/*
@ -69,8 +70,6 @@ struct virtio_hw {
#define PCI_CAP_ID_VNDR 0x09
#define PCI_CAP_ID_MSIX 0x11
static int g_dev_counter = 0;
static inline int
check_vq_phys_addr_ok(struct virtqueue *vq)
{
@ -414,27 +413,9 @@ next:
}
static int
virtio_dev_pci_init(struct virtio_dev *vdev)
{
int vdev_id = ++g_dev_counter;
vdev->name = spdk_sprintf_alloc("VirtioScsi%"PRIu32, vdev_id);
if (!vdev->name) {
return -1;
}
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues),
&vdev->max_queues, sizeof(vdev->max_queues));
vdev->max_queues += SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED;
TAILQ_INSERT_TAIL(&g_virtio_driver.init_ctrlrs, vdev, tailq);
return 0;
}
static int
pci_enum_virtio_probe_cb(void *ctx, struct spdk_pci_device *pci_dev)
virtio_pci_dev_probe(struct spdk_pci_device *pci_dev, virtio_pci_create_cb enum_cb)
{
struct virtio_hw *hw;
struct virtio_dev *vdev;
uint8_t *bar_vaddr;
uint64_t bar_paddr, bar_len;
int rc;
@ -470,43 +451,63 @@ pci_enum_virtio_probe_cb(void *ctx, struct spdk_pci_device *pci_dev)
return -1;
}
vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL) {
SPDK_ERRLOG("calloc failed\n");
free_virtio_hw(hw);
return -1;
}
rc = virtio_dev_construct(vdev, &modern_ops, hw);
rc = enum_cb((struct virtio_pci_ctx *)hw);
if (rc != 0) {
free(vdev);
free_virtio_hw(hw);
return -1;
}
vdev->is_hw = 1;
vdev->modern = 1;
rc = virtio_dev_pci_init(vdev);
if (rc != 0) {
goto err;
}
return 0;
return rc;
}
err:
virtio_dev_destruct(vdev);
return -1;
static int
virtio_pci_scsi_dev_probe_cb(void *ctx, struct spdk_pci_device *pci_dev)
{
virtio_pci_create_cb enum_cb = ctx;
uint16_t pci_device_id = spdk_pci_device_get_device_id(pci_dev);
if (pci_device_id != PCI_DEVICE_ID_VIRTIO_SCSI_MODERN) {
return 1;
}
return virtio_pci_dev_probe(pci_dev, enum_cb);
}
int
virtio_enumerate_pci(void)
virtio_pci_scsi_dev_enumerate(virtio_pci_create_cb enum_cb)
{
if (!spdk_process_is_primary()) {
SPDK_WARNLOG("virtio_pci secondary process support is not implemented yet.\n");
return 0;
}
return spdk_pci_virtio_enumerate(pci_enum_virtio_probe_cb, NULL);
return spdk_pci_virtio_enumerate(virtio_pci_scsi_dev_probe_cb, enum_cb);
}
int
virtio_pci_dev_init(struct virtio_dev *vdev, const char *name,
struct virtio_pci_ctx *pci_ctx)
{
int rc;
char *name_dup;
name_dup = strdup(name);
if (name_dup == NULL) {
return -1;
}
rc = virtio_dev_construct(vdev, &modern_ops, pci_ctx);
if (rc != 0) {
free(name_dup);
return -1;
}
vdev->name = name_dup;
vdev->is_hw = 1;
vdev->modern = 1;
vdev->max_queues = SPDK_VIRTIO_MAX_VIRTQUEUES;
TAILQ_INSERT_TAIL(&g_virtio_driver.init_ctrlrs, vdev, tailq);
return 0;
}
SPDK_LOG_REGISTER_TRACE_FLAG("virtio_pci", SPDK_TRACE_VIRTIO_PCI)

View File

@ -165,7 +165,7 @@ virtio_user_dev_setup(struct virtio_dev *vdev)
dev->vhostfd = -1;
for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; ++i) {
for (i = 0; i < SPDK_VIRTIO_MAX_VIRTQUEUES; ++i) {
dev->callfds[i] = -1;
dev->kickfds[i] = -1;
}

View File

@ -42,8 +42,6 @@
#include "../virtio.h"
#define VIRTIO_MAX_VIRTQUEUES 0x100
enum vhost_user_request {
VHOST_USER_NONE = 0,
VHOST_USER_GET_FEATURES = 1,
@ -74,13 +72,13 @@ struct virtio_user_dev {
int vhostfd;
/* for both vhost_user and vhost_kernel */
int callfds[VIRTIO_MAX_VIRTQUEUES];
int kickfds[VIRTIO_MAX_VIRTQUEUES];
int callfds[SPDK_VIRTIO_MAX_VIRTQUEUES];
int kickfds[SPDK_VIRTIO_MAX_VIRTQUEUES];
uint32_t queue_size;
uint8_t status;
char path[PATH_MAX];
struct vring vrings[VIRTIO_MAX_VIRTQUEUES];
struct vring vrings[SPDK_VIRTIO_MAX_VIRTQUEUES];
struct virtio_user_backend_ops *ops;
};