linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 6/7] MPIC MSI allocator
  2007-04-19  7:35 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
@ 2007-04-19  7:35 ` Michael Ellerman
  2007-04-21 23:17   ` Milton Miller
  2007-04-23  3:50   ` Olof Johansson
  0 siblings, 2 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-04-19  7:35 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-pci

To support MSI on MPIC we need a way to reserve and allocate hardware irq
numbers, this patch implements an allocator for that.

New firmware platforms must define a "msi-available-ranges" property on their
MPIC node for MSI to work. For BROKEN_U3 we do a best-guess setup.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/sysdev/Makefile   |    5 -
 arch/powerpc/sysdev/mpic.c     |    4 
 arch/powerpc/sysdev/mpic.h     |   24 +++++
 arch/powerpc/sysdev/mpic_msi.c |  175 +++++++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/mpic.h     |   11 ++
 5 files changed, 218 insertions(+), 1 deletion(-)

Index: msi-new/arch/powerpc/sysdev/Makefile
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/Makefile
+++ msi-new/arch/powerpc/sysdev/Makefile
@@ -2,7 +2,10 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-obj-$(CONFIG_MPIC)		+= mpic.o
+mpic-obj-y			:= mpic.o
+mpic-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o
+obj-$(CONFIG_MPIC)		+= $(mpic-obj-y)
+
 obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
 obj-$(CONFIG_PPC_DCR)		+= dcr.o
Index: msi-new/arch/powerpc/sysdev/mpic.c
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/mpic.c
+++ msi-new/arch/powerpc/sysdev/mpic.c
@@ -36,6 +36,8 @@
 #include <asm/mpic.h>
 #include <asm/smp.h>
 
+#include "mpic.h"
+
 #ifdef DEBUG
 #define DBG(fmt...) printk(fmt)
 #else
@@ -879,6 +881,8 @@ static int mpic_host_map(struct irq_host
 	if (hw >= mpic->irq_count)
 		return -EINVAL;
 
+	mpic_msi_reserve_hwirq(mpic, hw);
+
 	/* Default chip */
 	chip = &mpic->hc_irq;
 
Index: msi-new/arch/powerpc/sysdev/mpic.h
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/sysdev/mpic.h
@@ -0,0 +1,24 @@
+#ifndef _POWERPC_SYSDEV_MPIC_H
+#define _POWERPC_SYSDEV_MPIC_H
+
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#ifdef CONFIG_PCI_MSI
+extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
+#else
+static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
+					  irq_hw_number_t hwirq)
+{
+	return;
+}
+#endif
+
+#endif /* _POWERPC_SYSDEV_MPIC_H */
Index: msi-new/arch/powerpc/sysdev/mpic_msi.c
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/sysdev/mpic_msi.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/bitmap.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+
+static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+	pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
+	bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
+}
+
+void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+	unsigned long flags;
+
+	/* The mpic calls this even when there is no allocator setup */
+	if (!mpic->hwirq_bitmap)
+		return;
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	__mpic_msi_reserve_hwirq(mpic, hwirq);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
+{
+	unsigned long flags;
+	int offset, order = fls(num) - 1;
+
+	spin_lock_irqsave(&mpic->bitmap_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(mpic->hwirq_bitmap, mpic->irq_count,
+					 order);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+
+	pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
+		 num, order, offset);
+
+	return offset;
+}
+
+void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
+{
+	unsigned long flags;
+	int order = fls(num) - 1;
+
+	pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
+		 num, order, offset);
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	bitmap_release_region(mpic->hwirq_bitmap, offset, order);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+	irq_hw_number_t hwirq;
+	struct irq_host_ops *ops = mpic->irqhost->ops;
+	struct device_node *np;
+	int flags, index, i;
+	struct of_irq oirq;
+
+	pr_debug("mpic: found U3, guessing msi allocator setup\n");
+
+	/* Reserve source numbers we know are reserved in the HW */
+	for (i = 0;   i < 8;   i++) __mpic_msi_reserve_hwirq(mpic, i);
+	for (i = 42;  i < 46;  i++) __mpic_msi_reserve_hwirq(mpic, i);
+	for (i = 100; i < 105; i++) __mpic_msi_reserve_hwirq(mpic, i);
+
+	np = NULL;
+	while ((np = of_find_all_nodes(np))) {
+		pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
+
+		index = 0;
+		while (of_irq_map_one(np, index++, &oirq) == 0) {
+			ops->xlate(mpic->irqhost, NULL, oirq.specifier,
+						oirq.size, &hwirq, &flags);
+			__mpic_msi_reserve_hwirq(mpic, hwirq);
+		}
+	}
+
+	return 0;
+}
+#else
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { return -1; }
+#endif
+
+static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
+{
+	int i, len;
+	const u32 *p;
+
+	p = of_get_property(mpic->of_node, "msi-available-ranges", &len);
+	if (!p) {
+		pr_debug("mpic: no msi-available-ranges property found on %s\n",
+			  mpic->of_node->full_name);
+		return -ENODEV;
+	}
+
+	if (len % 8 != 0) {
+		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
+		       "property on %s\n", mpic->of_node->full_name);
+		return -EINVAL;
+	}
+
+	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
+			       fls(mpic->irq_count) - 1);
+
+	/* Format is: (<u32 start> <u32 count>)+ */
+	len /= sizeof(u32);
+	for (i = 0; i < len / 2; i++, p += 2)
+		mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
+
+	return 0;
+}
+
+int mpic_msi_init_allocator(struct mpic *mpic)
+{
+	int rc, size;
+
+	BUG_ON(mpic->hwirq_bitmap);
+	spin_lock_init(&mpic->bitmap_lock);
+
+	size = mpic->irq_count / 8;
+	pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
+
+	if (mem_init_done)
+		mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL);
+	else
+		mpic->hwirq_bitmap = alloc_bootmem(size);
+
+	if (!mpic->hwirq_bitmap) {
+		pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
+		return -ENOMEM;
+	}
+
+	memset(mpic->hwirq_bitmap, 0, size);
+
+	rc = mpic_msi_reserve_dt_hwirqs(mpic);
+	if (rc) {
+		if (mpic->flags & MPIC_BROKEN_U3)
+			rc = mpic_msi_reserve_u3_hwirqs(mpic);
+
+		if (rc)
+			goto out_free;
+	}
+
+	return 0;
+
+ out_free:
+	if (mem_init_done)
+		kfree(mpic->hwirq_bitmap);
+
+	mpic->hwirq_bitmap = NULL;
+	return rc;
+}
Index: msi-new/include/asm-powerpc/mpic.h
===================================================================
--- msi-new.orig/include/asm-powerpc/mpic.h
+++ msi-new/include/asm-powerpc/mpic.h
@@ -292,6 +292,11 @@ struct mpic
 	u32			*hw_set;
 #endif
 
+#ifdef CONFIG_PCI_MSI
+	spinlock_t		bitmap_lock;
+	unsigned long		*hwirq_bitmap;
+#endif
+
 	/* link */
 	struct mpic		*next;
 };
@@ -440,5 +445,11 @@ void mpic_set_clk_ratio(struct mpic *mpi
 /* Enable/Disable EPIC serial interrupt mode */
 void mpic_set_serial_int(struct mpic *mpic, int enable);
 
+#ifdef CONFIG_PCI_MSI
+extern int mpic_msi_init_allocator(struct mpic *mpic);
+extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
+extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
+#endif
+
 #endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_MPIC_H */

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-19  7:35 ` [PATCH 6/7] MPIC MSI allocator Michael Ellerman
@ 2007-04-21 23:17   ` Milton Miller
  2007-04-23  4:04     ` Michael Ellerman
  2007-04-23  3:50   ` Olof Johansson
  1 sibling, 1 reply; 23+ messages in thread
From: Milton Miller @ 2007-04-21 23:17 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, linux-pci

On Apr 19, 2007, Michael Ellerman wrote:
> To support MSI on MPIC we need a way to reserve and allocate hardware 
> irq
> numbers, this patch implements an allocator for that.

> Index: msi-new/arch/powerpc/sysdev/mpic_msi.c
> ===================================================================
> --- /dev/null
> +++ msi-new/arch/powerpc/sysdev/mpic_msi.c
...
> +irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
> +{
> +	unsigned long flags;
> +	int offset, order = fls(num) - 1;

get_count_order would be more clear.  Also it has
a correction factor.  (Applies several places).

> +#ifdef CONFIG_MPIC_BROKEN_U3
> +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
> +{
> +	irq_hw_number_t hwirq;
> +	struct irq_host_ops *ops = mpic->irqhost->ops;
> +	struct device_node *np;
> +	int flags, index, i;
> +	struct of_irq oirq;
> +
> +	pr_debug("mpic: found U3, guessing msi allocator setup\n");
> +
> +	/* Reserve source numbers we know are reserved in the HW */
> +	for (i = 0;   i < 8;   i++) __mpic_msi_reserve_hwirq(mpic, i);
> +	for (i = 42;  i < 46;  i++) __mpic_msi_reserve_hwirq(mpic, i);
> +	for (i = 100; i < 105; i++) __mpic_msi_reserve_hwirq(mpic, i);

More lines please.

> +#else
> +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { return -1; 
> }

and here.

> +	if (len % 8 != 0) {
> +		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
> +		       "property on %s\n", mpic->of_node->full_name);
> +		return -EINVAL;
> +	}
> +
> +	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
> +			       fls(mpic->irq_count) - 1);
> +
> +	/* Format is: (<u32 start> <u32 count>)+ */
> +	len /= sizeof(u32);
> +	for (i = 0; i < len / 2; i++, p += 2)

how about just dividing by the calculated 8 above?  or use
count = len / 8.

> +		mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
> +
> +	return 0;
> +}
> +
> +int mpic_msi_init_allocator(struct mpic *mpic)
> +{
> +	int rc, size;
> +
> +	BUG_ON(mpic->hwirq_bitmap);
> +	spin_lock_init(&mpic->bitmap_lock);
> +
> +	size = mpic->irq_count / 8;
> +	pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);

BITS_TO_LONGS() * sizeof(long).   We need to round up to longs to
use bitmask_*, especially being a big endian architecture.

milton

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-19  7:35 ` [PATCH 6/7] MPIC MSI allocator Michael Ellerman
  2007-04-21 23:17   ` Milton Miller
@ 2007-04-23  3:50   ` Olof Johansson
  2007-04-23  3:53     ` Michael Ellerman
  2007-04-24  1:29     ` Benjamin Herrenschmidt
  1 sibling, 2 replies; 23+ messages in thread
From: Olof Johansson @ 2007-04-23  3:50 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, linux-pci

On Thu, Apr 19, 2007 at 05:35:28PM +1000, Michael Ellerman wrote:
> To support MSI on MPIC we need a way to reserve and allocate hardware irq
> numbers, this patch implements an allocator for that.
> 
> New firmware platforms must define a "msi-available-ranges" property on their
> MPIC node for MSI to work. For BROKEN_U3 we do a best-guess setup.

It's time to rename BROKEN_U3. It used to be the config option to enable
a few workarounds, but now it's used to select whenever there's a U3 in
the system. Care to do it in the scope of this patch set?

> Index: msi-new/include/asm-powerpc/mpic.h
> ===================================================================
> --- msi-new.orig/include/asm-powerpc/mpic.h
> +++ msi-new/include/asm-powerpc/mpic.h
> @@ -292,6 +292,11 @@ struct mpic
>  	u32			*hw_set;
>  #endif
>  
> +#ifdef CONFIG_PCI_MSI
> +	spinlock_t		bitmap_lock;
> +	unsigned long		*hwirq_bitmap;
> +#endif

Besides the #ifdef there's nothing in the name that indicates that it's
used for msi. Better names could be useful.

> @@ -440,5 +445,11 @@ void mpic_set_clk_ratio(struct mpic *mpi
>  /* Enable/Disable EPIC serial interrupt mode */
>  void mpic_set_serial_int(struct mpic *mpic, int enable);
>  
> +#ifdef CONFIG_PCI_MSI
> +extern int mpic_msi_init_allocator(struct mpic *mpic);
> +extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
> +extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
> +#endif

These should go in mpic.h instead.


-Olof

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-23  3:50   ` Olof Johansson
@ 2007-04-23  3:53     ` Michael Ellerman
  2007-04-24  1:29     ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-04-23  3:53 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pci

[-- Attachment #1: Type: text/plain, Size: 2213 bytes --]

On Sun, 2007-04-22 at 22:50 -0500, Olof Johansson wrote:
> On Thu, Apr 19, 2007 at 05:35:28PM +1000, Michael Ellerman wrote:
> > To support MSI on MPIC we need a way to reserve and allocate hardware irq
> > numbers, this patch implements an allocator for that.
> > 
> > New firmware platforms must define a "msi-available-ranges" property on their
> > MPIC node for MSI to work. For BROKEN_U3 we do a best-guess setup.
> 
> It's time to rename BROKEN_U3. It used to be the config option to enable
> a few workarounds, but now it's used to select whenever there's a U3 in
> the system. Care to do it in the scope of this patch set?

Yeah it's pretty ugly. I guess I can do it. Got an idea for a better
name? MPIC_HT?

> > Index: msi-new/include/asm-powerpc/mpic.h
> > ===================================================================
> > --- msi-new.orig/include/asm-powerpc/mpic.h
> > +++ msi-new/include/asm-powerpc/mpic.h
> > @@ -292,6 +292,11 @@ struct mpic
> >  	u32			*hw_set;
> >  #endif
> >  
> > +#ifdef CONFIG_PCI_MSI
> > +	spinlock_t		bitmap_lock;
> > +	unsigned long		*hwirq_bitmap;
> > +#endif
> 
> Besides the #ifdef there's nothing in the name that indicates that it's
> used for msi. Better names could be useful.

True. Although, it doesn't necessarily have anything to do with MSI,
it's just a bitmap of hwirqs that are used/free. As it happens we only
need it when we're doing MSI though.

> 
> > @@ -440,5 +445,11 @@ void mpic_set_clk_ratio(struct mpic *mpi
> >  /* Enable/Disable EPIC serial interrupt mode */
> >  void mpic_set_serial_int(struct mpic *mpic, int enable);
> >  
> > +#ifdef CONFIG_PCI_MSI
> > +extern int mpic_msi_init_allocator(struct mpic *mpic);
> > +extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
> > +extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
> > +#endif
> 
> These should go in mpic.h instead.

Yep.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-21 23:17   ` Milton Miller
@ 2007-04-23  4:04     ` Michael Ellerman
  2007-04-23  6:20       ` Milton Miller
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Ellerman @ 2007-04-23  4:04 UTC (permalink / raw)
  To: Milton Miller; +Cc: linuxppc-dev, linux-pci

[-- Attachment #1: Type: text/plain, Size: 3035 bytes --]

On Sat, 2007-04-21 at 18:17 -0500, Milton Miller wrote:
> On Apr 19, 2007, Michael Ellerman wrote:
> > To support MSI on MPIC we need a way to reserve and allocate hardware 
> > irq
> > numbers, this patch implements an allocator for that.
> 
> > Index: msi-new/arch/powerpc/sysdev/mpic_msi.c
> > ===================================================================
> > --- /dev/null
> > +++ msi-new/arch/powerpc/sysdev/mpic_msi.c
> ...
> > +irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
> > +{
> > +	unsigned long flags;
> > +	int offset, order = fls(num) - 1;
> 
> get_count_order would be more clear.  Also it has
> a correction factor.  (Applies several places).

I was hoping someone would point out something better than fls, fixed.

> > +#ifdef CONFIG_MPIC_BROKEN_U3
> > +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
> > +{
> > +	irq_hw_number_t hwirq;
> > +	struct irq_host_ops *ops = mpic->irqhost->ops;
> > +	struct device_node *np;
> > +	int flags, index, i;
> > +	struct of_irq oirq;
> > +
> > +	pr_debug("mpic: found U3, guessing msi allocator setup\n");
> > +
> > +	/* Reserve source numbers we know are reserved in the HW */
> > +	for (i = 0;   i < 8;   i++) __mpic_msi_reserve_hwirq(mpic, i);
> > +	for (i = 42;  i < 46;  i++) __mpic_msi_reserve_hwirq(mpic, i);
> > +	for (i = 100; i < 105; i++) __mpic_msi_reserve_hwirq(mpic, i);
> 
> More lines please.
> 
> > +#else
> > +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { return -1; 
> > }
> 
> and here.

Blank lines aren't free you know!

> 
> > +	if (len % 8 != 0) {
> > +		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
> > +		       "property on %s\n", mpic->of_node->full_name);
> > +		return -EINVAL;
> > +	}
> > +
> > +	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
> > +			       fls(mpic->irq_count) - 1);
> > +
> > +	/* Format is: (<u32 start> <u32 count>)+ */
> > +	len /= sizeof(u32);
> > +	for (i = 0; i < len / 2; i++, p += 2)
> 
> how about just dividing by the calculated 8 above?  or use
> count = len / 8.

I'm not sure I follow. If you can think of a clearer way I'm all ears,
or are you just trying to save a divide :)

> 
> > +		mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
> > +
> > +	return 0;
> > +}
> > +
> > +int mpic_msi_init_allocator(struct mpic *mpic)
> > +{
> > +	int rc, size;
> > +
> > +	BUG_ON(mpic->hwirq_bitmap);
> > +	spin_lock_init(&mpic->bitmap_lock);
> > +
> > +	size = mpic->irq_count / 8;
> > +	pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
> 
> BITS_TO_LONGS() * sizeof(long).   We need to round up to longs to
> use bitmask_*, especially being a big endian architecture.

Eww, sorry that's horrible. Fixed.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-23  4:04     ` Michael Ellerman
@ 2007-04-23  6:20       ` Milton Miller
  0 siblings, 0 replies; 23+ messages in thread
From: Milton Miller @ 2007-04-23  6:20 UTC (permalink / raw)
  To: michael; +Cc: linuxppc-dev, linux-pci


On Apr 22, 2007, at 11:04 PM, Michael Ellerman wrote:

> On Sat, 2007-04-21 at 18:17 -0500, Milton Miller wrote:
>> On Apr 19, 2007, Michael Ellerman wrote:
>>> To support MSI on MPIC we need a way to reserve and allocate hardware
>>> irq
>>> numbers, this patch implements an allocator for that.

>>> +	/* Reserve source numbers we know are reserved in the HW */
>>> +	for (i = 0;   i < 8;   i++) __mpic_msi_reserve_hwirq(mpic, i);
>>> +	for (i = 42;  i < 46;  i++) __mpic_msi_reserve_hwirq(mpic, i);
>>> +	for (i = 100; i < 105; i++) __mpic_msi_reserve_hwirq(mpic, i);
>>
>> More lines please.
>>
>>> +#else
>>> +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { return 
>>> -1;
>>> }
>>
>> and here.
>
> Blank lines aren't free you know!

I didn't ask for any blank ones, so you can keep the bill. :-)

>>
>>> +	if (len % 8 != 0) {

Here you use 8 as the size of the element to process.

>>> +		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
>>> +		       "property on %s\n", mpic->of_node->full_name);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
>>> +			       fls(mpic->irq_count) - 1);
>>> +
>>> +	/* Format is: (<u32 start> <u32 count>)+ */
>>> +	len /= sizeof(u32);

Here you hide a divide by 4 and follow with divide by 2.

>>> +	for (i = 0; i < len / 2; i++, p += 2)
>>
>> how about just dividing by the calculated 8 above?  or use
>> count = len / 8.
>
> I'm not sure I follow. If you can think of a clearer way I'm all ears,
> or are you just trying to save a divide :)

I'm saying that it doesn't make sense to do both of the above.
I'd move the comment on being pairs of cells to before the
if () EINVAL then follow immediately with the divide.  If you
think that hides length being adjusted then I was optionally
suggesting making a new variable count to use in the for loop.

Actually, since i isn't used in the loop you could just
increment i by 8 while < len, and save both divides.

milton

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-23  3:50   ` Olof Johansson
  2007-04-23  3:53     ` Michael Ellerman
@ 2007-04-24  1:29     ` Benjamin Herrenschmidt
  2007-04-24  9:26       ` Segher Boessenkool
  1 sibling, 1 reply; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2007-04-24  1:29 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pci


> It's time to rename BROKEN_U3. It used to be the config option to enable
> a few workarounds, but now it's used to select whenever there's a U3 in
> the system. Care to do it in the scope of this patch set?

Not really.... first gen G5s don't use that :-) It's wether the MPIC is
part of U3/U4 -and- is used as a primary HT PIC.

Ben.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-24  1:29     ` Benjamin Herrenschmidt
@ 2007-04-24  9:26       ` Segher Boessenkool
  2007-04-24  9:39         ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 23+ messages in thread
From: Segher Boessenkool @ 2007-04-24  9:26 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Olof Johansson, linuxppc-dev, linux-pci

>> It's time to rename BROKEN_U3. It used to be the config option to 
>> enable
>> a few workarounds, but now it's used to select whenever there's a U3 
>> in
>> the system. Care to do it in the scope of this patch set?
>
> Not really.... first gen G5s don't use that :-) It's wether the MPIC is
> part of U3/U4 -and- is used as a primary HT PIC.

Not really...  It is whether the HT-to-MPIC interface
on the U3/U4 has the "feature" that ack-required
interrupts coming in over HT need to be acked by hand.

First-gen G5's need that just as well, they just don't
have such interrupts on the default system configuration,
as far as I remember.


Segher

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-24  9:26       ` Segher Boessenkool
@ 2007-04-24  9:39         ` Benjamin Herrenschmidt
  2007-04-24  9:44           ` Segher Boessenkool
  0 siblings, 1 reply; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2007-04-24  9:39 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Olof Johansson, linuxppc-dev, linux-pci

On Tue, 2007-04-24 at 11:26 +0200, Segher Boessenkool wrote:
> >> It's time to rename BROKEN_U3. It used to be the config option to 
> >> enable
> >> a few workarounds, but now it's used to select whenever there's a U3 
> >> in
> >> the system. Care to do it in the scope of this patch set?
> >
> > Not really.... first gen G5s don't use that :-) It's wether the MPIC is
> > part of U3/U4 -and- is used as a primary HT PIC.
> 
> Not really...  It is whether the HT-to-MPIC interface
> on the U3/U4 has the "feature" that ack-required
> interrupts coming in over HT need to be acked by hand.
> 
> First-gen G5's need that just as well, they just don't
> have such interrupts on the default system configuration,
> as far as I remember.

They didn't have an HT APIC or if they had one, they didn't enable it
(they probably did in the tunnel). They didn't use the U3 MPIC as an HT
IRQ master, thus it's irrelevant. Anyway, there is no point in this
discussion :-)

Ben.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-24  9:39         ` Benjamin Herrenschmidt
@ 2007-04-24  9:44           ` Segher Boessenkool
  2007-04-24  9:51             ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 23+ messages in thread
From: Segher Boessenkool @ 2007-04-24  9:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Olof Johansson, linuxppc-dev, linux-pci

>> First-gen G5's need that just as well, they just don't
>> have such interrupts on the default system configuration,
>> as far as I remember.
>
> They didn't have an HT APIC or if they had one, they didn't enable it
> (they probably did in the tunnel).

Yes, the two HT APICs on the tunnel were enabled.

> They didn't use the U3 MPIC as an HT
> IRQ master, thus it's irrelevant.

They did for the plugin PCI-X slots (well, it's chained
to another MPIC, but you still need the workaround).

> Anyway, there is no point in this
> discussion :-)

Yeah, the new name for CONFIG_BROKEN_U3 is fine
no matter what :-)


Segher

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] MPIC MSI allocator
  2007-04-24  9:44           ` Segher Boessenkool
@ 2007-04-24  9:51             ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2007-04-24  9:51 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Olof Johansson, linuxppc-dev, linux-pci

On Tue, 2007-04-24 at 11:44 +0200, Segher Boessenkool wrote:
> >> First-gen G5's need that just as well, they just don't
> >> have such interrupts on the default system configuration,
> >> as far as I remember.
> >
> > They didn't have an HT APIC or if they had one, they didn't enable it
> > (they probably did in the tunnel).
> 
> Yes, the two HT APICs on the tunnel were enabled.
> 
> > They didn't use the U3 MPIC as an HT
> > IRQ master, thus it's irrelevant.
> 
> They did for the plugin PCI-X slots (well, it's chained
> to another MPIC, but you still need the workaround).

No you didn't. The slots IRQ lines were physically routed to GPIOs on
the southbridge MPIC. The -only- thing the northbridge MPIC was useful
for was the NB internal interrupts (like the i2c one).

> > Anyway, there is no point in this
> > discussion :-)
> 
> Yeah, the new name for CONFIG_BROKEN_U3 is fine
> no matter what :-)
> 
> 
> Segher

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/7] Rip out the existing powerpc msi stubs
@ 2007-05-08  2:58 Michael Ellerman
  2007-05-08  2:58 ` [PATCH 2/7] Powerpc MSI infrastructure Michael Ellerman
                   ` (5 more replies)
  0 siblings, 6 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Rip out the existing powerpc msi stubs. These were the start of an
implementation based on ppc_md calls, but were never used in mainline.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/irq.c     |   27 ---------------------------
 include/asm-powerpc/machdep.h |    5 -----
 2 files changed, 32 deletions(-)

Index: msi-new/arch/powerpc/kernel/irq.c
===================================================================
--- msi-new.orig/arch/powerpc/kernel/irq.c
+++ msi-new/arch/powerpc/kernel/irq.c
@@ -958,33 +958,6 @@ arch_initcall(irq_late_init);
 
 #endif /* CONFIG_PPC_MERGE */
 
-#ifdef CONFIG_PCI_MSI
-int pci_enable_msi(struct pci_dev * pdev)
-{
-	if (ppc_md.enable_msi)
-		return ppc_md.enable_msi(pdev);
-	else
-		return -1;
-}
-EXPORT_SYMBOL(pci_enable_msi);
-
-void pci_disable_msi(struct pci_dev * pdev)
-{
-	if (ppc_md.disable_msi)
-		ppc_md.disable_msi(pdev);
-}
-EXPORT_SYMBOL(pci_disable_msi);
-
-void pci_scan_msi_device(struct pci_dev *dev) {}
-int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
-void pci_disable_msix(struct pci_dev *dev) {}
-void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
-void pci_no_msi(void) {}
-EXPORT_SYMBOL(pci_enable_msix);
-EXPORT_SYMBOL(pci_disable_msix);
-
-#endif
-
 #ifdef CONFIG_PPC64
 static int __init setup_noirqdistrib(char *str)
 {
Index: msi-new/include/asm-powerpc/machdep.h
===================================================================
--- msi-new.orig/include/asm-powerpc/machdep.h
+++ msi-new/include/asm-powerpc/machdep.h
@@ -240,11 +240,6 @@ struct machdep_calls {
 	 */
 	void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
-
-#ifdef CONFIG_PCI_MSI
-	int (*enable_msi)(struct pci_dev *pdev);
-	void (*disable_msi)(struct pci_dev *pdev);
-#endif /* CONFIG_PCI_MSI */
 };
 
 extern void power4_idle(void);

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 2/7] Powerpc MSI infrastructure
  2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
@ 2007-05-08  2:58 ` Michael Ellerman
  2007-05-08  2:58 ` [PATCH 3/7] RTAS MSI implementation Michael Ellerman
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

This patch provides the architecture specific hooks to support MSI on
powerpc. We implement the newly added arch_setup_msi_irqs() and
arch_teardown_msi_irqs(), and then delegate to ppc_md routines.

Platforms that don't implement MSI will leave the ppc_md calls blank,
arch_msi_check_device() will detect this and return ENOSYS. Drivers
should detect this error and continue to use LSI.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/Kconfig          |    1 +
 arch/powerpc/kernel/Makefile  |    1 +
 arch/powerpc/kernel/msi.c     |   38 ++++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/machdep.h |    8 ++++++++
 4 files changed, 48 insertions(+)

Index: msi-new/arch/powerpc/Kconfig
===================================================================
--- msi-new.orig/arch/powerpc/Kconfig
+++ msi-new/arch/powerpc/Kconfig
@@ -659,6 +659,7 @@ config PCI
 		&& !PPC_85xx && !PPC_86xx
 	default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
 	default PCI_QSPAN if !4xx && !CPM2 && 8xx
+	select ARCH_SUPPORTS_MSI
 	help
 	  Find out whether your system includes a PCI bus. PCI is the name of
 	  a bus system, i.e. the way the CPU talks to the other stuff inside
Index: msi-new/arch/powerpc/kernel/Makefile
===================================================================
--- msi-new.orig/arch/powerpc/kernel/Makefile
+++ msi-new/arch/powerpc/kernel/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_MODULES)		+= $(module-y)
 pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
+obj-$(CONFIG_PCI_MSI)		+= msi.o
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
 kexec-$(CONFIG_PPC32)		:= machine_kexec_32.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o crash.o $(kexec-y)
Index: msi-new/arch/powerpc/kernel/msi.c
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/kernel/msi.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/msi.h>
+
+#include <asm/machdep.h>
+
+int arch_msi_check_device(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");
+		return -ENOSYS;
+	}
+
+	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);
+}
+
+void arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+	return ppc_md.teardown_msi_irqs(dev);
+}
Index: msi-new/include/asm-powerpc/machdep.h
===================================================================
--- msi-new.orig/include/asm-powerpc/machdep.h
+++ msi-new/include/asm-powerpc/machdep.h
@@ -115,6 +115,14 @@ struct machdep_calls {
 	/* To setup PHBs when using automatic OF platform driver for PCI */
 	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);
+#endif
+
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
 	void		(*halt)(void);

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 3/7] RTAS MSI implementation
  2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
  2007-05-08  2:58 ` [PATCH 2/7] Powerpc MSI infrastructure Michael Ellerman
@ 2007-05-08  2:58 ` Michael Ellerman
  2007-05-08  2:58 ` [PATCH 4/7] Tell Phyp we support MSI Michael Ellerman
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Implement MSI support via RTAS. For now we assumes that if the required
RTAS tokens for MSI are present, then we want to use the RTAS MSI
routines.

When RTAS is managing MSIs for us, it will/may enable MSI on devices that
support it by default. This is contrary to the Linux model where a device
is in LSI mode until the driver requests MSIs.

To remedy this we add a pci_irq_fixup call, which disables MSI if they've
been assigned by firmware and the device also supports LSI. Devices that
don't support LSI at all will be left as is, drivers are still expected
to call pci_enable_msi() before using the device.

At the moment there is no pci_irq_fixup on pSeries, so we can just set it
unconditionally. If other platforms use the RTAS MSI backend they'll need
to check that still holds.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/platforms/pseries/Makefile |    1 
 arch/powerpc/platforms/pseries/msi.c    |  270 ++++++++++++++++++++++++++++++++
 2 files changed, 271 insertions(+)

Index: msi-new/arch/powerpc/platforms/pseries/Makefile
===================================================================
--- msi-new.orig/arch/powerpc/platforms/pseries/Makefile
+++ msi-new/arch/powerpc/platforms/pseries/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SCANLOG)	+= scanlog.o
 obj-$(CONFIG_EEH)	+= eeh.o eeh_cache.o eeh_driver.o eeh_event.o
 obj-$(CONFIG_KEXEC)	+= kexec.o
 obj-$(CONFIG_PCI)	+= pci.o pci_dlpar.o
+obj-$(CONFIG_PCI_MSI)	+= msi.o
 
 obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug-cpu.o
 
Index: msi-new/arch/powerpc/platforms/pseries/msi.c
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/platforms/pseries/msi.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
+ * Copyright 2006-2007 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int query_token, change_token;
+
+#define RTAS_QUERY_FN		0
+#define RTAS_CHANGE_FN		1
+#define RTAS_RESET_FN		2
+#define RTAS_CHANGE_MSI_FN	3
+#define RTAS_CHANGE_MSIX_FN	4
+
+static struct pci_dn *get_pdn(struct pci_dev *pdev)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+
+	dn = pci_device_to_OF_node(pdev);
+	if (!dn) {
+		dev_dbg(&pdev->dev, "rtas_msi: No OF device node\n");
+		return NULL;
+	}
+
+	pdn = PCI_DN(dn);
+	if (!pdn) {
+		dev_dbg(&pdev->dev, "rtas_msi: No PCI DN\n");
+		return NULL;
+	}
+
+	return pdn;
+}
+
+/* RTAS Helpers */
+
+static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)
+{
+	u32 addr, seq_num, rtas_ret[3];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	seq_num = 1;
+	do {
+		if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN)
+			rc = rtas_call(change_token, 6, 4, rtas_ret, addr,
+					BUID_HI(buid), BUID_LO(buid),
+					func, num_irqs, seq_num);
+		else
+			rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
+					BUID_HI(buid), BUID_LO(buid),
+					func, num_irqs, seq_num);
+
+		seq_num = rtas_ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc == 0) /* Success */
+		rc = rtas_ret[0];
+
+	pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n",
+		 func, num_irqs, rc);
+
+	return rc;
+}
+
+static void rtas_disable_msi(struct pci_dev *pdev)
+{
+	struct pci_dn *pdn;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return;
+
+	if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0)
+		pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
+}
+
+static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
+{
+	u32 addr, rtas_ret[2];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	do {
+		rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
+			       BUID_HI(buid), BUID_LO(buid), offset);
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		pr_debug("rtas_msi: error (%d) querying source number\n", rc);
+		return rc;
+	}
+
+	return rtas_ret[0];
+}
+
+static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
+{
+	struct msi_desc *entry;
+
+	list_for_each_entry(entry, &pdev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+
+		set_irq_msi(entry->irq, NULL);
+		irq_dispose_mapping(entry->irq);
+	}
+
+	rtas_disable_msi(pdev);
+}
+
+static int check_req_msi(struct pci_dev *pdev, int nvec)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+	const u32 *req_msi;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return -ENODEV;
+
+	dn = pdn->node;
+
+	req_msi = of_get_property(dn, "ibm,req#msi", NULL);
+	if (!req_msi) {
+		pr_debug("rtas_msi: No ibm,req#msi on %s\n", dn->full_name);
+		return -ENOENT;
+	}
+
+	if (*req_msi < nvec) {
+		pr_debug("rtas_msi: ibm,req#msi requests < %d MSIs\n", nvec);
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+	if (type == PCI_CAP_ID_MSIX)
+		pr_debug("rtas_msi: MSI-X untested, trying anyway.\n");
+
+	return check_req_msi(pdev, nvec);
+}
+
+static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+{
+	struct pci_dn *pdn;
+	int hwirq, virq, i, rc;
+	struct msi_desc *entry;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return -ENODEV;
+
+	/*
+	 * Try the new more explicit firmware interface, if that fails fall
+	 * back to the old interface. The old interface is known to never
+	 * return MSI-Xs.
+	 */
+	if (type == PCI_CAP_ID_MSI) {
+		rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
+
+		if (rc != nvec) {
+			pr_debug("rtas_msi: trying the old firmware call.\n");
+			rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
+		}
+	} else
+		rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
+
+	if (rc != nvec) {
+		pr_debug("rtas_msi: rtas_change_msi() failed\n");
+
+		/*
+		 * In case of an error it's not clear whether the device is
+		 * left with MSI enabled or not, so we explicitly disable.
+		 */
+		goto out_free;
+	}
+
+	i = 0;
+	list_for_each_entry(entry, &pdev->msi_list, list) {
+		hwirq = rtas_query_irq_number(pdn, i);
+		if (hwirq < 0) {
+			rc = hwirq;
+			pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
+			goto out_free;
+		}
+
+		virq = irq_create_mapping(NULL, hwirq);
+
+		if (virq == NO_IRQ) {
+			pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq);
+		set_irq_msi(virq, entry);
+		unmask_msi_irq(virq);
+	}
+
+	return 0;
+
+ out_free:
+	rtas_teardown_msi_irqs(pdev);
+	return rc;
+}
+
+static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
+{
+	/* No LSI -> leave MSIs (if any) configured */
+	if (pdev->irq == NO_IRQ) {
+		dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n");
+		return;
+	}
+
+	/* No MSI -> MSIs can't have been assigned by fw, leave LSI */
+	if (check_req_msi(pdev, 1)) {
+		dev_dbg(&pdev->dev, "rtas_msi: no req#msi, nothing to do.\n");
+		return;
+	}
+
+	dev_dbg(&pdev->dev, "rtas_msi: disabling existing MSI.\n");
+	rtas_disable_msi(pdev);
+}
+
+static int rtas_msi_init(void)
+{
+	query_token  = rtas_token("ibm,query-interrupt-source-number");
+	change_token = rtas_token("ibm,change-msi");
+
+	if ((query_token == RTAS_UNKNOWN_SERVICE) ||
+			(change_token == RTAS_UNKNOWN_SERVICE)) {
+		pr_debug("rtas_msi: no RTAS tokens, no MSI support.\n");
+		return -1;
+	}
+
+	pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n");
+
+	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;
+
+	return 0;
+}
+arch_initcall(rtas_msi_init);

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 4/7] Tell Phyp we support MSI
  2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
  2007-05-08  2:58 ` [PATCH 2/7] Powerpc MSI infrastructure Michael Ellerman
  2007-05-08  2:58 ` [PATCH 3/7] RTAS MSI implementation Michael Ellerman
@ 2007-05-08  2:58 ` Michael Ellerman
  2007-05-08  2:58 ` [PATCH 6/7] MPIC MSI allocator Michael Ellerman
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Tell Phyp we support MSI via the client architecture support mechanism.

Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

---

 arch/powerpc/kernel/prom_init.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Index: msi-new/arch/powerpc/kernel/prom_init.c
===================================================================
--- msi-new.orig/arch/powerpc/kernel/prom_init.c
+++ msi-new/arch/powerpc/kernel/prom_init.c
@@ -635,6 +635,12 @@ static void __init early_cmdline_parse(v
 /* ibm,dynamic-reconfiguration-memory property supported */
 #define OV5_DRCONF_MEMORY	0x20
 #define OV5_LARGE_PAGES		0x10	/* large pages supported */
+/* PCIe/MSI support.  Without MSI full PCIe is not supported */
+#ifdef CONFIG_PCI_MSI
+#define OV5_MSI			0x01	/* PCIe/MSI support */
+#else
+#define OV5_MSI			0x00
+#endif /* CONFIG_PCI_MSI */
 
 /*
  * The architecture vector has an array of PVR mask/value pairs,
@@ -679,7 +685,7 @@ static unsigned char ibm_architecture_ve
 	/* option vector 5: PAPR/OF options */
 	3 - 2,				/* length */
 	0,				/* don't ignore, don't halt */
-	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
+	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 5/7] Enable MSI mappings for MPIC
  2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
                   ` (3 preceding siblings ...)
  2007-05-08  2:58 ` [PATCH 6/7] MPIC MSI allocator Michael Ellerman
@ 2007-05-08  2:58 ` Michael Ellerman
  2007-05-08  2:58 ` [PATCH 7/7] MPIC U3/U4 MSI backend Michael Ellerman
  5 siblings, 0 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

On some Apple machines the HT MSI mappings are not enabled by firmware, so
we need to do it by hand.

We can't use the pci routines as this code runs too early.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/sysdev/mpic.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

Index: msi-new/arch/powerpc/sysdev/mpic.c
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/mpic.c
+++ msi-new/arch/powerpc/sysdev/mpic.c
@@ -377,6 +377,50 @@ static void mpic_shutdown_ht_interrupt(s
 	spin_unlock_irqrestore(&mpic->fixup_lock, flags);
 }
 
+#ifdef CONFIG_PCI_MSI
+static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
+				    unsigned int devfn)
+{
+	u8 __iomem *base;
+	u8 pos, flags;
+	u64 addr = 0;
+
+	for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+	     pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+		u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+		if (id == PCI_CAP_ID_HT) {
+			id = readb(devbase + pos + 3);
+			if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING)
+				break;
+		}
+	}
+
+	if (pos == 0)
+		return;
+
+	base = devbase + pos;
+
+	flags = readb(base + HT_MSI_FLAGS);
+	if (!(flags & HT_MSI_FLAGS_FIXED)) {
+		addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK;
+		addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32);
+	}
+
+	printk(KERN_DEBUG "mpic:   - HT:%02x.%x %s MSI mapping found @ 0x%lx\n",
+		PCI_SLOT(devfn), PCI_FUNC(devfn),
+		flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr);
+
+	if (!(flags & HT_MSI_FLAGS_ENABLE))
+		writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS);
+}
+#else
+static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
+				    unsigned int devfn)
+{
+	return;
+}
+#endif
+
 static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
 				    unsigned int devfn, u32 vdid)
 {
@@ -468,6 +512,7 @@ static void __init mpic_scan_ht_pics(str
 			goto next;
 
 		mpic_scan_ht_pic(mpic, devbase, devfn, l);
+		mpic_scan_ht_msi(mpic, devbase, devfn);
 
 	next:
 		/* next device, if function 0 */

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 6/7] MPIC MSI allocator
  2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
                   ` (2 preceding siblings ...)
  2007-05-08  2:58 ` [PATCH 4/7] Tell Phyp we support MSI Michael Ellerman
@ 2007-05-08  2:58 ` Michael Ellerman
  2007-05-08  2:58 ` [PATCH 5/7] Enable MSI mappings for MPIC Michael Ellerman
  2007-05-08  2:58 ` [PATCH 7/7] MPIC U3/U4 MSI backend Michael Ellerman
  5 siblings, 0 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

To support MSI on MPIC we need a way to reserve and allocate hardware irq
numbers, this patch implements an allocator for that purpose.

New firmware platforms must define a "msi-available-ranges" property on their
MPIC node for MSI to work. For U3/U4 we do a best-guess setup.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/sysdev/Makefile   |    4 
 arch/powerpc/sysdev/mpic.c     |    4 
 arch/powerpc/sysdev/mpic.h     |   27 ++++++
 arch/powerpc/sysdev/mpic_msi.c |  183 +++++++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/mpic.h     |    5 +
 5 files changed, 222 insertions(+), 1 deletion(-)

Index: msi-new/arch/powerpc/sysdev/Makefile
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/Makefile
+++ msi-new/arch/powerpc/sysdev/Makefile
@@ -2,7 +2,9 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-obj-$(CONFIG_MPIC)		+= mpic.o
+mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o
+obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
+
 obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
 obj-$(CONFIG_PPC_DCR)		+= dcr.o
Index: msi-new/arch/powerpc/sysdev/mpic.c
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/mpic.c
+++ msi-new/arch/powerpc/sysdev/mpic.c
@@ -36,6 +36,8 @@
 #include <asm/mpic.h>
 #include <asm/smp.h>
 
+#include "mpic.h"
+
 #ifdef DEBUG
 #define DBG(fmt...) printk(fmt)
 #else
@@ -879,6 +881,8 @@ static int mpic_host_map(struct irq_host
 	if (hw >= mpic->irq_count)
 		return -EINVAL;
 
+	mpic_msi_reserve_hwirq(mpic, hw);
+
 	/* Default chip */
 	chip = &mpic->hc_irq;
 
Index: msi-new/arch/powerpc/sysdev/mpic.h
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/sysdev/mpic.h
@@ -0,0 +1,27 @@
+#ifndef _POWERPC_SYSDEV_MPIC_H
+#define _POWERPC_SYSDEV_MPIC_H
+
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#ifdef CONFIG_PCI_MSI
+extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
+extern int mpic_msi_init_allocator(struct mpic *mpic);
+extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
+extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
+#else
+static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
+					  irq_hw_number_t hwirq)
+{
+	return;
+}
+#endif
+
+#endif /* _POWERPC_SYSDEV_MPIC_H */
Index: msi-new/arch/powerpc/sysdev/mpic_msi.c
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/sysdev/mpic_msi.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/bitmap.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+
+static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+	pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
+	bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
+}
+
+void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+	unsigned long flags;
+
+	/* The mpic calls this even when there is no allocator setup */
+	if (!mpic->hwirq_bitmap)
+		return;
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	__mpic_msi_reserve_hwirq(mpic, hwirq);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
+{
+	unsigned long flags;
+	int offset, order = get_count_order(num);
+
+	spin_lock_irqsave(&mpic->bitmap_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(mpic->hwirq_bitmap, mpic->irq_count,
+					 order);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+
+	pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
+		 num, order, offset);
+
+	return offset;
+}
+
+void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
+{
+	unsigned long flags;
+	int order = get_count_order(num);
+
+	pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
+		 num, order, offset);
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	bitmap_release_region(mpic->hwirq_bitmap, offset, order);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+	irq_hw_number_t hwirq;
+	struct irq_host_ops *ops = mpic->irqhost->ops;
+	struct device_node *np;
+	int flags, index, i;
+	struct of_irq oirq;
+
+	pr_debug("mpic: found U3, guessing msi allocator setup\n");
+
+	/* Reserve source numbers we know are reserved in the HW */
+	for (i = 0;   i < 8;   i++)
+		__mpic_msi_reserve_hwirq(mpic, i);
+
+	for (i = 42;  i < 46;  i++)
+		__mpic_msi_reserve_hwirq(mpic, i);
+
+	for (i = 100; i < 105; i++)
+		__mpic_msi_reserve_hwirq(mpic, i);
+
+	np = NULL;
+	while ((np = of_find_all_nodes(np))) {
+		pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
+
+		index = 0;
+		while (of_irq_map_one(np, index++, &oirq) == 0) {
+			ops->xlate(mpic->irqhost, NULL, oirq.specifier,
+						oirq.size, &hwirq, &flags);
+			__mpic_msi_reserve_hwirq(mpic, hwirq);
+		}
+	}
+
+	return 0;
+}
+#else
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+	return -1;
+}
+#endif
+
+static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
+{
+	int i, len;
+	const u32 *p;
+
+	p = of_get_property(mpic->of_node, "msi-available-ranges", &len);
+	if (!p) {
+		pr_debug("mpic: no msi-available-ranges property found on %s\n",
+			  mpic->of_node->full_name);
+		return -ENODEV;
+	}
+
+	if (len % 8 != 0) {
+		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
+		       "property on %s\n", mpic->of_node->full_name);
+		return -EINVAL;
+	}
+
+	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
+			       get_count_order(mpic->irq_count));
+
+	/* Format is: (<u32 start> <u32 count>)+ */
+	len /= sizeof(u32);
+	for (i = 0; i < len / 2; i++, p += 2)
+		mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
+
+	return 0;
+}
+
+int mpic_msi_init_allocator(struct mpic *mpic)
+{
+	int rc, size;
+
+	BUG_ON(mpic->hwirq_bitmap);
+	spin_lock_init(&mpic->bitmap_lock);
+
+	size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
+	pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
+
+	if (mem_init_done)
+		mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL);
+	else
+		mpic->hwirq_bitmap = alloc_bootmem(size);
+
+	if (!mpic->hwirq_bitmap) {
+		pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
+		return -ENOMEM;
+	}
+
+	memset(mpic->hwirq_bitmap, 0, size);
+
+	rc = mpic_msi_reserve_dt_hwirqs(mpic);
+	if (rc) {
+		if (mpic->flags & MPIC_U3_HT_IRQS)
+			rc = mpic_msi_reserve_u3_hwirqs(mpic);
+
+		if (rc)
+			goto out_free;
+	}
+
+	return 0;
+
+ out_free:
+	if (mem_init_done)
+		kfree(mpic->hwirq_bitmap);
+
+	mpic->hwirq_bitmap = NULL;
+	return rc;
+}
Index: msi-new/include/asm-powerpc/mpic.h
===================================================================
--- msi-new.orig/include/asm-powerpc/mpic.h
+++ msi-new/include/asm-powerpc/mpic.h
@@ -292,6 +292,11 @@ struct mpic
 	u32			*hw_set;
 #endif
 
+#ifdef CONFIG_PCI_MSI
+	spinlock_t		bitmap_lock;
+	unsigned long		*hwirq_bitmap;
+#endif
+
 	/* link */
 	struct mpic		*next;
 };

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 7/7] MPIC U3/U4 MSI backend
  2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
                   ` (4 preceding siblings ...)
  2007-05-08  2:58 ` [PATCH 5/7] Enable MSI mappings for MPIC Michael Ellerman
@ 2007-05-08  2:58 ` Michael Ellerman
  2007-05-08  8:55   ` Johannes Berg
  2007-05-12  8:28   ` Johannes Berg
  5 siblings, 2 replies; 23+ messages in thread
From: Michael Ellerman @ 2007-05-08  2:58 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

MPIC U3/U4 MSI backend. Based on code from Segher, heavily hacked by me.
This only deals with MSI on U3/U4 MPICs, aka. CPC 9x5.

If we find a U3/U4 then we enable this backend, ie. take over the ppc_md
MSI hooks. We might need more elaborate logic in future to decide which
backend is enabled.

We need our own irq_chip so that we can do MSI masking/unmasking on
the device itself. We also need to mask explicitly on shutdown to make
sure we don't get bitten by lazy-disable semantics.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/sysdev/Makefile     |    2 
 arch/powerpc/sysdev/mpic.c       |   14 +-
 arch/powerpc/sysdev/mpic.h       |   11 ++
 arch/powerpc/sysdev/mpic_u3msi.c |  186 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 206 insertions(+), 7 deletions(-)

Index: msi-new/arch/powerpc/sysdev/Makefile
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/Makefile
+++ msi-new/arch/powerpc/sysdev/Makefile
@@ -2,7 +2,7 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o
+mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 
 obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
Index: msi-new/arch/powerpc/sysdev/mpic.c
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/mpic.c
+++ msi-new/arch/powerpc/sysdev/mpic.c
@@ -606,7 +606,7 @@ static irqreturn_t mpic_ipi_action(int i
  */
 
 
-static void mpic_unmask_irq(unsigned int irq)
+void mpic_unmask_irq(unsigned int irq)
 {
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
@@ -626,7 +626,7 @@ static void mpic_unmask_irq(unsigned int
 	} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
 }
 
-static void mpic_mask_irq(unsigned int irq)
+void mpic_mask_irq(unsigned int irq)
 {
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
@@ -647,7 +647,7 @@ static void mpic_mask_irq(unsigned int i
 	} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
 }
 
-static void mpic_end_irq(unsigned int irq)
+void mpic_end_irq(unsigned int irq)
 {
 	struct mpic *mpic = mpic_from_irq(irq);
 
@@ -780,7 +780,7 @@ static unsigned int mpic_type_to_vecpri(
 	}
 }
 
-static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
+int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 {
 	struct mpic *mpic = mpic_from_irq(virq);
 	unsigned int src = mpic_irq_to_hw(virq);
@@ -1191,8 +1191,10 @@ void __init mpic_init(struct mpic *mpic)
 
 	/* Do the HT PIC fixups on U3 broken mpic */
 	DBG("MPIC flags: %x\n", mpic->flags);
-	if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY))
- 		mpic_scan_ht_pics(mpic);
+	if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) {
+		mpic_scan_ht_pics(mpic);
+		mpic_u3msi_init(mpic);
+	}
 
 	for (i = 0; i < mpic->num_sources; i++) {
 		/* start with vector = source number, and masked */
Index: msi-new/arch/powerpc/sysdev/mpic.h
===================================================================
--- msi-new.orig/arch/powerpc/sysdev/mpic.h
+++ msi-new/arch/powerpc/sysdev/mpic.h
@@ -16,12 +16,23 @@ extern void mpic_msi_reserve_hwirq(struc
 extern int mpic_msi_init_allocator(struct mpic *mpic);
 extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
 extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
+extern int mpic_u3msi_init(struct mpic *mpic);
 #else
 static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
 					  irq_hw_number_t hwirq)
 {
 	return;
 }
+
+static inline int mpic_u3msi_init(struct mpic *mpic)
+{
+	return -1;
+}
 #endif
 
+extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern void mpic_end_irq(unsigned int irq);
+extern void mpic_mask_irq(unsigned int irq);
+extern void mpic_unmask_irq(unsigned int irq);
+
 #endif /* _POWERPC_SYSDEV_MPIC_H */
Index: msi-new/arch/powerpc/sysdev/mpic_u3msi.c
===================================================================
--- /dev/null
+++ msi-new/arch/powerpc/sysdev/mpic_u3msi.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2006, Segher Boessenkool, IBM Corporation.
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+#include "mpic.h"
+
+/* A bit ugly, can we get this from the pci_dev somehow? */
+static struct mpic *msi_mpic;
+
+static void mpic_u3msi_mask_irq(unsigned int irq)
+{
+	mask_msi_irq(irq);
+	mpic_mask_irq(irq);
+}
+
+static void mpic_u3msi_unmask_irq(unsigned int irq)
+{
+	mpic_unmask_irq(irq);
+	unmask_msi_irq(irq);
+}
+
+static struct irq_chip mpic_u3msi_chip = {
+	.shutdown	= mpic_u3msi_mask_irq,
+	.mask		= mpic_u3msi_mask_irq,
+	.unmask		= mpic_u3msi_unmask_irq,
+	.eoi		= mpic_end_irq,
+	.set_type	= mpic_set_irq_type,
+	.typename	= "MPIC-U3MSI",
+};
+
+static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
+{
+	u8 flags;
+	u32 tmp;
+	u64 addr;
+
+	pci_read_config_byte(pdev, pos + HT_MSI_FLAGS, &flags);
+
+	if (flags & HT_MSI_FLAGS_FIXED)
+		return HT_MSI_FIXED_ADDR;
+
+	pci_read_config_dword(pdev, pos + HT_MSI_ADDR_LO, &tmp);
+	addr = tmp & HT_MSI_ADDR_LO_MASK;
+	pci_read_config_dword(pdev, pos + HT_MSI_ADDR_HI, &tmp);
+	addr = addr | ((u64)tmp << 32);
+
+	return addr;
+}
+
+static u64 find_ht_magic_addr(struct pci_dev *pdev)
+{
+	struct pci_bus *bus;
+	unsigned int pos;
+
+	for (bus = pdev->bus; bus; bus = bus->parent) {
+		pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING);
+		if (pos)
+			return read_ht_magic_addr(bus->self, pos);
+	}
+
+	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) {
+		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;
+
+        list_for_each_entry(entry, &pdev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+
+		set_irq_msi(entry->irq, NULL);
+		mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
+		irq_dispose_mapping(entry->irq);
+	}
+
+	return;
+}
+
+static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq,
+				  struct msi_msg *msg)
+{
+	u64 addr;
+
+	addr = find_ht_magic_addr(pdev);
+	msg->address_lo = addr & 0xFFFFFFFF;
+	msg->address_hi = addr >> 32;
+	msg->data = virq_to_hw(virq);
+
+	pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n",
+		 virq, virq_to_hw(virq), addr);
+}
+
+static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+{
+	irq_hw_number_t hwirq;
+	int rc;
+	unsigned int virq;
+	struct msi_desc *entry;
+	struct msi_msg msg;
+
+	list_for_each_entry(entry, &pdev->msi_list, list) {
+		hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1);
+		if (hwirq < 0) {
+			rc = hwirq;
+			pr_debug("u3msi: failed allocating hwirq\n");
+			goto out_free;
+		}
+
+		virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
+		if (virq == NO_IRQ) {
+			pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
+			mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		set_irq_msi(virq, entry);
+		set_irq_chip(virq, &mpic_u3msi_chip);
+		set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+
+		u3msi_compose_msi_msg(pdev, virq, &msg);
+		write_msi_msg(virq, &msg);
+
+		hwirq++;
+	}
+
+	return 0;
+
+ out_free:
+	u3msi_teardown_msi_irqs(pdev);
+	return rc;
+}
+
+int mpic_u3msi_init(struct mpic *mpic)
+{
+	int rc;
+
+	rc = mpic_msi_init_allocator(mpic);
+	if (rc) {
+		pr_debug("u3msi: Error allocating bitmap!\n");
+		return rc;
+	}
+
+	pr_debug("u3msi: Registering MPIC U3 MSI callbacks.\n");
+
+	BUG_ON(msi_mpic);
+	msi_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;
+}

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
  2007-05-08  2:58 ` [PATCH 7/7] MPIC U3/U4 MSI backend Michael Ellerman
@ 2007-05-08  8:55   ` Johannes Berg
  2007-05-08  9:04     ` Johannes Berg
  2007-05-08 23:43     ` Benjamin Herrenschmidt
  2007-05-12  8:28   ` Johannes Berg
  1 sibling, 2 replies; 23+ messages in thread
From: Johannes Berg @ 2007-05-08  8:55 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Paul Mackerras

[-- Attachment #1: Type: text/plain, Size: 725 bytes --]

On Tue, 2007-05-08 at 12:58 +1000, Michael Ellerman wrote:
> MPIC U3/U4 MSI backend. Based on code from Segher, heavily hacked by me.
> This only deals with MSI on U3/U4 MPICs, aka. CPC 9x5.
> 
> If we find a U3/U4 then we enable this backend, ie. take over the ppc_md
> MSI hooks. We might need more elaborate logic in future to decide which
> backend is enabled.
> 
> We need our own irq_chip so that we can do MSI masking/unmasking on
> the device itself. We also need to mask explicitly on shutdown to make
> sure we don't get bitten by lazy-disable semantics.

How badly will this clash with my patch that implements suspend/resume
for mpic, and will I need to do more suspend/resume for this?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
  2007-05-08  8:55   ` Johannes Berg
@ 2007-05-08  9:04     ` Johannes Berg
  2007-05-08 23:43     ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 23+ messages in thread
From: Johannes Berg @ 2007-05-08  9:04 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Paul Mackerras

[-- Attachment #1: Type: text/plain, Size: 318 bytes --]

On Tue, 2007-05-08 at 10:55 +0200, Johannes Berg wrote:

> How badly will this clash with my patch that implements suspend/resume
> for mpic, and will I need to do more suspend/resume for this?

Oh. I see that my patch is in there already. Will we have to implement
suspend/resume for the MSI case?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
  2007-05-08  8:55   ` Johannes Berg
  2007-05-08  9:04     ` Johannes Berg
@ 2007-05-08 23:43     ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2007-05-08 23:43 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev, Paul Mackerras

On Tue, 2007-05-08 at 10:55 +0200, Johannes Berg wrote:
> On Tue, 2007-05-08 at 12:58 +1000, Michael Ellerman wrote:
> > MPIC U3/U4 MSI backend. Based on code from Segher, heavily hacked by me.
> > This only deals with MSI on U3/U4 MPICs, aka. CPC 9x5.
> > 
> > If we find a U3/U4 then we enable this backend, ie. take over the ppc_md
> > MSI hooks. We might need more elaborate logic in future to decide which
> > backend is enabled.
> > 
> > We need our own irq_chip so that we can do MSI masking/unmasking on
> > the device itself. We also need to mask explicitly on shutdown to make
> > sure we don't get bitten by lazy-disable semantics.
> 
> How badly will this clash with my patch that implements suspend/resume
> for mpic, and will I need to do more suspend/resume for this?

Maybe... for now, don't bother, we'll do fixups later on. I think your
patch can be done differently and more simply. I don't think we need to
save/restore all this state, we can proably reconfigure everything with
what we have.

Ben.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
  2007-05-08  2:58 ` [PATCH 7/7] MPIC U3/U4 MSI backend Michael Ellerman
  2007-05-08  8:55   ` Johannes Berg
@ 2007-05-12  8:28   ` Johannes Berg
  2007-05-12  9:06     ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 23+ messages in thread
From: Johannes Berg @ 2007-05-12  8:28 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Paul Mackerras

[-- Attachment #1: Type: text/plain, Size: 461 bytes --]


> +	pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n",
> +		 virq, virq_to_hw(virq), addr);

I get
arch/powerpc/sysdev/mpic_u3msi.c: In function ‘u3msi_compose_msi_msg’:
arch/powerpc/sysdev/mpic_u3msi.c:121: warning: format ‘%lx’ expects type
‘long unsigned int’, but argument 4 has type ‘u64’

when building this on ppc32 (I wonder if that even makes sense anyway
but Kconfig allowed me to select MSI)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
  2007-05-12  8:28   ` Johannes Berg
@ 2007-05-12  9:06     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2007-05-12  9:06 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev, Paul Mackerras

On Sat, 2007-05-12 at 10:28 +0200, Johannes Berg wrote:
> > +	pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n",
> > +		 virq, virq_to_hw(virq), addr);
> 
> I get
> arch/powerpc/sysdev/mpic_u3msi.c: In function ‘u3msi_compose_msi_msg’:
> arch/powerpc/sysdev/mpic_u3msi.c:121: warning: format ‘%lx’ expects type
> ‘long unsigned int’, but argument 4 has type ‘u64’
> 
> when building this on ppc32 (I wonder if that even makes sense anyway
> but Kconfig allowed me to select MSI)

Hrm... we should definitely make the U3 MSI bits 64 bits only for now at
least.

Ben.

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2007-05-12  9:06 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-08  2:58 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
2007-05-08  2:58 ` [PATCH 2/7] Powerpc MSI infrastructure Michael Ellerman
2007-05-08  2:58 ` [PATCH 3/7] RTAS MSI implementation Michael Ellerman
2007-05-08  2:58 ` [PATCH 4/7] Tell Phyp we support MSI Michael Ellerman
2007-05-08  2:58 ` [PATCH 6/7] MPIC MSI allocator Michael Ellerman
2007-05-08  2:58 ` [PATCH 5/7] Enable MSI mappings for MPIC Michael Ellerman
2007-05-08  2:58 ` [PATCH 7/7] MPIC U3/U4 MSI backend Michael Ellerman
2007-05-08  8:55   ` Johannes Berg
2007-05-08  9:04     ` Johannes Berg
2007-05-08 23:43     ` Benjamin Herrenschmidt
2007-05-12  8:28   ` Johannes Berg
2007-05-12  9:06     ` Benjamin Herrenschmidt
  -- strict thread matches above, loose matches on Subject: below --
2007-04-19  7:35 [PATCH 1/7] Rip out the existing powerpc msi stubs Michael Ellerman
2007-04-19  7:35 ` [PATCH 6/7] MPIC MSI allocator Michael Ellerman
2007-04-21 23:17   ` Milton Miller
2007-04-23  4:04     ` Michael Ellerman
2007-04-23  6:20       ` Milton Miller
2007-04-23  3:50   ` Olof Johansson
2007-04-23  3:53     ` Michael Ellerman
2007-04-24  1:29     ` Benjamin Herrenschmidt
2007-04-24  9:26       ` Segher Boessenkool
2007-04-24  9:39         ` Benjamin Herrenschmidt
2007-04-24  9:44           ` Segher Boessenkool
2007-04-24  9:51             ` Benjamin Herrenschmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).