Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
Note: File does not exist in v5.9.
  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
 16static 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
 27static 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
 43static 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
 54static 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
 65static 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
 99failed:
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
108static 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 */
145int 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}