xref: /linux/drivers/gpu/drm/xe/xe_pci_sriov.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023-2024 Intel Corporation
4  */
5 
6 #include <linux/bitops.h>
7 #include <linux/pci.h>
8 
9 #include "regs/xe_bars.h"
10 #include "xe_assert.h"
11 #include "xe_device.h"
12 #include "xe_gt_sriov_pf_config.h"
13 #include "xe_gt_sriov_pf_control.h"
14 #include "xe_gt_sriov_printk.h"
15 #include "xe_guc_engine_activity.h"
16 #include "xe_pci_sriov.h"
17 #include "xe_pm.h"
18 #include "xe_sriov.h"
19 #include "xe_sriov_pf.h"
20 #include "xe_sriov_pf_control.h"
21 #include "xe_sriov_pf_helpers.h"
22 #include "xe_sriov_pf_provision.h"
23 #include "xe_sriov_pf_sysfs.h"
24 #include "xe_sriov_printk.h"
25 
26 static void pf_reset_vfs(struct xe_device *xe, unsigned int num_vfs)
27 {
28 	unsigned int n;
29 
30 	for (n = 1; n <= num_vfs; n++)
31 		xe_sriov_pf_control_reset_vf(xe, n);
32 }
33 
34 static void pf_link_vfs(struct xe_device *xe, int num_vfs)
35 {
36 	struct pci_dev *pdev_pf = to_pci_dev(xe->drm.dev);
37 	struct device_link *link;
38 	struct pci_dev *pdev_vf;
39 	unsigned int n;
40 
41 	/*
42 	 * When both PF and VF devices are enabled on the host, during system
43 	 * resume they are resuming in parallel.
44 	 *
45 	 * But PF has to complete the provision of VF first to allow any VFs to
46 	 * successfully resume.
47 	 *
48 	 * Create a parent-child device link between PF and VF devices that will
49 	 * enforce correct resume order.
50 	 */
51 	for (n = 1; n <= num_vfs; n++) {
52 		pdev_vf = xe_pci_sriov_get_vf_pdev(pdev_pf, n);
53 
54 		/* unlikely, something weird is happening, abort */
55 		if (!pdev_vf) {
56 			xe_sriov_err(xe, "Cannot find VF%u device, aborting link%s creation!\n",
57 				     n, str_plural(num_vfs));
58 			break;
59 		}
60 
61 		link = device_link_add(&pdev_vf->dev, &pdev_pf->dev,
62 				       DL_FLAG_AUTOREMOVE_CONSUMER);
63 		/* unlikely and harmless, continue with other VFs */
64 		if (!link)
65 			xe_sriov_notice(xe, "Failed linking VF%u\n", n);
66 
67 		pci_dev_put(pdev_vf);
68 	}
69 }
70 
71 static void pf_engine_activity_stats(struct xe_device *xe, unsigned int num_vfs, bool enable)
72 {
73 	struct xe_gt *gt;
74 	unsigned int id;
75 	int ret = 0;
76 
77 	for_each_gt(gt, xe, id) {
78 		ret = xe_guc_engine_activity_function_stats(&gt->uc.guc, num_vfs, enable);
79 		if (ret)
80 			xe_gt_sriov_info(gt, "Failed to %s engine activity function stats (%pe)\n",
81 					 str_enable_disable(enable), ERR_PTR(ret));
82 	}
83 }
84 
85 static int resize_vf_vram_bar(struct xe_device *xe, int num_vfs)
86 {
87 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
88 	u32 sizes;
89 
90 	sizes = pci_iov_vf_bar_get_sizes(pdev, VF_LMEM_BAR, num_vfs);
91 	if (!sizes)
92 		return 0;
93 
94 	return pci_iov_vf_bar_set_size(pdev, VF_LMEM_BAR, __fls(sizes));
95 }
96 
97 static int pf_prepare_vfs_enabling(struct xe_device *xe)
98 {
99 	xe_assert(xe, IS_SRIOV_PF(xe));
100 	/* make sure we are not locked-down by other components */
101 	return xe_sriov_pf_arm_guard(xe, &xe->sriov.pf.guard_vfs_enabling, false, NULL);
102 }
103 
104 static void pf_finish_vfs_enabling(struct xe_device *xe)
105 {
106 	xe_assert(xe, IS_SRIOV_PF(xe));
107 	/* allow other components to lockdown VFs enabling */
108 	xe_sriov_pf_disarm_guard(xe, &xe->sriov.pf.guard_vfs_enabling, false, NULL);
109 }
110 
111 static int pf_enable_vfs(struct xe_device *xe, int num_vfs)
112 {
113 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
114 	int total_vfs = xe_sriov_pf_get_totalvfs(xe);
115 	int err;
116 
117 	xe_assert(xe, IS_SRIOV_PF(xe));
118 	xe_assert(xe, num_vfs > 0);
119 	xe_assert(xe, num_vfs <= total_vfs);
120 	xe_sriov_dbg(xe, "enabling %u VF%s\n", num_vfs, str_plural(num_vfs));
121 
122 	err = xe_sriov_pf_wait_ready(xe);
123 	if (err)
124 		goto out;
125 
126 	err = pf_prepare_vfs_enabling(xe);
127 	if (err)
128 		goto out;
129 
130 	/*
131 	 * We must hold additional reference to the runtime PM to keep PF in D0
132 	 * during VFs lifetime, as our VFs do not implement the PM capability.
133 	 *
134 	 * With PF being in D0 state, all VFs will also behave as in D0 state.
135 	 * This will also keep GuC alive with all VFs' configurations.
136 	 *
137 	 * We will release this additional PM reference in pf_disable_vfs().
138 	 */
139 	xe_pm_runtime_get_noresume(xe);
140 
141 	err = xe_sriov_pf_provision_vfs(xe, num_vfs);
142 	if (err < 0)
143 		goto failed;
144 
145 	if (IS_DGFX(xe)) {
146 		err = resize_vf_vram_bar(xe, num_vfs);
147 		if (err)
148 			xe_sriov_info(xe, "Failed to set VF LMEM BAR size: %d\n", err);
149 	}
150 
151 	err = pci_enable_sriov(pdev, num_vfs);
152 	if (err < 0)
153 		goto failed;
154 
155 	pf_link_vfs(xe, num_vfs);
156 
157 	xe_sriov_info(xe, "Enabled %u of %u VF%s\n",
158 		      num_vfs, total_vfs, str_plural(total_vfs));
159 
160 	xe_sriov_pf_sysfs_link_vfs(xe, num_vfs);
161 
162 	pf_engine_activity_stats(xe, num_vfs, true);
163 
164 	return num_vfs;
165 
166 failed:
167 	xe_sriov_pf_unprovision_vfs(xe, num_vfs);
168 	xe_pm_runtime_put(xe);
169 	pf_finish_vfs_enabling(xe);
170 out:
171 	xe_sriov_notice(xe, "Failed to enable %u VF%s (%pe)\n",
172 			num_vfs, str_plural(num_vfs), ERR_PTR(err));
173 	return err;
174 }
175 
176 static int pf_disable_vfs(struct xe_device *xe)
177 {
178 	struct device *dev = xe->drm.dev;
179 	struct pci_dev *pdev = to_pci_dev(dev);
180 	u16 num_vfs = pci_num_vf(pdev);
181 
182 	xe_assert(xe, IS_SRIOV_PF(xe));
183 	xe_sriov_dbg(xe, "disabling %u VF%s\n", num_vfs, str_plural(num_vfs));
184 
185 	if (!num_vfs)
186 		return 0;
187 
188 	pf_engine_activity_stats(xe, num_vfs, false);
189 
190 	xe_sriov_pf_sysfs_unlink_vfs(xe, num_vfs);
191 
192 	pci_disable_sriov(pdev);
193 
194 	pf_reset_vfs(xe, num_vfs);
195 
196 	xe_sriov_pf_unprovision_vfs(xe, num_vfs);
197 
198 	/* not needed anymore - see pf_enable_vfs() */
199 	xe_pm_runtime_put(xe);
200 
201 	pf_finish_vfs_enabling(xe);
202 
203 	xe_sriov_info(xe, "Disabled %u VF%s\n", num_vfs, str_plural(num_vfs));
204 	return 0;
205 }
206 
207 /**
208  * xe_pci_sriov_configure - Configure SR-IOV (enable/disable VFs).
209  * @pdev: the &pci_dev
210  * @num_vfs: number of VFs to enable or zero to disable all VFs
211  *
212  * This is the Xe implementation of struct pci_driver.sriov_configure callback.
213  *
214  * This callback will be called by the PCI subsystem to enable or disable SR-IOV
215  * Virtual Functions (VFs) as requested by the used via the PCI sysfs interface.
216  *
217  * Return: number of configured VFs or a negative error code on failure.
218  */
219 int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
220 {
221 	struct xe_device *xe = pdev_to_xe_device(pdev);
222 	int ret;
223 
224 	if (!IS_SRIOV_PF(xe))
225 		return -ENODEV;
226 
227 	if (num_vfs < 0)
228 		return -EINVAL;
229 
230 	if (num_vfs > xe_sriov_pf_get_totalvfs(xe))
231 		return -ERANGE;
232 
233 	if (num_vfs && pci_num_vf(pdev))
234 		return -EBUSY;
235 
236 	xe_pm_runtime_get(xe);
237 	if (num_vfs > 0)
238 		ret = pf_enable_vfs(xe, num_vfs);
239 	else
240 		ret = pf_disable_vfs(xe);
241 	xe_pm_runtime_put(xe);
242 
243 	return ret;
244 }
245 
246 /**
247  * xe_pci_sriov_get_vf_pdev() - Lookup the VF's PCI device using the VF identifier.
248  * @pdev: the PF's &pci_dev
249  * @vfid: VF identifier (1-based)
250  *
251  * The caller must decrement the reference count by calling pci_dev_put().
252  *
253  * Return: the VF's &pci_dev or NULL if the VF device was not found.
254  */
255 struct pci_dev *xe_pci_sriov_get_vf_pdev(struct pci_dev *pdev, unsigned int vfid)
256 {
257 	struct xe_device *xe = pdev_to_xe_device(pdev);
258 
259 	xe_assert(xe, dev_is_pf(&pdev->dev));
260 	xe_assert(xe, vfid);
261 	xe_assert(xe, vfid <= pci_sriov_get_totalvfs(pdev));
262 
263 	return pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
264 					   pdev->bus->number,
265 					   pci_iov_virtfn_devfn(pdev, vfid - 1));
266 }
267