Commit aa0c1a69 authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Jim Harris
Browse files

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: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/388302


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 56f61c8f
Loading
Loading
Loading
Loading
+40 −1
Original line number Diff line number Diff line
@@ -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:
+33 −4
Original line number Diff line number Diff line
@@ -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 */
+47 −46
Original line number Diff line number Diff line
@@ -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 rc;
}

	return 0;
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);

err:
	virtio_dev_destruct(vdev);
	return -1;
	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)
+1 −1
Original line number Diff line number Diff line
@@ -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;
	}
+3 −5
Original line number Diff line number Diff line
@@ -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;
};