Skip to content

Commit

Permalink
Merge branch 'pci/don-sriov' into next
Browse files Browse the repository at this point in the history
* pci/don-sriov:
  PCI: Remove useless "!dev" tests
  PCI: Use spec names for SR-IOV capability fields
  PCI: Provide method to reduce the number of total VFs supported
  PCI: SRIOV control and status via sysfs
  PCI: Use is_visible() with boot_vga attribute for pci_dev
  PCI: Add pci_device_type to pdev's device struct
  • Loading branch information
Bjorn Helgaas committed Nov 13, 2012
2 parents 0dcccc5 + 1452cd7 commit f9c15b4
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 34 deletions.
87 changes: 67 additions & 20 deletions drivers/pci/iov.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
virtfn->resource[i].name = pci_name(virtfn);
virtfn->resource[i].flags = res->flags;
size = resource_size(res);
do_div(size, iov->total);
do_div(size, iov->total_VFs);
virtfn->resource[i].start = res->start + size * id;
virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
rc = request_resource(res, &virtfn->resource[i]);
Expand Down Expand Up @@ -194,7 +194,7 @@ static int sriov_migration(struct pci_dev *dev)
u16 status;
struct pci_sriov *iov = dev->sriov;

if (!iov->nr_virtfn)
if (!iov->num_VFs)
return 0;

if (!(iov->cap & PCI_SRIOV_CAP_VFM))
Expand All @@ -216,7 +216,7 @@ static void sriov_migration_task(struct work_struct *work)
u16 status;
struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask);

for (i = iov->initial; i < iov->nr_virtfn; i++) {
for (i = iov->initial_VFs; i < iov->num_VFs; i++) {
state = readb(iov->mstate + i);
if (state == PCI_SRIOV_VFM_MI) {
writeb(PCI_SRIOV_VFM_AV, iov->mstate + i);
Expand Down Expand Up @@ -244,7 +244,7 @@ static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn)
resource_size_t pa;
struct pci_sriov *iov = dev->sriov;

if (nr_virtfn <= iov->initial)
if (nr_virtfn <= iov->initial_VFs)
return 0;

pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table);
Expand Down Expand Up @@ -294,15 +294,15 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
if (!nr_virtfn)
return 0;

if (iov->nr_virtfn)
if (iov->num_VFs)
return -EINVAL;

pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial);
if (initial > iov->total ||
(!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total)))
if (initial > iov->total_VFs ||
(!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs)))
return -EIO;

if (nr_virtfn < 0 || nr_virtfn > iov->total ||
if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs ||
(!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
return -EINVAL;

Expand Down Expand Up @@ -359,7 +359,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
msleep(100);
pci_cfg_access_unlock(dev);

iov->initial = initial;
iov->initial_VFs = initial;
if (nr_virtfn < initial)
initial = nr_virtfn;

Expand All @@ -376,7 +376,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
}

kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
iov->nr_virtfn = nr_virtfn;
iov->num_VFs = nr_virtfn;

return 0;

Expand All @@ -401,13 +401,13 @@ static void sriov_disable(struct pci_dev *dev)
int i;
struct pci_sriov *iov = dev->sriov;

if (!iov->nr_virtfn)
if (!iov->num_VFs)
return;

if (iov->cap & PCI_SRIOV_CAP_VFM)
sriov_disable_migration(dev);

for (i = 0; i < iov->nr_virtfn; i++)
for (i = 0; i < iov->num_VFs; i++)
virtfn_remove(dev, i, 0);

iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
Expand All @@ -419,7 +419,7 @@ static void sriov_disable(struct pci_dev *dev)
if (iov->link != dev->devfn)
sysfs_remove_link(&dev->dev.kobj, "dep_link");

iov->nr_virtfn = 0;
iov->num_VFs = 0;
}

static int sriov_init(struct pci_dev *dev, int pos)
Expand Down Expand Up @@ -496,7 +496,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
iov->pos = pos;
iov->nres = nres;
iov->ctrl = ctrl;
iov->total = total;
iov->total_VFs = total;
iov->offset = offset;
iov->stride = stride;
iov->pgsz = pgsz;
Expand Down Expand Up @@ -529,7 +529,7 @@ static int sriov_init(struct pci_dev *dev, int pos)

static void sriov_release(struct pci_dev *dev)
{
BUG_ON(dev->sriov->nr_virtfn);
BUG_ON(dev->sriov->num_VFs);

if (dev != dev->sriov->dev)
pci_dev_put(dev->sriov->dev);
Expand All @@ -554,7 +554,7 @@ static void sriov_restore_state(struct pci_dev *dev)
pci_update_resource(dev, i);

pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->nr_virtfn);
pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->num_VFs);
pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
msleep(100);
Expand Down Expand Up @@ -661,7 +661,7 @@ int pci_iov_bus_range(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (!dev->is_physfn)
continue;
busnr = virtfn_bus(dev, dev->sriov->total - 1);
busnr = virtfn_bus(dev, dev->sriov->total_VFs - 1);
if (busnr > max)
max = busnr;
}
Expand Down Expand Up @@ -729,9 +729,56 @@ EXPORT_SYMBOL_GPL(pci_sriov_migration);
*/
int pci_num_vf(struct pci_dev *dev)
{
if (!dev || !dev->is_physfn)
if (!dev->is_physfn)
return 0;
else
return dev->sriov->nr_virtfn;

return dev->sriov->num_VFs;
}
EXPORT_SYMBOL_GPL(pci_num_vf);

/**
* pci_sriov_set_totalvfs -- reduce the TotalVFs available
* @dev: the PCI PF device
* numvfs: number that should be used for TotalVFs supported
*
* Should be called from PF driver's probe routine with
* device's mutex held.
*
* Returns 0 if PF is an SRIOV-capable device and
* value of numvfs valid. If not a PF with VFS, return -EINVAL;
* if VFs already enabled, return -EBUSY.
*/
int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
{
if (!dev->is_physfn || (numvfs > dev->sriov->total_VFs))
return -EINVAL;

/* Shouldn't change if VFs already enabled */
if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE)
return -EBUSY;
else
dev->sriov->driver_max_VFs = numvfs;

return 0;
}
EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs);

/**
* pci_sriov_get_totalvfs -- get total VFs supported on this devic3
* @dev: the PCI PF device
*
* For a PCIe device with SRIOV support, return the PCIe
* SRIOV capability value of TotalVFs or the value of driver_max_VFs
* if the driver reduced it. Otherwise, -EINVAL.
*/
int pci_sriov_get_totalvfs(struct pci_dev *dev)
{
if (!dev->is_physfn)
return -EINVAL;

if (dev->sriov->driver_max_VFs)
return dev->sriov->driver_max_VFs;

return dev->sriov->total_VFs;
}
EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs);
172 changes: 161 additions & 11 deletions drivers/pci/pci-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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", pci_sriov_get_totalvfs(pdev));
}


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->num_VFs);
}

/*
* 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 = pci_sriov_get_totalvfs(pdev);
/* Requested VFs to enable < totalvfs and none enabled already */
if ((num_vfs > 0) && (num_vfs <= total)) {
if (pdev->sriov->num_VFs == 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->num_VFs) {
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->num_VFs, num_vfs);
return -EINVAL;
}
}

/* disable vfs */
if (num_vfs == 0) {
if (pdev->sriov->num_VFs != 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),
Expand Down Expand Up @@ -1303,29 +1403,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);
Expand Down Expand Up @@ -1411,3 +1502,62 @@ 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;
}

#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,
};

static const struct attribute_group *pci_dev_attr_groups[] = {
&pci_dev_attr_group,
#ifdef CONFIG_PCI_IOV
&sriov_dev_attr_group,
#endif
NULL,
};

struct device_type pci_dev_type = {
.groups = pci_dev_attr_groups,
};
Loading

0 comments on commit f9c15b4

Please sign in to comment.