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 77efbaec7b9..9fadc6e4dc4 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-70-g09d2 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 +++++++++++------ arch/powerpc/sysdev/fsl_msi.h | 4 +++- 2 files changed, 14 insertions(+), 7 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 9fadc6e4dc4..05a0dd918de 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); diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index df9aa9fe093..420cfcbdac0 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -27,6 +27,8 @@ #define FSL_PIC_IP_IPIC 0x00000002 #define FSL_PIC_IP_VMPIC 0x00000003 +struct fsl_msi_cascade_data; + struct fsl_msi { struct irq_domain *irqhost; @@ -37,7 +39,7 @@ struct fsl_msi { u32 srs_shift; /* Shift of the shared interrupt register select */ void __iomem *msi_regs; u32 feature; - int msi_virqs[NR_MSI_REG_MAX]; + struct fsl_msi_cascade_data *cascade_array[NR_MSI_REG_MAX]; struct msi_bitmap bitmap; -- cgit v1.2.3-70-g09d2 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 05a0dd918de..0cfc32a6303 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-70-g09d2 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 0cfc32a6303..e2ee226464f 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-70-g09d2 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/include/asm/msi_bitmap.h | 2 ++ arch/powerpc/sysdev/fsl_msi.c | 31 ++++++++++++++++++++++++++++++- arch/powerpc/sysdev/fsl_msi.h | 5 +++++ arch/powerpc/sysdev/msi_bitmap.c | 25 +++++++++++++++---------- 4 files changed, 52 insertions(+), 11 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/include/asm/msi_bitmap.h b/arch/powerpc/include/asm/msi_bitmap.h index 97ac3f46ae0..96c2f950057 100644 --- a/arch/powerpc/include/asm/msi_bitmap.h +++ b/arch/powerpc/include/asm/msi_bitmap.h @@ -25,6 +25,8 @@ int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num); void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset, unsigned int num); void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq); +int msi_bitmap_alloc_hwirqs_from_offset(struct msi_bitmap *bmp, int offset, + int num); int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp); diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index e2ee226464f..37254eff732 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", diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 420cfcbdac0..50ec4b04c73 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -15,6 +15,7 @@ #include #include +#include #define NR_MSI_REG_MSIIR 8 /* MSIIR can index 8 MSI registers */ #define NR_MSI_REG_MSIIR1 16 /* MSIIR1 can index 16 MSI registers */ @@ -27,6 +28,8 @@ #define FSL_PIC_IP_IPIC 0x00000002 #define FSL_PIC_IP_VMPIC 0x00000003 +#define FSL_PIC_FTR_MPIC_4_3 0x00000010 + struct fsl_msi_cascade_data; struct fsl_msi { @@ -37,6 +40,8 @@ struct fsl_msi { u32 msiir_offset; /* Offset of MSIIR, relative to start of CCSR */ u32 ibs_shift; /* Shift of interrupt bit select */ u32 srs_shift; /* Shift of the shared interrupt register select */ + u32 msir_num; /* Number of available MSIR regs */ + atomic_t msi_alloc_cnt; /* Counter for MSI hwirq allocations */ void __iomem *msi_regs; u32 feature; struct fsl_msi_cascade_data *cascade_array[NR_MSI_REG_MAX]; diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c index 2ff630267e9..8b7d8fc2b12 100644 --- a/arch/powerpc/sysdev/msi_bitmap.c +++ b/arch/powerpc/sysdev/msi_bitmap.c @@ -14,23 +14,28 @@ #include #include -int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) +int msi_bitmap_alloc_hwirqs_from_offset(struct msi_bitmap *bmp, int offset, + int num) { unsigned long flags; - int offset, order = get_count_order(num); + int index; + int order = get_count_order(num); spin_lock_irqsave(&bmp->lock, flags); - /* - * This is fast, but stricter than we need. We might want to add - * a fallback routine which does a linear search with no alignment. - */ - offset = bitmap_find_free_region(bmp->bitmap, bmp->irq_count, order); + index = bitmap_find_next_zero_area(bmp->bitmap, bmp->irq_count, + offset, num, (1 << order) - 1); + bitmap_set(bmp->bitmap, index, num); spin_unlock_irqrestore(&bmp->lock, flags); - pr_debug("msi_bitmap: allocated 0x%x (2^%d) at offset 0x%x\n", - num, order, offset); + pr_debug("msi_bitmap: found %d free bits starting from offset %d at index %d\n", + num, offset, index); - return offset; + return index; +} + +int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) +{ + return msi_bitmap_alloc_hwirqs_from_offset(bmp, 0, num); } void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset, -- cgit v1.2.3-70-g09d2 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/include/asm/msi_bitmap.h | 2 -- arch/powerpc/sysdev/fsl_msi.c | 31 +------------------------------ arch/powerpc/sysdev/fsl_msi.h | 5 ----- arch/powerpc/sysdev/msi_bitmap.c | 25 ++++++++++--------------- 4 files changed, 11 insertions(+), 52 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/include/asm/msi_bitmap.h b/arch/powerpc/include/asm/msi_bitmap.h index 96c2f950057..97ac3f46ae0 100644 --- a/arch/powerpc/include/asm/msi_bitmap.h +++ b/arch/powerpc/include/asm/msi_bitmap.h @@ -25,8 +25,6 @@ int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num); void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset, unsigned int num); void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq); -int msi_bitmap_alloc_hwirqs_from_offset(struct msi_bitmap *bmp, int offset, - int num); int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp); diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 37254eff732..e2ee226464f 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", diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 50ec4b04c73..420cfcbdac0 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -15,7 +15,6 @@ #include #include -#include #define NR_MSI_REG_MSIIR 8 /* MSIIR can index 8 MSI registers */ #define NR_MSI_REG_MSIIR1 16 /* MSIIR1 can index 16 MSI registers */ @@ -28,8 +27,6 @@ #define FSL_PIC_IP_IPIC 0x00000002 #define FSL_PIC_IP_VMPIC 0x00000003 -#define FSL_PIC_FTR_MPIC_4_3 0x00000010 - struct fsl_msi_cascade_data; struct fsl_msi { @@ -40,8 +37,6 @@ struct fsl_msi { u32 msiir_offset; /* Offset of MSIIR, relative to start of CCSR */ u32 ibs_shift; /* Shift of interrupt bit select */ u32 srs_shift; /* Shift of the shared interrupt register select */ - u32 msir_num; /* Number of available MSIR regs */ - atomic_t msi_alloc_cnt; /* Counter for MSI hwirq allocations */ void __iomem *msi_regs; u32 feature; struct fsl_msi_cascade_data *cascade_array[NR_MSI_REG_MAX]; diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c index 8b7d8fc2b12..2ff630267e9 100644 --- a/arch/powerpc/sysdev/msi_bitmap.c +++ b/arch/powerpc/sysdev/msi_bitmap.c @@ -14,28 +14,23 @@ #include #include -int msi_bitmap_alloc_hwirqs_from_offset(struct msi_bitmap *bmp, int offset, - int num) +int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) { unsigned long flags; - int index; - int order = get_count_order(num); + int offset, order = get_count_order(num); spin_lock_irqsave(&bmp->lock, flags); - index = bitmap_find_next_zero_area(bmp->bitmap, bmp->irq_count, - offset, num, (1 << order) - 1); - bitmap_set(bmp->bitmap, index, num); + /* + * This is fast, but stricter than we need. We might want to add + * a fallback routine which does a linear search with no alignment. + */ + offset = bitmap_find_free_region(bmp->bitmap, bmp->irq_count, order); spin_unlock_irqrestore(&bmp->lock, flags); - pr_debug("msi_bitmap: found %d free bits starting from offset %d at index %d\n", - num, offset, index); - - return index; -} + pr_debug("msi_bitmap: allocated 0x%x (2^%d) at offset 0x%x\n", + num, order, offset); -int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) -{ - return msi_bitmap_alloc_hwirqs_from_offset(bmp, 0, num); + return offset; } void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset, -- cgit v1.2.3-70-g09d2 From 6b2fd7efeb888fa781c1f767de6c36497ac1596b Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sun, 7 Sep 2014 20:57:53 +0200 Subject: PCI/MSI/PPC: Remove arch_msi_check_device() Move MSI checks from arch_msi_check_device() to arch_setup_msi_irqs(). This makes the code more compact and allows removing arch_msi_check_device() from generic MSI code. Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas Acked-by: Michael Ellerman --- arch/powerpc/include/asm/machdep.h | 2 -- arch/powerpc/kernel/msi.c | 12 +--------- arch/powerpc/platforms/cell/axon_msi.c | 9 -------- arch/powerpc/platforms/powernv/pci.c | 19 ++++----------- arch/powerpc/platforms/pseries/msi.c | 42 +++++++++++++--------------------- arch/powerpc/sysdev/fsl_msi.c | 12 +++------- arch/powerpc/sysdev/mpic_pasemi_msi.c | 11 ++------- arch/powerpc/sysdev/mpic_u3msi.c | 28 +++++++++-------------- arch/powerpc/sysdev/ppc4xx_hsta_msi.c | 18 +++++---------- arch/powerpc/sysdev/ppc4xx_msi.c | 19 +++++---------- 10 files changed, 50 insertions(+), 122 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_msi.c') diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index b125ceab149..3af72163361 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -136,8 +136,6 @@ struct machdep_calls { int (*pci_setup_phb)(struct pci_controller *host); #ifdef CONFIG_PCI_MSI - int (*msi_check_device)(struct pci_dev* dev, - int nvec, int type); int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); void (*teardown_msi_irqs)(struct pci_dev *dev); diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c index 8bbc12d20f5..71bd161640c 100644 --- a/arch/powerpc/kernel/msi.c +++ b/arch/powerpc/kernel/msi.c @@ -13,7 +13,7 @@ #include -int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) { pr_debug("msi: Platform doesn't provide MSI callbacks.\n"); @@ -24,16 +24,6 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) 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); - } - - return 0; -} - -int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -{ return ppc_md.setup_msi_irqs(dev, nvec, type); } diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 85825b5401e..862b32702d2 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -199,14 +199,6 @@ out_error: return msic; } -static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type) -{ - if (!find_msi_translator(dev)) - return -ENODEV; - - return 0; -} - static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) { struct device_node *dn; @@ -416,7 +408,6 @@ static int axon_msi_probe(struct platform_device *device) ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; - ppc_md.msi_check_device = axon_msi_check_device; axon_msi_debug_setup(dn, msic); diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index b854b57ed5e..b45c49249a5 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -46,29 +46,21 @@ //#define cfg_dbg(fmt...) printk(fmt) #ifdef CONFIG_PCI_MSI -static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) -{ - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pci_get_pdn(pdev); - - if (pdn && pdn->force_32bit_msi && !phb->msi32_support) - return -ENODEV; - - return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV; -} - static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { struct pci_controller *hose = pci_bus_to_host(pdev->bus); struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn = pci_get_pdn(pdev); struct msi_desc *entry; struct msi_msg msg; int hwirq; unsigned int virq; int rc; - if (WARN_ON(!phb)) + if (WARN_ON(!phb) || !phb->msi_bmp.bitmap) + return -ENODEV; + + if (pdn && pdn->force_32bit_msi && !phb->msi32_support) return -ENODEV; list_for_each_entry(entry, &pdev->msi_list, list) { @@ -860,7 +852,6 @@ void __init pnv_pci_init(void) /* Configure MSIs */ #ifdef CONFIG_PCI_MSI - ppc_md.msi_check_device = pnv_msi_check_device; ppc_md.setup_msi_irqs = pnv_setup_msi_irqs; ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs; #endif diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 18ff4626d74..e68c196def1 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -336,26 +336,6 @@ out: return request; } -static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - int quota, rc; - - if (type == PCI_CAP_ID_MSIX) - rc = check_req_msix(pdev, nvec); - else - rc = check_req_msi(pdev, nvec); - - if (rc) - return rc; - - quota = msi_quota_for_device(pdev, nvec); - - if (quota && quota < nvec) - return quota; - - return 0; -} - static int check_msix_entries(struct pci_dev *pdev) { struct msi_desc *entry; @@ -397,15 +377,24 @@ static void rtas_hack_32bit_msi_gen2(struct pci_dev *pdev) static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) { struct pci_dn *pdn; - int hwirq, virq, i, rc; + int hwirq, virq, i, quota, rc; struct msi_desc *entry; struct msi_msg msg; int nvec = nvec_in; int use_32bit_msi_hack = 0; - pdn = pci_get_pdn(pdev); - if (!pdn) - return -ENODEV; + if (type == PCI_CAP_ID_MSIX) + rc = check_req_msix(pdev, nvec); + else + rc = check_req_msi(pdev, nvec); + + if (rc) + return rc; + + quota = msi_quota_for_device(pdev, nvec); + + if (quota && quota < nvec) + return quota; if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev)) return -EINVAL; @@ -416,12 +405,14 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) */ if (type == PCI_CAP_ID_MSIX) { int m = roundup_pow_of_two(nvec); - int quota = msi_quota_for_device(pdev, m); + quota = msi_quota_for_device(pdev, m); if (quota >= m) nvec = m; } + pdn = pci_get_pdn(pdev); + /* * Try the new more explicit firmware interface, if that fails fall * back to the old interface. The old interface is known to never @@ -526,7 +517,6 @@ static int rtas_msi_init(void) WARN_ON(ppc_md.setup_msi_irqs); ppc_md.setup_msi_irqs = rtas_setup_msi_irqs; ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs; - ppc_md.msi_check_device = rtas_msi_check_device; WARN_ON(ppc_md.pci_irq_fixup); ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 77efbaec7b9..b32e79dbef4 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -109,14 +109,6 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data) return 0; } -static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - if (type == PCI_CAP_ID_MSIX) - pr_debug("fslmsi: MSI-X untested, trying anyway.\n"); - - return 0; -} - static void fsl_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; @@ -173,6 +165,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) struct msi_msg msg; struct fsl_msi *msi_data; + if (type == PCI_CAP_ID_MSIX) + pr_debug("fslmsi: MSI-X untested, trying anyway.\n"); + /* * If the PCI node has an fsl,msi property, then we need to use it * to find the specific MSI. @@ -527,7 +522,6 @@ static int fsl_of_msi_probe(struct platform_device *dev) if (!ppc_md.setup_msi_irqs) { ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; - ppc_md.msi_check_device = fsl_msi_check_device; } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) { dev_err(&dev->dev, "Different MSI driver already installed!\n"); err = -ENODEV; diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 38e62382070..15dccd35fa1 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c @@ -63,14 +63,6 @@ static struct irq_chip mpic_pasemi_msi_chip = { .name = "PASEMI-MSI", }; -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"); - - return 0; -} - static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; @@ -97,6 +89,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) struct msi_msg msg; int hwirq; + if (type == PCI_CAP_ID_MSIX) + pr_debug("pasemi_msi: MSI-X untested, trying anyway\n"); pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", pdev, nvec, type); @@ -169,7 +163,6 @@ int mpic_pasemi_msi_init(struct mpic *mpic) WARN_ON(ppc_md.setup_msi_irqs); ppc_md.setup_msi_irqs = pasemi_msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs; - ppc_md.msi_check_device = pasemi_msi_check_device; return 0; } diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 9a7aa0ed9c1..623d7fba15b 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -105,22 +105,6 @@ static u64 find_u4_magic_addr(struct pci_dev *pdev, unsigned int hwirq) return 0; } -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 we can't find a magic address then MSI ain't gonna work */ - if (find_ht_magic_addr(pdev, 0) == 0 && - find_u4_magic_addr(pdev, 0) == 0) { - pr_debug("u3msi: no magic address found for %s\n", - pci_name(pdev)); - return -ENXIO; - } - - return 0; -} - static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; @@ -146,6 +130,17 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) u64 addr; int hwirq; + if (type == PCI_CAP_ID_MSIX) + pr_debug("u3msi: MSI-X untested, trying anyway.\n"); + + /* If we can't find a magic address then MSI ain't gonna work */ + if (find_ht_magic_addr(pdev, 0) == 0 && + find_u4_magic_addr(pdev, 0) == 0) { + pr_debug("u3msi: no magic address found for %s\n", + pci_name(pdev)); + return -ENXIO; + } + list_for_each_entry(entry, &pdev->msi_list, list) { hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1); if (hwirq < 0) { @@ -202,7 +197,6 @@ int mpic_u3msi_init(struct mpic *mpic) WARN_ON(ppc_md.setup_msi_irqs); ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs; - ppc_md.msi_check_device = u3msi_msi_check_device; return 0; } diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c index 11c888416f0..a6a4dbda907 100644 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -44,6 +44,12 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) int irq, hwirq; u64 addr; + /* We don't support MSI-X */ + if (type == PCI_CAP_ID_MSIX) { + pr_debug("%s: MSI-X not supported.\n", __func__); + return -EINVAL; + } + list_for_each_entry(entry, &dev->msi_list, list) { irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1); if (irq < 0) { @@ -117,17 +123,6 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev) } } -static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - /* We don't support MSI-X */ - if (type == PCI_CAP_ID_MSIX) { - pr_debug("%s: MSI-X not supported.\n", __func__); - return -EINVAL; - } - - return 0; -} - static int hsta_msi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -178,7 +173,6 @@ static int hsta_msi_probe(struct platform_device *pdev) ppc_md.setup_msi_irqs = hsta_setup_msi_irqs; ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs; - ppc_md.msi_check_device = hsta_msi_check_device; return 0; out2: diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c index 43948da837a..22b5200636e 100644 --- a/arch/powerpc/sysdev/ppc4xx_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_msi.c @@ -85,8 +85,12 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) struct msi_desc *entry; struct ppc4xx_msi *msi_data = &ppc4xx_msi; - msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), - GFP_KERNEL); + dev_dbg(&dev->dev, "PCIE-MSI:%s called. vec %x type %d\n", + __func__, nvec, type); + if (type == PCI_CAP_ID_MSIX) + pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n"); + + msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), GFP_KERNEL); if (!msi_data->msi_virqs) return -ENOMEM; @@ -134,16 +138,6 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev) } } -static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n", - __func__, nvec, type); - if (type == PCI_CAP_ID_MSIX) - pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n"); - - return 0; -} - static int ppc4xx_setup_pcieh_hw(struct platform_device *dev, struct resource res, struct ppc4xx_msi *msi) { @@ -259,7 +253,6 @@ static int ppc4xx_msi_probe(struct platform_device *dev) ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs; ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs; - ppc_md.msi_check_device = ppc4xx_msi_check_device; return err; error_out: -- cgit v1.2.3-70-g09d2