1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023-2024 Intel Corporation 4 */ 5 6 #include "xe_assert.h" 7 #include "xe_device.h" 8 #include "xe_gt_sriov_pf_config.h" 9 #include "xe_pci_sriov.h" 10 #include "xe_pm.h" 11 #include "xe_sriov.h" 12 #include "xe_sriov_pf_helpers.h" 13 #include "xe_sriov_printk.h" 14 15 static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs) 16 { 17 struct xe_gt *gt; 18 unsigned int id; 19 int result = 0, err; 20 21 for_each_gt(gt, xe, id) { 22 err = xe_gt_sriov_pf_config_set_fair(gt, VFID(1), num_vfs); 23 result = result ?: err; 24 } 25 26 return result; 27 } 28 29 static void pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs) 30 { 31 struct xe_gt *gt; 32 unsigned int id; 33 unsigned int n; 34 35 for_each_gt(gt, xe, id) 36 for (n = 1; n <= num_vfs; n++) 37 xe_gt_sriov_pf_config_release(gt, n, true); 38 } 39 40 static int pf_enable_vfs(struct xe_device *xe, int num_vfs) 41 { 42 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 43 int total_vfs = xe_sriov_pf_get_totalvfs(xe); 44 int err; 45 46 xe_assert(xe, IS_SRIOV_PF(xe)); 47 xe_assert(xe, num_vfs > 0); 48 xe_assert(xe, num_vfs <= total_vfs); 49 xe_sriov_dbg(xe, "enabling %u VF%s\n", num_vfs, str_plural(num_vfs)); 50 51 /* 52 * We must hold additional reference to the runtime PM to keep PF in D0 53 * during VFs lifetime, as our VFs do not implement the PM capability. 54 * 55 * With PF being in D0 state, all VFs will also behave as in D0 state. 56 * This will also keep GuC alive with all VFs' configurations. 57 * 58 * We will release this additional PM reference in pf_disable_vfs(). 59 */ 60 xe_pm_runtime_get_noresume(xe); 61 62 err = pf_provision_vfs(xe, num_vfs); 63 if (err < 0) 64 goto failed; 65 66 err = pci_enable_sriov(pdev, num_vfs); 67 if (err < 0) 68 goto failed; 69 70 xe_sriov_info(xe, "Enabled %u of %u VF%s\n", 71 num_vfs, total_vfs, str_plural(total_vfs)); 72 return num_vfs; 73 74 failed: 75 pf_unprovision_vfs(xe, num_vfs); 76 xe_pm_runtime_put(xe); 77 78 xe_sriov_notice(xe, "Failed to enable %u VF%s (%pe)\n", 79 num_vfs, str_plural(num_vfs), ERR_PTR(err)); 80 return err; 81 } 82 83 static int pf_disable_vfs(struct xe_device *xe) 84 { 85 struct device *dev = xe->drm.dev; 86 struct pci_dev *pdev = to_pci_dev(dev); 87 u16 num_vfs = pci_num_vf(pdev); 88 89 xe_assert(xe, IS_SRIOV_PF(xe)); 90 xe_sriov_dbg(xe, "disabling %u VF%s\n", num_vfs, str_plural(num_vfs)); 91 92 if (!num_vfs) 93 return 0; 94 95 pci_disable_sriov(pdev); 96 97 pf_unprovision_vfs(xe, num_vfs); 98 99 /* not needed anymore - see pf_enable_vfs() */ 100 xe_pm_runtime_put(xe); 101 102 xe_sriov_info(xe, "Disabled %u VF%s\n", num_vfs, str_plural(num_vfs)); 103 return 0; 104 } 105 106 /** 107 * xe_pci_sriov_configure - Configure SR-IOV (enable/disable VFs). 108 * @pdev: the &pci_dev 109 * @num_vfs: number of VFs to enable or zero to disable all VFs 110 * 111 * This is the Xe implementation of struct pci_driver.sriov_configure callback. 112 * 113 * This callback will be called by the PCI subsystem to enable or disable SR-IOV 114 * Virtual Functions (VFs) as requested by the used via the PCI sysfs interface. 115 * 116 * Return: number of configured VFs or a negative error code on failure. 117 */ 118 int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) 119 { 120 struct xe_device *xe = pdev_to_xe_device(pdev); 121 int ret; 122 123 if (!IS_SRIOV_PF(xe)) 124 return -ENODEV; 125 126 if (num_vfs < 0) 127 return -EINVAL; 128 129 if (num_vfs > xe_sriov_pf_get_totalvfs(xe)) 130 return -ERANGE; 131 132 if (num_vfs && pci_num_vf(pdev)) 133 return -EBUSY; 134 135 xe_pm_runtime_get(xe); 136 if (num_vfs > 0) 137 ret = pf_enable_vfs(xe, num_vfs); 138 else 139 ret = pf_disable_vfs(xe); 140 xe_pm_runtime_put(xe); 141 142 return ret; 143 } 144