xref: /linux/drivers/gpu/drm/xe/xe_pci_sriov.c (revision 569d7db70e5dcf13fbf072f10e9096577ac1e565)
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_pci_sriov.h"
10 #include "xe_pm.h"
11 #include "xe_sriov.h"
12 #include "xe_sriov_pf_helpers.h"
13 #include "xe_sriov_printk.h"
14 
15 static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs)
16 {
17 	struct xe_gt *gt;
18 	unsigned int id;
19 	int result = 0, err;
20 
21 	for_each_gt(gt, xe, id) {
22 		err = xe_gt_sriov_pf_config_set_fair(gt, VFID(1), num_vfs);
23 		result = result ?: err;
24 	}
25 
26 	return result;
27 }
28 
29 static void pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs)
30 {
31 	struct xe_gt *gt;
32 	unsigned int id;
33 	unsigned int n;
34 
35 	for_each_gt(gt, xe, id)
36 		for (n = 1; n <= num_vfs; n++)
37 			xe_gt_sriov_pf_config_release(gt, n, true);
38 }
39 
40 static int pf_enable_vfs(struct xe_device *xe, int num_vfs)
41 {
42 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
43 	int total_vfs = xe_sriov_pf_get_totalvfs(xe);
44 	int err;
45 
46 	xe_assert(xe, IS_SRIOV_PF(xe));
47 	xe_assert(xe, num_vfs > 0);
48 	xe_assert(xe, num_vfs <= total_vfs);
49 	xe_sriov_dbg(xe, "enabling %u VF%s\n", num_vfs, str_plural(num_vfs));
50 
51 	/*
52 	 * We must hold additional reference to the runtime PM to keep PF in D0
53 	 * during VFs lifetime, as our VFs do not implement the PM capability.
54 	 *
55 	 * With PF being in D0 state, all VFs will also behave as in D0 state.
56 	 * This will also keep GuC alive with all VFs' configurations.
57 	 *
58 	 * We will release this additional PM reference in pf_disable_vfs().
59 	 */
60 	xe_pm_runtime_get_noresume(xe);
61 
62 	err = pf_provision_vfs(xe, num_vfs);
63 	if (err < 0)
64 		goto failed;
65 
66 	err = pci_enable_sriov(pdev, num_vfs);
67 	if (err < 0)
68 		goto failed;
69 
70 	xe_sriov_info(xe, "Enabled %u of %u VF%s\n",
71 		      num_vfs, total_vfs, str_plural(total_vfs));
72 	return num_vfs;
73 
74 failed:
75 	pf_unprovision_vfs(xe, num_vfs);
76 	xe_pm_runtime_put(xe);
77 
78 	xe_sriov_notice(xe, "Failed to enable %u VF%s (%pe)\n",
79 			num_vfs, str_plural(num_vfs), ERR_PTR(err));
80 	return err;
81 }
82 
83 static int pf_disable_vfs(struct xe_device *xe)
84 {
85 	struct device *dev = xe->drm.dev;
86 	struct pci_dev *pdev = to_pci_dev(dev);
87 	u16 num_vfs = pci_num_vf(pdev);
88 
89 	xe_assert(xe, IS_SRIOV_PF(xe));
90 	xe_sriov_dbg(xe, "disabling %u VF%s\n", num_vfs, str_plural(num_vfs));
91 
92 	if (!num_vfs)
93 		return 0;
94 
95 	pci_disable_sriov(pdev);
96 
97 	pf_unprovision_vfs(xe, num_vfs);
98 
99 	/* not needed anymore - see pf_enable_vfs() */
100 	xe_pm_runtime_put(xe);
101 
102 	xe_sriov_info(xe, "Disabled %u VF%s\n", num_vfs, str_plural(num_vfs));
103 	return 0;
104 }
105 
106 /**
107  * xe_pci_sriov_configure - Configure SR-IOV (enable/disable VFs).
108  * @pdev: the &pci_dev
109  * @num_vfs: number of VFs to enable or zero to disable all VFs
110  *
111  * This is the Xe implementation of struct pci_driver.sriov_configure callback.
112  *
113  * This callback will be called by the PCI subsystem to enable or disable SR-IOV
114  * Virtual Functions (VFs) as requested by the used via the PCI sysfs interface.
115  *
116  * Return: number of configured VFs or a negative error code on failure.
117  */
118 int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
119 {
120 	struct xe_device *xe = pdev_to_xe_device(pdev);
121 	int ret;
122 
123 	if (!IS_SRIOV_PF(xe))
124 		return -ENODEV;
125 
126 	if (num_vfs < 0)
127 		return -EINVAL;
128 
129 	if (num_vfs > xe_sriov_pf_get_totalvfs(xe))
130 		return -ERANGE;
131 
132 	if (num_vfs && pci_num_vf(pdev))
133 		return -EBUSY;
134 
135 	xe_pm_runtime_get(xe);
136 	if (num_vfs > 0)
137 		ret = pf_enable_vfs(xe, num_vfs);
138 	else
139 		ret = pf_disable_vfs(xe);
140 	xe_pm_runtime_put(xe);
141 
142 	return ret;
143 }
144