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 some more changes based on the feedback. I figured if the
sysfs entries were removed before the msi_desc structs were deleted
from msi_list then we wouldn't have to worry about synchronization.
How does it look? What's the decision on the directory name?


Thanks,


-- Vinnie
>From 89928bd9145228ed7691c593b4f0369dd12b3929 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 vector. The name of the entry is
based on the entry_nr attribute in msi_desc.msi_attrib. The file
contains the MSI-X vector number corresponding to that entry_nr value.

Signed-off-by: Vincent Rizza <vinnie@xxxxxxx>
Signed-off-by: Brett Grandbois <brettg@xxxxxxx>
Signed-off-by: Ken Sandars <ksandars@xxxxxxx>
---
 Documentation/ABI/testing/sysfs-bus-pci |   10 +++++
 drivers/pci/msi.c                       |   62 +++++++++++++++++++++++++++++++
 include/linux/msi.h                     |    4 ++
 include/linux/pci.h                     |    1 +
 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..9941233 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/.../msix_irq/<IRQ vector number>
+Date:		November 2008
+Contact:	Vincent Rizza <vinnie@xxxxxxx>
+Description:
+		If a pci device uses any MSI-X IRQs a new directory
+		is created called "msix_irq". 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 vector corresponding to their entry_nr number.
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 74801f7..c2c43df 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -25,6 +25,31 @@
 
 static int pci_msi_enable = 1;
 
+static ssize_t
+pci_msix_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	/* kobj = msix_dir. The parent kobj is needed to get pci_dev */
+	struct kobject *p_kobj = kobj->parent;
+	struct pci_dev *pdev = to_pci_dev(container_of(p_kobj, struct device,
+					  kobj));
+	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))
@@ -488,10 +513,32 @@ static int msix_capability_init(struct pci_dev *dev,
 		return avail;
 	}
 
+	/* create directory "msix_irq" */
+	dev->msix_dir = kobject_create_and_add("msix_irq", &dev->dev.kobj);
+	if (!dev->msix_dir) {
+		msi_free_irqs(dev);
+		return -ENOMEM;
+	}
+
 	i = 0;
 	list_for_each_entry(entry, &dev->msi_list, list) {
 		entries[i].vector = entry->irq;
 		set_irq_msi(entry->irq, entry);
+
+		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;
+
+		ret = sysfs_create_file(dev->msix_dir,
+					&entry->sysfs_entry.attr);
+		if (ret) {
+			/* Using name as a flag during clean-up */
+			entry->sysfs_entry.attr.name = NULL;
+			msi_free_irqs(dev);
+			return ret;
+		}
 		i++;
 	}
 	/* Set MSI-X enabled bits */
@@ -628,6 +675,14 @@ static int msi_free_irqs(struct pci_dev* dev)
 	list_for_each_entry(entry, &dev->msi_list, list) {
 		if (entry->irq)
 			BUG_ON(irq_has_action(entry->irq));
+		/*
+		 *  Only remove if it's been created. If the attribute's name is
+		 *  set then this particular "entry" corresponds to a sysfs
+		 *  file.
+		 */
+		if (entry->sysfs_entry.attr.name)
+			sysfs_remove_file(&dev->dev.kobj,
+					  &entry->sysfs_entry.attr);
 	}
 
 	arch_teardown_msi_irqs(dev);
@@ -645,6 +700,13 @@ static int msi_free_irqs(struct pci_dev* dev)
 		kfree(entry);
 	}
 
+	/* Also doesn't exist in MSI mode */
+	if (dev->msix_dir) {
+		sysfs_remove_dir(dev->msix_dir);
+		kobject_put(dev->msix_dir);
+		dev->msix_dir = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 8f29392..242e068 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -33,6 +33,10 @@ struct msi_desc {
 	void __iomem *mask_base;
 	struct pci_dev *dev;
 
+	struct kobj_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..6b818f7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -234,6 +234,7 @@ 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 kobject *msix_dir;
 #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