* multiple MSI interrupts on FSL-MPIC
@ 2014-02-20 20:53 Sebastian Andrzej Siewior
2014-02-20 20:53 ` [PATCH 1/2] irqdomain: add support for creating a continous mapping Sebastian Andrzej Siewior
2014-02-20 20:53 ` [PATCH 2/2] powerpc: msi: fsl: add support for multiple MSI interrupts Sebastian Andrzej Siewior
0 siblings, 2 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-02-20 20:53 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Scott Wood, linuxppc-dev
This series adds support for multiple MSI interrupts on FSL's MPIC. The
code has been tested on v3.2 with custom FPGA device on PCIe and then
forward ported. Patch #1 has been created from scratch during porting,
patch #2 almost applied as-it.
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-02-20 20:53 multiple MSI interrupts on FSL-MPIC Sebastian Andrzej Siewior
@ 2014-02-20 20:53 ` Sebastian Andrzej Siewior
2014-02-20 21:06 ` Scott Wood
2014-02-20 20:53 ` [PATCH 2/2] powerpc: msi: fsl: add support for multiple MSI interrupts Sebastian Andrzej Siewior
1 sibling, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-02-20 20:53 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Scott Wood, Sebastian Andrzej Siewior, linuxppc-dev, Thomas Gleixner
A MSI device may have multiple interrupts. That means that the
interrupts numbers should be continuos so that pdev->irq refers to the
first interrupt, pdev->irq + 1 to the second and so on.
This patch adds support for continuous allocation of virqs for a range
of hwirqs. The function is based on irq_create_mapping() but due to the
number argument there is very little in common now.
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/linux/irqdomain.h | 2 ++
kernel/irq/irqdomain.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index c983ed1..21d0635 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -175,6 +175,8 @@ extern void irq_domain_associate_many(struct irq_domain *domain,
extern unsigned int irq_create_mapping(struct irq_domain *host,
irq_hw_number_t hwirq);
+extern unsigned int irq_create_mapping_block(struct irq_domain *host,
+ irq_hw_number_t hwirq, unsigned int num);
extern void irq_dispose_mapping(unsigned int virq);
/**
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index cf68bb3..323d417 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -433,6 +433,67 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
EXPORT_SYMBOL_GPL(irq_create_mapping);
/**
+ * irq_create_mapping_block() - Map multiple hardware interrupts
+ * @domain: domain owning this hardware interrupt or NULL for default domain
+ * @hwirq: hardware irq number in that domain space
+ * @num: number of interrupts
+ *
+ * Maps a hwirq to a newly allocated virq. Num should be greater than 1 so num
+ * hwirqs (hwirq … hwirq + num - 1) will be mapped which and virq will be
+ * continuous. Returns the first linux virq number.
+ *
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
+ */
+unsigned int irq_create_mapping_block(struct irq_domain *domain,
+ irq_hw_number_t hwirq, unsigned int num)
+{
+ int virq;
+ int i;
+
+ pr_debug("%s(0x%p, 0x%lx) %d\n", __func__, domain, hwirq, num);
+
+ if (num < 2)
+ return 0;
+
+ /* Look for default domain if nececssary */
+ if (domain == NULL) {
+ WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
+ return 0;
+ }
+ for (i = 0; i < num; i++) {
+ /* Check if mapping already exists */
+ virq = irq_find_mapping(domain, hwirq);
+ if (virq != NO_IRQ) {
+ if (i == 0) {
+ pr_debug("-> existing mapping on virq %d\n",
+ virq);
+ return virq;
+ }
+ pr_err("irq: hwirq %ld has no mapping but hwirq %ld "
+ "maps to virq %d. This can't be a block\n",
+ hwirq, hwirq + i, virq);
+ return -EINVAL;
+ }
+ }
+
+ /* Allocate a virtual interrupt number */
+ virq = irq_alloc_descs_from(1, num, of_node_to_nid(domain->of_node));
+ if (virq <= 0) {
+ pr_debug("-> virq allocation failed\n");
+ return 0;
+ }
+
+ irq_domain_associate_many(domain, virq, hwirq, num);
+
+ pr_debug("irqs %lu…%lu on domain %s mapped to virtual irqs %u…%u\n",
+ hwirq, hwirq + num - 1, of_node_full_name(domain->of_node),
+ virq, virq + num - 1);
+
+ return virq;
+}
+
+/**
* irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs
* @domain: domain owning the interrupt range
* @irq_base: beginning of linux IRQ range
--
1.9.0.rc3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] powerpc: msi: fsl: add support for multiple MSI interrupts
2014-02-20 20:53 multiple MSI interrupts on FSL-MPIC Sebastian Andrzej Siewior
2014-02-20 20:53 ` [PATCH 1/2] irqdomain: add support for creating a continous mapping Sebastian Andrzej Siewior
@ 2014-02-20 20:53 ` Sebastian Andrzej Siewior
1 sibling, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-02-20 20:53 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Gavin Shan, Arnd Bergmann, Minghuan Lian, Alexey Kardashevskiy,
Alistair Popple, Sebastian Andrzej Siewior, Brian King,
Anton Blanchard, Scott Wood, linuxppc-dev
This patch pushes the check for nvec > 1 && MSI into the check function
of each MSI driver except for FSL's MSI where the functionality is
added.
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Gavin Shan <shangw@linux.vnet.ibm.com>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: Alistair Popple <alistair@popple.id.au>
Cc: Brian King <brking@linux.vnet.ibm.com>
Cc: Anton Blanchard <anton@samba.org>
Cc: Scott Wood <scottwood@freescale.com>
Cc: Minghuan Lian <Minghuan.Lian@freescale.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
arch/powerpc/kernel/msi.c | 4 ----
arch/powerpc/platforms/cell/axon_msi.c | 3 +++
arch/powerpc/platforms/powernv/pci.c | 2 ++
arch/powerpc/platforms/pseries/msi.c | 3 +++
arch/powerpc/platforms/wsp/msi.c | 8 ++++++++
arch/powerpc/sysdev/fsl_msi.c | 29 +++++++++++++++++++++--------
arch/powerpc/sysdev/mpic_pasemi_msi.c | 3 ++-
arch/powerpc/sysdev/mpic_u3msi.c | 2 ++
arch/powerpc/sysdev/ppc4xx_msi.c | 2 ++
9 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
index 8bbc12d..46b1470 100644
--- a/arch/powerpc/kernel/msi.c
+++ b/arch/powerpc/kernel/msi.c
@@ -20,10 +20,6 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
return -ENOSYS;
}
- /* PowerPC doesn't support multiple MSI yet */
- if (type == PCI_CAP_ID_MSI && nvec > 1)
- return 1;
-
if (ppc_md.msi_check_device) {
pr_debug("msi: Using platform check routine.\n");
return ppc_md.msi_check_device(dev, nvec, type);
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 85825b5..6e592ed 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -204,6 +204,9 @@ static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
if (!find_msi_translator(dev))
return -ENODEV;
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
+
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 95633d7..1d08040 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -54,6 +54,8 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type)
if (pdn && pdn->force_32bit_msi && !phb->msi32_support)
return -ENODEV;
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV;
}
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index 0c882e8..ad5e766 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -339,6 +339,9 @@ static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
int quota, rc;
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
+
if (type == PCI_CAP_ID_MSIX)
rc = check_req_msix(pdev, nvec);
else
diff --git a/arch/powerpc/platforms/wsp/msi.c b/arch/powerpc/platforms/wsp/msi.c
index 380882f..0cabd46 100644
--- a/arch/powerpc/platforms/wsp/msi.c
+++ b/arch/powerpc/platforms/wsp/msi.c
@@ -21,6 +21,13 @@
#define MSI_ADDR_32 0xFFFF0000ul
#define MSI_ADDR_64 0x1000000000000000ul
+static int wsp_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
+ return 0;
+}
+
int wsp_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
struct pci_controller *phb;
@@ -98,5 +105,6 @@ void wsp_setup_phb_msi(struct pci_controller *phb)
out_be64(phb->cfg_data + PCIE_REG_IODA_DATA0, 1ull << 63);
ppc_md.setup_msi_irqs = wsp_setup_msi_irqs;
+ ppc_md.msi_check_device = wsp_msi_check_device;
ppc_md.teardown_msi_irqs = wsp_teardown_msi_irqs;
}
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 77efbae..f07840f 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -123,13 +123,19 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
struct fsl_msi *msi_data;
list_for_each_entry(entry, &pdev->msi_list, list) {
+ int num;
+ int i;
+
if (entry->irq == NO_IRQ)
continue;
msi_data = irq_get_chip_data(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
+ num = 1 << entry->msi_attrib.multiple;
msi_bitmap_free_hwirqs(&msi_data->bitmap,
- virq_to_hw(entry->irq), 1);
- irq_dispose_mapping(entry->irq);
+ virq_to_hw(entry->irq), num);
+
+ for (i = 0; i < num; i++)
+ irq_dispose_mapping(entry->irq + i);
}
return;
@@ -172,6 +178,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
struct msi_desc *entry;
struct msi_msg msg;
struct fsl_msi *msi_data;
+ int i;
/*
* If the PCI node has an fsl,msi property, then we need to use it
@@ -207,7 +214,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
if (phandle && (phandle != msi_data->phandle))
continue;
- hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap,
+ nvec);
if (hwirq >= 0)
break;
}
@@ -218,17 +226,22 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
goto out_free;
}
- virq = irq_create_mapping(msi_data->irqhost, hwirq);
-
+ virq = irq_create_mapping_block(msi_data->irqhost, hwirq, nvec);
if (virq == NO_IRQ) {
dev_err(&pdev->dev, "fail mapping hwirq %i\n", hwirq);
- msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, nvec);
rc = -ENOSPC;
goto out_free;
}
+ entry->msi_attrib.multiple = get_count_order(nvec);
/* chip_data is msi_data via host->hostdata in host->map() */
- irq_set_msi_desc(virq, entry);
-
+ for (i = nvec - 1; i >= 0; i--) {
+ /*
+ * write the virq mapping last so entry->irq will point
+ * to first virq
+ */
+ irq_set_msi_desc(virq + i, entry);
+ }
fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
write_msi_msg(virq, &msg);
}
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
index 38e6238..3d36f7e 100644
--- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
+++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
@@ -67,7 +67,8 @@ static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSIX)
pr_debug("pasemi_msi: MSI-X untested, trying anyway\n");
-
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
return 0;
}
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index 9a7aa0e..f6f86ac 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -109,6 +109,8 @@ static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSIX)
pr_debug("u3msi: MSI-X untested, trying anyway.\n");
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
/* If we can't find a magic address then MSI ain't gonna work */
if (find_ht_magic_addr(pdev, 0) == 0 &&
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
index 43948da..af1efeb 100644
--- a/arch/powerpc/sysdev/ppc4xx_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -140,6 +140,8 @@ static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
__func__, nvec, type);
if (type == PCI_CAP_ID_MSIX)
pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n");
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
return 0;
}
--
1.9.0.rc3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-02-20 20:53 ` [PATCH 1/2] irqdomain: add support for creating a continous mapping Sebastian Andrzej Siewior
@ 2014-02-20 21:06 ` Scott Wood
2014-02-21 8:04 ` Sebastian Andrzej Siewior
2014-02-21 8:57 ` [PATCH 1/2 v2] " Sebastian Andrzej Siewior
0 siblings, 2 replies; 11+ messages in thread
From: Scott Wood @ 2014-02-20 21:06 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: Thomas Gleixner, linuxppc-dev
On Thu, 2014-02-20 at 21:53 +0100, Sebastian Andrzej Siewior wrote:
> A MSI device may have multiple interrupts. That means that the
> interrupts numbers should be continuos so that pdev->irq refers to the
> first interrupt, pdev->irq + 1 to the second and so on.
> This patch adds support for continuous allocation of virqs for a range
> of hwirqs. The function is based on irq_create_mapping() but due to the
> number argument there is very little in common now.
Would it make sense to turn irq_create_mapping() into a call to
irq_create_mapping_block() with num = 1?
-Scott
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-02-20 21:06 ` Scott Wood
@ 2014-02-21 8:04 ` Sebastian Andrzej Siewior
2014-02-21 8:57 ` [PATCH 1/2 v2] " Sebastian Andrzej Siewior
1 sibling, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-02-21 8:04 UTC (permalink / raw)
To: Scott Wood; +Cc: Thomas Gleixner, linuxppc-dev
On 02/20/2014 10:06 PM, Scott Wood wrote:
> On Thu, 2014-02-20 at 21:53 +0100, Sebastian Andrzej Siewior wrote:
>> A MSI device may have multiple interrupts. That means that the
>> interrupts numbers should be continuos so that pdev->irq refers to the
>> first interrupt, pdev->irq + 1 to the second and so on.
>> This patch adds support for continuous allocation of virqs for a range
>> of hwirqs. The function is based on irq_create_mapping() but due to the
>> number argument there is very little in common now.
>
> Would it make sense to turn irq_create_mapping() into a call to
> irq_create_mapping_block() with num = 1?
There are few things different and I didn't like it. Now I that I look
at it again I've found a bug the way irq_find_mapping() is called.
Let me redo it with your suggestion and we will see if it makes sense.
> -Scott
>
>
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2 v2] irqdomain: add support for creating a continous mapping
2014-02-20 21:06 ` Scott Wood
2014-02-21 8:04 ` Sebastian Andrzej Siewior
@ 2014-02-21 8:57 ` Sebastian Andrzej Siewior
2014-03-14 11:18 ` Thomas Gleixner
1 sibling, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-02-21 8:57 UTC (permalink / raw)
To: Scott Wood; +Cc: Thomas Gleixner, linuxppc-dev
A MSI device may have multiple interrupts. That means that the
interrupts numbers should be continuos so that pdev->irq refers to the
first interrupt, pdev->irq + 1 to the second and so on.
This patch adds support for continuous allocation of virqs for a range
of hwirqs. The function is based on irq_create_mapping() but due to the
number argument there is very little in common now.
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Scott, this is what you suggested. I must admit, it does not look that
bad. It is just compile tested.
v1.v2:
- use irq_create_mapping_block() for irq_create_mapping()
include/linux/irqdomain.h | 10 ++++--
kernel/irq/irqdomain.c | 87 ++++++++++++++++++++++++++++++++++---------=
----
2 files changed, 72 insertions(+), 25 deletions(-)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index c983ed1..8b09a6b 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -171,12 +171,18 @@ extern int irq_domain_associate(struct irq_domain *do=
main, unsigned int irq,
irq_hw_number_t hwirq);
extern void irq_domain_associate_many(struct irq_domain *domain,
unsigned int irq_base,
irq_hw_number_t hwirq_base, int count);
=20
-extern unsigned int irq_create_mapping(struct irq_domain *host,
- irq_hw_number_t hwirq);
+extern unsigned int irq_create_mapping_block(struct irq_domain *host,
+ irq_hw_number_t hwirq, unsigned int num);
+static inline unsigned int irq_create_mapping(struct irq_domain *host,
+ irq_hw_number_t hwirq)
+{
+ return irq_create_mapping_block(host, hwirq, 1);
+}
+
extern void irq_dispose_mapping(unsigned int virq);
=20
/**
* irq_linear_revmap() - Find a linux irq from a hw irq number.
* @domain: domain owning this hardware interrupt
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index cf68bb3..cdc6627 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -372,67 +372,108 @@ unsigned int irq_create_direct_mapping(struct irq_do=
main *domain)
=20
return virq;
}
EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
=20
+static int irq_check_continuous_mapping(struct irq_domain *domain,
+ irq_hw_number_t hwirq, unsigned int num)
+{
+ int virq;
+ int i;
+
+ virq =3D irq_find_mapping(domain, hwirq);
+
+ for (i =3D 1; i < num; i++) {
+ unsigned int next;
+
+ next =3D irq_find_mapping(domain, hwirq + i);
+ if (next =3D=3D virq + i)
+ continue;
+
+ pr_err("irq: invalid partial mapping. First hwirq %lu maps to "
+ "%d and \n", hwirq, virq);
+ pr_err("irq: +%d hwirq (%lu) maps to %d but should be %d.\n",
+ i, hwirq + i, next, virq + i);
+ return -EINVAL;
+ }
+
+ pr_debug("-> existing mapping on virq %d\n", virq);
+ return virq;
+}
+
/**
- * irq_create_mapping() - Map a hardware interrupt into linux irq space
+ * irq_create_mapping_block() - Map multiple hardware interrupts
* @domain: domain owning this hardware interrupt or NULL for default doma=
in
* @hwirq: hardware irq number in that domain space
+ * @num: number of interrupts
+ *
+ * Maps a hwirq to a newly allocated virq. If num is greater than 1 then n=
um
+ * hwirqs (hwirq =E2=80=A6 hwirq + num - 1) will be mapped and virq will b=
e continuous.
+ * Returns the first linux virq number.
*
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * irq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
-unsigned int irq_create_mapping(struct irq_domain *domain,
- irq_hw_number_t hwirq)
+unsigned int irq_create_mapping_block(struct irq_domain *domain,
+ irq_hw_number_t hwirq, unsigned int num)
{
- unsigned int hint;
int virq;
+ int i;
+ int node;
+ unsigned int hint;
=20
- pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+ pr_debug("%s(0x%p, 0x%lx, %d)\n", __func__, domain, hwirq, num);
=20
/* Look for default domain if nececssary */
- if (domain =3D=3D NULL)
+ if (!domain && num =3D=3D 1)
domain =3D irq_default_domain;
+
if (domain =3D=3D NULL) {
WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
return 0;
}
pr_debug("-> using domain @%p\n", domain);
=20
/* Check if mapping already exists */
- virq =3D irq_find_mapping(domain, hwirq);
- if (virq) {
- pr_debug("-> existing mapping on virq %d\n", virq);
- return virq;
+ for (i =3D 0; i < num; i++) {
+ virq =3D irq_find_mapping(domain, hwirq + i);
+ if (virq !=3D NO_IRQ) {
+ if (i =3D=3D 0)
+ return irq_check_continuous_mapping(domain,
+ hwirq, num);
+ pr_err("irq: hwirq %ld has no mapping but hwirq %ld "
+ "maps to virq %d. This can't be a block\n",
+ hwirq, hwirq + i, virq);
+ return -EINVAL;
+ }
}
=20
+ node =3D of_node_to_nid(domain->of_node);
/* Allocate a virtual interrupt number */
hint =3D hwirq % nr_irqs;
if (hint =3D=3D 0)
hint++;
- virq =3D irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
- if (virq <=3D 0)
- virq =3D irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
+ virq =3D irq_alloc_descs_from(hint, num, node);
+ if (virq <=3D 0 && hint !=3D 1)
+ virq =3D irq_alloc_descs_from(1, num, node);
if (virq <=3D 0) {
pr_debug("-> virq allocation failed\n");
return 0;
}
=20
- if (irq_domain_associate(domain, virq, hwirq)) {
- irq_free_desc(virq);
- return 0;
+ irq_domain_associate_many(domain, virq, hwirq, num);
+ if (num =3D=3D 1) {
+ pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
+ hwirq, of_node_full_name(domain->of_node), virq);
+ return virq;
}
-
- pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
- hwirq, of_node_full_name(domain->of_node), virq);
-
+ pr_debug("irqs %lu=E2=80=A6%lu on domain %s mapped to virtual irqs %u=E2=
=80=A6%u\n",
+ hwirq, hwirq + num - 1, of_node_full_name(domain->of_node),
+ virq, virq + num - 1);
return virq;
}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
+EXPORT_SYMBOL_GPL(irq_create_mapping_block);
=20
/**
* irq_create_strict_mappings() - Map a range of hw irqs to fixed linux ir=
qs
* @domain: domain owning the interrupt range
* @irq_base: beginning of linux IRQ range
--=20
1.9.0.rc3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2 v2] irqdomain: add support for creating a continous mapping
2014-02-21 8:57 ` [PATCH 1/2 v2] " Sebastian Andrzej Siewior
@ 2014-03-14 11:18 ` Thomas Gleixner
0 siblings, 0 replies; 11+ messages in thread
From: Thomas Gleixner @ 2014-03-14 11:18 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: Scott Wood, linuxppc-dev
[-- Attachment #1: Type: TEXT/PLAIN, Size: 4896 bytes --]
On Fri, 21 Feb 2014, Sebastian Andrzej Siewior wrote:
> A MSI device may have multiple interrupts. That means that the
> interrupts numbers should be continuos so that pdev->irq refers to the
> first interrupt, pdev->irq + 1 to the second and so on.
> This patch adds support for continuous allocation of virqs for a range
> of hwirqs. The function is based on irq_create_mapping() but due to the
> number argument there is very little in common now.
>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> Scott, this is what you suggested. I must admit, it does not look that
> bad. It is just compile tested.
Is it tested for real as well?
> +static int irq_check_continuous_mapping(struct irq_domain *domain,
> + irq_hw_number_t hwirq, unsigned int num)
> +{
> + int virq;
> + int i;
> +
> + virq = irq_find_mapping(domain, hwirq);
> +
> + for (i = 1; i < num; i++) {
> + unsigned int next;
> +
> + next = irq_find_mapping(domain, hwirq + i);
> + if (next == virq + i)
> + continue;
> +
> + pr_err("irq: invalid partial mapping. First hwirq %lu maps to "
> + "%d and \n", hwirq, virq);
> + pr_err("irq: +%d hwirq (%lu) maps to %d but should be %d.\n",
> + i, hwirq + i, next, virq + i);
> + return -EINVAL;
> + }
> +
> + pr_debug("-> existing mapping on virq %d\n", virq);
> + return virq;
> +}
> +
> /**
> - * irq_create_mapping() - Map a hardware interrupt into linux irq space
> + * irq_create_mapping_block() - Map multiple hardware interrupts
> * @domain: domain owning this hardware interrupt or NULL for default domain
> * @hwirq: hardware irq number in that domain space
> + * @num: number of interrupts
> + *
> + * Maps a hwirq to a newly allocated virq. If num is greater than 1 then num
> + * hwirqs (hwirq … hwirq + num - 1) will be mapped and virq will be continuous.
> + * Returns the first linux virq number.
> *
> - * Only one mapping per hardware interrupt is permitted. Returns a linux
> - * irq number.
> * If the sense/trigger is to be specified, set_irq_type() should be called
> * on the number returned from that call.
> */
> -unsigned int irq_create_mapping(struct irq_domain *domain,
> - irq_hw_number_t hwirq)
> +unsigned int irq_create_mapping_block(struct irq_domain *domain,
> + irq_hw_number_t hwirq, unsigned int num)
> {
> - unsigned int hint;
> int virq;
> + int i;
> + int node;
> + unsigned int hint;
What's wrong with
unsigned int hint;
int virq, i, node;
?
> - pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
> + pr_debug("%s(0x%p, 0x%lx, %d)\n", __func__, domain, hwirq, num);
>
> /* Look for default domain if nececssary */
> - if (domain == NULL)
> + if (!domain && num == 1)
> domain = irq_default_domain;
> +
> if (domain == NULL) {
> WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
> return 0;
> }
> pr_debug("-> using domain @%p\n", domain);
>
> /* Check if mapping already exists */
> - virq = irq_find_mapping(domain, hwirq);
> - if (virq) {
> - pr_debug("-> existing mapping on virq %d\n", virq);
> - return virq;
> + for (i = 0; i < num; i++) {
> + virq = irq_find_mapping(domain, hwirq + i);
> + if (virq != NO_IRQ) {
> + if (i == 0)
> + return irq_check_continuous_mapping(domain,
> + hwirq, num);
So what is the loop for? If i == 0 and virq != NO_IRQ you return. That
does not make sense at all.
> + pr_err("irq: hwirq %ld has no mapping but hwirq %ld "
> + "maps to virq %d. This can't be a block\n",
> + hwirq, hwirq + i, virq);
> + return -EINVAL;
> + }
> }
>
> + node = of_node_to_nid(domain->of_node);
> /* Allocate a virtual interrupt number */
> hint = hwirq % nr_irqs;
> if (hint == 0)
> hint++;
> - virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
> - if (virq <= 0)
> - virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
> + virq = irq_alloc_descs_from(hint, num, node);
> + if (virq <= 0 && hint != 1)
> + virq = irq_alloc_descs_from(1, num, node);
> if (virq <= 0) {
> pr_debug("-> virq allocation failed\n");
> return 0;
> }
>
> - if (irq_domain_associate(domain, virq, hwirq)) {
> - irq_free_desc(virq);
> - return 0;
> + irq_domain_associate_many(domain, virq, hwirq, num);
So irq_domain_associate can fail, but irq_domain_associate_many cannot ?
> + if (num == 1) {
> + pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
> + hwirq, of_node_full_name(domain->of_node), virq);
> + return virq;
> }
> -
> - pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
> - hwirq, of_node_full_name(domain->of_node), virq);
> -
> + pr_debug("irqs %lu…%lu on domain %s mapped to virtual irqs %u…%u\n",
> + hwirq, hwirq + num - 1, of_node_full_name(domain->of_node),
> + virq, virq + num - 1);
A single pr_debug is sufficient, hmm?
Thanks,
tglx
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-11-03 22:18 ` Scott Wood
2014-11-04 8:35 ` Sebastian Andrzej Siewior
@ 2014-11-05 16:55 ` Johannes Thumshirn
1 sibling, 0 replies; 11+ messages in thread
From: Johannes Thumshirn @ 2014-11-05 16:55 UTC (permalink / raw)
To: Scott Wood; +Cc: Johannes Thumshirn, Sebastian Andrzej Siewior, linuxppc-dev
On Mon, Nov 03, 2014 at 04:18:51PM -0600, Scott Wood wrote:
> On Mon, 2014-11-03 at 17:18 +0100, Johannes Thumshirn wrote:
> > A MSI device may have multiple interrupts. That means that the
> > interrupts numbers should be continuos so that pdev->irq refers to the
> > first interrupt, pdev->irq + 1 to the second and so on.
> > This patch adds support for continuous allocation of virqs for a range
> > of hwirqs. The function is based on irq_create_mapping() but due to the
> > number argument there is very little in common now.
> >
> > Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> > Signed-off-by: Johannes Thumshirn <johannes.thumshirn@men.de>
> > ---
> > include/linux/irqdomain.h | 10 ++++--
> > kernel/irq/irqdomain.c | 85 ++++++++++++++++++++++++++++++++++++-----------
> > 2 files changed, 73 insertions(+), 22 deletions(-)
>
> This is changing core kernel code and thus LKML should be CCed, as well
> as Ben Herrenschmidt who is the maintainer of kernel/irq/irqdomain.c.
>
> Also please respond to feedback in
> http://patchwork.ozlabs.org/patch/322497/
>
> Is it really necessary for the virqs to be contiguous? How is the
> availability of multiple MSIs communicated to the driver? Is there an
> example of a driver that currently uses multiple MSIs?
>
> > /**
> > - * irq_create_mapping() - Map a hardware interrupt into linux irq space
> > + * irq_create_mapping_block() - Map multiple hardware interrupts
> > * @domain: domain owning this hardware interrupt or NULL for default domain
> > * @hwirq: hardware irq number in that domain space
> > + * @num: number of interrupts
> > + *
> > + * Maps a hwirq to a newly allocated virq. If num is greater than 1 then num
> > + * hwirqs (hwirq ... hwirq + num - 1) will be mapped and virq will be
> > + * continuous.
> > + * Returns the first linux virq number.
> > *
> > - * Only one mapping per hardware interrupt is permitted. Returns a linux
> > - * irq number.
> > * If the sense/trigger is to be specified, set_irq_type() should be called
> > * on the number returned from that call.
> > */
> > -unsigned int irq_create_mapping(struct irq_domain *domain,
> > +unsigned int irq_create_mapping_block(struct irq_domain *domain,
> > irq_hw_number_t hwirq)
> > {
>
> Where is the num parameter? How does this even build?
F**k this was an error from porting the patch from 3.4.x to 3.18.
>
> > unsigned int hint;
> > int virq;
> > + int node;
> > + int i;
> >
> > - pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
> > + pr_debug("%s(0x%p, 0x%lx, %d)\n", __func__, domain, hwirq, num);
> >
> > /* Look for default domain if nececssary */
> > - if (domain == NULL)
> > + if (!domain && num == 1)
> > domain = irq_default_domain;
> > +
> > if (domain == NULL) {
> > WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
> > return 0;
> > @@ -403,35 +437,46 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
> > pr_debug("-> using domain @%p\n", domain);
> >
> > /* Check if mapping already exists */
> > - virq = irq_find_mapping(domain, hwirq);
> > - if (virq) {
> > - pr_debug("-> existing mapping on virq %d\n", virq);
> > - return virq;
> > + for (i = 0; i < num; i++) {
> > + virq = irq_find_mapping(domain, hwirq + i);
> > + if (virq != NO_IRQ) {
>
> Please don't introduce new uses of NO_IRQ. irq_find_mapping() returns
> zero on failure. Some architectures (e.g. ARM) define NO_IRQ as
> something other than zero, which will cause this to break.
OK
>
> > + if (i == 0)
> > + return irq_check_continuous_mapping(domain,
> > + hwirq, num);
> > + pr_err("irq: hwirq %ld has no mapping but hwirq %ld "
> > + "maps to virq %d. This can't be a block\n",
> > + hwirq, hwirq + i, virq);
> > + return -EINVAL;
> > + }
> > }
>
> Explain how you'd get into this error state, and how you'd avoid doing
> so.
According to Thomas Gleixner (http://patchwork.ozlabs.org/patch/322497/) the
whole loop is nonsense, so I'll have to rework it anyways.
>
> > + node = of_node_to_nid(domain->of_node);
> > +
> > /* Allocate a virtual interrupt number */
> > hint = hwirq % nr_irqs;
> > if (hint == 0)
> > hint++;
> > - virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
> > - if (virq <= 0)
> > - virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
> > + virq = irq_alloc_desc_from(hint, node);
> > + if (virq <= 0 && hint != 1)
> > + virq = irq_alloc_desc_from(1, node);
>
> Factoring out node seems irrelevant to, and obscures, what you're doing
> which is adding a chcek for hint. Why is a hint value of 1 special?
>
OK
> You're also still allocating only one virq, unlike in
> http://patchwork.ozlabs.org/patch/322497/
>
> -Scott
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-11-03 22:18 ` Scott Wood
@ 2014-11-04 8:35 ` Sebastian Andrzej Siewior
2014-11-05 16:55 ` Johannes Thumshirn
1 sibling, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-11-04 8:35 UTC (permalink / raw)
To: Scott Wood, Johannes Thumshirn; +Cc: linuxppc-dev
On 11/03/2014 11:18 PM, Scott Wood wrote:
> Is it really necessary for the virqs to be contiguous? How is the
> availability of multiple MSIs communicated to the driver? Is there an
> example of a driver that currently uses multiple MSIs?
I used this in PCI and after enabling 2^x, I allocated an continuous
block starting at virq. There is no way of communicating this in any
other way. The first irq number is saved in pci_dev->irq and the
remaining have to follow.
Take a look at drivers/ata/ahci.c and you will see:
- pci_msi_vec_count() for number of irqs
- pci_enable_msi_block() to allocate the number of irqs
- pci_enable_msi() (no X)
- ahci_host_activate() does request_threaded_irq() for pdev->irq and
loops "number of ports" times which matches number of number of irqs
(or is less then).
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-11-03 16:18 ` [PATCH 1/2] irqdomain: add support for creating a continous mapping Johannes Thumshirn
@ 2014-11-03 22:18 ` Scott Wood
2014-11-04 8:35 ` Sebastian Andrzej Siewior
2014-11-05 16:55 ` Johannes Thumshirn
0 siblings, 2 replies; 11+ messages in thread
From: Scott Wood @ 2014-11-03 22:18 UTC (permalink / raw)
To: Johannes Thumshirn; +Cc: Sebastian Andrzej Siewior, linuxppc-dev
On Mon, 2014-11-03 at 17:18 +0100, Johannes Thumshirn wrote:
> A MSI device may have multiple interrupts. That means that the
> interrupts numbers should be continuos so that pdev->irq refers to the
> first interrupt, pdev->irq + 1 to the second and so on.
> This patch adds support for continuous allocation of virqs for a range
> of hwirqs. The function is based on irq_create_mapping() but due to the
> number argument there is very little in common now.
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@men.de>
> ---
> include/linux/irqdomain.h | 10 ++++--
> kernel/irq/irqdomain.c | 85 ++++++++++++++++++++++++++++++++++++-----------
> 2 files changed, 73 insertions(+), 22 deletions(-)
This is changing core kernel code and thus LKML should be CCed, as well
as Ben Herrenschmidt who is the maintainer of kernel/irq/irqdomain.c.
Also please respond to feedback in
http://patchwork.ozlabs.org/patch/322497/
Is it really necessary for the virqs to be contiguous? How is the
availability of multiple MSIs communicated to the driver? Is there an
example of a driver that currently uses multiple MSIs?
> /**
> - * irq_create_mapping() - Map a hardware interrupt into linux irq space
> + * irq_create_mapping_block() - Map multiple hardware interrupts
> * @domain: domain owning this hardware interrupt or NULL for default domain
> * @hwirq: hardware irq number in that domain space
> + * @num: number of interrupts
> + *
> + * Maps a hwirq to a newly allocated virq. If num is greater than 1 then num
> + * hwirqs (hwirq ... hwirq + num - 1) will be mapped and virq will be
> + * continuous.
> + * Returns the first linux virq number.
> *
> - * Only one mapping per hardware interrupt is permitted. Returns a linux
> - * irq number.
> * If the sense/trigger is to be specified, set_irq_type() should be called
> * on the number returned from that call.
> */
> -unsigned int irq_create_mapping(struct irq_domain *domain,
> +unsigned int irq_create_mapping_block(struct irq_domain *domain,
> irq_hw_number_t hwirq)
> {
Where is the num parameter? How does this even build?
> unsigned int hint;
> int virq;
> + int node;
> + int i;
>
> - pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
> + pr_debug("%s(0x%p, 0x%lx, %d)\n", __func__, domain, hwirq, num);
>
> /* Look for default domain if nececssary */
> - if (domain == NULL)
> + if (!domain && num == 1)
> domain = irq_default_domain;
> +
> if (domain == NULL) {
> WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
> return 0;
> @@ -403,35 +437,46 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
> pr_debug("-> using domain @%p\n", domain);
>
> /* Check if mapping already exists */
> - virq = irq_find_mapping(domain, hwirq);
> - if (virq) {
> - pr_debug("-> existing mapping on virq %d\n", virq);
> - return virq;
> + for (i = 0; i < num; i++) {
> + virq = irq_find_mapping(domain, hwirq + i);
> + if (virq != NO_IRQ) {
Please don't introduce new uses of NO_IRQ. irq_find_mapping() returns
zero on failure. Some architectures (e.g. ARM) define NO_IRQ as
something other than zero, which will cause this to break.
> + if (i == 0)
> + return irq_check_continuous_mapping(domain,
> + hwirq, num);
> + pr_err("irq: hwirq %ld has no mapping but hwirq %ld "
> + "maps to virq %d. This can't be a block\n",
> + hwirq, hwirq + i, virq);
> + return -EINVAL;
> + }
> }
Explain how you'd get into this error state, and how you'd avoid doing
so.
> + node = of_node_to_nid(domain->of_node);
> +
> /* Allocate a virtual interrupt number */
> hint = hwirq % nr_irqs;
> if (hint == 0)
> hint++;
> - virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
> - if (virq <= 0)
> - virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
> + virq = irq_alloc_desc_from(hint, node);
> + if (virq <= 0 && hint != 1)
> + virq = irq_alloc_desc_from(1, node);
Factoring out node seems irrelevant to, and obscures, what you're doing
which is adding a chcek for hint. Why is a hint value of 1 special?
You're also still allocating only one virq, unlike in
http://patchwork.ozlabs.org/patch/322497/
-Scott
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] irqdomain: add support for creating a continous mapping
2014-11-03 16:18 [PATCH 0/2] Support multiple MSI interrupts on FSL-MPIC Johannes Thumshirn
@ 2014-11-03 16:18 ` Johannes Thumshirn
2014-11-03 22:18 ` Scott Wood
0 siblings, 1 reply; 11+ messages in thread
From: Johannes Thumshirn @ 2014-11-03 16:18 UTC (permalink / raw)
To: Sebastian Andrzej Siewior, Scott Wood, Michael Ellerman
Cc: Johannes Thumshirn, linuxppc-dev
A MSI device may have multiple interrupts. That means that the
interrupts numbers should be continuos so that pdev->irq refers to the
first interrupt, pdev->irq + 1 to the second and so on.
This patch adds support for continuous allocation of virqs for a range
of hwirqs. The function is based on irq_create_mapping() but due to the
number argument there is very little in common now.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@men.de>
---
include/linux/irqdomain.h | 10 ++++--
kernel/irq/irqdomain.c | 85 ++++++++++++++++++++++++++++++++++++-----------
2 files changed, 73 insertions(+), 22 deletions(-)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index b0f9d16..75662f3 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -175,8 +175,14 @@ extern void irq_domain_associate_many(struct irq_domain *domain,
extern void irq_domain_disassociate(struct irq_domain *domain,
unsigned int irq);
-extern unsigned int irq_create_mapping(struct irq_domain *host,
- irq_hw_number_t hwirq);
+extern unsigned int irq_create_mapping_block(struct irq_domain *host,
+ irq_hw_number_t hwirq, unsigned int num);
+static inline unsigned int irq_create_mapping(struct irq_domain *host,
+ irq_hw_number_t hwirq)
+{
+ return irq_create_mapping_block(host, hwirq, 1);
+}
+
extern void irq_dispose_mapping(unsigned int virq);
/**
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 6534ff6..fba488f 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -375,27 +375,61 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
}
EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
+static int irq_check_continuous_mapping(struct irq_domain *domain,
+ irq_hw_number_t hwirq, unsigned int num)
+{
+ int virq;
+ int i;
+
+ virq = irq_find_mapping(domain, hwirq);
+
+ for (i = 1; i < num; i++) {
+ unsigned int next;
+
+ next = irq_find_mapping(domain, hwirq + i);
+ if (next == virq + i)
+ continue;
+
+ pr_err("irq: invalid partial mapping. First hwirq %lu maps to "
+ "%d and\n", hwirq, virq);
+ pr_err("irq: +%d hwirq (%lu) maps to %d but should be %d.\n",
+ i, hwirq + i, next, virq + i);
+ return -EINVAL;
+ }
+
+ pr_debug("-> existing mapping on virq %d\n", virq);
+ return virq;
+}
+
+
/**
- * irq_create_mapping() - Map a hardware interrupt into linux irq space
+ * irq_create_mapping_block() - Map multiple hardware interrupts
* @domain: domain owning this hardware interrupt or NULL for default domain
* @hwirq: hardware irq number in that domain space
+ * @num: number of interrupts
+ *
+ * Maps a hwirq to a newly allocated virq. If num is greater than 1 then num
+ * hwirqs (hwirq ... hwirq + num - 1) will be mapped and virq will be
+ * continuous.
+ * Returns the first linux virq number.
*
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * irq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
-unsigned int irq_create_mapping(struct irq_domain *domain,
+unsigned int irq_create_mapping_block(struct irq_domain *domain,
irq_hw_number_t hwirq)
{
unsigned int hint;
int virq;
+ int node;
+ int i;
- pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+ pr_debug("%s(0x%p, 0x%lx, %d)\n", __func__, domain, hwirq, num);
/* Look for default domain if nececssary */
- if (domain == NULL)
+ if (!domain && num == 1)
domain = irq_default_domain;
+
if (domain == NULL) {
WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
return 0;
@@ -403,35 +437,46 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
pr_debug("-> using domain @%p\n", domain);
/* Check if mapping already exists */
- virq = irq_find_mapping(domain, hwirq);
- if (virq) {
- pr_debug("-> existing mapping on virq %d\n", virq);
- return virq;
+ for (i = 0; i < num; i++) {
+ virq = irq_find_mapping(domain, hwirq + i);
+ if (virq != NO_IRQ) {
+ if (i == 0)
+ return irq_check_continuous_mapping(domain,
+ hwirq, num);
+ pr_err("irq: hwirq %ld has no mapping but hwirq %ld "
+ "maps to virq %d. This can't be a block\n",
+ hwirq, hwirq + i, virq);
+ return -EINVAL;
+ }
}
+ node = of_node_to_nid(domain->of_node);
+
/* Allocate a virtual interrupt number */
hint = hwirq % nr_irqs;
if (hint == 0)
hint++;
- virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
- if (virq <= 0)
- virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
+ virq = irq_alloc_desc_from(hint, node);
+ if (virq <= 0 && hint != 1)
+ virq = irq_alloc_desc_from(1, node);
if (virq <= 0) {
pr_debug("-> virq allocation failed\n");
return 0;
}
- if (irq_domain_associate(domain, virq, hwirq)) {
- irq_free_desc(virq);
- return 0;
+ irq_domain_associate_many(domain, virq, hwirq, num);
+ if (num == 1) {
+ pr_debug("irq %lu on domain %s mapped to virtual irq %u\n"
+ hwirq, of_node_full_name(domain->of_node), virq);
+ return virq;
}
- pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
- hwirq, of_node_full_name(domain->of_node), virq);
-
+ pr_debug("irqs %lu...%lu on domain %s mapped to virtual irqs %u..%u\n",
+ hwirq, hwirq + num - 1, of_node_full_name(domain->of_node),
+ virq, virq + num - 1);
return virq;
}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
+EXPORT_SYMBOL_GPL(irq_create_mapping_block);
/**
* irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs
--
1.9.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-11-05 16:56 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-20 20:53 multiple MSI interrupts on FSL-MPIC Sebastian Andrzej Siewior
2014-02-20 20:53 ` [PATCH 1/2] irqdomain: add support for creating a continous mapping Sebastian Andrzej Siewior
2014-02-20 21:06 ` Scott Wood
2014-02-21 8:04 ` Sebastian Andrzej Siewior
2014-02-21 8:57 ` [PATCH 1/2 v2] " Sebastian Andrzej Siewior
2014-03-14 11:18 ` Thomas Gleixner
2014-02-20 20:53 ` [PATCH 2/2] powerpc: msi: fsl: add support for multiple MSI interrupts Sebastian Andrzej Siewior
2014-11-03 16:18 [PATCH 0/2] Support multiple MSI interrupts on FSL-MPIC Johannes Thumshirn
2014-11-03 16:18 ` [PATCH 1/2] irqdomain: add support for creating a continous mapping Johannes Thumshirn
2014-11-03 22:18 ` Scott Wood
2014-11-04 8:35 ` Sebastian Andrzej Siewior
2014-11-05 16:55 ` Johannes Thumshirn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).