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
pf_needs_provisioning(struct xe_gt * gt,unsigned int num_vfs)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
pf_provision_vfs(struct xe_device * xe,unsigned int num_vfs)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
pf_unprovision_vfs(struct xe_device * xe,unsigned int num_vfs)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
pf_reset_vfs(struct xe_device * xe,unsigned int num_vfs)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
pf_enable_vfs(struct xe_device * xe,int num_vfs)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
pf_disable_vfs(struct xe_device * xe)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 */
xe_pci_sriov_configure(struct pci_dev * pdev,int num_vfs)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