diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-12-26 12:39:22 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-12-26 12:39:22 -0500 |
commit | faa48a507fd328013886426f9437fd7e2e7b820b (patch) | |
tree | 61c299361e749c7886d79ec6f0daad40ef947e66 /drivers/pci/pci-sysfs.c | |
parent | a49f0d1ea3ec94fc7cf33a7c36a16343b74bd565 (diff) |
PCI: Remove spurious error for sriov_numvfs store and simplify flow
If we request "num_vfs" and the driver's sriov_configure() method enables
exactly that number ("num_vfs_enabled"), we complain "Invalid value for
number of VFs to enable" and return an error. We should silently return
success instead.
Also, use kstrtou16() since numVFs is defined to be a 16-bit field and
rework to simplify control flow.
Reported-by: Greg Rose <gregory.v.rose@intel.com>
Reference: http://lkml.kernel.org/r/20121214101911.00002f59@unknown
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Donald Dutile <ddutile@redhat.com>
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 85 |
1 files changed, 34 insertions, 51 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 05b78b16d20b..9c6e9bb674ec 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -422,77 +422,60 @@ static ssize_t sriov_numvfs_show(struct device *dev, | |||
422 | } | 422 | } |
423 | 423 | ||
424 | /* | 424 | /* |
425 | * num_vfs > 0; number of vfs to enable | 425 | * num_vfs > 0; number of VFs to enable |
426 | * num_vfs = 0; disable all vfs | 426 | * num_vfs = 0; disable all VFs |
427 | * | 427 | * |
428 | * Note: SRIOV spec doesn't allow partial VF | 428 | * Note: SRIOV spec doesn't allow partial VF |
429 | * disable, so its all or none. | 429 | * disable, so it's all or none. |
430 | */ | 430 | */ |
431 | static ssize_t sriov_numvfs_store(struct device *dev, | 431 | static ssize_t sriov_numvfs_store(struct device *dev, |
432 | struct device_attribute *attr, | 432 | struct device_attribute *attr, |
433 | const char *buf, size_t count) | 433 | const char *buf, size_t count) |
434 | { | 434 | { |
435 | struct pci_dev *pdev = to_pci_dev(dev); | 435 | struct pci_dev *pdev = to_pci_dev(dev); |
436 | int num_vfs_enabled = 0; | 436 | int ret; |
437 | int num_vfs; | 437 | u16 num_vfs; |
438 | int ret = 0; | ||
439 | u16 total; | ||
440 | 438 | ||
441 | if (kstrtoint(buf, 0, &num_vfs) < 0) | 439 | ret = kstrtou16(buf, 0, &num_vfs); |
442 | return -EINVAL; | 440 | if (ret < 0) |
441 | return ret; | ||
442 | |||
443 | if (num_vfs > pci_sriov_get_totalvfs(pdev)) | ||
444 | return -ERANGE; | ||
445 | |||
446 | if (num_vfs == pdev->sriov->num_VFs) | ||
447 | return count; /* no change */ | ||
443 | 448 | ||
444 | /* is PF driver loaded w/callback */ | 449 | /* is PF driver loaded w/callback */ |
445 | if (!pdev->driver || !pdev->driver->sriov_configure) { | 450 | if (!pdev->driver || !pdev->driver->sriov_configure) { |
446 | dev_info(&pdev->dev, | 451 | dev_info(&pdev->dev, "Driver doesn't support SRIOV configuration via sysfs\n"); |
447 | "Driver doesn't support SRIOV configuration via sysfs\n"); | ||
448 | return -ENOSYS; | 452 | return -ENOSYS; |
449 | } | 453 | } |
450 | 454 | ||
451 | /* if enabling vf's ... */ | 455 | if (num_vfs == 0) { |
452 | total = pci_sriov_get_totalvfs(pdev); | 456 | /* disable VFs */ |
453 | /* Requested VFs to enable < totalvfs and none enabled already */ | 457 | ret = pdev->driver->sriov_configure(pdev, 0); |
454 | if ((num_vfs > 0) && (num_vfs <= total)) { | 458 | if (ret < 0) |
455 | if (pdev->sriov->num_VFs == 0) { | 459 | return ret; |
456 | num_vfs_enabled = | 460 | return count; |
457 | pdev->driver->sriov_configure(pdev, num_vfs); | ||
458 | if ((num_vfs_enabled >= 0) && | ||
459 | (num_vfs_enabled != num_vfs)) { | ||
460 | dev_warn(&pdev->dev, | ||
461 | "Only %d VFs enabled\n", | ||
462 | num_vfs_enabled); | ||
463 | return count; | ||
464 | } else if (num_vfs_enabled < 0) | ||
465 | /* error code from driver callback */ | ||
466 | return num_vfs_enabled; | ||
467 | } else if (num_vfs == pdev->sriov->num_VFs) { | ||
468 | dev_warn(&pdev->dev, | ||
469 | "%d VFs already enabled; no enable action taken\n", | ||
470 | num_vfs); | ||
471 | return count; | ||
472 | } else { | ||
473 | dev_warn(&pdev->dev, | ||
474 | "%d VFs already enabled. Disable before enabling %d VFs\n", | ||
475 | pdev->sriov->num_VFs, num_vfs); | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | } | 461 | } |
479 | 462 | ||
480 | /* disable vfs */ | 463 | /* enable VFs */ |
481 | if (num_vfs == 0) { | 464 | if (pdev->sriov->num_VFs) { |
482 | if (pdev->sriov->num_VFs != 0) { | 465 | dev_warn(&pdev->dev, "%d VFs already enabled. Disable before enabling %d VFs\n", |
483 | ret = pdev->driver->sriov_configure(pdev, 0); | 466 | pdev->sriov->num_VFs, num_vfs); |
484 | return ret ? ret : count; | 467 | return -EBUSY; |
485 | } else { | ||
486 | dev_warn(&pdev->dev, | ||
487 | "All VFs disabled; no disable action taken\n"); | ||
488 | return count; | ||
489 | } | ||
490 | } | 468 | } |
491 | 469 | ||
492 | dev_err(&pdev->dev, | 470 | ret = pdev->driver->sriov_configure(pdev, num_vfs); |
493 | "Invalid value for number of VFs to enable: %d\n", num_vfs); | 471 | if (ret < 0) |
472 | return ret; | ||
494 | 473 | ||
495 | return -EINVAL; | 474 | if (ret != num_vfs) |
475 | dev_warn(&pdev->dev, "%d VFs requested; only %d enabled\n", | ||
476 | num_vfs, ret); | ||
477 | |||
478 | return count; | ||
496 | } | 479 | } |
497 | 480 | ||
498 | static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs); | 481 | static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs); |