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:
parent
56f61c8feb
commit
aa0c1a699a
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user