[PATCH 5/5] powerpc/fsl_msi: add 'msiregs' kernel parameter

Minghuan Lian Minghuan.Lian at freescale.com
Fri Jun 14 17:15:59 EST 2013


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.Lian at 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




More information about the Linuxppc-dev mailing list