diff options
-rw-r--r-- | include/libvfio-user.h | 38 | ||||
-rw-r--r-- | include/pci.h | 7 | ||||
-rw-r--r-- | lib/libvfio-user.c | 53 | ||||
-rw-r--r-- | lib/private.h | 2 | ||||
-rw-r--r-- | samples/gpio-pci-idio-16.c | 6 | ||||
-rw-r--r-- | samples/null.c | 10 | ||||
-rw-r--r-- | samples/server.c | 6 |
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"); } |