1. Only MSIIR1 can index 16 MSI registers, but when using MSIIR1 the IRQs of a register are not continuous. for example, the first register irq values are 0x0, 0x10, 0x20, 0x30 ... 0x1f0. So it is hard to use 'msi-available-ranges' property to indicate the available ranges and 'msi-available-ranges' property has been removed from dts node, so this patch removes the related code.
2. Add 'msiregs' kernel parameter instead of 'msi-available-ranges' functionality. 'msiregs' is used to indicate the available MSI registers ranges and uses a colon ':' to separate the multiple banks. The range representation format is 'start-end', 'start' and 'end' are integers describe the start and end register index, the available registers lies between start and end and not include end. For example, the available register x satisfying start <= x < end. Signed-off-by: Minghuan Lian <minghuan.l...@freescale.com> --- arch/powerpc/sysdev/fsl_msi.c | 118 ++++++++++++++++++++++++++++-------------- arch/powerpc/sysdev/fsl_msi.h | 1 + 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 34510b7..db382ef9b 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -52,6 +52,60 @@ struct fsl_msi_cascade_data { int index; }; +struct msi_reg_range { + u32 start; + u32 end; +}; + +static struct msi_reg_range msiregs[NR_MSI_BANK] = { + {.start = 0, .end = NR_MSI_REG }, + {.start = 0, .end = NR_MSI_REG }, + {.start = 0, .end = NR_MSI_REG }, + {.start = 0, .end = NR_MSI_REG }, +}; + +/* + * Handle 'msiregs' parameter. + * msiregs is used to indicate the available MSI registers range and + * uses colon ':' to separate the multiple banks ranges. + * For each bank, the registers range format is 'start-end' + * start and end are integers, used to the indicate the start and end + * register index. The range is a set of real numbers that lies between + * start and end but not include end. For example, the set of all numbers + * x satisfying start <= x < end. + * if no range specified, driver will use the default range including all + * the registers. + * if you do no want to use this bank, you can set range as '0-0' + * For example msiregs=0-16:0-0::0-2 + */ +static int msi_regs_setup(char *s) +{ + int bank = 0; + char *p; + struct msi_reg_range *range; + + while ((p = strsep(&s, ":")) != NULL) { + int start = 0, end = NR_MSI_REG; + + if (bank >= NR_MSI_BANK) + break; + range = &msiregs[bank]; + + if ((*p != '\0') && (sscanf(p, "%d-%d", &start, &end) < 1)) + pr_err("msiregs correct format is: start-end\n"); + + /* Ok, gets the specified value */ + range->start = start; + range->end = end; + pr_info("MSI bank%d available regs range is %d-%d\n", + bank, range->start, range->end); + bank++; + } + return 1; +} + +__setup("msiregs=", msi_regs_setup); + static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) { return in_be32(base + (reg >> 2)); @@ -350,7 +404,7 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) static struct lock_class_key fsl_msi_irq_class; static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, - int offset, int irq_index) + int irq_index) { struct fsl_msi_cascade_data *cascade_data = NULL; int virt_msir, i; @@ -369,7 +423,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, } irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class); msi->msi_virqs[irq_index] = virt_msir; - cascade_data->index = offset; + cascade_data->index = irq_index; cascade_data->msi_data = msi; irq_set_handler_data(virt_msir, cascade_data); irq_set_chained_handler(virt_msir, fsl_msi_cascade); @@ -377,7 +431,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, /* Release the hwirqs corresponding to this MSI register */ for (i = 0; i < IRQS_PER_MSI_REG; i++) msi_bitmap_free_hwirqs(&msi->bitmap, - msi_hwirq(msi, offset, i), 1); + msi_hwirq(msi, irq_index, i), 1); return 0; } @@ -387,21 +441,29 @@ static int fsl_of_msi_probe(struct platform_device *dev) { const struct of_device_id *match; struct fsl_msi *msi; + static int bank; + struct msi_reg_range *range; struct resource res, msiir; - int err, i, j, irq_index, count; + int err, irq_index, count; int rc; - const u32 *p; const struct fsl_msi_feature *features; - int len; - u32 offset; - static const u32 all_avail[] = { 0, NR_MSI_IRQS }; match = of_match_device(fsl_of_msi_ids, &dev->dev); if (!match) return -EINVAL; features = match->data; - printk(KERN_DEBUG "Setting up Freescale MSI support\n"); + if (bank >= NR_MSI_BANK) + return -EINVAL; + range = &msiregs[bank]; + pr_debug("Setting up Freescale MSI bank%d support\n", bank); + + count = of_irq_count(dev->dev.of_node); + if (!count) + return -ENODEV; + + if (count > NR_MSI_REG) + count = NR_MSI_REG; msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); if (!msi) { @@ -475,39 +537,17 @@ static int fsl_of_msi_probe(struct platform_device *dev) goto error_out; } - p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); - if (p && len % (2 * sizeof(u32)) != 0) { - dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n", - __func__); - err = -EINVAL; - goto error_out; - } - - if (!p) { - p = all_avail; - len = sizeof(all_avail); - } - - for (irq_index = 0, i = 0; i < len / (2 * sizeof(u32)); i++) { - if (p[i * 2] % IRQS_PER_MSI_REG || - p[i * 2 + 1] % IRQS_PER_MSI_REG) { - printk(KERN_WARNING "%s: %s: msi available range of %u at %u is not IRQ-aligned\n", - __func__, dev->dev.of_node->full_name, - p[i * 2 + 1], p[i * 2]); - err = -EINVAL; + for (irq_index = 0; irq_index < count; irq_index++) { + /* Check whether the register is contained in range */ + if (irq_index < range->start || + irq_index >= range->end) + continue; + err = fsl_msi_setup_hwirq(msi, dev, irq_index); + if (err) goto error_out; - } - - offset = p[i * 2] / IRQS_PER_MSI_REG; - count = p[i * 2 + 1] / IRQS_PER_MSI_REG; - - for (j = 0; j < count; j++, irq_index++) { - err = fsl_msi_setup_hwirq(msi, dev, offset + j, irq_index); - if (err) - goto error_out; - } } + bank++; list_add_tail(&msi->list, &msi_head); /* The multiple setting ppc_md.setup_msi_irqs will not harm things */ diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 43a9d99..6048415 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -16,6 +16,7 @@ #include <linux/of.h> #include <asm/msi_bitmap.h> +#define NR_MSI_BANK 4 #define NR_MSI_REG 16 #define IRQS_PER_MSI_REG 32 #define NR_MSI_IRQS (NR_MSI_REG * IRQS_PER_MSI_REG) -- 1.8.1.2 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev