From 4e15c46bdc4d5ea0e7991a05edbd807328d38a2c Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 5 Nov 2012 15:20:34 -0500 Subject: PCI: Add pci_device_type to pdev's device struct Need type filled in device structure so it can be used for visible attribute control in sysfs for pci_dev. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/pci/pci-sysfs.c') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 02d107b15281..3d160aa608c1 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1411,3 +1411,27 @@ static int __init pci_sysfs_init(void) } late_initcall(pci_sysfs_init); + +static struct attribute *pci_dev_dev_attrs[] = { + NULL, +}; + +static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + return a->mode; +} + +static struct attribute_group pci_dev_attr_group = { + .attrs = pci_dev_dev_attrs, + .is_visible = pci_dev_attrs_are_visible, +}; + +static const struct attribute_group *pci_dev_attr_groups[] = { + &pci_dev_attr_group, + NULL, +}; + +struct device_type pci_dev_type = { + .groups = pci_dev_attr_groups, +}; -- cgit v1.2.3 From 625e1d59a89f50bace376f429d8cf50347af75f7 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 5 Nov 2012 15:20:35 -0500 Subject: PCI: Use is_visible() with boot_vga attribute for pci_dev Should make pci_create_sysfs_dev_files() simpler. Also fix possible memleak in remove path. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/pci/pci-sysfs.c') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 3d160aa608c1..fbbb97f28259 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1303,29 +1303,20 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) pdev->rom_attr = attr; } - if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - retval = device_create_file(&pdev->dev, &vga_attr); - if (retval) - goto err_rom_file; - } - /* add platform-specific attributes */ retval = pcibios_add_platform_entries(pdev); if (retval) - goto err_vga_file; + goto err_rom_file; /* add sysfs entries for various capabilities */ retval = pci_create_capabilities_sysfs(pdev); if (retval) - goto err_vga_file; + goto err_rom_file; pci_create_firmware_label_files(pdev); return 0; -err_vga_file: - if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) - device_remove_file(&pdev->dev, &vga_attr); err_rom_file: if (rom_size) { sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); @@ -1413,12 +1404,20 @@ static int __init pci_sysfs_init(void) late_initcall(pci_sysfs_init); static struct attribute *pci_dev_dev_attrs[] = { + &vga_attr.attr, NULL, }; static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { + struct device *dev = container_of(kobj, struct device, kobj); + struct pci_dev *pdev = to_pci_dev(dev); + + if (a == &vga_attr.attr) + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return 0; + return a->mode; } -- cgit v1.2.3 From 1789382a72a537447d65ea4131d8bcc1ad85ce7b Mon Sep 17 00:00:00 2001 From: Donald Dutile Date: Mon, 5 Nov 2012 15:20:36 -0500 Subject: 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 Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'drivers/pci/pci-sysfs.c') 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, } #endif +#ifdef CONFIG_PCI_IOV +static ssize_t sriov_totalvfs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%u\n", pdev->sriov->total); +} + + +static ssize_t sriov_numvfs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%u\n", pdev->sriov->nr_virtfn); +} + +/* + * num_vfs > 0; number of vfs to enable + * num_vfs = 0; disable all vfs + * + * Note: SRIOV spec doesn't allow partial VF + * disable, so its all or none. + */ +static ssize_t sriov_numvfs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int num_vfs_enabled = 0; + int num_vfs; + int ret = 0; + u16 total; + + if (kstrtoint(buf, 0, &num_vfs) < 0) + return -EINVAL; + + /* is PF driver loaded w/callback */ + if (!pdev->driver || !pdev->driver->sriov_configure) { + dev_info(&pdev->dev, + "Driver doesn't support SRIOV configuration via sysfs\n"); + return -ENOSYS; + } + + /* if enabling vf's ... */ + total = pdev->sriov->total; + /* Requested VFs to enable < totalvfs and none enabled already */ + if ((num_vfs > 0) && (num_vfs <= total)) { + if (pdev->sriov->nr_virtfn == 0) { + num_vfs_enabled = + pdev->driver->sriov_configure(pdev, num_vfs); + if ((num_vfs_enabled >= 0) && + (num_vfs_enabled != num_vfs)) { + dev_warn(&pdev->dev, + "Only %d VFs enabled\n", + num_vfs_enabled); + return count; + } else if (num_vfs_enabled < 0) + /* error code from driver callback */ + return num_vfs_enabled; + } else if (num_vfs == pdev->sriov->nr_virtfn) { + dev_warn(&pdev->dev, + "%d VFs already enabled; no enable action taken\n", + num_vfs); + return count; + } else { + dev_warn(&pdev->dev, + "%d VFs already enabled. Disable before enabling %d VFs\n", + pdev->sriov->nr_virtfn, num_vfs); + return -EINVAL; + } + } + + /* disable vfs */ + if (num_vfs == 0) { + if (pdev->sriov->nr_virtfn != 0) { + ret = pdev->driver->sriov_configure(pdev, 0); + return ret ? ret : count; + } else { + dev_warn(&pdev->dev, + "All VFs disabled; no disable action taken\n"); + return count; + } + } + + dev_err(&pdev->dev, + "Invalid value for number of VFs to enable: %d\n", num_vfs); + + return -EINVAL; +} + +static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs); +static struct device_attribute sriov_numvfs_attr = + __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP), + sriov_numvfs_show, sriov_numvfs_store); +#endif /* CONFIG_PCI_IOV */ + struct device_attribute pci_dev_attrs[] = { __ATTR_RO(resource), __ATTR_RO(vendor), @@ -1421,6 +1521,30 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, return a->mode; } +#ifdef CONFIG_PCI_IOV +static struct attribute *sriov_dev_attrs[] = { + &sriov_totalvfs_attr.attr, + &sriov_numvfs_attr.attr, + NULL, +}; + +static umode_t sriov_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + + if (!dev_is_pf(dev)) + return 0; + + return a->mode; +} + +static struct attribute_group sriov_dev_attr_group = { + .attrs = sriov_dev_attrs, + .is_visible = sriov_attrs_are_visible, +}; +#endif /* CONFIG_PCI_IOV */ + static struct attribute_group pci_dev_attr_group = { .attrs = pci_dev_dev_attrs, .is_visible = pci_dev_attrs_are_visible, @@ -1428,6 +1552,9 @@ static struct attribute_group pci_dev_attr_group = { static const struct attribute_group *pci_dev_attr_groups[] = { &pci_dev_attr_group, +#ifdef CONFIG_PCI_IOV + &sriov_dev_attr_group, +#endif NULL, }; -- cgit v1.2.3 From bff73156d3ad661655e6d9ef04c2284cf3abb0f1 Mon Sep 17 00:00:00 2001 From: Donald Dutile Date: Mon, 5 Nov 2012 15:20:37 -0500 Subject: PCI: Provide method to reduce the number of total VFs supported Some implementations of SRIOV provide a capability structure value of TotalVFs that is greater than what the software can support. Provide a method to reduce the capability structure reported value to the value the driver can support. This ensures sysfs reports the current capability of the system, hardware and software. Example for its use: igb & ixgbe -- report 8 & 64 as TotalVFs, but drivers only support 7 & 63 maximum. Signed-off-by: Donald Dutile Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/pci-sysfs.c') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 74508c63bd47..99b5f83d2468 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -411,7 +411,7 @@ static ssize_t sriov_totalvfs_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->total); + return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); } @@ -452,7 +452,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, } /* if enabling vf's ... */ - total = pdev->sriov->total; + total = pci_sriov_get_totalvfs(pdev); /* Requested VFs to enable < totalvfs and none enabled already */ if ((num_vfs > 0) && (num_vfs <= total)) { if (pdev->sriov->nr_virtfn == 0) { -- cgit v1.2.3 From 6b136724691a6f247ada0c6a5f02370ed46de9f4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 9 Nov 2012 20:27:53 -0700 Subject: PCI: Use spec names for SR-IOV capability fields Use the same names (almost) as the spec for TotalVFs, InitialVFs, NumVFs. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/pci/pci-sysfs.c') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 99b5f83d2468..2f21991b8bcd 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -421,7 +421,7 @@ static ssize_t sriov_numvfs_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->nr_virtfn); + return sprintf(buf, "%u\n", pdev->sriov->num_VFs); } /* @@ -455,7 +455,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, total = pci_sriov_get_totalvfs(pdev); /* Requested VFs to enable < totalvfs and none enabled already */ if ((num_vfs > 0) && (num_vfs <= total)) { - if (pdev->sriov->nr_virtfn == 0) { + if (pdev->sriov->num_VFs == 0) { num_vfs_enabled = pdev->driver->sriov_configure(pdev, num_vfs); if ((num_vfs_enabled >= 0) && @@ -467,7 +467,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, } else if (num_vfs_enabled < 0) /* error code from driver callback */ return num_vfs_enabled; - } else if (num_vfs == pdev->sriov->nr_virtfn) { + } else if (num_vfs == pdev->sriov->num_VFs) { dev_warn(&pdev->dev, "%d VFs already enabled; no enable action taken\n", num_vfs); @@ -475,14 +475,14 @@ static ssize_t sriov_numvfs_store(struct device *dev, } else { dev_warn(&pdev->dev, "%d VFs already enabled. Disable before enabling %d VFs\n", - pdev->sriov->nr_virtfn, num_vfs); + pdev->sriov->num_VFs, num_vfs); return -EINVAL; } } /* disable vfs */ if (num_vfs == 0) { - if (pdev->sriov->nr_virtfn != 0) { + if (pdev->sriov->num_VFs != 0) { ret = pdev->driver->sriov_configure(pdev, 0); return ret ? ret : count; } else { -- cgit v1.2.3