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