diff options
author | Minghuan Lian <Minghuan.Lian@nxp.com> | 2017-07-05 08:59:02 +0200 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2017-08-31 17:19:39 +0200 |
commit | fd100dab63ef634e1e0e8b5d9d6d4ba7df9be93f (patch) | |
tree | f928d82b8007a5403c9a7ccbff2fcba7ebd4c288 | |
parent | irqchip/ls-scfg-msi: Add LS1046a MSI support (diff) | |
download | linux-fd100dab63ef634e1e0e8b5d9d6d4ba7df9be93f.tar.xz linux-fd100dab63ef634e1e0e8b5d9d6d4ba7df9be93f.zip |
irqchip/ls-scfg-msi: Add LS1043a v1.1 MSI support
A MSI controller of LS1043a v1.0 only includes one MSIR and
is assigned one GIC interrupt. In order to support affinity,
LS1043a v1.1 MSI is assigned 4 MSIRs and 4 GIC interrupts.
But the MSIR has the different offset and only supports 8 MSIs.
The bits between variable bit_start and bit_end in structure
ls_scfg_msir are used to show 8 MSI interrupts. msir_irqs and
msir_base are added to describe the difference of MSI between
LS1043a v1.1 and other SoCs.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-ls-scfg-msi.c | 45 |
2 files changed, 40 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt index dde455289c16..49ccabbfa6f3 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -7,6 +7,7 @@ Required properties: "fsl,ls1021a-msi" "fsl,ls1043a-msi" "fsl,ls1046a-msi" + "fsl,ls1043a-v1.1-msi" - msi-controller: indicates that this is a PCIe MSI controller node - reg: physical base address of the controller and length of memory mapped. - interrupts: an interrupt to the parent interrupt controller. diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 0b1f34ddab00..8d57a599c0fb 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -25,14 +25,21 @@ #define MSI_IRQS_PER_MSIR 32 #define MSI_MSIR_OFFSET 4 +#define MSI_LS1043V1_1_IRQS_PER_MSIR 8 +#define MSI_LS1043V1_1_MSIR_OFFSET 0x10 + struct ls_scfg_msi_cfg { u32 ibs_shift; /* Shift of interrupt bit select */ + u32 msir_irqs; /* The irq number per MSIR */ + u32 msir_base; /* The base address of MSIR */ }; struct ls_scfg_msir { struct ls_scfg_msi *msi_data; unsigned int index; unsigned int gic_irq; + unsigned int bit_start; + unsigned int bit_end; void __iomem *reg; }; @@ -140,13 +147,18 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc) struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc); struct ls_scfg_msi *msi_data = msir->msi_data; unsigned long val; - int pos, virq, hwirq; + int pos, size, virq, hwirq; chained_irq_enter(irq_desc_get_chip(desc), desc); val = ioread32be(msir->reg); - for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) { - hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index; + + pos = msir->bit_start; + size = msir->bit_end + 1; + + for_each_set_bit_from(pos, &val, size) { + hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) | + msir->index; virq = irq_find_mapping(msi_data->parent, hwirq); if (virq) generic_handle_irq(virq); @@ -193,14 +205,24 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) msir->index = index; msir->msi_data = msi_data; msir->gic_irq = virq; - msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index; + msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index; + + if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) { + msir->bit_start = 32 - ((msir->index + 1) * + MSI_LS1043V1_1_IRQS_PER_MSIR); + msir->bit_end = msir->bit_start + + MSI_LS1043V1_1_IRQS_PER_MSIR - 1; + } else { + msir->bit_start = 0; + msir->bit_end = msi_data->cfg->msir_irqs - 1; + } irq_set_chained_handler_and_data(msir->gic_irq, ls_scfg_msi_irq_handler, msir); /* Release the hwirqs corresponding to this MSIR */ - for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { + for (i = 0; i < msi_data->cfg->msir_irqs; i++) { hwirq = i << msi_data->cfg->ibs_shift | msir->index; bitmap_clear(msi_data->used, hwirq, 1); } @@ -216,7 +238,7 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir) if (msir->gic_irq > 0) irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL); - for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { + for (i = 0; i < msi_data->cfg->msir_irqs; i++) { hwirq = i << msi_data->cfg->ibs_shift | msir->index; bitmap_set(msi_data->used, hwirq, 1); } @@ -226,10 +248,20 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir) static struct ls_scfg_msi_cfg ls1021_msi_cfg = { .ibs_shift = 3, + .msir_irqs = MSI_IRQS_PER_MSIR, + .msir_base = MSI_MSIR_OFFSET, }; static struct ls_scfg_msi_cfg ls1046_msi_cfg = { .ibs_shift = 2, + .msir_irqs = MSI_IRQS_PER_MSIR, + .msir_base = MSI_MSIR_OFFSET, +}; + +static struct ls_scfg_msi_cfg ls1043_v1_1_msi_cfg = { + .ibs_shift = 2, + .msir_irqs = MSI_LS1043V1_1_IRQS_PER_MSIR, + .msir_base = MSI_LS1043V1_1_MSIR_OFFSET, }; static const struct of_device_id ls_scfg_msi_id[] = { @@ -239,6 +271,7 @@ static const struct of_device_id ls_scfg_msi_id[] = { { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg }, { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg }, + { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg }, { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg }, {}, }; |