From: Jiang Liu <jiang.liu@linux.intel.com>
To: Bjorn Helgaas <bhelgaas@google.com>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>,
Grant Likely <grant.likely@linaro.org>,
Marc Zyngier <marc.zyngier@arm.com>,
Yijing Wang <wangyijing@huawei.com>,
Yingjoe Chen <yingjoe.chen@mediatek.com>,
Borislav Petkov <bp@alien8.de>, "H. Peter Anvin" <hpa@zytor.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
Jiang Liu <jiang.liu@linux.intel.com>,
Alexander Gordeev <agordeev@redhat.com>
Cc: Tony Luck <tony.luck@intel.com>,
linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Subject: [Patch V3 8/9] PCI, MSI: Refine irqdomain interfaces to simplify its usage
Date: Mon, 17 Nov 2014 19:03:21 +0800 [thread overview]
Message-ID: <1416222202-28002-9-git-send-email-jiang.liu@linux.intel.com> (raw)
In-Reply-To: <1416222202-28002-1-git-send-email-jiang.liu@linux.intel.com>
Refine irqdomain interfaces to simplify its usage.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
drivers/pci/msi.c | 121 +++++++++++++++++++++++++++++++++++++++------------
include/linux/msi.h | 13 +++---
2 files changed, 100 insertions(+), 34 deletions(-)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 9c53b865cb1b..62f504887c1d 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -1099,38 +1099,101 @@ irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
(pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
}
-int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
- struct pci_dev *dev, void *arg)
+static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
{
- struct msi_domain_info *info = domain->host_data;
- int node = dev_to_node(&dev->dev);
- struct msi_desc *desc;
- int i, virq;
-
- list_for_each_entry(desc, &dev->msi_list, list) {
- if (info->ops->calc_hwirq)
- info->ops->calc_hwirq(info, arg, desc);
-
- virq = irq_domain_alloc_irqs(domain, desc->nvec_used,
- node, arg);
- if (virq < 0) {
- /* Special handling for pci_enable_msi_range(). */
- if (type == PCI_CAP_ID_MSI && desc->nvec_used > 1)
- return 1;
- else
- return -ENOSPC;
- }
- for (i = 0; i < desc->nvec_used; i++)
- irq_set_msi_desc_off(virq, i, desc);
- }
+ return !desc->msi_attrib.is_msix && desc->nvec_used > 1;
+}
+
+int pci_msi_domain_check_cap(struct irq_domain *domain,
+ struct msi_domain_info *info, struct device *dev)
+{
+ struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
+
+ /* Special handling to support pci_enable_msi_range() */
+ if (pci_msi_desc_is_multi_msi(desc) &&
+ !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
+ return 1;
+ else if (desc->msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
+ return -ENOTSUPP;
- list_for_each_entry(desc, &dev->msi_list, list)
- if (desc->nvec_used == 1)
- dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", virq);
- else
- dev_dbg(&dev->dev, "irq [%d-%d] for MSI/MSI-X\n",
- virq, virq + desc->nvec_used - 1);
+ return 0;
+}
+
+static int pci_msi_domain_handle_error(msi_alloc_info_t *arg,
+ struct msi_desc *desc, int error)
+{
+ /* Special handling to support pci_enable_msi_range() */
+ if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
+ return 1;
+
+ return error;
+}
+
+#ifndef msi_alloc_info_t
+static int pci_msi_domain_set_desc(struct msi_alloc_info *arg,
+ struct msi_desc *desc)
+{
+ arg->desc = desc;
+ arg->hwirq = pci_msi_domain_calc_hwirq(msi_desc_to_pci_dev(desc),
+ desc);
return 0;
}
+#else
+#define pci_msi_domain_set_desc NULL
+#endif
+
+static struct msi_domain_ops pci_msi_domain_ops_default = {
+ .set_desc = pci_msi_domain_set_desc,
+ .msi_check = pci_msi_domain_check_cap,
+ .handle_error = pci_msi_domain_handle_error,
+};
+
+static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
+{
+ struct msi_domain_ops *ops = info->ops;
+
+ if (ops == NULL) {
+ info->ops = &pci_msi_domain_ops_default;
+ } else {
+ if (ops->set_desc == NULL)
+ ops->set_desc = pci_msi_domain_set_desc;
+ if (ops->msi_check == NULL)
+ ops->msi_check = pci_msi_domain_check_cap;
+ if (ops->handle_error == NULL)
+ ops->handle_error = pci_msi_domain_handle_error;
+ }
+}
+
+static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
+{
+ struct irq_chip *chip = info->chip;
+
+ BUG_ON(!chip);
+ if (!chip->irq_write_msi_msg)
+ chip->irq_write_msi_msg = pci_msi_domain_write_msg;
+}
+
+struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent)
+{
+ if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
+ pci_msi_domain_update_dom_ops(info);
+ if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
+ pci_msi_domain_update_chip_ops(info);
+
+ return msi_create_irq_domain(node, info, parent);
+}
+
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev,
+ int nvec, int type)
+{
+ return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
+}
+
+void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev)
+{
+ msi_domain_free_irqs(domain, &dev->dev);
+}
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 3571b4715c75..eadd47c309a7 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -125,9 +125,6 @@ typedef struct msi_alloc_info msi_alloc_info_t;
struct msi_domain_ops {
/* Callbacks for msi_create_irq_domain() */
- void (*calc_hwirq)(struct msi_domain_info *info,
- msi_alloc_info_t *arg,
- struct msi_desc *desc);
irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,
msi_alloc_info_t *arg);
int (*msi_init)(struct irq_domain *domain,
@@ -189,10 +186,16 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
-int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
- struct pci_dev *dev, void *arg);
+struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent);
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev,
+ int nvec, int type);
+void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev);
irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
struct msi_desc *desc);
+int pci_msi_domain_check_cap(struct irq_domain *domain,
+ struct msi_domain_info *info, struct device *dev);
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
#endif /* LINUX_MSI_H */
--
1.7.10.4
WARNING: multiple messages have this Message-ID (diff)
From: jiang.liu@linux.intel.com (Jiang Liu)
To: linux-arm-kernel@lists.infradead.org
Subject: [Patch V3 8/9] PCI, MSI: Refine irqdomain interfaces to simplify its usage
Date: Mon, 17 Nov 2014 19:03:21 +0800 [thread overview]
Message-ID: <1416222202-28002-9-git-send-email-jiang.liu@linux.intel.com> (raw)
In-Reply-To: <1416222202-28002-1-git-send-email-jiang.liu@linux.intel.com>
Refine irqdomain interfaces to simplify its usage.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
drivers/pci/msi.c | 121 +++++++++++++++++++++++++++++++++++++++------------
include/linux/msi.h | 13 +++---
2 files changed, 100 insertions(+), 34 deletions(-)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 9c53b865cb1b..62f504887c1d 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -1099,38 +1099,101 @@ irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
(pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
}
-int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
- struct pci_dev *dev, void *arg)
+static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
{
- struct msi_domain_info *info = domain->host_data;
- int node = dev_to_node(&dev->dev);
- struct msi_desc *desc;
- int i, virq;
-
- list_for_each_entry(desc, &dev->msi_list, list) {
- if (info->ops->calc_hwirq)
- info->ops->calc_hwirq(info, arg, desc);
-
- virq = irq_domain_alloc_irqs(domain, desc->nvec_used,
- node, arg);
- if (virq < 0) {
- /* Special handling for pci_enable_msi_range(). */
- if (type == PCI_CAP_ID_MSI && desc->nvec_used > 1)
- return 1;
- else
- return -ENOSPC;
- }
- for (i = 0; i < desc->nvec_used; i++)
- irq_set_msi_desc_off(virq, i, desc);
- }
+ return !desc->msi_attrib.is_msix && desc->nvec_used > 1;
+}
+
+int pci_msi_domain_check_cap(struct irq_domain *domain,
+ struct msi_domain_info *info, struct device *dev)
+{
+ struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
+
+ /* Special handling to support pci_enable_msi_range() */
+ if (pci_msi_desc_is_multi_msi(desc) &&
+ !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
+ return 1;
+ else if (desc->msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
+ return -ENOTSUPP;
- list_for_each_entry(desc, &dev->msi_list, list)
- if (desc->nvec_used == 1)
- dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", virq);
- else
- dev_dbg(&dev->dev, "irq [%d-%d] for MSI/MSI-X\n",
- virq, virq + desc->nvec_used - 1);
+ return 0;
+}
+
+static int pci_msi_domain_handle_error(msi_alloc_info_t *arg,
+ struct msi_desc *desc, int error)
+{
+ /* Special handling to support pci_enable_msi_range() */
+ if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
+ return 1;
+
+ return error;
+}
+
+#ifndef msi_alloc_info_t
+static int pci_msi_domain_set_desc(struct msi_alloc_info *arg,
+ struct msi_desc *desc)
+{
+ arg->desc = desc;
+ arg->hwirq = pci_msi_domain_calc_hwirq(msi_desc_to_pci_dev(desc),
+ desc);
return 0;
}
+#else
+#define pci_msi_domain_set_desc NULL
+#endif
+
+static struct msi_domain_ops pci_msi_domain_ops_default = {
+ .set_desc = pci_msi_domain_set_desc,
+ .msi_check = pci_msi_domain_check_cap,
+ .handle_error = pci_msi_domain_handle_error,
+};
+
+static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
+{
+ struct msi_domain_ops *ops = info->ops;
+
+ if (ops == NULL) {
+ info->ops = &pci_msi_domain_ops_default;
+ } else {
+ if (ops->set_desc == NULL)
+ ops->set_desc = pci_msi_domain_set_desc;
+ if (ops->msi_check == NULL)
+ ops->msi_check = pci_msi_domain_check_cap;
+ if (ops->handle_error == NULL)
+ ops->handle_error = pci_msi_domain_handle_error;
+ }
+}
+
+static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
+{
+ struct irq_chip *chip = info->chip;
+
+ BUG_ON(!chip);
+ if (!chip->irq_write_msi_msg)
+ chip->irq_write_msi_msg = pci_msi_domain_write_msg;
+}
+
+struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent)
+{
+ if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
+ pci_msi_domain_update_dom_ops(info);
+ if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
+ pci_msi_domain_update_chip_ops(info);
+
+ return msi_create_irq_domain(node, info, parent);
+}
+
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev,
+ int nvec, int type)
+{
+ return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
+}
+
+void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev)
+{
+ msi_domain_free_irqs(domain, &dev->dev);
+}
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 3571b4715c75..eadd47c309a7 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -125,9 +125,6 @@ typedef struct msi_alloc_info msi_alloc_info_t;
struct msi_domain_ops {
/* Callbacks for msi_create_irq_domain() */
- void (*calc_hwirq)(struct msi_domain_info *info,
- msi_alloc_info_t *arg,
- struct msi_desc *desc);
irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,
msi_alloc_info_t *arg);
int (*msi_init)(struct irq_domain *domain,
@@ -189,10 +186,16 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
-int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
- struct pci_dev *dev, void *arg);
+struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent);
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev,
+ int nvec, int type);
+void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev);
irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
struct msi_desc *desc);
+int pci_msi_domain_check_cap(struct irq_domain *domain,
+ struct msi_domain_info *info, struct device *dev);
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
#endif /* LINUX_MSI_H */
--
1.7.10.4
next prev parent reply other threads:[~2014-11-17 11:00 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-17 11:03 [Patch V3 0/9] Refine generic/PCI MSI irqodmian interfaces Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 1/9] PCI, MSI: Fix errors caused by commit e5f1a59c4e12 Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 2/9] irqdomain: Use consistent prototype for irq_domain_free_irqs_* Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 3/9] irqdomain: Implement a method to automatically call parent domain's alloc/free Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 4/9] irqdomain: Introduce helper function irq_domain_add_hierarchy() Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 5/9] PCI, MSI: Introduce helpers to hide struct msi_desc implementation details Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 6/9] genirq: Introduce msi_domain_{alloc|free}_irqs() Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:30 ` Thomas Gleixner
2014-11-17 11:30 ` Thomas Gleixner
2014-11-17 11:37 ` Jiang Liu
2014-11-17 11:37 ` Jiang Liu
2014-11-17 11:03 ` [Patch V3 7/9] genirq: Provide default callbacks for msi_domain_ops Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-17 11:03 ` Jiang Liu [this message]
2014-11-17 11:03 ` [Patch V3 8/9] PCI, MSI: Refine irqdomain interfaces to simplify its usage Jiang Liu
2014-11-17 11:03 ` [Patch V3 9/9] PCI, MSI: Provide mechanism to alloc/free MSI/MSIX interrupt from irqdomain Jiang Liu
2014-11-17 11:03 ` Jiang Liu
2014-11-18 0:59 ` [Patch V3 0/9] Refine generic/PCI MSI irqodmian interfaces Thomas Gleixner
2014-11-18 0:59 ` Thomas Gleixner
2014-11-18 5:08 ` Jiang Liu
2014-11-18 5:08 ` Jiang Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1416222202-28002-9-git-send-email-jiang.liu@linux.intel.com \
--to=jiang.liu@linux.intel.com \
--cc=agordeev@redhat.com \
--cc=bhelgaas@google.com \
--cc=bp@alien8.de \
--cc=grant.likely@linaro.org \
--cc=hpa@zytor.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=matthias.bgg@gmail.com \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=tony.luck@intel.com \
--cc=wangyijing@huawei.com \
--cc=yingjoe.chen@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.