Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Neil Horman and committed by
Jesse Barnes
da8d1c8b 8b6a5af9

+133
+18
Documentation/ABI/testing/sysfs-bus-pci
··· 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>
+111
drivers/pci/msi.c
··· 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 } ··· 405 403 } 406 404 EXPORT_SYMBOL_GPL(pci_restore_msi_state); 407 405 406 + 407 + #define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr) 408 + #define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj) 409 + 410 + struct msi_attribute { 411 + struct attribute attr; 412 + ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr, 413 + char *buf); 414 + ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr, 415 + const char *buf, size_t count); 416 + }; 417 + 418 + static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr, 419 + char *buf) 420 + { 421 + return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi"); 422 + } 423 + 424 + static ssize_t msi_irq_attr_show(struct kobject *kobj, 425 + struct attribute *attr, char *buf) 426 + { 427 + struct msi_attribute *attribute = to_msi_attr(attr); 428 + struct msi_desc *entry = to_msi_desc(kobj); 429 + 430 + if (!attribute->show) 431 + return -EIO; 432 + 433 + return attribute->show(entry, attribute, buf); 434 + } 435 + 436 + static const struct sysfs_ops msi_irq_sysfs_ops = { 437 + .show = msi_irq_attr_show, 438 + }; 439 + 440 + static struct msi_attribute mode_attribute = 441 + __ATTR(mode, S_IRUGO, show_msi_mode, NULL); 442 + 443 + 444 + struct attribute *msi_irq_default_attrs[] = { 445 + &mode_attribute.attr, 446 + NULL 447 + }; 448 + 449 + void msi_kobj_release(struct kobject *kobj) 450 + { 451 + struct msi_desc *entry = to_msi_desc(kobj); 452 + 453 + pci_dev_put(entry->dev); 454 + } 455 + 456 + static struct kobj_type msi_irq_ktype = { 457 + .release = msi_kobj_release, 458 + .sysfs_ops = &msi_irq_sysfs_ops, 459 + .default_attrs = msi_irq_default_attrs, 460 + }; 461 + 462 + static int populate_msi_sysfs(struct pci_dev *pdev) 463 + { 464 + struct msi_desc *entry; 465 + struct kobject *kobj; 466 + int ret; 467 + int count = 0; 468 + 469 + pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj); 470 + if (!pdev->msi_kset) 471 + return -ENOMEM; 472 + 473 + list_for_each_entry(entry, &pdev->msi_list, list) { 474 + kobj = &entry->kobj; 475 + kobj->kset = pdev->msi_kset; 476 + pci_dev_get(pdev); 477 + ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL, 478 + "%u", entry->irq); 479 + if (ret) 480 + goto out_unroll; 481 + 482 + count++; 483 + } 484 + 485 + return 0; 486 + 487 + out_unroll: 488 + list_for_each_entry(entry, &pdev->msi_list, list) { 489 + if (!count) 490 + break; 491 + kobject_del(&entry->kobj); 492 + kobject_put(&entry->kobj); 493 + count--; 494 + } 495 + return ret; 496 + } 497 + 408 498 /** 409 499 * msi_capability_init - configure device's MSI capability structure 410 500 * @dev: pointer to the pci_dev data structure of MSI device function ··· 542 448 543 449 /* Configure MSI capability structure */ 544 450 ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); 451 + if (ret) { 452 + msi_mask_irq(entry, mask, ~mask); 453 + free_msi_irqs(dev); 454 + return ret; 455 + } 456 + 457 + ret = populate_msi_sysfs(dev); 545 458 if (ret) { 546 459 msi_mask_irq(entry, mask, ~mask); 547 460 free_msi_irqs(dev); ··· 674 573 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); 675 574 676 575 msix_program_entries(dev, entries); 576 + 577 + ret = populate_msi_sysfs(dev); 578 + if (ret) { 579 + ret = 0; 580 + goto error; 581 + } 677 582 678 583 /* Set MSI-X enabled bits and unmask the function */ 679 584 pci_intx_for_msi(dev, 0); ··· 839 732 840 733 pci_msi_shutdown(dev); 841 734 free_msi_irqs(dev); 735 + kset_unregister(dev->msi_kset); 736 + dev->msi_kset = NULL; 842 737 } 843 738 EXPORT_SYMBOL(pci_disable_msi); 844 739 ··· 939 830 940 831 pci_msix_shutdown(dev); 941 832 free_msi_irqs(dev); 833 + kset_unregister(dev->msi_kset); 834 + dev->msi_kset = NULL; 942 835 } 943 836 EXPORT_SYMBOL(pci_disable_msix); 944 837
+3
include/linux/msi.h
··· 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 { ··· 45 44 46 45 /* Last set MSI message */ 47 46 struct msi_msg msg; 47 + 48 + struct kobject kobj; 48 49 }; 49 50 50 51 /*
+1
include/linux/pci.h
··· 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