1*a6e4e726SRaghavendra Rao Ananta // SPDX-License-Identifier: GPL-2.0-only 2*a6e4e726SRaghavendra Rao Ananta #include "lib/include/libvfio/assert.h" 3*a6e4e726SRaghavendra Rao Ananta #include <fcntl.h> 4*a6e4e726SRaghavendra Rao Ananta #include <unistd.h> 5*a6e4e726SRaghavendra Rao Ananta #include <stdlib.h> 6*a6e4e726SRaghavendra Rao Ananta #include <sys/ioctl.h> 7*a6e4e726SRaghavendra Rao Ananta #include <linux/limits.h> 8*a6e4e726SRaghavendra Rao Ananta 9*a6e4e726SRaghavendra Rao Ananta #include <libvfio.h> 10*a6e4e726SRaghavendra Rao Ananta 11*a6e4e726SRaghavendra Rao Ananta #include "../kselftest_harness.h" 12*a6e4e726SRaghavendra Rao Ananta 13*a6e4e726SRaghavendra Rao Ananta #define UUID_1 "52ac9bff-3a88-4fbd-901a-0d767c3b6c97" 14*a6e4e726SRaghavendra Rao Ananta #define UUID_2 "88594674-90a0-47a9-aea8-9d9b352ac08a" 15*a6e4e726SRaghavendra Rao Ananta 16*a6e4e726SRaghavendra Rao Ananta static const char *pf_bdf; 17*a6e4e726SRaghavendra Rao Ananta static char *vf_bdf; 18*a6e4e726SRaghavendra Rao Ananta 19*a6e4e726SRaghavendra Rao Ananta static pid_t main_pid; 20*a6e4e726SRaghavendra Rao Ananta 21*a6e4e726SRaghavendra Rao Ananta static int container_setup(struct vfio_pci_device *device, const char *bdf, 22*a6e4e726SRaghavendra Rao Ananta const char *vf_token) 23*a6e4e726SRaghavendra Rao Ananta { 24*a6e4e726SRaghavendra Rao Ananta vfio_pci_group_setup(device, bdf); 25*a6e4e726SRaghavendra Rao Ananta vfio_container_set_iommu(device); 26*a6e4e726SRaghavendra Rao Ananta __vfio_pci_group_get_device_fd(device, bdf, vf_token); 27*a6e4e726SRaghavendra Rao Ananta 28*a6e4e726SRaghavendra Rao Ananta /* The device fd will be -1 in case of mismatched tokens */ 29*a6e4e726SRaghavendra Rao Ananta return (device->fd < 0); 30*a6e4e726SRaghavendra Rao Ananta } 31*a6e4e726SRaghavendra Rao Ananta 32*a6e4e726SRaghavendra Rao Ananta static int iommufd_setup(struct vfio_pci_device *device, const char *bdf, 33*a6e4e726SRaghavendra Rao Ananta const char *vf_token) 34*a6e4e726SRaghavendra Rao Ananta { 35*a6e4e726SRaghavendra Rao Ananta vfio_pci_cdev_open(device, bdf); 36*a6e4e726SRaghavendra Rao Ananta return __vfio_device_bind_iommufd(device->fd, 37*a6e4e726SRaghavendra Rao Ananta device->iommu->iommufd, vf_token); 38*a6e4e726SRaghavendra Rao Ananta } 39*a6e4e726SRaghavendra Rao Ananta 40*a6e4e726SRaghavendra Rao Ananta static int device_init(const char *bdf, struct iommu *iommu, 41*a6e4e726SRaghavendra Rao Ananta const char *vf_token, struct vfio_pci_device **out_dev) 42*a6e4e726SRaghavendra Rao Ananta { 43*a6e4e726SRaghavendra Rao Ananta struct vfio_pci_device *device = vfio_pci_device_alloc(bdf, iommu); 44*a6e4e726SRaghavendra Rao Ananta int ret; 45*a6e4e726SRaghavendra Rao Ananta 46*a6e4e726SRaghavendra Rao Ananta if (iommu->mode->container_path) 47*a6e4e726SRaghavendra Rao Ananta ret = container_setup(device, bdf, vf_token); 48*a6e4e726SRaghavendra Rao Ananta else 49*a6e4e726SRaghavendra Rao Ananta ret = iommufd_setup(device, bdf, vf_token); 50*a6e4e726SRaghavendra Rao Ananta 51*a6e4e726SRaghavendra Rao Ananta *out_dev = device; 52*a6e4e726SRaghavendra Rao Ananta return ret; 53*a6e4e726SRaghavendra Rao Ananta } 54*a6e4e726SRaghavendra Rao Ananta 55*a6e4e726SRaghavendra Rao Ananta static void device_cleanup(struct vfio_pci_device *device) 56*a6e4e726SRaghavendra Rao Ananta { 57*a6e4e726SRaghavendra Rao Ananta if (!device) 58*a6e4e726SRaghavendra Rao Ananta return; 59*a6e4e726SRaghavendra Rao Ananta 60*a6e4e726SRaghavendra Rao Ananta if (device->fd > 0) 61*a6e4e726SRaghavendra Rao Ananta VFIO_ASSERT_EQ(close(device->fd), 0); 62*a6e4e726SRaghavendra Rao Ananta 63*a6e4e726SRaghavendra Rao Ananta if (device->group_fd) 64*a6e4e726SRaghavendra Rao Ananta VFIO_ASSERT_EQ(close(device->group_fd), 0); 65*a6e4e726SRaghavendra Rao Ananta 66*a6e4e726SRaghavendra Rao Ananta vfio_pci_device_free(device); 67*a6e4e726SRaghavendra Rao Ananta } 68*a6e4e726SRaghavendra Rao Ananta 69*a6e4e726SRaghavendra Rao Ananta FIXTURE(vfio_pci_sriov_uapi_test) { 70*a6e4e726SRaghavendra Rao Ananta struct vfio_pci_device *pf; 71*a6e4e726SRaghavendra Rao Ananta struct vfio_pci_device *vf; 72*a6e4e726SRaghavendra Rao Ananta struct iommu *iommu; 73*a6e4e726SRaghavendra Rao Ananta char *pf_token; 74*a6e4e726SRaghavendra Rao Ananta }; 75*a6e4e726SRaghavendra Rao Ananta 76*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT(vfio_pci_sriov_uapi_test) { 77*a6e4e726SRaghavendra Rao Ananta const char *iommu_mode; 78*a6e4e726SRaghavendra Rao Ananta char *vf_token; 79*a6e4e726SRaghavendra Rao Ananta }; 80*a6e4e726SRaghavendra Rao Ananta 81*a6e4e726SRaghavendra Rao Ananta #define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _vf_token) \ 82*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD(vfio_pci_sriov_uapi_test, _iommu_mode ## _ ## _name) { \ 83*a6e4e726SRaghavendra Rao Ananta .iommu_mode = #_iommu_mode, \ 84*a6e4e726SRaghavendra Rao Ananta .vf_token = (_vf_token), \ 85*a6e4e726SRaghavendra Rao Ananta } 86*a6e4e726SRaghavendra Rao Ananta 87*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(same_uuid, UUID_1); 88*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(diff_uuid, UUID_2); 89*a6e4e726SRaghavendra Rao Ananta FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(null_uuid, NULL); 90*a6e4e726SRaghavendra Rao Ananta 91*a6e4e726SRaghavendra Rao Ananta FIXTURE_SETUP(vfio_pci_sriov_uapi_test) 92*a6e4e726SRaghavendra Rao Ananta { 93*a6e4e726SRaghavendra Rao Ananta self->iommu = iommu_init(variant->iommu_mode); 94*a6e4e726SRaghavendra Rao Ananta 95*a6e4e726SRaghavendra Rao Ananta self->pf_token = UUID_1; 96*a6e4e726SRaghavendra Rao Ananta ASSERT_EQ(device_init(pf_bdf, self->iommu, self->pf_token, &self->pf), 0); 97*a6e4e726SRaghavendra Rao Ananta } 98*a6e4e726SRaghavendra Rao Ananta 99*a6e4e726SRaghavendra Rao Ananta FIXTURE_TEARDOWN(vfio_pci_sriov_uapi_test) 100*a6e4e726SRaghavendra Rao Ananta { 101*a6e4e726SRaghavendra Rao Ananta device_cleanup(self->vf); 102*a6e4e726SRaghavendra Rao Ananta device_cleanup(self->pf); 103*a6e4e726SRaghavendra Rao Ananta iommu_cleanup(self->iommu); 104*a6e4e726SRaghavendra Rao Ananta } 105*a6e4e726SRaghavendra Rao Ananta 106*a6e4e726SRaghavendra Rao Ananta /* 107*a6e4e726SRaghavendra Rao Ananta * This asserts if the VF device is successfully created if its token matches 108*a6e4e726SRaghavendra Rao Ananta * with the token used to create/override the PF or fails during a mismatch. 109*a6e4e726SRaghavendra Rao Ananta */ 110*a6e4e726SRaghavendra Rao Ananta #define ASSERT_COND_VF_CREATION(_ret) do { \ 111*a6e4e726SRaghavendra Rao Ananta if (!variant->vf_token || strcmp(self->pf_token, variant->vf_token)) { \ 112*a6e4e726SRaghavendra Rao Ananta ASSERT_NE((_ret), 0); \ 113*a6e4e726SRaghavendra Rao Ananta } else { \ 114*a6e4e726SRaghavendra Rao Ananta ASSERT_EQ((_ret), 0); \ 115*a6e4e726SRaghavendra Rao Ananta } \ 116*a6e4e726SRaghavendra Rao Ananta } while (0) 117*a6e4e726SRaghavendra Rao Ananta 118*a6e4e726SRaghavendra Rao Ananta /* 119*a6e4e726SRaghavendra Rao Ananta * Validate if the UAPI handles correctly and incorrectly set token on the VF. 120*a6e4e726SRaghavendra Rao Ananta */ 121*a6e4e726SRaghavendra Rao Ananta TEST_F(vfio_pci_sriov_uapi_test, init_token_match) 122*a6e4e726SRaghavendra Rao Ananta { 123*a6e4e726SRaghavendra Rao Ananta int ret; 124*a6e4e726SRaghavendra Rao Ananta 125*a6e4e726SRaghavendra Rao Ananta ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf); 126*a6e4e726SRaghavendra Rao Ananta ASSERT_COND_VF_CREATION(ret); 127*a6e4e726SRaghavendra Rao Ananta } 128*a6e4e726SRaghavendra Rao Ananta 129*a6e4e726SRaghavendra Rao Ananta /* 130*a6e4e726SRaghavendra Rao Ananta * After closing the PF, validate if the VF access still needs the right token. 131*a6e4e726SRaghavendra Rao Ananta */ 132*a6e4e726SRaghavendra Rao Ananta TEST_F(vfio_pci_sriov_uapi_test, pf_early_close) 133*a6e4e726SRaghavendra Rao Ananta { 134*a6e4e726SRaghavendra Rao Ananta int ret; 135*a6e4e726SRaghavendra Rao Ananta 136*a6e4e726SRaghavendra Rao Ananta device_cleanup(self->pf); 137*a6e4e726SRaghavendra Rao Ananta 138*a6e4e726SRaghavendra Rao Ananta /* Clean the 'pf' to avoid calling device_cleanup() again. */ 139*a6e4e726SRaghavendra Rao Ananta self->pf = NULL; 140*a6e4e726SRaghavendra Rao Ananta 141*a6e4e726SRaghavendra Rao Ananta ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf); 142*a6e4e726SRaghavendra Rao Ananta ASSERT_COND_VF_CREATION(ret); 143*a6e4e726SRaghavendra Rao Ananta } 144*a6e4e726SRaghavendra Rao Ananta 145*a6e4e726SRaghavendra Rao Ananta /* 146*a6e4e726SRaghavendra Rao Ananta * After PF device init, override the existing token and validate if the newly 147*a6e4e726SRaghavendra Rao Ananta * set token is the one that's active. 148*a6e4e726SRaghavendra Rao Ananta */ 149*a6e4e726SRaghavendra Rao Ananta TEST_F(vfio_pci_sriov_uapi_test, override_token) 150*a6e4e726SRaghavendra Rao Ananta { 151*a6e4e726SRaghavendra Rao Ananta int ret; 152*a6e4e726SRaghavendra Rao Ananta 153*a6e4e726SRaghavendra Rao Ananta self->pf_token = UUID_2; 154*a6e4e726SRaghavendra Rao Ananta vfio_device_set_vf_token(self->pf->fd, self->pf_token); 155*a6e4e726SRaghavendra Rao Ananta 156*a6e4e726SRaghavendra Rao Ananta ret = device_init(vf_bdf, self->iommu, variant->vf_token, &self->vf); 157*a6e4e726SRaghavendra Rao Ananta ASSERT_COND_VF_CREATION(ret); 158*a6e4e726SRaghavendra Rao Ananta } 159*a6e4e726SRaghavendra Rao Ananta 160*a6e4e726SRaghavendra Rao Ananta static void vf_teardown(void) 161*a6e4e726SRaghavendra Rao Ananta { 162*a6e4e726SRaghavendra Rao Ananta /* 163*a6e4e726SRaghavendra Rao Ananta * The child processes, created by TEST_F()s, inherits this atexit() 164*a6e4e726SRaghavendra Rao Ananta * handler. Hence, check and destroy the VF only when the main/parent 165*a6e4e726SRaghavendra Rao Ananta * process exits. 166*a6e4e726SRaghavendra Rao Ananta */ 167*a6e4e726SRaghavendra Rao Ananta if (getpid() != main_pid) 168*a6e4e726SRaghavendra Rao Ananta return; 169*a6e4e726SRaghavendra Rao Ananta 170*a6e4e726SRaghavendra Rao Ananta free(vf_bdf); 171*a6e4e726SRaghavendra Rao Ananta sysfs_sriov_numvfs_set(pf_bdf, 0); 172*a6e4e726SRaghavendra Rao Ananta } 173*a6e4e726SRaghavendra Rao Ananta 174*a6e4e726SRaghavendra Rao Ananta static void vf_setup(void) 175*a6e4e726SRaghavendra Rao Ananta { 176*a6e4e726SRaghavendra Rao Ananta char *vf_driver; 177*a6e4e726SRaghavendra Rao Ananta int nr_vfs; 178*a6e4e726SRaghavendra Rao Ananta 179*a6e4e726SRaghavendra Rao Ananta nr_vfs = sysfs_sriov_totalvfs_get(pf_bdf); 180*a6e4e726SRaghavendra Rao Ananta if (nr_vfs <= 0) 181*a6e4e726SRaghavendra Rao Ananta ksft_exit_skip("SR-IOV may not be supported by the PF: %s\n", pf_bdf); 182*a6e4e726SRaghavendra Rao Ananta 183*a6e4e726SRaghavendra Rao Ananta nr_vfs = sysfs_sriov_numvfs_get(pf_bdf); 184*a6e4e726SRaghavendra Rao Ananta if (nr_vfs != 0) 185*a6e4e726SRaghavendra Rao Ananta ksft_exit_skip("SR-IOV already configured for the PF: %s\n", pf_bdf); 186*a6e4e726SRaghavendra Rao Ananta 187*a6e4e726SRaghavendra Rao Ananta /* Create only one VF for testing */ 188*a6e4e726SRaghavendra Rao Ananta sysfs_sriov_numvfs_set(pf_bdf, 1); 189*a6e4e726SRaghavendra Rao Ananta 190*a6e4e726SRaghavendra Rao Ananta /* 191*a6e4e726SRaghavendra Rao Ananta * Setup an exit handler to destroy the VF in case of failures 192*a6e4e726SRaghavendra Rao Ananta * during further setup at the end of the test run. 193*a6e4e726SRaghavendra Rao Ananta */ 194*a6e4e726SRaghavendra Rao Ananta main_pid = getpid(); 195*a6e4e726SRaghavendra Rao Ananta VFIO_ASSERT_EQ(atexit(vf_teardown), 0); 196*a6e4e726SRaghavendra Rao Ananta 197*a6e4e726SRaghavendra Rao Ananta vf_bdf = sysfs_sriov_vf_bdf_get(pf_bdf, 0); 198*a6e4e726SRaghavendra Rao Ananta 199*a6e4e726SRaghavendra Rao Ananta /* 200*a6e4e726SRaghavendra Rao Ananta * The VF inherits the driver from the PF. 201*a6e4e726SRaghavendra Rao Ananta * Ensure this is 'vfio-pci' before proceeding. 202*a6e4e726SRaghavendra Rao Ananta */ 203*a6e4e726SRaghavendra Rao Ananta vf_driver = sysfs_driver_get(vf_bdf); 204*a6e4e726SRaghavendra Rao Ananta VFIO_ASSERT_NE(vf_driver, NULL); 205*a6e4e726SRaghavendra Rao Ananta VFIO_ASSERT_EQ(strcmp(vf_driver, "vfio-pci"), 0); 206*a6e4e726SRaghavendra Rao Ananta free(vf_driver); 207*a6e4e726SRaghavendra Rao Ananta 208*a6e4e726SRaghavendra Rao Ananta printf("Created 1 VF (%s) under the PF: %s\n", vf_bdf, pf_bdf); 209*a6e4e726SRaghavendra Rao Ananta } 210*a6e4e726SRaghavendra Rao Ananta 211*a6e4e726SRaghavendra Rao Ananta int main(int argc, char *argv[]) 212*a6e4e726SRaghavendra Rao Ananta { 213*a6e4e726SRaghavendra Rao Ananta pf_bdf = vfio_selftests_get_bdf(&argc, argv); 214*a6e4e726SRaghavendra Rao Ananta vf_setup(); 215*a6e4e726SRaghavendra Rao Ananta 216*a6e4e726SRaghavendra Rao Ananta return test_harness_run(argc, argv); 217*a6e4e726SRaghavendra Rao Ananta } 218