File Index
Files and directories
Sign in
FILE

xe_pci_sriov.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/xe/xe_pci_sriov.c C
  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
 26static 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
 34static 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
 71static 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
 85static 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
 97static 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
104static 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
111static 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
166failed:
167	xe_sriov_pf_unprovision_vfs(xe, num_vfs);
168	xe_pm_runtime_put(xe);
169	pf_finish_vfs_enabling(xe);
170out:
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
176static 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 */
219int 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 */
255struct 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}
~/ Read-only file preview.