Merge branch 'pci/don-sriov' into next
* 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
This commit is contained in:
Коммит
f9c15b429a
|
@ -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]);
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -496,7 +496,7 @@ found:
|
|||
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;
|
||||
|
@ -529,7 +529,7 @@ failed:
|
|||
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -157,6 +157,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
|
|||
}
|
||||
extern struct device_attribute pci_dev_attrs[];
|
||||
extern struct device_attribute pcibus_dev_attrs[];
|
||||
extern struct device_type pci_dev_type;
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
extern struct bus_attribute pci_bus_attrs[];
|
||||
#else
|
||||
|
@ -232,13 +233,14 @@ struct pci_sriov {
|
|||
int nres; /* number of resources */
|
||||
u32 cap; /* SR-IOV Capabilities */
|
||||
u16 ctrl; /* SR-IOV Control */
|
||||
u16 total; /* total VFs associated with the PF */
|
||||
u16 initial; /* initial VFs associated with the PF */
|
||||
u16 nr_virtfn; /* number of VFs available */
|
||||
u16 total_VFs; /* total VFs associated with the PF */
|
||||
u16 initial_VFs; /* initial VFs associated with the PF */
|
||||
u16 num_VFs; /* number of VFs available */
|
||||
u16 offset; /* first VF Routing ID offset */
|
||||
u16 stride; /* following VF stride */
|
||||
u32 pgsz; /* page size for BAR alignment */
|
||||
u8 link; /* Function Dependency Link */
|
||||
u16 driver_max_VFs; /* max num VFs driver supports */
|
||||
struct pci_dev *dev; /* lowest numbered PF */
|
||||
struct pci_dev *self; /* this PF */
|
||||
struct mutex lock; /* lock for VF bus */
|
||||
|
|
|
@ -975,6 +975,7 @@ int pci_setup_device(struct pci_dev *dev)
|
|||
dev->sysdata = dev->bus->sysdata;
|
||||
dev->dev.parent = dev->bus->bridge;
|
||||
dev->dev.bus = &pci_bus_type;
|
||||
dev->dev.type = &pci_dev_type;
|
||||
dev->hdr_type = hdr_type & 0x7f;
|
||||
dev->multifunction = !!(hdr_type & 0x80);
|
||||
dev->error_state = pci_channel_io_normal;
|
||||
|
|
|
@ -573,6 +573,7 @@ struct pci_driver {
|
|||
int (*resume_early) (struct pci_dev *dev);
|
||||
int (*resume) (struct pci_dev *dev); /* Device woken up */
|
||||
void (*shutdown) (struct pci_dev *dev);
|
||||
int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */
|
||||
const struct pci_error_handlers *err_handler;
|
||||
struct device_driver driver;
|
||||
struct pci_dynids dynids;
|
||||
|
@ -1613,6 +1614,8 @@ extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
|
|||
extern void pci_disable_sriov(struct pci_dev *dev);
|
||||
extern irqreturn_t pci_sriov_migration(struct pci_dev *dev);
|
||||
extern int pci_num_vf(struct pci_dev *dev);
|
||||
extern int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
|
||||
extern int pci_sriov_get_totalvfs(struct pci_dev *dev);
|
||||
#else
|
||||
static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
|
||||
{
|
||||
|
@ -1629,6 +1632,14 @@ static inline int pci_num_vf(struct pci_dev *dev)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
|
||||
|
|
Загрузка…
Ссылка в новой задаче