aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-sysfs.c
diff options
context:
space:
mode:
authorDonald Dutile <ddutile@redhat.com>2012-11-05 15:20:36 -0500
committerBjorn Helgaas <bhelgaas@google.com>2012-11-09 22:10:39 -0500
commit1789382a72a537447d65ea4131d8bcc1ad85ce7b (patch)
treea22142cf3882ccf95e9be73642d3738fb5a72af1 /drivers/pci/pci-sysfs.c
parent625e1d59a89f50bace376f429d8cf50347af75f7 (diff)
PCI: SRIOV control and status via sysfs
Provide files under sysfs to determine the maximum number of VFs an SR-IOV-capable PCIe device supports, and methods to enable and disable the VFs on a per-device basis. Currently, VF enablement by SR-IOV-capable PCIe devices is done via driver-specific module parameters. If not setup in modprobe files, it requires admin to unload & reload PF drivers with number of desired VFs to enable. Additionally, the enablement is system wide: all devices controlled by the same driver have the same number of VFs enabled. Although the latter is probably desired, there are PCI configurations setup by system BIOS that may not enable that to occur. Two files are created for the PF of PCIe devices with SR-IOV support: sriov_totalvfs Contains the maximum number of VFs the device could support as reported by the TotalVFs register in the SR-IOV extended capability. sriov_numvfs Contains the number of VFs currently enabled on this device as reported by the NumVFs register in the SR-IOV extended capability. Writing zero to this file disables all VFs. Writing a positive number to this file enables that number of VFs. These files are readable for all SR-IOV PF devices. Writes to the sriov_numvfs file are effective only if a driver that supports the sriov_configure() method is attached. Signed-off-by: Donald Dutile <ddutile@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r--drivers/pci/pci-sysfs.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index fbbb97f28259..74508c63bd47 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -404,6 +404,106 @@ static ssize_t d3cold_allowed_show(struct device *dev,
404} 404}
405#endif 405#endif
406 406
407#ifdef CONFIG_PCI_IOV
408static ssize_t sriov_totalvfs_show(struct device *dev,
409 struct device_attribute *attr,
410 char *buf)
411{
412 struct pci_dev *pdev = to_pci_dev(dev);
413
414 return sprintf(buf, "%u\n", pdev->sriov->total);
415}
416
417
418static ssize_t sriov_numvfs_show(struct device *dev,
419 struct device_attribute *attr,
420 char *buf)
421{
422 struct pci_dev *pdev = to_pci_dev(dev);
423
424 return sprintf(buf, "%u\n", pdev->sriov->nr_virtfn);
425}
426
427/*
428 * num_vfs > 0; number of vfs to enable
429 * num_vfs = 0; disable all vfs
430 *
431 * Note: SRIOV spec doesn't allow partial VF
432 * disable, so its all or none.
433 */
434static ssize_t sriov_numvfs_store(struct device *dev,
435 struct device_attribute *attr,
436 const char *buf, size_t count)
437{
438 struct pci_dev *pdev = to_pci_dev(dev);
439 int num_vfs_enabled = 0;
440 int num_vfs;
441 int ret = 0;
442 u16 total;
443
444 if (kstrtoint(buf, 0, &num_vfs) < 0)
445 return -EINVAL;
446
447 /* is PF driver loaded w/callback */
448 if (!pdev->driver || !pdev->driver->sriov_configure) {
449 dev_info(&pdev->dev,
450 "Driver doesn't support SRIOV configuration via sysfs\n");
451 return -ENOSYS;
452 }
453
454 /* if enabling vf's ... */
455 total = pdev->sriov->total;
456 /* Requested VFs to enable < totalvfs and none enabled already */
457 if ((num_vfs > 0) && (num_vfs <= total)) {
458 if (pdev->sriov->nr_virtfn == 0) {
459 num_vfs_enabled =
460 pdev->driver->sriov_configure(pdev, num_vfs);
461 if ((num_vfs_enabled >= 0) &&
462 (num_vfs_enabled != num_vfs)) {
463 dev_warn(&pdev->dev,
464 "Only %d VFs enabled\n",
465 num_vfs_enabled);
466 return count;
467 } else if (num_vfs_enabled < 0)
468 /* error code from driver callback */
469 return num_vfs_enabled;
470 } else if (num_vfs == pdev->sriov->nr_virtfn) {
471 dev_warn(&pdev->dev,
472 "%d VFs already enabled; no enable action taken\n",
473 num_vfs);
474 return count;
475 } else {
476 dev_warn(&pdev->dev,
477 "%d VFs already enabled. Disable before enabling %d VFs\n",
478 pdev->sriov->nr_virtfn, num_vfs);
479 return -EINVAL;
480 }
481 }
482
483 /* disable vfs */
484 if (num_vfs == 0) {
485 if (pdev->sriov->nr_virtfn != 0) {
486 ret = pdev->driver->sriov_configure(pdev, 0);
487 return ret ? ret : count;
488 } else {
489 dev_warn(&pdev->dev,
490 "All VFs disabled; no disable action taken\n");
491 return count;
492 }
493 }
494
495 dev_err(&pdev->dev,
496 "Invalid value for number of VFs to enable: %d\n", num_vfs);
497
498 return -EINVAL;
499}
500
501static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs);
502static struct device_attribute sriov_numvfs_attr =
503 __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP),
504 sriov_numvfs_show, sriov_numvfs_store);
505#endif /* CONFIG_PCI_IOV */
506
407struct device_attribute pci_dev_attrs[] = { 507struct device_attribute pci_dev_attrs[] = {
408 __ATTR_RO(resource), 508 __ATTR_RO(resource),
409 __ATTR_RO(vendor), 509 __ATTR_RO(vendor),
@@ -1421,6 +1521,30 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
1421 return a->mode; 1521 return a->mode;
1422} 1522}
1423 1523
1524#ifdef CONFIG_PCI_IOV
1525static struct attribute *sriov_dev_attrs[] = {
1526 &sriov_totalvfs_attr.attr,
1527 &sriov_numvfs_attr.attr,
1528 NULL,
1529};
1530
1531static umode_t sriov_attrs_are_visible(struct kobject *kobj,
1532 struct attribute *a, int n)
1533{
1534 struct device *dev = container_of(kobj, struct device, kobj);
1535
1536 if (!dev_is_pf(dev))
1537 return 0;
1538
1539 return a->mode;
1540}
1541
1542static struct attribute_group sriov_dev_attr_group = {
1543 .attrs = sriov_dev_attrs,
1544 .is_visible = sriov_attrs_are_visible,
1545};
1546#endif /* CONFIG_PCI_IOV */
1547
1424static struct attribute_group pci_dev_attr_group = { 1548static struct attribute_group pci_dev_attr_group = {
1425 .attrs = pci_dev_dev_attrs, 1549 .attrs = pci_dev_dev_attrs,
1426 .is_visible = pci_dev_attrs_are_visible, 1550 .is_visible = pci_dev_attrs_are_visible,
@@ -1428,6 +1552,9 @@ static struct attribute_group pci_dev_attr_group = {
1428 1552
1429static const struct attribute_group *pci_dev_attr_groups[] = { 1553static const struct attribute_group *pci_dev_attr_groups[] = {
1430 &pci_dev_attr_group, 1554 &pci_dev_attr_group,
1555#ifdef CONFIG_PCI_IOV
1556 &sriov_dev_attr_group,
1557#endif
1431 NULL, 1558 NULL,
1432}; 1559};
1433 1560