Re: [RFC][PATCH] Add sysfs entry that displays MSI-X IRQs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I've made quite a few changes again, got rid of the kobject and used
an attribute group. I also tried your tests Matthew and didn't oops
on either of them. I also wrote some code that open()'ed the file then
continuously read() from the file while I rmmod'ed the driver. After
the driver was removed the read() call was returning bad file
descriptor errors until I modprobe'ed the driver back in. I ran that
test for about 1 hour and the behaviour was the same each time.



Thanks,


-- Vinnie
>From 96ce20b78031515274f6f6e67fc02110bd94f15f Mon Sep 17 00:00:00 2001
From: Vincent Rizza <vinnie@xxxxxxx>
Date: Thu, 13 Nov 2008 10:27:33 +1100
Subject: [PATCH] Add sysfs entry that displays MSI-X IRQs

Creates a sysfs entry for each MSI-X IRQ. The name of the entry is
based on the entry_nr attribute in msi_desc.msi_attrib. The file
contains the MSI-X IRQ number corresponding to that entry_nr value.

Signed-off-by: Vincent Rizza <vinnie@xxxxxxx>
Signed-off-by: Brett Grandbois <brettg@xxxxxxx>
---
 Documentation/ABI/testing/sysfs-bus-pci |   10 +++++
 drivers/pci/msi.c                       |   60 +++++++++++++++++++++++++++++++
 include/linux/msi.h                     |    5 +++
 include/linux/pci.h                     |    2 +
 4 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index ceddcff..9b868d4 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -9,3 +9,13 @@ Description:
 		that some devices may have malformatted data.  If the
 		underlying VPD has a writable section then the
 		corresponding section of this file will be writable.
+
+What:		/sys/bus/pci/devices/.../irqs/<MSI-X entry_nr>
+Date:		November 2008
+Contact:	Vincent Rizza <vinnie@xxxxxxx>
+Description:
+		If a pci device uses any MSI-X IRQs a new directory is
+		created called "irqs". The directory contains a file for
+		each MSI-X IRQ used. The filename is the number stored
+		in msi_desc.msi_attrib.entry_nr. The files contain the
+		MSI-X IRQ corresponding to their entry_nr number.
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 74801f7..58991dc 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -25,6 +25,28 @@
 
 static int pci_msi_enable = 1;
 
+static ssize_t
+pci_msix_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct msi_desc *entry;
+	unsigned long msi_index;
+	int ret = 0;
+
+	ret = strict_strtoul(attr->attr.name, 10, &msi_index);
+	if (!ret) {
+		list_for_each_entry(entry, &pdev->msi_list, list) {
+			if (entry->msi_attrib.entry_nr == msi_index) {
+				ret = snprintf(buf, PAGE_SIZE, "%d\n",
+					       entry->irq);
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
 /* Arch hooks */
 
 int __attribute__ ((weak))
@@ -494,6 +516,37 @@ static int msix_capability_init(struct pci_dev *dev,
 		set_irq_msi(entry->irq, entry);
 		i++;
 	}
+
+	dev->msix_dir.attrs = kzalloc(sizeof(struct attribute *) * (i + 1),
+				      GFP_KERNEL);
+	if (!dev->msix_dir.attrs) {
+		msi_free_irqs(dev);
+		return -ENOMEM;
+	}
+
+	i = 0;
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		snprintf(entry->msix_fname, sizeof(entry->msix_fname), "%d",
+			 entry->msi_attrib.entry_nr);
+		entry->sysfs_entry.attr.name = (const char *) entry->msix_fname;
+		entry->sysfs_entry.attr.mode = 0444;
+		entry->sysfs_entry.show = pci_msix_show;
+
+		dev->msix_dir.attrs[i] = &entry->sysfs_entry.attr;
+		i++;
+	}
+	/* NULL terminate to mark end of array */
+	dev->msix_dir.attrs[i] = NULL;
+
+	snprintf(dev->msix_gname, sizeof(dev->msix_gname), "%s", "irqs");
+	dev->msix_dir.name = (const char *) dev->msix_gname;
+	ret = sysfs_create_group(&dev->dev.kobj, &dev->msix_dir);
+	if (ret) {
+		dev->msix_dir.name = NULL;
+		msi_free_irqs(dev);
+		return ret;
+	}
+
 	/* Set MSI-X enabled bits */
 	pci_intx_for_msi(dev, 0);
 	msix_set_enable(dev, 1);
@@ -625,6 +678,13 @@ static int msi_free_irqs(struct pci_dev* dev)
 {
 	struct msi_desc *entry, *tmp;
 
+	if (dev->msix_dir.attrs) {
+		if (dev->msix_dir.name)
+			sysfs_remove_group(&dev->dev.kobj, &dev->msix_dir);
+
+		kfree(dev->msix_dir.attrs);
+	}
+
 	list_for_each_entry(entry, &dev->msi_list, list) {
 		if (entry->irq)
 			BUG_ON(irq_has_action(entry->irq));
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 8f29392..9de7d9d 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -2,6 +2,7 @@
 #define LINUX_MSI_H
 
 #include <linux/list.h>
+#include <linux/device.h>
 
 struct msi_msg {
 	u32	address_lo;	/* low 32 bits of msi message address */
@@ -33,6 +34,10 @@ struct msi_desc {
 	void __iomem *mask_base;
 	struct pci_dev *dev;
 
+	struct device_attribute sysfs_entry;
+	/* filename = IRQ */
+	char msix_fname[16];
+
 	/* Last set MSI message */
 	struct msi_msg msg;
 };
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c75b82b..6b5e393 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -234,6 +234,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;
+	char msix_gname[8];
 #endif
 	struct pci_vpd *vpd;
 };
-- 
1.5.4.5


[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux