forked from Minki/linux
PCI/MSI: Add "msi_bus" sysfs MSI/MSI-X control for endpoints
The "msi_bus" sysfs file for bridges sets a bus flag to allow or disallow future driver requests for MSI or MSI-X. Previously, the sysfs file existed for endpoints but did nothing. Add "msi_bus" support for endpoints, so an administrator can prevent the use of MSI and MSI-X for individual devices. Note that as for bridges, these changes only affect future driver requests for MSI or MSI-X, so drivers may need to be reloaded. Add documentation for the "msi_bus" sysfs file. [bhelgaas: changelog, comments, add "subordinate", add endpoint printk, rework bus_flags setting, make bus_flags printk unconditional] Signed-off-by: Yijing Wang <wangyijing@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
48c3c38f00
commit
468ff15a3a
@ -65,6 +65,16 @@ Description:
|
||||
force a rescan of all PCI buses in the system, and
|
||||
re-discover previously removed devices.
|
||||
|
||||
What: /sys/bus/pci/devices/.../msi_bus
|
||||
Date: September 2014
|
||||
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
|
||||
Description:
|
||||
Writing a zero value to this attribute disallows MSI and
|
||||
MSI-X for any future drivers of the device. If the device
|
||||
is a bridge, MSI and MSI-X will be disallowed for future
|
||||
drivers of all child devices under the bridge. Drivers
|
||||
must be reloaded for the new setting to take effect.
|
||||
|
||||
What: /sys/bus/pci/devices/.../msi_irqs/
|
||||
Date: September, 2011
|
||||
Contact: Neil Horman <nhorman@tuxdriver.com>
|
||||
|
@ -250,46 +250,45 @@ static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct pci_bus *subordinate = pdev->subordinate;
|
||||
|
||||
if (!pdev->subordinate)
|
||||
return 0;
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
|
||||
return sprintf(buf, "%u\n", subordinate ?
|
||||
!(subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)
|
||||
: !pdev->no_msi);
|
||||
}
|
||||
|
||||
static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct pci_bus *subordinate = pdev->subordinate;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 0, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Bad things may happen if the no_msi flag is changed
|
||||
* while drivers are loaded.
|
||||
*/
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* Maybe devices without subordinate buses shouldn't have this
|
||||
* attribute in the first place?
|
||||
* "no_msi" and "bus_flags" only affect what happens when a driver
|
||||
* requests MSI or MSI-X. They don't affect any drivers that have
|
||||
* already requested MSI or MSI-X.
|
||||
*/
|
||||
if (!pdev->subordinate)
|
||||
if (!subordinate) {
|
||||
pdev->no_msi = !val;
|
||||
dev_info(&pdev->dev, "MSI/MSI-X %s for future drivers\n",
|
||||
val ? "allowed" : "disallowed");
|
||||
return count;
|
||||
|
||||
/* Is the flag going to change, or keep the value it already had? */
|
||||
if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^
|
||||
!!val) {
|
||||
pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI;
|
||||
|
||||
dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI, bad things could happen\n",
|
||||
val ? "" : " not");
|
||||
}
|
||||
|
||||
if (val)
|
||||
subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
|
||||
else
|
||||
subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
|
||||
|
||||
dev_info(&subordinate->dev, "MSI/MSI-X %s for future drivers of devices on this bus\n",
|
||||
val ? "allowed" : "disallowed");
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(msi_bus);
|
||||
|
Loading…
Reference in New Issue
Block a user