diff options
author | Swapnil Ingle <swapnil.ingle@nutanix.com> | 2021-05-25 15:25:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-25 15:25:35 +0200 |
commit | 405f2ffc3125d44c7fde31fe2bb9b312746eb4e1 (patch) | |
tree | e2ab2e95b859e71010a574815ba0664a35b02789 | |
parent | f74a146a6b93f7bd366853739d8ec0dfc9c4a48f (diff) | |
download | libvfio-user-405f2ffc3125d44c7fde31fe2bb9b312746eb4e1.zip libvfio-user-405f2ffc3125d44c7fde31fe2bb9b312746eb4e1.tar.gz libvfio-user-405f2ffc3125d44c7fde31fe2bb9b312746eb4e1.tar.bz2 |
Handle support of PCI FLR capability (#517)
* Handle support of PCI FLR capability
If device supports FLR cap then call vfu_reset_cb_t when FLR is
initiated by client.
Signed-off-by: Swapnil Ingle <swapnil.ingle@nutanix.com>
Reviewed-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
-rw-r--r-- | include/libvfio-user.h | 8 | ||||
-rw-r--r-- | lib/pci_caps.c | 12 | ||||
-rw-r--r-- | test/py/libvfio_user.py | 12 | ||||
-rw-r--r-- | test/py/test_pci_caps.py | 32 |
4 files changed, 58 insertions, 6 deletions
diff --git a/include/libvfio-user.h b/include/libvfio-user.h index 6cb817d..009ba83 100644 --- a/include/libvfio-user.h +++ b/include/libvfio-user.h @@ -317,12 +317,18 @@ typedef enum vfu_reset_type { * reset to a known-good initial state (including any PCI register state). */ VFU_RESET_DEVICE, + /* * The vfio-user socket client connection was closed or reset. The attached * context is cleaned up after returning from the reset callback, and * vfu_attach_ctx() must be called to establish a new client. */ - VFU_RESET_LOST_CONN + VFU_RESET_LOST_CONN, + + /* + * Client requested to initiate PCI function level reset. + */ + VFU_RESET_PCI_FLR } vfu_reset_type_t; /* diff --git a/lib/pci_caps.c b/lib/pci_caps.c index 550d373..b00b9b8 100644 --- a/lib/pci_caps.c +++ b/lib/pci_caps.c @@ -277,8 +277,16 @@ handle_px_pxdc_write(vfu_ctx_t *vfu_ctx, struct pxcap *px, } if (p->iflr) { - vfu_log(vfu_ctx, LOG_DEBUG, - "initiate function level reset"); + if (px->pxdcap.flrc == 0) { + vfu_log(vfu_ctx, LOG_ERR, "FLR capability is not supported"); + return ERROR_INT(EINVAL); + } + if (vfu_ctx->reset != NULL) { + vfu_log(vfu_ctx, LOG_DEBUG, "initiate function level reset"); + return vfu_ctx->reset(vfu_ctx, VFU_RESET_PCI_FLR); + } else { + vfu_log(vfu_ctx, LOG_ERR, "FLR callback is not implemented"); + } } return 0; diff --git a/test/py/libvfio_user.py b/test/py/libvfio_user.py index 930c88a..d53740a 100644 --- a/test/py/libvfio_user.py +++ b/test/py/libvfio_user.py @@ -58,6 +58,7 @@ PCI_CAP_LIST_NEXT = 1 PCI_CAP_ID_PM = 0x1 PCI_CAP_ID_VNDR = 0x9 +PCI_CAP_ID_EXP = 0x10 PCI_EXT_CAP_ID_DSN = 0x03 PCI_EXT_CAP_ID_VNDR = 0x0b @@ -151,6 +152,11 @@ VFU_DEV_ERR_IRQ = 3 VFU_DEV_REQ_IRQ = 4 VFU_DEV_NUM_IRQS = 5 +# enum vfu_reset_type +VFU_RESET_DEVICE = 0 +VFU_RESET_LOST_CONN = 1 +VFU_RESET_PCI_FLR = 2 + # vfu_pci_type_t VFU_PCI_TYPE_CONVENTIONAL = 0 VFU_PCI_TYPE_PCI_X_1 = 1 @@ -234,6 +240,8 @@ vfu_region_access_cb_t = c.CFUNCTYPE(c.c_int, c.c_void_p, c.POINTER(c.c_char), lib.vfu_setup_region.argtypes = (c.c_void_p, c.c_int, c.c_ulong, vfu_region_access_cb_t, c.c_int, c.c_void_p, c.c_uint32, c.c_int, c.c_ulong) +vfu_reset_cb_t = c.CFUNCTYPE(c.c_int, c.c_void_p, c.c_int) +lib.vfu_setup_device_reset_cb.argtypes = (c.c_void_p, vfu_reset_cb_t) lib.vfu_pci_get_config_space.argtypes = (c.c_void_p,) lib.vfu_pci_get_config_space.restype = (c.c_void_p) lib.vfu_setup_device_nr_irqs.argtypes = (c.c_void_p, c.c_int, c.c_uint32) @@ -457,6 +465,10 @@ def vfu_setup_region(ctx, index, size, cb=None, flags=0, return ret +def vfu_setup_device_reset_cb(ctx, cb): + assert ctx != None + return lib.vfu_setup_device_reset_cb(ctx, c.cast(cb, vfu_reset_cb_t)) + def vfu_setup_device_nr_irqs(ctx, irqtype, count): assert ctx != None return lib.vfu_setup_device_nr_irqs(ctx, irqtype, count) diff --git a/test/py/test_pci_caps.py b/test/py/test_pci_caps.py index 9691fe1..d510727 100644 --- a/test/py/test_pci_caps.py +++ b/test/py/test_pci_caps.py @@ -100,7 +100,8 @@ cap_offsets = ( # NB: note 4-byte alignment of vsc2 PCI_STD_HEADER_SIZEOF + PCI_PM_SIZEOF + 8, 0x80, - 0x90 + 0x90, + 0xa0 ) def test_add_caps(): @@ -293,9 +294,34 @@ def test_pci_cap_write_pmcs(): disconnect_client(ctx, sock) +reset_flag = -1 +@c.CFUNCTYPE(c.c_int, c.c_void_p, c.c_int) +def vfu_reset_cb(ctx, reset_type): + assert reset_type == VFU_RESET_PCI_FLR or reset_type == VFU_RESET_LOST_CONN + global reset_flag + reset_flag = reset_type + return 0 + def test_pci_cap_write_px(): - # FIXME - pass + sock = connect_client(ctx) + ret = vfu_setup_device_reset_cb(ctx, vfu_reset_cb) + assert ret == 0 + + #flrc + cap = struct.pack("ccHHcc52c", to_byte(PCI_CAP_ID_EXP), b'\0', 0, 0, b'\0', + b'\x02', *[b'\0' for _ in range(52)]) + pos = vfu_pci_add_capability(ctx, pos=cap_offsets[5], flags=0, data=cap) + assert pos == cap_offsets[5] + + #iflr + offset = cap_offsets[5] + 8 + data = b'\x00\x80' + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, + count=len(data), data=data) + assert reset_flag == VFU_RESET_PCI_FLR + + disconnect_client(ctx, sock) + assert reset_flag == VFU_RESET_LOST_CONN def test_pci_cap_write_msix(): # FIXME |