aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libvfio-user.h38
-rw-r--r--include/pci.h7
-rw-r--r--lib/libvfio-user.c53
-rw-r--r--lib/private.h2
-rw-r--r--samples/gpio-pci-idio-16.c6
-rw-r--r--samples/null.c10
-rw-r--r--samples/server.c6
7 files changed, 92 insertions, 30 deletions
diff --git a/include/libvfio-user.h b/include/libvfio-user.h
index ed4e302..4735991 100644
--- a/include/libvfio-user.h
+++ b/include/libvfio-user.h
@@ -238,17 +238,24 @@ typedef struct {
*/
#define LIBVFIO_USER_FLAG_ATTACH_NB (1 << 0)
+typedef enum {
+ VFU_DEV_TYPE_PCI
+} vfu_dev_type_t;
+
/**
* Creates libvfio-user context.
+ *
* @trans: transport type
* @path: path to socket file.
* @flags: context flag
* @pvt: private data
+ * @dev_type: device type
+ *
* @returns the vfu_ctx to be used or NULL on error. Sets errno.
*/
vfu_ctx_t *
vfu_create_ctx(vfu_trans_t trans, const char *path,
- int flags, void *pvt);
+ int flags, void *pvt, vfu_dev_type_t dev_type);
/**
* Setup logging information.
@@ -261,18 +268,32 @@ vfu_setup_log(vfu_ctx_t *vfu_ctx, vfu_log_fn_t *log, vfu_log_lvl_t log_lvl);
//TODO: Check other PCI header registers suitable to be filled by device.
// Or should we pass whole vfu_pci_hdr_t to be filled by user.
+
+typedef enum {
+ VFU_PCI_TYPE_CONVENTIONAL,
+ VFU_PCI_TYPE_PCI_X_1,
+ VFU_PCI_TYPE_PCI_X_2,
+ VFU_PCI_TYPE_EXPRESS
+} vfu_pci_type_t;
+
/**
- * Setup PCI header data.
+ * Setup PCI configuration space header data. This function must be called only
+ * once per libvfio-user context.
+ *
* @vfu_ctx: the libvfio-user context
* @id: Device and vendor ID
* @ss: Subsystem vendor and device ID
* @cc: Class code
- * @extended: support extended PCI config space
+ * @pci_type: PCI type (convention PCI, PCI-X mode 1, PCI-X mode2, PCI-Express)
+ * @revision: PCI/PCI-X/PCIe revision
+ *
+ * @returns 0 on success, -1 on failure and sets errno.
*/
int
vfu_pci_setup_config_hdr(vfu_ctx_t *vfu_ctx, vfu_pci_hdr_id_t id,
vfu_pci_hdr_ss_t ss, vfu_pci_hdr_cc_t cc,
- bool extended);
+ vfu_pci_type_t pci_type,
+ int revision __attribute__((unused)));
//TODO: Support variable size capabilities.
/**
@@ -322,6 +343,13 @@ enum {
/**
* Set up a region.
+ *
+ * If this is the PCI configuration space, the @size argument is ignored. The
+ * size of the region is determined by the PCI type (set when the libvfio-user
+ * context is created). Accesses to the PCI configuration space header and the
+ * PCI capabilities are handled internally; the user supplied callback is not
+ * called.
+ *
* @vfu_ctx: the libvfio-user context
* @region_idx: region index
* @size: size of the region
@@ -330,6 +358,8 @@ enum {
* @mmap_areas: array of struct vfu_mmap_area
* @nr_mmap_areas: size of mmap_areas
* @map: callback function to map region
+ *
+ * @returns 0 on success, -1 on error, Sets errno.
*/
int
vfu_setup_region(vfu_ctx_t *vfu_ctx, int region_idx, size_t size,
diff --git a/include/pci.h b/include/pci.h
index 2bf82b1..9511ba9 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -42,13 +42,6 @@ extern "C" {
#endif
/*
- * These are already defined in include/uapi/linux/pci_regs.h, however that
- * file doesn't seem to installed.
- */
-#define PCI_CFG_SPACE_SIZE 256
-#define PCI_CFG_SPACE_EXP_SIZE 4096
-
-/*
* TODO lots of the sizes of each member are defined in pci_regs.h, use those
* instead?
*/
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c
index 964091c..70b019b 100644
--- a/lib/libvfio-user.c
+++ b/lib/libvfio-user.c
@@ -1277,8 +1277,15 @@ vfu_ctx_try_attach(vfu_ctx_t *vfu_ctx)
return vfu_ctx->trans->attach(vfu_ctx);
}
+bool
+is_valid_pci_type(vfu_pci_type_t t)
+{
+ return t >= VFU_PCI_TYPE_CONVENTIONAL && t <= VFU_PCI_TYPE_EXPRESS;
+}
+
vfu_ctx_t *
-vfu_create_ctx(vfu_trans_t trans, const char *path, int flags, void *pvt)
+vfu_create_ctx(vfu_trans_t trans, const char *path, int flags, void *pvt,
+ vfu_dev_type_t dev_type)
{
vfu_ctx_t *vfu_ctx = NULL;
int err = 0;
@@ -1288,10 +1295,16 @@ vfu_create_ctx(vfu_trans_t trans, const char *path, int flags, void *pvt)
return NULL;
}
+ if (dev_type != VFU_DEV_TYPE_PCI) {
+ errno = EINVAL;
+ return NULL;
+ }
+
vfu_ctx = calloc(1, sizeof(vfu_ctx_t));
if (vfu_ctx == NULL) {
return NULL;
}
+ vfu_ctx->dev_type = dev_type;
vfu_ctx->trans = &sock_transport_ops;
//FIXME: Validate arguments.
@@ -1356,21 +1369,39 @@ vfu_setup_log(vfu_ctx_t *vfu_ctx, vfu_log_fn_t *log, vfu_log_lvl_t log_lvl)
int
vfu_pci_setup_config_hdr(vfu_ctx_t *vfu_ctx, vfu_pci_hdr_id_t id,
vfu_pci_hdr_ss_t ss, vfu_pci_hdr_cc_t cc,
- UNUSED bool extended)
+ vfu_pci_type_t pci_type,
+ int revision __attribute__((unused)))
{
vfu_pci_config_space_t *config_space;
+ size_t size;
assert(vfu_ctx != NULL);
+ /*
+ * TODO there no real reason why we shouldn't allow this, we should just
+ * clean up and redo it.
+ */
if (vfu_ctx->pci_config_space != NULL) {
- vfu_log(vfu_ctx, VFU_ERR, "pci header already setup");
+ vfu_log(vfu_ctx, VFU_ERR, "PCI configuration space header already setup");
return ERROR(EEXIST);
}
- /* TODO: supported extended PCI config space. */
+ switch (vfu_ctx->pci_type) {
+ case VFU_PCI_TYPE_CONVENTIONAL:
+ case VFU_PCI_TYPE_PCI_X_1:
+ size = PCI_CFG_SPACE_SIZE;
+ break;
+ case VFU_PCI_TYPE_PCI_X_2:
+ case VFU_PCI_TYPE_EXPRESS:
+ size = PCI_CFG_SPACE_EXP_SIZE;
+ break;
+ default:
+ vfu_log(vfu_ctx, VFU_ERR, "invalid PCI type %d", pci_type);
+ return ERROR(EINVAL);
+ }
// Allocate a buffer for the config space.
- config_space = calloc(1, PCI_CFG_SPACE_SIZE);
+ config_space = calloc(1, size);
if (config_space == NULL) {
return ERROR(ENOMEM);
}
@@ -1379,6 +1410,7 @@ vfu_pci_setup_config_hdr(vfu_ctx_t *vfu_ctx, vfu_pci_hdr_id_t id,
config_space->hdr.ss = ss;
config_space->hdr.cc = cc;
vfu_ctx->pci_config_space = config_space;
+ vfu_ctx->reg_info[VFU_PCI_DEV_CFG_REGION_IDX].size = size;
return 0;
}
@@ -1435,13 +1467,6 @@ copy_sparse_mmap_areas(vfu_reg_info_t *reg_info,
return 0;
}
-static inline bool
-is_valid_pci_config_space_region(int flags, size_t size)
-{
- return flags == VFU_REG_FLAG_RW && (size == PCI_CFG_SPACE_SIZE
- || size == PCI_CFG_SPACE_EXP_SIZE);
-}
-
int
vfu_setup_region(vfu_ctx_t *vfu_ctx, int region_idx, size_t size,
vfu_region_access_cb_t *region_access, int flags,
@@ -1456,8 +1481,8 @@ vfu_setup_region(vfu_ctx_t *vfu_ctx, int region_idx, size_t size,
case VFU_PCI_DEV_BAR0_REGION_IDX ... VFU_PCI_DEV_VGA_REGION_IDX:
// Validate the config region provided.
if (region_idx == VFU_PCI_DEV_CFG_REGION_IDX &&
- !is_valid_pci_config_space_region(flags, size)) {
- return ERROR(EINVAL);
+ flags != VFU_REG_FLAG_RW) {
+ return ERROR(EINVAL);
}
vfu_ctx->reg_info[region_idx].flags = flags;
diff --git a/lib/private.h b/lib/private.h
index a2fb3a7..2f51594 100644
--- a/lib/private.h
+++ b/lib/private.h
@@ -129,6 +129,8 @@ struct vfu_ctx {
uint32_t irq_count[VFU_DEV_NUM_IRQS];
vfu_irqs_t *irqs;
int ready;
+ vfu_dev_type_t dev_type;
+ vfu_pci_type_t pci_type;
};
int
diff --git a/samples/gpio-pci-idio-16.c b/samples/gpio-pci-idio-16.c
index 17dfdaa..be8ecdb 100644
--- a/samples/gpio-pci-idio-16.c
+++ b/samples/gpio-pci-idio-16.c
@@ -99,7 +99,8 @@ main(int argc, char *argv[])
err(EXIT_FAILURE, "failed to register signal handler");
}
- vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, argv[optind], 0, NULL);
+ vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, argv[optind], 0, NULL,
+ VFU_DEV_TYPE_PCI);
if (vfu_ctx == NULL) {
if (errno == EINTR) {
printf("interrupted\n");
@@ -113,7 +114,8 @@ main(int argc, char *argv[])
err(EXIT_FAILURE, "failed to setup log");
}
- ret = vfu_pci_setup_config_hdr(vfu_ctx, id, ss, cc, false);
+ ret = vfu_pci_setup_config_hdr(vfu_ctx, id, ss, cc,
+ VFU_PCI_TYPE_CONVENTIONAL, 0);
if (ret < 0) {
fprintf(stderr, "failed to setup pci header\n");
goto out;
diff --git a/samples/null.c b/samples/null.c
index 99e35cc..adf3a46 100644
--- a/samples/null.c
+++ b/samples/null.c
@@ -71,12 +71,17 @@ int main(int argc, char **argv)
{
int ret;
pthread_t thread;
+ vfu_pci_hdr_id_t id = { 0 };
+ vfu_pci_hdr_ss_t ss = { 0 };
+ vfu_pci_hdr_cc_t cc = { { 0 } };
+
if (argc != 2) {
errx(EXIT_FAILURE, "missing vfio-user socket path");
}
- vfu_ctx_t *vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, argv[1], 0, NULL);
+ vfu_ctx_t *vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, argv[1], 0, NULL,
+ VFU_DEV_TYPE_PCI);
if (vfu_ctx == NULL) {
err(EXIT_FAILURE, "failed to create libvfio-user context");
}
@@ -86,6 +91,9 @@ int main(int argc, char **argv)
err(EXIT_FAILURE, "failed to setup log");
}
+ ret = vfu_pci_setup_config_hdr(vfu_ctx, id, ss, cc,
+ VFU_PCI_TYPE_CONVENTIONAL, 0);
+
ret = pthread_create(&thread, NULL, null_drive, vfu_ctx);
if (ret != 0) {
errno = ret;
diff --git a/samples/server.c b/samples/server.c
index 571e374..ccfad1c 100644
--- a/samples/server.c
+++ b/samples/server.c
@@ -411,7 +411,8 @@ int main(int argc, char *argv[])
}
server_data.vfu_ctx = vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, argv[optind],
- 0, &server_data);
+ 0, &server_data,
+ VFU_DEV_TYPE_PCI);
if (vfu_ctx == NULL) {
err(EXIT_FAILURE, "failed to initialize device emulation\n");
}
@@ -421,7 +422,8 @@ int main(int argc, char *argv[])
err(EXIT_FAILURE, "failed to setup log");
}
- ret = vfu_pci_setup_config_hdr(vfu_ctx, id, ss, cc, false);
+ ret = vfu_pci_setup_config_hdr(vfu_ctx, id, ss, cc,
+ VFU_PCI_TYPE_CONVENTIONAL, 0);
if (ret < 0) {
err(EXIT_FAILURE, "failed to setup PCI header");
}