From 67e35c3a79b7349a9b0dbe1dd0bf82def0296714 Mon Sep 17 00:00:00 2001 From: Tudor Laurentiu Date: Wed, 13 Aug 2014 16:55:13 +0300 Subject: powerpc/fsl_msi: support vmpic msi with mpic 4.3 The new MSI block in MPIC 4.3 added the MSIIR1 register, with a different layout, in order to support 16 MSIR registers. The msi binding was also updated so that the "reg" reflects the newly introduced MSIIR1 register. Virtual machines advertise these msi nodes by using the compatible "fsl,vmpic-msi-v4.3" so add support for it. Signed-off-by: Laurentiu Tudor Cc: Scott Wood Signed-off-by: Scott Wood --- arch/powerpc/sysdev/fsl_msi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 77efbaec7b9c..9fadc6e4dc47 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -180,7 +180,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) np = of_parse_phandle(hose->dn, "fsl,msi", 0); if (np) { if (of_device_is_compatible(np, "fsl,mpic-msi") || - of_device_is_compatible(np, "fsl,vmpic-msi")) + of_device_is_compatible(np, "fsl,vmpic-msi") || + of_device_is_compatible(np, "fsl,vmpic-msi-v4.3")) phandle = np->phandle; else { dev_err(&pdev->dev, @@ -466,7 +467,8 @@ static int fsl_of_msi_probe(struct platform_device *dev) p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); - if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3")) { + if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") || + of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) { msi->srs_shift = MSIIR1_SRS_SHIFT; msi->ibs_shift = MSIIR1_IBS_SHIFT; if (p) @@ -572,6 +574,10 @@ static const struct of_device_id fsl_of_msi_ids[] = { .compatible = "fsl,vmpic-msi", .data = &vmpic_msi_feature, }, + { + .compatible = "fsl,vmpic-msi-v4.3", + .data = &vmpic_msi_feature, + }, #endif {} }; -- cgit v1.2.3 From 834952314c8bae7331b0797a071958dda9bec60d Mon Sep 17 00:00:00 2001 From: Tudor Laurentiu Date: Tue, 19 Aug 2014 14:25:01 +0300 Subject: powerpc/fsl_msi: reorganize structs to improve clarity and flexibility Store cascade_data in an array inside the driver data for later use. Get rid of the msi_virq array since now we can encapsulate the virqs in the cascade_data directly and access them through the array mentioned earlier. Signed-off-by: Laurentiu Tudor Cc: Scott Wood Cc: Mihai Caraman Signed-off-by: Scott Wood --- arch/powerpc/sysdev/fsl_msi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 9fadc6e4dc47..05a0dd918de2 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -50,6 +50,7 @@ struct fsl_msi_feature { struct fsl_msi_cascade_data { struct fsl_msi *msi_data; int index; + int virq; }; static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) @@ -327,15 +328,18 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) { struct fsl_msi *msi = platform_get_drvdata(ofdev); int virq, i; - struct fsl_msi_cascade_data *cascade_data; if (msi->list.prev != NULL) list_del(&msi->list); for (i = 0; i < NR_MSI_REG_MAX; i++) { - virq = msi->msi_virqs[i]; - if (virq != NO_IRQ) { - cascade_data = irq_get_handler_data(virq); - kfree(cascade_data); + if (msi->cascade_array[i]) { + virq = msi->cascade_array[i]->virq; + + BUG_ON(virq == NO_IRQ); + BUG_ON(msi->cascade_array[i] != + irq_get_handler_data(virq)); + + kfree(msi->cascade_array[i]); irq_dispose_mapping(virq); } } @@ -369,9 +373,10 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, return -ENOMEM; } irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class); - msi->msi_virqs[irq_index] = virt_msir; cascade_data->index = offset; cascade_data->msi_data = msi; + cascade_data->virq = virt_msir; + msi->cascade_array[irq_index] = cascade_data; irq_set_handler_data(virt_msir, cascade_data); irq_set_chained_handler(virt_msir, fsl_msi_cascade); -- cgit v1.2.3 From 543c043cbae79164aa087f96294cb37fc4a19a59 Mon Sep 17 00:00:00 2001 From: Tudor Laurentiu Date: Tue, 19 Aug 2014 14:25:03 +0300 Subject: powerpc/fsl_msi: change the irq handler from chained to normal As we do for other fsl-mpic related cascaded irqchips (e.g. error ints, mpic timers), use a normal irq handler for msi irqs too. This brings some advantages such as mask/unmask/ack/eoi and irq state taken care behind the scenes, kstats updates a.s.o plus access to features provided by mpic, such as affinity. Signed-off-by: Laurentiu Tudor Cc: Scott Wood Cc: Mihai Caraman Signed-off-by: Scott Wood --- arch/powerpc/sysdev/fsl_msi.c | 56 ++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 05a0dd918de2..0cfc32a63039 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -241,40 +242,24 @@ out_free: return rc; } -static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) +static irqreturn_t fsl_msi_cascade(int irq, void *data) { - struct irq_chip *chip = irq_desc_get_chip(desc); - struct irq_data *idata = irq_desc_get_irq_data(desc); unsigned int cascade_irq; struct fsl_msi *msi_data; int msir_index = -1; u32 msir_value = 0; u32 intr_index; u32 have_shift = 0; - struct fsl_msi_cascade_data *cascade_data; + struct fsl_msi_cascade_data *cascade_data = data; + irqreturn_t ret = IRQ_NONE; - cascade_data = irq_get_handler_data(irq); msi_data = cascade_data->msi_data; - raw_spin_lock(&desc->lock); - if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { - if (chip->irq_mask_ack) - chip->irq_mask_ack(idata); - else { - chip->irq_mask(idata); - chip->irq_ack(idata); - } - } - - if (unlikely(irqd_irq_inprogress(idata))) - goto unlock; - msir_index = cascade_data->index; if (msir_index >= NR_MSI_REG_MAX) cascade_irq = NO_IRQ; - irqd_set_chained_irq_inprogress(idata); switch (msi_data->feature & FSL_PIC_IP_MASK) { case FSL_PIC_IP_MPIC: msir_value = fsl_msi_read(msi_data->msi_regs, @@ -303,25 +288,15 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) cascade_irq = irq_linear_revmap(msi_data->irqhost, msi_hwirq(msi_data, msir_index, intr_index + have_shift)); - if (cascade_irq != NO_IRQ) + if (cascade_irq != NO_IRQ) { generic_handle_irq(cascade_irq); + ret = IRQ_HANDLED; + } have_shift += intr_index + 1; msir_value = msir_value >> (intr_index + 1); } - irqd_clr_chained_irq_inprogress(idata); - switch (msi_data->feature & FSL_PIC_IP_MASK) { - case FSL_PIC_IP_MPIC: - case FSL_PIC_IP_VMPIC: - chip->irq_eoi(idata); - break; - case FSL_PIC_IP_IPIC: - if (!irqd_irq_disabled(idata) && chip->irq_unmask) - chip->irq_unmask(idata); - break; - } -unlock: - raw_spin_unlock(&desc->lock); + return ret; } static int fsl_of_msi_remove(struct platform_device *ofdev) @@ -336,9 +311,8 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) virq = msi->cascade_array[i]->virq; BUG_ON(virq == NO_IRQ); - BUG_ON(msi->cascade_array[i] != - irq_get_handler_data(virq)); + free_irq(virq, msi->cascade_array[i]); kfree(msi->cascade_array[i]); irq_dispose_mapping(virq); } @@ -358,7 +332,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, int offset, int irq_index) { struct fsl_msi_cascade_data *cascade_data = NULL; - int virt_msir, i; + int virt_msir, i, ret; virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); if (virt_msir == NO_IRQ) { @@ -377,8 +351,14 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, cascade_data->msi_data = msi; cascade_data->virq = virt_msir; msi->cascade_array[irq_index] = cascade_data; - irq_set_handler_data(virt_msir, cascade_data); - irq_set_chained_handler(virt_msir, fsl_msi_cascade); + + ret = request_irq(virt_msir, fsl_msi_cascade, 0, + "fsl-msi-cascade", cascade_data); + if (ret) { + dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n", + virt_msir, ret); + return ret; + } /* Release the hwirqs corresponding to this MSI register */ for (i = 0; i < IRQS_PER_MSI_REG; i++) -- cgit v1.2.3 From de99f53d3af0e1bb9bc6c9e3107d72f3af6e05e9 Mon Sep 17 00:00:00 2001 From: Tudor Laurentiu Date: Tue, 19 Aug 2014 14:25:05 +0300 Subject: powerpc/fsl_msi: show more meaningful names in /proc/interrupts Rename the irq controller associated with a MSI interrupt to fsl-msi-, where is the virq of the cascade irq backing up this MSI interrupt. This way, one can set the affinity of a MSI through the cascade irq associated with said MSI interrupt. Given this example /proc/interrupts snippet: CPU0 CPU1 CPU2 CPU3 16: 0 0 0 0 OpenPIC 16 Edge mpic-error-int 17: 0 4 0 0 fsl-msi-224 0 Edge eth0-rx-0 18: 0 5 0 0 fsl-msi-225 1 Edge eth0-tx-0 19: 0 2 0 0 fsl-msi-226 2 Edge eth0 [...] 224: 0 11 0 0 OpenPIC 224 Edge fsl-msi-cascade 225: 0 0 0 0 OpenPIC 225 Edge fsl-msi-cascade 226: 0 0 0 0 OpenPIC 226 Edge fsl-msi-cascade [...] To change the affinity of MSI interrupt 17 (having the irq controller named "fsl-msi-224") instead of writing /proc/irq/17/smp_affinity, use the associated MSI cascade irq, in this case, interrupt 224, e.g.: echo 6 > /proc/irq/224/smp_affinity Note that a MSI cascade irq covers several MSI interrupts, so changing the affinity on the cascade will impact all of the associated MSI interrupts. Signed-off-by: Laurentiu Tudor Cc: Scott Wood Cc: Mihai Caraman Signed-off-by: Scott Wood --- arch/powerpc/sysdev/fsl_msi.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 0cfc32a63039..e2ee226464f8 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -67,11 +68,24 @@ static void fsl_msi_end_irq(struct irq_data *d) { } +static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p) +{ + struct fsl_msi *msi_data = irqd->domain->host_data; + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + int cascade_virq, srs; + + srs = (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK; + cascade_virq = msi_data->cascade_array[srs]->virq; + + seq_printf(p, " fsl-msi-%d", cascade_virq); +} + + static struct irq_chip fsl_msi_chip = { .irq_mask = mask_msi_irq, .irq_unmask = unmask_msi_irq, .irq_ack = fsl_msi_end_irq, - .name = "FSL-MSI", + .irq_print_chip = fsl_msi_print_chip, }; static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq, -- cgit v1.2.3 From c822e73731fce3b49a4887140878d084d8a44c08 Mon Sep 17 00:00:00 2001 From: Tudor Laurentiu Date: Thu, 21 Aug 2014 12:33:53 +0300 Subject: powerpc/fsl_msi: spread msi ints across different MSIRs Allocate msis such that each time a new interrupt is requested, the SRS (MSIR register select) to be used is allocated in a round-robin fashion. The end result is that the msi interrupts will be spread across distinct MSIRs with the main benefit that now users can set affinity to each msi int through the mpic irq backing up the MSIR register. This is achieved with the help of a newly introduced msi bitmap api that allows specifying the starting point when searching for a free msi interrupt. Signed-off-by: Laurentiu Tudor Cc: Scott Wood Cc: Mihai Caraman Signed-off-by: Scott Wood --- arch/powerpc/sysdev/fsl_msi.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index e2ee226464f8..37254eff7324 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -213,6 +213,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) * available interrupt. */ list_for_each_entry(msi_data, &msi_head, list) { + int off; + /* * If the PCI node has an fsl,msi property, then we * restrict our search to the corresponding MSI node. @@ -224,7 +226,28 @@ 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); + /* + * Allocate the msi message so that it fits on distinct + * MSIR registers. Obviously, since MSIR registers are + * limited they will overlap at one point. + * + * Due to the format of the newly introduced MSIIR1 in + * mpic 4.3, consecutive msi message values map to + * distinct MSIRs, thus distinct msi irq cascades, so + * nothing special needs to be done in this case. + * On older mpic versions the chose distinct SRS + * values by aligning the msi message value to the + * SRS field shift. + */ + if (msi_data->feature & FSL_PIC_FTR_MPIC_4_3) { + off = 0; + } else { + off = atomic_inc_return(&msi_data->msi_alloc_cnt) % + msi_data->msir_num; + off <<= msi_data->srs_shift; + } + hwirq = msi_bitmap_alloc_hwirqs_from_offset( + &msi_data->bitmap, off, 1); if (hwirq >= 0) break; } @@ -464,12 +487,17 @@ static int fsl_of_msi_probe(struct platform_device *dev) goto error_out; } + atomic_set(&msi->msi_alloc_cnt, -1); + p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") || of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) { msi->srs_shift = MSIIR1_SRS_SHIFT; msi->ibs_shift = MSIIR1_IBS_SHIFT; + msi->msir_num = NR_MSI_REG_MSIIR1; + msi->feature |= FSL_PIC_FTR_MPIC_4_3; + if (p) dev_warn(&dev->dev, "%s: dose not support msi-available-ranges property\n", __func__); @@ -487,6 +515,7 @@ static int fsl_of_msi_probe(struct platform_device *dev) msi->srs_shift = MSIIR_SRS_SHIFT; msi->ibs_shift = MSIIR_IBS_SHIFT; + msi->msir_num = NR_MSI_REG_MSIIR; if (p && len % (2 * sizeof(u32)) != 0) { dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n", -- cgit v1.2.3 From cb0446c1b625326682ec4f9d1dd10779433646bc Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 19 Sep 2014 15:20:36 -0500 Subject: Revert "powerpc/fsl_msi: spread msi ints across different MSIRs" This reverts commit c822e73731fce3b49a4887140878d084d8a44c08. This commit conflicted with a bitmap allocator change that partially accomplishes the same thing, but which does so more correctly. Revert this one until it can be respun on top of the correct change. Signed-off-by: Scott Wood --- arch/powerpc/sysdev/fsl_msi.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 37254eff7324..e2ee226464f8 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -213,8 +213,6 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) * available interrupt. */ list_for_each_entry(msi_data, &msi_head, list) { - int off; - /* * If the PCI node has an fsl,msi property, then we * restrict our search to the corresponding MSI node. @@ -226,28 +224,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (phandle && (phandle != msi_data->phandle)) continue; - /* - * Allocate the msi message so that it fits on distinct - * MSIR registers. Obviously, since MSIR registers are - * limited they will overlap at one point. - * - * Due to the format of the newly introduced MSIIR1 in - * mpic 4.3, consecutive msi message values map to - * distinct MSIRs, thus distinct msi irq cascades, so - * nothing special needs to be done in this case. - * On older mpic versions the chose distinct SRS - * values by aligning the msi message value to the - * SRS field shift. - */ - if (msi_data->feature & FSL_PIC_FTR_MPIC_4_3) { - off = 0; - } else { - off = atomic_inc_return(&msi_data->msi_alloc_cnt) % - msi_data->msir_num; - off <<= msi_data->srs_shift; - } - hwirq = msi_bitmap_alloc_hwirqs_from_offset( - &msi_data->bitmap, off, 1); + hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); if (hwirq >= 0) break; } @@ -487,17 +464,12 @@ static int fsl_of_msi_probe(struct platform_device *dev) goto error_out; } - atomic_set(&msi->msi_alloc_cnt, -1); - p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") || of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) { msi->srs_shift = MSIIR1_SRS_SHIFT; msi->ibs_shift = MSIIR1_IBS_SHIFT; - msi->msir_num = NR_MSI_REG_MSIIR1; - msi->feature |= FSL_PIC_FTR_MPIC_4_3; - if (p) dev_warn(&dev->dev, "%s: dose not support msi-available-ranges property\n", __func__); @@ -515,7 +487,6 @@ static int fsl_of_msi_probe(struct platform_device *dev) msi->srs_shift = MSIIR_SRS_SHIFT; msi->ibs_shift = MSIIR_IBS_SHIFT; - msi->msir_num = NR_MSI_REG_MSIIR; if (p && len % (2 * sizeof(u32)) != 0) { dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n", -- cgit v1.2.3