genirq/msi: Move MSI sysfs handling from PCI to MSI core
authorBarry Song <song.bao.hua@hisilicon.com>
Fri, 13 Aug 2021 03:56:27 +0000 (15:56 +1200)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 24 Aug 2021 07:16:20 +0000 (09:16 +0200)
Move PCI's MSI sysfs code to the irq core so that other busses such as
platform can reuse it.

Signed-off-by: Barry Song <song.bao.hua@hisilicon.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210813035628.6844-2-21cnbao@gmail.com
drivers/pci/msi.c
include/linux/msi.h
kernel/irq/msi.c

index ce841f3..6eb0ae3 100644 (file)
@@ -363,9 +363,7 @@ static void free_msi_irqs(struct pci_dev *dev)
 {
        struct list_head *msi_list = dev_to_msi_list(&dev->dev);
        struct msi_desc *entry, *tmp;
-       struct attribute **msi_attrs;
-       struct device_attribute *dev_attr;
-       int i, count = 0;
+       int i;
 
        for_each_pci_msi_entry(entry, dev)
                if (entry->irq)
@@ -385,18 +383,7 @@ static void free_msi_irqs(struct pci_dev *dev)
        }
 
        if (dev->msi_irq_groups) {
-               sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups);
-               msi_attrs = dev->msi_irq_groups[0]->attrs;
-               while (msi_attrs[count]) {
-                       dev_attr = container_of(msi_attrs[count],
-                                               struct device_attribute, attr);
-                       kfree(dev_attr->attr.name);
-                       kfree(dev_attr);
-                       ++count;
-               }
-               kfree(msi_attrs);
-               kfree(dev->msi_irq_groups[0]);
-               kfree(dev->msi_irq_groups);
+               msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
                dev->msi_irq_groups = NULL;
        }
 }
@@ -476,102 +463,6 @@ void pci_restore_msi_state(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_restore_msi_state);
 
-static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr,
-                            char *buf)
-{
-       struct msi_desc *entry;
-       unsigned long irq;
-       int retval;
-
-       retval = kstrtoul(attr->attr.name, 10, &irq);
-       if (retval)
-               return retval;
-
-       entry = irq_get_msi_desc(irq);
-       if (!entry)
-               return -ENODEV;
-
-       return sysfs_emit(buf, "%s\n",
-                         entry->msi_attrib.is_msix ? "msix" : "msi");
-}
-
-static int populate_msi_sysfs(struct pci_dev *pdev)
-{
-       struct attribute **msi_attrs;
-       struct attribute *msi_attr;
-       struct device_attribute *msi_dev_attr;
-       struct attribute_group *msi_irq_group;
-       const struct attribute_group **msi_irq_groups;
-       struct msi_desc *entry;
-       int ret = -ENOMEM;
-       int num_msi = 0;
-       int count = 0;
-       int i;
-
-       /* Determine how many msi entries we have */
-       for_each_pci_msi_entry(entry, pdev)
-               num_msi += entry->nvec_used;
-       if (!num_msi)
-               return 0;
-
-       /* Dynamically create the MSI attributes for the PCI device */
-       msi_attrs = kcalloc(num_msi + 1, sizeof(void *), GFP_KERNEL);
-       if (!msi_attrs)
-               return -ENOMEM;
-       for_each_pci_msi_entry(entry, pdev) {
-               for (i = 0; i < entry->nvec_used; i++) {
-                       msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
-                       if (!msi_dev_attr)
-                               goto error_attrs;
-                       msi_attrs[count] = &msi_dev_attr->attr;
-
-                       sysfs_attr_init(&msi_dev_attr->attr);
-                       msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d",
-                                                           entry->irq + i);
-                       if (!msi_dev_attr->attr.name)
-                               goto error_attrs;
-                       msi_dev_attr->attr.mode = S_IRUGO;
-                       msi_dev_attr->show = msi_mode_show;
-                       ++count;
-               }
-       }
-
-       msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL);
-       if (!msi_irq_group)
-               goto error_attrs;
-       msi_irq_group->name = "msi_irqs";
-       msi_irq_group->attrs = msi_attrs;
-
-       msi_irq_groups = kcalloc(2, sizeof(void *), GFP_KERNEL);
-       if (!msi_irq_groups)
-               goto error_irq_group;
-       msi_irq_groups[0] = msi_irq_group;
-
-       ret = sysfs_create_groups(&pdev->dev.kobj, msi_irq_groups);
-       if (ret)
-               goto error_irq_groups;
-       pdev->msi_irq_groups = msi_irq_groups;
-
-       return 0;
-
-error_irq_groups:
-       kfree(msi_irq_groups);
-error_irq_group:
-       kfree(msi_irq_group);
-error_attrs:
-       count = 0;
-       msi_attr = msi_attrs[count];
-       while (msi_attr) {
-               msi_dev_attr = container_of(msi_attr, struct device_attribute, attr);
-               kfree(msi_attr->name);
-               kfree(msi_dev_attr);
-               ++count;
-               msi_attr = msi_attrs[count];
-       }
-       kfree(msi_attrs);
-       return ret;
-}
-
 static struct msi_desc *
 msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
 {
@@ -667,9 +558,11 @@ static int msi_capability_init(struct pci_dev *dev, int nvec,
        if (ret)
                goto err;
 
-       ret = populate_msi_sysfs(dev);
-       if (ret)
+       dev->msi_irq_groups = msi_populate_sysfs(&dev->dev);
+       if (IS_ERR(dev->msi_irq_groups)) {
+               ret = PTR_ERR(dev->msi_irq_groups);
                goto err;
+       }
 
        /* Set MSI enabled bits */
        pci_intx_for_msi(dev, 0);
@@ -834,9 +727,11 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
 
        msix_update_entries(dev, entries);
 
-       ret = populate_msi_sysfs(dev);
-       if (ret)
+       dev->msi_irq_groups = msi_populate_sysfs(&dev->dev);
+       if (IS_ERR(dev->msi_irq_groups)) {
+               ret = PTR_ERR(dev->msi_irq_groups);
                goto out_free;
+       }
 
        /* Set MSI-X enabled bits and unmask the function */
        pci_intx_for_msi(dev, 0);
index a20dc66..49cf6eb 100644 (file)
@@ -239,6 +239,10 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 void pci_msi_mask_irq(struct irq_data *data);
 void pci_msi_unmask_irq(struct irq_data *data);
 
+const struct attribute_group **msi_populate_sysfs(struct device *dev);
+void msi_destroy_sysfs(struct device *dev,
+                      const struct attribute_group **msi_irq_groups);
+
 /*
  * The arch hooks to setup up msi irqs. Default functions are implemented
  * as weak symbols so that they /can/ be overriden by architecture specific
index bb18040..48ef144 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/irqdomain.h>
 #include <linux/msi.h>
 #include <linux/slab.h>
+#include <linux/pci.h>
 
 #include "internals.h"
 
@@ -71,6 +72,139 @@ void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
 }
 EXPORT_SYMBOL_GPL(get_cached_msi_msg);
 
+static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct msi_desc *entry;
+       bool is_msix = false;
+       unsigned long irq;
+       int retval;
+
+       retval = kstrtoul(attr->attr.name, 10, &irq);
+       if (retval)
+               return retval;
+
+       entry = irq_get_msi_desc(irq);
+       if (!entry)
+               return -ENODEV;
+
+       if (dev_is_pci(dev))
+               is_msix = entry->msi_attrib.is_msix;
+
+       return sysfs_emit(buf, "%s\n", is_msix ? "msix" : "msi");
+}
+
+/**
+ * msi_populate_sysfs - Populate msi_irqs sysfs entries for devices
+ * @dev:       The device(PCI, platform etc) who will get sysfs entries
+ *
+ * Return attribute_group ** so that specific bus MSI can save it to
+ * somewhere during initilizing msi irqs. If devices has no MSI irq,
+ * return NULL; if it fails to populate sysfs, return ERR_PTR
+ */
+const struct attribute_group **msi_populate_sysfs(struct device *dev)
+{
+       const struct attribute_group **msi_irq_groups;
+       struct attribute **msi_attrs, *msi_attr;
+       struct device_attribute *msi_dev_attr;
+       struct attribute_group *msi_irq_group;
+       struct msi_desc *entry;
+       int ret = -ENOMEM;
+       int num_msi = 0;
+       int count = 0;
+       int i;
+
+       /* Determine how many msi entries we have */
+       for_each_msi_entry(entry, dev)
+               num_msi += entry->nvec_used;
+       if (!num_msi)
+               return NULL;
+
+       /* Dynamically create the MSI attributes for the device */
+       msi_attrs = kcalloc(num_msi + 1, sizeof(void *), GFP_KERNEL);
+       if (!msi_attrs)
+               return ERR_PTR(-ENOMEM);
+
+       for_each_msi_entry(entry, dev) {
+               for (i = 0; i < entry->nvec_used; i++) {
+                       msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
+                       if (!msi_dev_attr)
+                               goto error_attrs;
+                       msi_attrs[count] = &msi_dev_attr->attr;
+
+                       sysfs_attr_init(&msi_dev_attr->attr);
+                       msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d",
+                                                           entry->irq + i);
+                       if (!msi_dev_attr->attr.name)
+                               goto error_attrs;
+                       msi_dev_attr->attr.mode = 0444;
+                       msi_dev_attr->show = msi_mode_show;
+                       ++count;
+               }
+       }
+
+       msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL);
+       if (!msi_irq_group)
+               goto error_attrs;
+       msi_irq_group->name = "msi_irqs";
+       msi_irq_group->attrs = msi_attrs;
+
+       msi_irq_groups = kcalloc(2, sizeof(void *), GFP_KERNEL);
+       if (!msi_irq_groups)
+               goto error_irq_group;
+       msi_irq_groups[0] = msi_irq_group;
+
+       ret = sysfs_create_groups(&dev->kobj, msi_irq_groups);
+       if (ret)
+               goto error_irq_groups;
+
+       return msi_irq_groups;
+
+error_irq_groups:
+       kfree(msi_irq_groups);
+error_irq_group:
+       kfree(msi_irq_group);
+error_attrs:
+       count = 0;
+       msi_attr = msi_attrs[count];
+       while (msi_attr) {
+               msi_dev_attr = container_of(msi_attr, struct device_attribute, attr);
+               kfree(msi_attr->name);
+               kfree(msi_dev_attr);
+               ++count;
+               msi_attr = msi_attrs[count];
+       }
+       kfree(msi_attrs);
+       return ERR_PTR(ret);
+}
+
+/**
+ * msi_destroy_sysfs - Destroy msi_irqs sysfs entries for devices
+ * @dev:               The device(PCI, platform etc) who will remove sysfs entries
+ * @msi_irq_groups:    attribute_group for device msi_irqs entries
+ */
+void msi_destroy_sysfs(struct device *dev, const struct attribute_group **msi_irq_groups)
+{
+       struct device_attribute *dev_attr;
+       struct attribute **msi_attrs;
+       int count = 0;
+
+       if (msi_irq_groups) {
+               sysfs_remove_groups(&dev->kobj, msi_irq_groups);
+               msi_attrs = msi_irq_groups[0]->attrs;
+               while (msi_attrs[count]) {
+                       dev_attr = container_of(msi_attrs[count],
+                                       struct device_attribute, attr);
+                       kfree(dev_attr->attr.name);
+                       kfree(dev_attr);
+                       ++count;
+               }
+               kfree(msi_attrs);
+               kfree(msi_irq_groups[0]);
+               kfree(msi_irq_groups);
+       }
+}
+
 #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
 static inline void irq_chip_write_msi_msg(struct irq_data *data,
                                          struct msi_msg *msg)