MSI: Export the PCI_BUS_FLAGS_NO_MSI flag in sysfs
authorBrice Goglin <brice@myri.com>
Thu, 31 Aug 2006 05:55:15 +0000 (01:55 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 27 Sep 2006 00:43:52 +0000 (17:43 -0700)
Export the PCI_BUS_FLAGS_NO_MSI flag of a PCI bus in the sysfs files
of its parent device and make it writable. Could be used to:
* disable MSI on a device which has not been blacklisted yet
* allow MSI when some setpci hacks enable MSI support (for instance
  on the ServerWorks HT2000 chipset where the MSI HT cap is disabled
  by default).
Architecture where some bus have no parent chipset cannot use this
strategy to change MSI support.

If the chipset does not have a subordinate bus, its 'bus_msi' file
is empty.

Also document and warn about the possible danger of changing the flag.

Signed-off-by: Brice Goglin <brice@myri.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/pci-sysfs.c

index fdefa7dcd15675758f31c3ce3ababd69368433d4..010e01c4bd4367d87d34f48800f50e026f97ea0d 100644 (file)
@@ -131,6 +131,46 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static ssize_t
+msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (!pdev->subordinate)
+               return 0;
+
+       return sprintf (buf, "%u\n",
+                       !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_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);
+
+       /* bad things may happen if the no_msi flag is changed
+        * while some drivers are loaded */
+       if (!capable(CAP_SYS_ADMIN))
+               return count;
+
+       if (!pdev->subordinate)
+               return count;
+
+       if (*buf == '0') {
+               pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+               dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"
+                        " bad things could happen.\n");
+       }
+
+       if (*buf == '1') {
+               pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
+               dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
+                        " bad things could happen.\n");
+       }
+
+       return count;
+}
 
 struct device_attribute pci_dev_attrs[] = {
        __ATTR_RO(resource),
@@ -145,6 +185,7 @@ struct device_attribute pci_dev_attrs[] = {
        __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
        __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
                broken_parity_status_show,broken_parity_status_store),
+       __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
        __ATTR_NULL,
 };