diff options
author | John Levon <john.levon@nutanix.com> | 2021-01-05 15:18:42 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-05 15:18:42 +0000 |
commit | 70524c550322948765415d9b0eb29ac766e32e79 (patch) | |
tree | 02ad60182191238de12f7df4121f137018a29840 /lib | |
parent | 1fa90d5abecd896362e551b2bd2ec987d8f60a6b (diff) | |
download | libvfio-user-70524c550322948765415d9b0eb29ac766e32e79.zip libvfio-user-70524c550322948765415d9b0eb29ac766e32e79.tar.gz libvfio-user-70524c550322948765415d9b0eb29ac766e32e79.tar.bz2 |
re-work capability-locating API (#199)
Explicitly mimic the Linux kernel API: the searching functions return an offset
into configuration space. Just like a driver, libvfio-user devices can then
look into config space via vfu_pci_get_config_space() to read the capability as
needed. In general, the driver itself will know exactly what the size and shape
of the capability is, so this seems like a low-friction, and familiar to driver
writers, API.
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/cap.c | 112 | ||||
-rw-r--r-- | lib/cap.h | 3 | ||||
-rw-r--r-- | lib/libvfio-user.c | 8 |
3 files changed, 69 insertions, 54 deletions
@@ -37,8 +37,10 @@ #include <stddef.h> #include <string.h> -#include "libvfio-user.h" #include "cap.h" +#include "common.h" +#include "libvfio-user.h" +#include "private.h" #define VFU_MAX_CAPS \ ((PCI_CFG_SPACE_SIZE - PCI_STD_HEADER_SIZEOF) / PCI_CAP_SIZEOF) @@ -132,48 +134,6 @@ cap_find(vfu_pci_config_space_t *config_space, struct caps *caps, loff_t offset, return NULL; } -static bool -cap_is_valid(uint8_t id) -{ - /* TODO 0 is a valid capability ID (Null Capability), check - * https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf: - * - */ - return id >= PCI_CAP_ID_PM && id <= PCI_CAP_ID_MAX; -} - -uint8_t * -cap_find_by_id(vfu_ctx_t *vfu_ctx, uint8_t id) -{ - uint8_t *pos; - vfu_pci_config_space_t *config_space; - - if (!cap_is_valid(id)) { - errno = EINVAL; - return NULL; - } - - config_space = vfu_pci_get_config_space(vfu_ctx); - - if (config_space->hdr.cap == 0) { - errno = ENOENT; - return NULL; - } - - pos = config_space->raw + config_space->hdr.cap; - while (true) { - if (*(pos + PCI_CAP_LIST_ID) == id) { - return pos; - } - if (*(pos + PCI_CAP_LIST_NEXT) == 0) { - break; - } - pos = config_space->raw + *(pos + PCI_CAP_LIST_NEXT); - } - errno = ENOENT; - return NULL; -} - /* * Tells whether the header of a PCI capability is accessed. */ @@ -430,6 +390,16 @@ cap_maybe_access(vfu_ctx_t *vfu_ctx, struct caps *caps, char *buf, size_t count, offset - (loff_t)(cap - config_space->raw)); } +static bool +cap_is_valid(uint8_t id) +{ + /* TODO 0 is a valid capability ID (Null Capability), check + * https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf: + * + */ + return id >= PCI_CAP_ID_PM && id <= PCI_CAP_ID_MAX; +} + struct caps * caps_create(vfu_ctx_t *vfu_ctx, vfu_cap_t **vfu_caps, int nr_caps, int *err) { @@ -502,4 +472,60 @@ err_out: return NULL; } +size_t +vfu_pci_find_next_capability(vfu_ctx_t *vfu_ctx, bool extended, + size_t offset, int cap_id) +{ + size_t space_size = vfu_ctx->reg_info[VFU_PCI_DEV_CFG_REGION_IDX].size; + vfu_pci_config_space_t *config_space; + + if (extended) { + errno = ENOTSUP; + return 0; + } + + if (offset + PCI_CAP_LIST_NEXT >= space_size) { + errno = EINVAL; + return 0; + } + + config_space = vfu_pci_get_config_space(vfu_ctx); + + if (offset == 0) { + offset = config_space->hdr.cap; + } else { + offset = config_space->raw[offset + PCI_CAP_LIST_NEXT]; + } + + if (offset == 0) { + errno = ENOENT; + return 0; + } + + for (;;) { + /* Sanity check. */ + if (offset + PCI_CAP_LIST_NEXT >= space_size) { + errno = EINVAL; + return 0; + } + + if (config_space->raw[offset + PCI_CAP_LIST_ID] == cap_id) { + return offset; + } + + offset = config_space->raw[offset + PCI_CAP_LIST_NEXT]; + + if (offset == 0) { + errno = ENOENT; + return 0; + } + } +} + +size_t +vfu_pci_find_capability(vfu_ctx_t *vfu_ctx, bool extended, int cap_id) +{ + return vfu_pci_find_next_capability(vfu_ctx, extended, 0, cap_id); +} + /* ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */ @@ -54,9 +54,6 @@ ssize_t cap_maybe_access(vfu_ctx_t *vfu_ctx, struct caps *caps, char *buf, size_t count, loff_t offset); -uint8_t * -cap_find_by_id(vfu_ctx_t *vfu_ctx, uint8_t id); - #endif /* LIB_VFIO_USER_CAP_H */ /* ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 6d75e15..4e9f58c 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -1530,14 +1530,6 @@ vfu_unmap_sg(vfu_ctx_t *vfu_ctx, const dma_sg_t *sg, struct iovec *iov, int cnt) return dma_unmap_sg(vfu_ctx->dma, sg, iov, cnt); } -uint8_t * -vfu_ctx_get_cap(vfu_ctx_t *vfu_ctx, uint8_t id) -{ - assert(vfu_ctx != NULL); - - return cap_find_by_id(vfu_ctx, id); -} - int vfu_dma_read(vfu_ctx_t *vfu_ctx, dma_sg_t *sg, void *data) { |