Commit b50cac55bf859d5b2fdcc1803a553a251b703456

Authored by Neil Horman
Committed by Jesse Barnes
1 parent 8e8da023f5

PCI/sysfs: add per pci device msi[x] irq listing (v5)

This patch adds a per-pci-device subdirectory in sysfs called:
/sys/bus/pci/devices/<device>/msi_irqs

This sub-directory exports the set of msi vectors allocated by a given
pci device, by creating a numbered sub-directory for each vector beneath
msi_irqs.  For each vector various attributes can be exported.
Currently the only attribute is called mode, which tracks the
operational mode of that vector (msi vs. msix)

Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

Showing 4 changed files with 133 additions and 0 deletions Side-by-side Diff

Documentation/ABI/testing/sysfs-bus-pci
... ... @@ -66,6 +66,24 @@
66 66 re-discover previously removed devices.
67 67 Depends on CONFIG_HOTPLUG.
68 68  
  69 +What: /sys/bus/pci/devices/.../msi_irqs/
  70 +Date: September, 2011
  71 +Contact: Neil Horman <nhorman@tuxdriver.com>
  72 +Description:
  73 + The /sys/devices/.../msi_irqs directory contains a variable set
  74 + of sub-directories, with each sub-directory being named after a
  75 + corresponding msi irq vector allocated to that device. Each
  76 + numbered sub-directory N contains attributes of that irq.
  77 + Note that this directory is not created for device drivers which
  78 + do not support msi irqs
  79 +
  80 +What: /sys/bus/pci/devices/.../msi_irqs/<N>/mode
  81 +Date: September 2011
  82 +Contact: Neil Horman <nhorman@tuxdriver.com>
  83 +Description:
  84 + This attribute indicates the mode that the irq vector named by
  85 + the parent directory is in (msi vs. msix)
  86 +
69 87 What: /sys/bus/pci/devices/.../remove
70 88 Date: January 2009
71 89 Contact: Linux PCI developers <linux-pci@vger.kernel.org>
... ... @@ -323,6 +323,8 @@
323 323 if (list_is_last(&entry->list, &dev->msi_list))
324 324 iounmap(entry->mask_base);
325 325 }
  326 + kobject_del(&entry->kobj);
  327 + kobject_put(&entry->kobj);
326 328 list_del(&entry->list);
327 329 kfree(entry);
328 330 }
... ... @@ -403,6 +405,98 @@
403 405 }
404 406 EXPORT_SYMBOL_GPL(pci_restore_msi_state);
405 407  
  408 +
  409 +#define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr)
  410 +#define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj)
  411 +
  412 +struct msi_attribute {
  413 + struct attribute attr;
  414 + ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr,
  415 + char *buf);
  416 + ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr,
  417 + const char *buf, size_t count);
  418 +};
  419 +
  420 +static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr,
  421 + char *buf)
  422 +{
  423 + return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi");
  424 +}
  425 +
  426 +static ssize_t msi_irq_attr_show(struct kobject *kobj,
  427 + struct attribute *attr, char *buf)
  428 +{
  429 + struct msi_attribute *attribute = to_msi_attr(attr);
  430 + struct msi_desc *entry = to_msi_desc(kobj);
  431 +
  432 + if (!attribute->show)
  433 + return -EIO;
  434 +
  435 + return attribute->show(entry, attribute, buf);
  436 +}
  437 +
  438 +static const struct sysfs_ops msi_irq_sysfs_ops = {
  439 + .show = msi_irq_attr_show,
  440 +};
  441 +
  442 +static struct msi_attribute mode_attribute =
  443 + __ATTR(mode, S_IRUGO, show_msi_mode, NULL);
  444 +
  445 +
  446 +struct attribute *msi_irq_default_attrs[] = {
  447 + &mode_attribute.attr,
  448 + NULL
  449 +};
  450 +
  451 +void msi_kobj_release(struct kobject *kobj)
  452 +{
  453 + struct msi_desc *entry = to_msi_desc(kobj);
  454 +
  455 + pci_dev_put(entry->dev);
  456 +}
  457 +
  458 +static struct kobj_type msi_irq_ktype = {
  459 + .release = msi_kobj_release,
  460 + .sysfs_ops = &msi_irq_sysfs_ops,
  461 + .default_attrs = msi_irq_default_attrs,
  462 +};
  463 +
  464 +static int populate_msi_sysfs(struct pci_dev *pdev)
  465 +{
  466 + struct msi_desc *entry;
  467 + struct kobject *kobj;
  468 + int ret;
  469 + int count = 0;
  470 +
  471 + pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj);
  472 + if (!pdev->msi_kset)
  473 + return -ENOMEM;
  474 +
  475 + list_for_each_entry(entry, &pdev->msi_list, list) {
  476 + kobj = &entry->kobj;
  477 + kobj->kset = pdev->msi_kset;
  478 + pci_dev_get(pdev);
  479 + ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL,
  480 + "%u", entry->irq);
  481 + if (ret)
  482 + goto out_unroll;
  483 +
  484 + count++;
  485 + }
  486 +
  487 + return 0;
  488 +
  489 +out_unroll:
  490 + list_for_each_entry(entry, &pdev->msi_list, list) {
  491 + if (!count)
  492 + break;
  493 + kobject_del(&entry->kobj);
  494 + kobject_put(&entry->kobj);
  495 + count--;
  496 + }
  497 + return ret;
  498 +}
  499 +
406 500 /**
407 501 * msi_capability_init - configure device's MSI capability structure
408 502 * @dev: pointer to the pci_dev data structure of MSI device function
... ... @@ -454,6 +548,13 @@
454 548 return ret;
455 549 }
456 550  
  551 + ret = populate_msi_sysfs(dev);
  552 + if (ret) {
  553 + msi_mask_irq(entry, mask, ~mask);
  554 + free_msi_irqs(dev);
  555 + return ret;
  556 + }
  557 +
457 558 /* Set MSI enabled bits */
458 559 pci_intx_for_msi(dev, 0);
459 560 msi_set_enable(dev, pos, 1);
... ... @@ -574,6 +675,12 @@
574 675  
575 676 msix_program_entries(dev, entries);
576 677  
  678 + ret = populate_msi_sysfs(dev);
  679 + if (ret) {
  680 + ret = 0;
  681 + goto error;
  682 + }
  683 +
577 684 /* Set MSI-X enabled bits and unmask the function */
578 685 pci_intx_for_msi(dev, 0);
579 686 dev->msix_enabled = 1;
... ... @@ -732,6 +839,8 @@
732 839  
733 840 pci_msi_shutdown(dev);
734 841 free_msi_irqs(dev);
  842 + kset_unregister(dev->msi_kset);
  843 + dev->msi_kset = NULL;
735 844 }
736 845 EXPORT_SYMBOL(pci_disable_msi);
737 846  
... ... @@ -830,6 +939,8 @@
830 939  
831 940 pci_msix_shutdown(dev);
832 941 free_msi_irqs(dev);
  942 + kset_unregister(dev->msi_kset);
  943 + dev->msi_kset = NULL;
833 944 }
834 945 EXPORT_SYMBOL(pci_disable_msix);
835 946  
1 1 #ifndef LINUX_MSI_H
2 2 #define LINUX_MSI_H
3 3  
  4 +#include <linux/kobject.h>
4 5 #include <linux/list.h>
5 6  
6 7 struct msi_msg {
... ... @@ -44,6 +45,8 @@
44 45  
45 46 /* Last set MSI message */
46 47 struct msi_msg msg;
  48 +
  49 + struct kobject kobj;
47 50 };
48 51  
49 52 /*
... ... @@ -336,6 +336,7 @@
336 336 struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
337 337 #ifdef CONFIG_PCI_MSI
338 338 struct list_head msi_list;
  339 + struct kset *msi_kset;
339 340 #endif
340 341 struct pci_vpd *vpd;
341 342 #ifdef CONFIG_PCI_ATS