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