aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJohn Levon <john.levon@nutanix.com>2021-01-05 15:18:42 +0000
committerGitHub <noreply@github.com>2021-01-05 15:18:42 +0000
commit70524c550322948765415d9b0eb29ac766e32e79 (patch)
tree02ad60182191238de12f7df4121f137018a29840 /lib
parent1fa90d5abecd896362e551b2bd2ec987d8f60a6b (diff)
downloadlibvfio-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.c112
-rw-r--r--lib/cap.h3
-rw-r--r--lib/libvfio-user.c8
3 files changed, 69 insertions, 54 deletions
diff --git a/lib/cap.c b/lib/cap.c
index d58d7f1..f427d1a 100644
--- a/lib/cap.c
+++ b/lib/cap.c
@@ -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: */
diff --git a/lib/cap.h b/lib/cap.h
index 37c31d8..acd63e2 100644
--- a/lib/cap.h
+++ b/lib/cap.h
@@ -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)
{