Skip to content

Commit c3d5c2d

Browse files
committed
PCI/IOV: Add sysfs MSI-X vector assignment interface
A typical cloud provider SR-IOV use case is to create many VFs for use by guest VMs. The VFs may not be assigned to a VM until a customer requests a VM of a certain size, e.g., number of CPUs. A VF may need MSI-X vectors proportional to the number of CPUs in the VM, but there is no standard way to change the number of MSI-X vectors supported by a VF. Some Mellanox ConnectX devices support dynamic assignment of MSI-X vectors to SR-IOV VFs. This can be done by the PF driver after VFs are enabled, and it can be done without affecting VFs that are already in use. The hardware supports a limited pool of MSI-X vectors that can be assigned to the PF or to individual VFs. This is device-specific behavior that requires support in the PF driver. Add a read-only "sriov_vf_total_msix" sysfs file for the PF and a writable "sriov_vf_msix_count" file for each VF. Management software may use these to learn how many MSI-X vectors are available and to dynamically assign them to VFs before the VFs are passed through to a VM. If the PF driver implements the ->sriov_get_vf_total_msix() callback, "sriov_vf_total_msix" contains the total number of MSI-X vectors available for distribution among VFs. If no driver is bound to the VF, writing "N" to "sriov_vf_msix_count" uses the PF driver ->sriov_set_msix_vec_count() callback to assign "N" MSI-X vectors to the VF. When a VF driver subsequently reads the MSI-X Message Control register, it will see the new Table Size "N". Link: https://lore.kernel.org/linux-pci/[email protected] Acked-by: Bjorn Helgaas <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]>
1 parent 26bf309 commit c3d5c2d

File tree

5 files changed

+137
-8
lines changed

5 files changed

+137
-8
lines changed

Documentation/ABI/testing/sysfs-bus-pci

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,32 @@ Description:
375375
The value comes from the PCI kernel device state and can be one
376376
of: "unknown", "error", "D0", D1", "D2", "D3hot", "D3cold".
377377
The file is read only.
378+
379+
What: /sys/bus/pci/devices/.../sriov_vf_total_msix
380+
Date: January 2021
381+
Contact: Leon Romanovsky <[email protected]>
382+
Description:
383+
This file is associated with a SR-IOV physical function (PF).
384+
It contains the total number of MSI-X vectors available for
385+
assignment to all virtual functions (VFs) associated with PF.
386+
The value will be zero if the device doesn't support this
387+
functionality. For supported devices, the value will be
388+
constant and won't be changed after MSI-X vectors assignment.
389+
390+
What: /sys/bus/pci/devices/.../sriov_vf_msix_count
391+
Date: January 2021
392+
Contact: Leon Romanovsky <[email protected]>
393+
Description:
394+
This file is associated with a SR-IOV virtual function (VF).
395+
It allows configuration of the number of MSI-X vectors for
396+
the VF. This allows devices that have a global pool of MSI-X
397+
vectors to optimally divide them between VFs based on VF usage.
398+
399+
The values accepted are:
400+
* > 0 - this number will be reported as the Table Size in the
401+
VF's MSI-X capability
402+
* < 0 - not valid
403+
* = 0 - will reset to the device default value
404+
405+
The file is writable if the PF is bound to a driver that
406+
implements ->sriov_set_msix_vec_count().

drivers/pci/iov.c

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ int pci_iov_virtfn_devfn(struct pci_dev *dev, int vf_id)
3131
return (dev->devfn + dev->sriov->offset +
3232
dev->sriov->stride * vf_id) & 0xff;
3333
}
34+
EXPORT_SYMBOL_GPL(pci_iov_virtfn_devfn);
3435

3536
/*
3637
* Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may
@@ -157,6 +158,92 @@ int pci_iov_sysfs_link(struct pci_dev *dev,
157158
return rc;
158159
}
159160

161+
#ifdef CONFIG_PCI_MSI
162+
static ssize_t sriov_vf_total_msix_show(struct device *dev,
163+
struct device_attribute *attr,
164+
char *buf)
165+
{
166+
struct pci_dev *pdev = to_pci_dev(dev);
167+
u32 vf_total_msix = 0;
168+
169+
device_lock(dev);
170+
if (!pdev->driver || !pdev->driver->sriov_get_vf_total_msix)
171+
goto unlock;
172+
173+
vf_total_msix = pdev->driver->sriov_get_vf_total_msix(pdev);
174+
unlock:
175+
device_unlock(dev);
176+
return sysfs_emit(buf, "%u\n", vf_total_msix);
177+
}
178+
static DEVICE_ATTR_RO(sriov_vf_total_msix);
179+
180+
static ssize_t sriov_vf_msix_count_store(struct device *dev,
181+
struct device_attribute *attr,
182+
const char *buf, size_t count)
183+
{
184+
struct pci_dev *vf_dev = to_pci_dev(dev);
185+
struct pci_dev *pdev = pci_physfn(vf_dev);
186+
int val, ret;
187+
188+
ret = kstrtoint(buf, 0, &val);
189+
if (ret)
190+
return ret;
191+
192+
if (val < 0)
193+
return -EINVAL;
194+
195+
device_lock(&pdev->dev);
196+
if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) {
197+
ret = -EOPNOTSUPP;
198+
goto err_pdev;
199+
}
200+
201+
device_lock(&vf_dev->dev);
202+
if (vf_dev->driver) {
203+
/*
204+
* A driver is already attached to this VF and has configured
205+
* itself based on the current MSI-X vector count. Changing
206+
* the vector size could mess up the driver, so block it.
207+
*/
208+
ret = -EBUSY;
209+
goto err_dev;
210+
}
211+
212+
ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val);
213+
214+
err_dev:
215+
device_unlock(&vf_dev->dev);
216+
err_pdev:
217+
device_unlock(&pdev->dev);
218+
return ret ? : count;
219+
}
220+
static DEVICE_ATTR_WO(sriov_vf_msix_count);
221+
#endif
222+
223+
static struct attribute *sriov_vf_dev_attrs[] = {
224+
#ifdef CONFIG_PCI_MSI
225+
&dev_attr_sriov_vf_msix_count.attr,
226+
#endif
227+
NULL,
228+
};
229+
230+
static umode_t sriov_vf_attrs_are_visible(struct kobject *kobj,
231+
struct attribute *a, int n)
232+
{
233+
struct device *dev = kobj_to_dev(kobj);
234+
struct pci_dev *pdev = to_pci_dev(dev);
235+
236+
if (!pdev->is_virtfn)
237+
return 0;
238+
239+
return a->mode;
240+
}
241+
242+
const struct attribute_group sriov_vf_dev_attr_group = {
243+
.attrs = sriov_vf_dev_attrs,
244+
.is_visible = sriov_vf_attrs_are_visible,
245+
};
246+
160247
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
161248
{
162249
int i;
@@ -400,18 +487,21 @@ static DEVICE_ATTR_RO(sriov_stride);
400487
static DEVICE_ATTR_RO(sriov_vf_device);
401488
static DEVICE_ATTR_RW(sriov_drivers_autoprobe);
402489

403-
static struct attribute *sriov_dev_attrs[] = {
490+
static struct attribute *sriov_pf_dev_attrs[] = {
404491
&dev_attr_sriov_totalvfs.attr,
405492
&dev_attr_sriov_numvfs.attr,
406493
&dev_attr_sriov_offset.attr,
407494
&dev_attr_sriov_stride.attr,
408495
&dev_attr_sriov_vf_device.attr,
409496
&dev_attr_sriov_drivers_autoprobe.attr,
497+
#ifdef CONFIG_PCI_MSI
498+
&dev_attr_sriov_vf_total_msix.attr,
499+
#endif
410500
NULL,
411501
};
412502

413-
static umode_t sriov_attrs_are_visible(struct kobject *kobj,
414-
struct attribute *a, int n)
503+
static umode_t sriov_pf_attrs_are_visible(struct kobject *kobj,
504+
struct attribute *a, int n)
415505
{
416506
struct device *dev = kobj_to_dev(kobj);
417507

@@ -421,9 +511,9 @@ static umode_t sriov_attrs_are_visible(struct kobject *kobj,
421511
return a->mode;
422512
}
423513

424-
const struct attribute_group sriov_dev_attr_group = {
425-
.attrs = sriov_dev_attrs,
426-
.is_visible = sriov_attrs_are_visible,
514+
const struct attribute_group sriov_pf_dev_attr_group = {
515+
.attrs = sriov_pf_dev_attrs,
516+
.is_visible = sriov_pf_attrs_are_visible,
427517
};
428518

429519
int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)

drivers/pci/pci-sysfs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,8 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
15671567
&pci_dev_attr_group,
15681568
&pci_dev_hp_attr_group,
15691569
#ifdef CONFIG_PCI_IOV
1570-
&sriov_dev_attr_group,
1570+
&sriov_pf_dev_attr_group,
1571+
&sriov_vf_dev_attr_group,
15711572
#endif
15721573
&pci_bridge_attr_group,
15731574
&pcie_dev_attr_group,

drivers/pci/pci.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,8 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
501501
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
502502
void pci_restore_iov_state(struct pci_dev *dev);
503503
int pci_iov_bus_range(struct pci_bus *bus);
504-
extern const struct attribute_group sriov_dev_attr_group;
504+
extern const struct attribute_group sriov_pf_dev_attr_group;
505+
extern const struct attribute_group sriov_vf_dev_attr_group;
505506
#else
506507
static inline int pci_iov_init(struct pci_dev *dev)
507508
{

include/linux/pci.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,12 @@ struct module;
856856
* e.g. drivers/net/e100.c.
857857
* @sriov_configure: Optional driver callback to allow configuration of
858858
* number of VFs to enable via sysfs "sriov_numvfs" file.
859+
* @sriov_set_msix_vec_count: PF Driver callback to change number of MSI-X
860+
* vectors on a VF. Triggered via sysfs "sriov_vf_msix_count".
861+
* This will change MSI-X Table Size in the VF Message Control
862+
* registers.
863+
* @sriov_get_vf_total_msix: PF driver callback to get the total number of
864+
* MSI-X vectors available for distribution to the VFs.
859865
* @err_handler: See Documentation/PCI/pci-error-recovery.rst
860866
* @groups: Sysfs attribute groups.
861867
* @driver: Driver model structure.
@@ -871,6 +877,8 @@ struct pci_driver {
871877
int (*resume)(struct pci_dev *dev); /* Device woken up */
872878
void (*shutdown)(struct pci_dev *dev);
873879
int (*sriov_configure)(struct pci_dev *dev, int num_vfs); /* On PF */
880+
int (*sriov_set_msix_vec_count)(struct pci_dev *vf, int msix_vec_count); /* On PF */
881+
u32 (*sriov_get_vf_total_msix)(struct pci_dev *pf);
874882
const struct pci_error_handlers *err_handler;
875883
const struct attribute_group **groups;
876884
struct device_driver driver;

0 commit comments

Comments
 (0)