From patchwork Tue Oct 29 21:46:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "gregkh@linuxfoundation.org" X-Patchwork-Id: 287054 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 8701F2C0370 for ; Wed, 30 Oct 2013 08:46:34 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752772Ab3J2Vqd (ORCPT ); Tue, 29 Oct 2013 17:46:33 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:39060 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751889Ab3J2Vqc (ORCPT ); Tue, 29 Oct 2013 17:46:32 -0400 Received: from localhost (c-76-28-172-123.hsd1.wa.comcast.net [76.28.172.123]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id D64F987A; Tue, 29 Oct 2013 21:46:31 +0000 (UTC) Date: Tue, 29 Oct 2013 14:46:31 -0700 From: Greg Kroah-Hartman To: Linus Torvalds , Bjorn Helgaas Cc: Veaceslav Falico , "linux-pci@vger.kernel.org" , Thomas Gleixner , Yinghai Lu , Knut Petersen , Ingo Molnar , Paul McKenney , =?iso-8859-1?Q?Fr=E9d=E9ric?= Weisbecker , Linux Kernel Mailing List , Neil Horman Subject: [RFC PATCH] PCI: export MSI mode using attributes, not kobjects Message-ID: <20131029214631.GA19354@kroah.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Greg Kroah-Hartman The PCI MSI sysfs code is a mess with kobjects for things that don't really need to be kobjects. This patch creates attributes dynamically for the MSI interrupts instead of using kobjects. Note, this does not delete the existing sysfs MSI code, but puts the attributes under a "msi_irqs_2" directory for testing / example. Also note, this removes a directory from the current MSI interrupt sysfs code: old MSI kobjects: pci_device └── msi_irqs    └── 40    └── mode new MSI attributes: pci_device └── msi_irqs_2    └── 40 As there was only one file "mode" with the kobject model, the interrupt number is now a file that returns the "mode" of the interrupt (msi vs. msix). Signed-off-by: Greg Kroah-Hartman --- Bjorn, I can make up a patch that rips out the existing kobject code here, but I figured this patch would make things easier to follow instead of having to dig through the removed logic at the same time. I'll clean up the error handling path for the create attribute logic as well, this was just a proof of concept that this could be done. Do you think that anyone cares about the current mode files in sysfs to move things in this manner? drivers/pci/msi.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 2 files changed, 86 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index d5f90d63..53848ab9 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -353,6 +353,9 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) static void free_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry, *tmp; + struct attribute **msi_attrs; + struct device_attribute *dev_attr; + int count = 0; list_for_each_entry(entry, &dev->msi_list, list) { int i, nvec; @@ -388,6 +391,22 @@ static void free_msi_irqs(struct pci_dev *dev) list_del(&entry->list); kfree(entry); } + + if (dev->msi_irq_groups) { + sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups); + msi_attrs = dev->msi_irq_groups[0]->attrs; + list_for_each_entry(entry, &dev->msi_list, list) { + dev_attr = container_of(msi_attrs[count], + struct device_attribute, attr); + kfree(dev_attr->attr.name); + kfree(dev_attr); + ++count; + } + kfree(msi_attrs); + kfree(dev->msi_irq_groups[0]); + kfree(dev->msi_irq_groups); + dev->msi_irq_groups = NULL; + } } static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) @@ -517,13 +536,79 @@ static struct kobj_type msi_irq_ktype = { .default_attrs = msi_irq_default_attrs, }; +static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct msi_desc *entry; + unsigned long irq; + int retval; + + retval = kstrtoul(attr->attr.name, 10, &irq); + if (retval) + return retval; + + list_for_each_entry(entry, &pdev->msi_list, list) { + if (entry->irq == irq) { + return sprintf(buf, "%s\n", + entry->msi_attrib.is_msix ? "msix" : "msi"); + } + } + return -ENODEV; +} + static int populate_msi_sysfs(struct pci_dev *pdev) { + struct attribute **msi_attrs; + struct device_attribute *msi_dev_attr; + struct attribute_group *msi_irq_group; + const struct attribute_group **msi_irq_groups; struct msi_desc *entry; struct kobject *kobj; int ret; + int num_msi = 0; int count = 0; + /* Determine how many msi entries we have */ + list_for_each_entry(entry, &pdev->msi_list, list) { + ++num_msi; + } + if (!num_msi) + return 0; + + /* Dynamically create the MSI attributes for the PCI device */ + msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL); + if (!msi_attrs) + return -ENOMEM; + list_for_each_entry(entry, &pdev->msi_list, list) { + char *name = kmalloc(20, GFP_KERNEL); + msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); + if (!msi_dev_attr) + return -ENOMEM; + sprintf(name, "%d", entry->irq); + msi_dev_attr->attr.name = name; + msi_dev_attr->attr.mode = S_IRUGO; + msi_dev_attr->show = msi_mode_show; + msi_attrs[count] = &msi_dev_attr->attr; + ++count; + } + + msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL); + if (!msi_irq_group) + return -ENOMEM; + msi_irq_group->name = "msi_irqs_2"; + msi_irq_group->attrs = msi_attrs; + + msi_irq_groups = kzalloc(sizeof(void *) * 2, GFP_KERNEL); + if (!msi_irq_groups) + return -ENOMEM; + msi_irq_groups[0] = msi_irq_group; + + ret = sysfs_create_groups(&pdev->dev.kobj, msi_irq_groups); + if (ret) + return ret; + pdev->msi_irq_groups = msi_irq_groups; + pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj); if (!pdev->msi_kset) return -ENOMEM; diff --git a/include/linux/pci.h b/include/linux/pci.h index da172f95..9540110f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -354,6 +354,7 @@ struct pci_dev { #ifdef CONFIG_PCI_MSI struct list_head msi_list; struct kset *msi_kset; + const struct attribute_group **msi_irq_groups; #endif struct pci_vpd *vpd; #ifdef CONFIG_PCI_ATS