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_gt_sriov_printk.h" 11 #include "xe_guc_engine_activity.h" 12 #include "xe_pci_sriov.h" 13 #include "xe_pm.h" 14 #include "xe_sriov.h" 15 #include "xe_sriov_pf_helpers.h" 16 #include "xe_sriov_printk.h" 17 18 static int pf_needs_provisioning(struct xe_gt *gt, unsigned int num_vfs) 19 { 20 unsigned int n; 21 22 for (n = 1; n <= num_vfs; n++) 23 if (!xe_gt_sriov_pf_config_is_empty(gt, n)) 24 return false; 25 26 return true; 27 } 28 29 static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs) 30 { 31 struct xe_gt *gt; 32 unsigned int id; 33 int result = 0, err; 34 35 for_each_gt(gt, xe, id) { 36 if (!pf_needs_provisioning(gt, num_vfs)) 37 continue; 38 err = xe_gt_sriov_pf_config_set_fair(gt, VFID(1), num_vfs); 39 result = result ?: err; 40 } 41 42 return result; 43 } 44 45 static void pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs) 46 { 47 struct xe_gt *gt; 48 unsigned int id; 49 unsigned int n; 50 51 for_each_gt(gt, xe, id) 52 for (n = 1; n <= num_vfs; n++) 53 xe_gt_sriov_pf_config_release(gt, n, true); 54 } 55 56 static void pf_reset_vfs(struct xe_device *xe, unsigned int num_vfs) 57 { 58 struct xe_gt *gt; 59 unsigned int id; 60 unsigned int n; 61 62 for_each_gt(gt, xe, id) 63 for (n = 1; n <= num_vfs; n++) 64 xe_gt_sriov_pf_control_trigger_flr(gt, n); 65 } 66 67 static struct pci_dev *xe_pci_pf_get_vf_dev(struct xe_device *xe, unsigned int vf_id) 68 { 69 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 70 71 xe_assert(xe, IS_SRIOV_PF(xe)); 72 73 /* caller must use pci_dev_put() */ 74 return pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), 75 pdev->bus->number, 76 pci_iov_virtfn_devfn(pdev, vf_id)); 77 } 78 79 static void pf_link_vfs(struct xe_device *xe, int num_vfs) 80 { 81 struct pci_dev *pdev_pf = to_pci_dev(xe->drm.dev); 82 struct device_link *link; 83 struct pci_dev *pdev_vf; 84 unsigned int n; 85 86 /* 87 * When both PF and VF devices are enabled on the host, during system 88 * resume they are resuming in parallel. 89 * 90 * But PF has to complete the provision of VF first to allow any VFs to 91 * successfully resume. 92 * 93 * Create a parent-child device link between PF and VF devices that will 94 * enforce correct resume order. 95 */ 96 for (n = 1; n <= num_vfs; n++) { 97 pdev_vf = xe_pci_pf_get_vf_dev(xe, n - 1); 98 99 /* unlikely, something weird is happening, abort */ 100 if (!pdev_vf) { 101 xe_sriov_err(xe, "Cannot find VF%u device, aborting link%s creation!\n", 102 n, str_plural(num_vfs)); 103 break; 104 } 105 106 link = device_link_add(&pdev_vf->dev, &pdev_pf->dev, 107 DL_FLAG_AUTOREMOVE_CONSUMER); 108 /* unlikely and harmless, continue with other VFs */ 109 if (!link) 110 xe_sriov_notice(xe, "Failed linking VF%u\n", n); 111 112 pci_dev_put(pdev_vf); 113 } 114 } 115 116 static void pf_engine_activity_stats(struct xe_device *xe, unsigned int num_vfs, bool enable) 117 { 118 struct xe_gt *gt; 119 unsigned int id; 120 int ret = 0; 121 122 for_each_gt(gt, xe, id) { 123 ret = xe_guc_engine_activity_function_stats(>->uc.guc, num_vfs, enable); 124 if (ret) 125 xe_gt_sriov_info(gt, "Failed to %s engine activity function stats (%pe)\n", 126 str_enable_disable(enable), ERR_PTR(ret)); 127 } 128 } 129 130 static int pf_enable_vfs(struct xe_device *xe, int num_vfs) 131 { 132 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 133 int total_vfs = xe_sriov_pf_get_totalvfs(xe); 134 int err; 135 136 xe_assert(xe, IS_SRIOV_PF(xe)); 137 xe_assert(xe, num_vfs > 0); 138 xe_assert(xe, num_vfs <= total_vfs); 139 xe_sriov_dbg(xe, "enabling %u VF%s\n", num_vfs, str_plural(num_vfs)); 140 141 /* 142 * We must hold additional reference to the runtime PM to keep PF in D0 143 * during VFs lifetime, as our VFs do not implement the PM capability. 144 * 145 * With PF being in D0 state, all VFs will also behave as in D0 state. 146 * This will also keep GuC alive with all VFs' configurations. 147 * 148 * We will release this additional PM reference in pf_disable_vfs(). 149 */ 150 xe_pm_runtime_get_noresume(xe); 151 152 err = pf_provision_vfs(xe, num_vfs); 153 if (err < 0) 154 goto failed; 155 156 err = pci_enable_sriov(pdev, num_vfs); 157 if (err < 0) 158 goto failed; 159 160 pf_link_vfs(xe, num_vfs); 161 162 xe_sriov_info(xe, "Enabled %u of %u VF%s\n", 163 num_vfs, total_vfs, str_plural(total_vfs)); 164 165 pf_engine_activity_stats(xe, num_vfs, true); 166 167 return num_vfs; 168 169 failed: 170 pf_unprovision_vfs(xe, num_vfs); 171 xe_pm_runtime_put(xe); 172 173 xe_sriov_notice(xe, "Failed to enable %u VF%s (%pe)\n", 174 num_vfs, str_plural(num_vfs), ERR_PTR(err)); 175 return err; 176 } 177 178 static int pf_disable_vfs(struct xe_device *xe) 179 { 180 struct device *dev = xe->drm.dev; 181 struct pci_dev *pdev = to_pci_dev(dev); 182 u16 num_vfs = pci_num_vf(pdev); 183 184 xe_assert(xe, IS_SRIOV_PF(xe)); 185 xe_sriov_dbg(xe, "disabling %u VF%s\n", num_vfs, str_plural(num_vfs)); 186 187 if (!num_vfs) 188 return 0; 189 190 pf_engine_activity_stats(xe, num_vfs, false); 191 192 pci_disable_sriov(pdev); 193 194 pf_reset_vfs(xe, num_vfs); 195 196 pf_unprovision_vfs(xe, num_vfs); 197 198 /* not needed anymore - see pf_enable_vfs() */ 199 xe_pm_runtime_put(xe); 200 201 xe_sriov_info(xe, "Disabled %u VF%s\n", num_vfs, str_plural(num_vfs)); 202 return 0; 203 } 204 205 /** 206 * xe_pci_sriov_configure - Configure SR-IOV (enable/disable VFs). 207 * @pdev: the &pci_dev 208 * @num_vfs: number of VFs to enable or zero to disable all VFs 209 * 210 * This is the Xe implementation of struct pci_driver.sriov_configure callback. 211 * 212 * This callback will be called by the PCI subsystem to enable or disable SR-IOV 213 * Virtual Functions (VFs) as requested by the used via the PCI sysfs interface. 214 * 215 * Return: number of configured VFs or a negative error code on failure. 216 */ 217 int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) 218 { 219 struct xe_device *xe = pdev_to_xe_device(pdev); 220 int ret; 221 222 if (!IS_SRIOV_PF(xe)) 223 return -ENODEV; 224 225 if (num_vfs < 0) 226 return -EINVAL; 227 228 if (num_vfs > xe_sriov_pf_get_totalvfs(xe)) 229 return -ERANGE; 230 231 if (num_vfs && pci_num_vf(pdev)) 232 return -EBUSY; 233 234 xe_pm_runtime_get(xe); 235 if (num_vfs > 0) 236 ret = pf_enable_vfs(xe, num_vfs); 237 else 238 ret = pf_disable_vfs(xe); 239 xe_pm_runtime_put(xe); 240 241 return ret; 242 } 243