All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Wilcox <matthew@wil.cx>
To: Greg Kroah-Hartman <gregkh@suse.de>
Cc: linux-kernel@vger.kernel.org,
	Jesse Barnes <jbarnes@virtuousgeek.org>,
	linux-pci@vger.kernel.org
Subject: [PATCH 3/3] Expose MSI-X interrupts through a dynamically generated sysfs directory
Date: Mon, 19 Oct 2009 23:50:55 -0600	[thread overview]
Message-ID: <20091020055055.GF29158@parisc-linux.org> (raw)
In-Reply-To: <20091020054740.GC29158@parisc-linux.org>


From: Matthew Wilcox <willy@linux.intel.com>
Date: Mon, 19 Oct 2009 01:35:41 -0400
Subject: [PATCH 3/3] Expose MSI-X interrupts through a dynamically generated sysfs directory

Introduce the ability to dynamically generate the attributes (which are
then added to sysfs).  Add a user in the form of the PCI MSI code, which
was why I started on this in the first place.
---
 drivers/pci/msi.c     |   77 ++++++++++++++++++++++++++++++++++++++++++++++--
 fs/sysfs/group.c      |    7 ++++-
 include/linux/pci.h   |    2 +
 include/linux/sysfs.h |    9 ++++++
 4 files changed, 90 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index f9cf317..e0971e6 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -275,6 +275,9 @@ static void free_msi_irqs(struct pci_dev *dev)
 {
 	struct msi_desc *entry, *tmp;
 
+	if (dev->msix_dir.name)
+		sysfs_remove_group(&dev->dev.kobj, &dev->msix_dir);
+
 	list_for_each_entry(entry, &dev->msi_list, list) {
 		int i, nvec;
 		if (!entry->irq)
@@ -447,13 +450,12 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned pos,
 }
 
 static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
-				void __iomem *base, struct msix_entry *entries,
-				int nvec)
+				void __iomem *base, struct msix_entry *entries)
 {
 	struct msi_desc *entry;
 	int i;
 
-	for (i = 0; i < nvec; i++) {
+	for (i = 0; i < dev->nr_irqs; i++) {
 		entry = alloc_msi_entry(dev);
 		if (!entry) {
 			if (!i)
@@ -495,6 +497,64 @@ static void msix_program_entries(struct pci_dev *dev,
 	}
 }
 
+struct pci_msix_attribute {
+	struct device_attribute da;
+	unsigned irq;
+	char name[8];	/* current max is 5: "2047\0" */
+};
+
+static ssize_t
+pci_msix_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pci_msix_attribute *msix_attr;
+	msix_attr = container_of(attr, struct pci_msix_attribute, da);
+	return snprintf(buf, PAGE_SIZE, "%u\n", msix_attr->irq);
+}
+
+#define kobj_to_pci_dev(obj) to_pci_dev(container_of(obj, struct device, kobj))
+
+static int msix_populate(struct dentry *dentry, struct attribute_group *grp)
+{
+	struct pci_dev *pdev = container_of(grp, struct pci_dev, msix_dir);
+	unsigned i, nr_irqs = pdev->nr_irqs;
+	struct pci_msix_attribute *attr;
+	struct attribute **array;
+	struct msi_desc *desc;
+
+	array = kmalloc((nr_irqs + 1) * sizeof(void *), GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+	attr = kmalloc(nr_irqs * sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_irqs; i++)
+		array[i] = &attr[i].da.attr;
+	array[i] = NULL;
+	grp->attrs = array;
+
+	list_for_each_entry(desc, &pdev->msi_list, list) {
+		attr->irq = desc->irq;
+		snprintf(attr->name, sizeof(attr->name), "%u",
+						desc->msi_attrib.entry_nr);
+		attr->da.attr.name = (const char *)&attr->name;
+		attr->da.attr.mode = 0444;
+		attr->da.show = pci_msix_show;
+		attr++;
+	}
+
+	return sysfs_populate_group(dentry, grp);
+}
+
+static void msix_depopulate(struct dentry *dentry, struct attribute_group *grp)
+{
+	sysfs_depopulate_group(dentry, grp);
+
+	kfree(grp->attrs[0]);
+	kfree(grp->attrs);
+	grp->attrs = NULL;
+}
+
 /**
  * msix_capability_init - configure device's MSI-X capability
  * @dev: pointer to the pci_dev data structure of MSI-X device function
@@ -524,10 +584,19 @@ static int msix_capability_init(struct pci_dev *dev,
 	if (!base)
 		return -ENOMEM;
 
-	ret = msix_setup_entries(dev, pos, base, entries, nvec);
+	dev->nr_irqs = nvec;
+
+	dev->msix_dir.name = "irqs";
+	dev->msix_dir.populate = msix_populate;
+	dev->msix_dir.depopulate = msix_depopulate;
+	ret = sysfs_create_group(&dev->dev.kobj, &dev->msix_dir);
 	if (ret)
 		return ret;
 
+	ret = msix_setup_entries(dev, pos, base, entries);
+	if (ret)
+		goto error;
+
 	ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
 	if (ret)
 		goto error;
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 37ac584..c97139f 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -102,6 +102,8 @@ static
 int group_populate(struct dentry *dentry, struct sysfs_dirent *sd)
 {
 	struct attribute_group *grp = sd->s_dir.data;
+	if (grp->populate)
+		return grp->populate(dentry, grp);
 	return sysfs_populate_group(dentry, grp);
 }
 
@@ -109,7 +111,10 @@ static
 void group_depopulate(struct dentry *dentry, struct sysfs_dirent *sd)
 {
 	struct attribute_group *grp = sd->s_dir.data;
-	sysfs_depopulate_group(dentry, grp);
+	if (grp->depopulate)
+		grp->depopulate(dentry, grp);
+	else
+		sysfs_depopulate_group(dentry, grp);
 }
 
 static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f5c7cd3..47c7fc6 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -291,6 +291,8 @@ struct pci_dev {
 	struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
 #ifdef CONFIG_PCI_MSI
 	struct list_head msi_list;
+	struct attribute_group msix_dir;
+	unsigned short nr_irqs;
 #endif
 	struct pci_vpd *vpd;
 #ifdef CONFIG_PCI_IOV
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 9d68fed..cf9d200 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -19,6 +19,7 @@
 
 struct kobject;
 struct module;
+struct dentry;
 
 /* FIXME
  * The *owner field is no longer used.
@@ -36,6 +37,10 @@ struct attribute_group {
 	mode_t			(*is_visible)(struct kobject *,
 					      struct attribute *, int);
 	struct attribute	**attrs;
+	int			(*populate)(struct dentry *,
+						struct attribute_group *);
+	void			(*depopulate)(struct dentry *,
+						struct attribute_group *);
 };
 
 
@@ -115,6 +120,10 @@ int sysfs_update_group(struct kobject *kobj,
 		       const struct attribute_group *grp);
 void sysfs_remove_group(struct kobject *kobj,
 			const struct attribute_group *grp);
+int sysfs_populate_group(struct dentry *dentry,
+			const struct attribute_group *grp);
+void sysfs_depopulate_group(struct dentry *dentry,
+			const struct attribute_group *grp);
 int sysfs_add_file_to_group(struct kobject *kobj,
 			const struct attribute *attr, const char *group);
 void sysfs_remove_file_from_group(struct kobject *kobj,
-- 
1.6.3.3

-- 
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."

  parent reply	other threads:[~2009-10-20  5:50 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-20  5:47 [PATCH 0/3] Allow sysfs to be dynamically populated Matthew Wilcox
2009-10-20  5:49 ` [PATCH 1/3] Fix updating of named attribute groups Matthew Wilcox
2009-10-29 15:59   ` Tejun Heo
2009-10-29 16:19     ` Matthew Wilcox
2009-10-29 16:24       ` Tejun Heo
2009-10-20  5:50 ` [PATCH 2/3] Sysfs: Allow directories to be populated dynamically Matthew Wilcox
2009-10-29 16:20   ` Tejun Heo
2009-10-29 16:21     ` Matthew Wilcox
2009-10-29 16:28       ` Tejun Heo
2009-10-29 19:24         ` Matthew Wilcox
2009-10-30 10:17           ` Tejun Heo
2009-10-30 11:14             ` Matthew Wilcox
2009-10-30 16:06               ` Tejun Heo
2009-10-20  5:50 ` Matthew Wilcox [this message]
2009-10-20  8:14   ` [PATCH 3/3] Expose MSI-X interrupts through a dynamically generated sysfs directory Américo Wang
2009-10-20  8:26     ` Matthew Wilcox
2009-10-27 17:32       ` Greg KH
2009-10-20  5:52 ` [PATCH 0/3] Allow sysfs to be dynamically populated Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20091020055055.GF29158@parisc-linux.org \
    --to=matthew@wil.cx \
    --cc=gregkh@suse.de \
    --cc=jbarnes@virtuousgeek.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.