Skip to contentSkip to conversation

pasemi: Implement MSI support

PATCH Superseded Olof Johansson 2 participants 6 messages Dec 12, 2007 PowerPC

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pasemi: Implement MSI support

[POWERPC] pasemi: Implement MSI support

Implement MSI support for PA Semi PWRficient platforms. MSI is done through a special range of sources on the openpic controller, and they're unfortunately breaking the usual concepts of how sources are programmed:

* The source is calculated as 512 + the value written into the MSI register
* The vector for this source is added to the source and reported through IACK

This means that for simplicity, it makes much more sense to just set the vector to 0 for the source, since that's really the vector we expect to see from IACK.

Also, the affinity/priority registers will affect 16 sources at a time. To avoid most (simple) users from being limited by this, allocate 16 sources per device but use only one. This means that there's a total of 32 sources.

If we get usage scenarions that need more sources, the allocator should probably be revised to take an alignment argument and size, not just do natural alignment.

Finally, since I'm already touching the MPIC names on pasemi, rename the base one from the somewhat odd " PAS-OPIC " to "PASEMI-OPIC".

---

 arch/powerpc/platforms/pasemi/setup.c |    2 
 arch/powerpc/sysdev/Makefile          |    2 
 arch/powerpc/sysdev/mpic.c            |   20 +++
 arch/powerpc/sysdev/mpic.h            |    6 +
 arch/powerpc/sysdev/mpic_pasemi_msi.c |  172 ++++++++++++++++++++++++++++++++++
 5 files changed, 200 insertions(+), 2 deletions(-)
arch/powerpc/platforms/pasemi/setup.c +1 -1
index 3d62060..8549901 100644
@@ -215,7 +215,7 @@ static __init void pas_init_IRQ(void)
 
 	mpic = mpic_alloc(mpic_node, openpic_addr,
 			  MPIC_PRIMARY|MPIC_LARGE_VECTORS,
-			  0, 0, " PAS-OPIC  ");
+			  0, 0, "PASEMI-OPIC");
 	BUG_ON(!mpic);
 
 	mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
arch/powerpc/sysdev/Makefile +1 -1
index 99a77d7..85cf8c6 100644
@@ -2,7 +2,7 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o
+mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
arch/powerpc/sysdev/mpic.c +20 -0
index e479388..aebf025 100644
@@ -842,6 +842,24 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 	return 0;
 }
 
+void mpic_set_vector(unsigned int virq, unsigned int vector)
+{
+	struct mpic *mpic = mpic_from_irq(virq);
+	unsigned int src = mpic_irq_to_hw(virq);
+	unsigned int vecpri;
+
+	DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
+	    mpic, virq, src, vector);
+
+	if (src >= mpic->irq_count)
+		return;
+
+	vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
+	vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK);
+	vecpri |= vector;
+	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+}
+
 static struct irq_chip mpic_irq_chip = {
 	.mask		= mpic_mask_irq,
 	.unmask		= mpic_unmask_irq,
@@ -1230,6 +1248,8 @@ void __init mpic_init(struct mpic *mpic)
 		mpic_u3msi_init(mpic);
 	}
 
+	mpic_pasemi_msi_init(mpic);
+
 	for (i = 0; i < mpic->num_sources; i++) {
 		/* start with vector = source number, and masked */
 		u32 vecpri = MPIC_VECPRI_MASK | i |
arch/powerpc/sysdev/mpic.h +6 -0
index 1cb6bd8..3937c2b 100644
@@ -17,6 +17,7 @@ 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);
+extern int mpic_pasemi_msi_init(struct mpic *mpic);
 #else
 static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
 					  irq_hw_number_t hwirq)
@@ -28,9 +29,14 @@ static inline int mpic_u3msi_init(struct mpic *mpic)
 {
 	return -1;
 }
+extern int mpic_pasemi_msi_init(struct mpic *mpic)
+{
+	return -1;
+}
 #endif
 
 extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern void mpic_set_vector(unsigned int virq, unsigned int vector);
 extern void mpic_end_irq(unsigned int irq);
 extern void mpic_mask_irq(unsigned int irq);
 extern void mpic_unmask_irq(unsigned int irq);
arch/powerpc/sysdev/mpic_pasemi_msi.c new file +172 -0

172 lines not on this page · raw message

#1 lore raw

PATCH v2 1/1 pasemi: Implement MSI support

[POWERPC] pasemi: Implement MSI support

Implement MSI support for PA Semi PWRficient platforms. MSI is done through a special range of sources on the openpic controller, and they're unfortunately breaking the usual concepts of how sources are programmed:

* The source is calculated as 512 + the value written into the MSI register
* The vector for this source is added to the source and reported through IACK

This means that for simplicity, it makes much more sense to just set the vector to 0 for the source, since that's really the vector we expect to see from IACK.

Also, the affinity/priority registers will affect 16 sources at a time. To avoid most (simple) users from being limited by this, allocate 16 sources per device but use only one. This means that there's a total of 32 sources.

If we get usage scenarions that need more sources, the allocator should probably be revised to take an alignment argument and size, not just do natural alignment.

Finally, since I'm already touching the MPIC names on pasemi, rename the base one from the somewhat odd " PAS-OPIC " to "PASEMI-OPIC".

---

Oops, fixed the CONFIG_PCI_MSI=n prototype to be static inline instead of extern.

 arch/powerpc/platforms/pasemi/setup.c |    2 
 arch/powerpc/sysdev/Makefile          |    2 
 arch/powerpc/sysdev/mpic.c            |   20 +++
 arch/powerpc/sysdev/mpic.h            |    7 +
 arch/powerpc/sysdev/mpic_pasemi_msi.c |  172 ++++++++++++++++++++++++++++++++++
 5 files changed, 201 insertions(+), 2 deletions(-)
arch/powerpc/platforms/pasemi/setup.c +1 -1
index 6d7d068..b5dfd42 100644
@@ -223,7 +223,7 @@ static __init void pas_init_IRQ(void)
 
 	mpic = mpic_alloc(mpic_node, openpic_addr,
 			  MPIC_PRIMARY|MPIC_LARGE_VECTORS,
-			  0, 0, " PAS-OPIC  ");
+			  0, 0, "PASEMI-OPIC");
 	BUG_ON(!mpic);
 
 	mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
arch/powerpc/sysdev/Makefile +1 -1
index 99a77d7..85cf8c6 100644
@@ -2,7 +2,7 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o
+mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
arch/powerpc/sysdev/mpic.c +20 -0
index e479388..aebf025 100644
@@ -842,6 +842,24 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 	return 0;
 }
 
+void mpic_set_vector(unsigned int virq, unsigned int vector)
+{
+	struct mpic *mpic = mpic_from_irq(virq);
+	unsigned int src = mpic_irq_to_hw(virq);
+	unsigned int vecpri;
+
+	DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
+	    mpic, virq, src, vector);
+
+	if (src >= mpic->irq_count)
+		return;
+
+	vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
+	vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK);
+	vecpri |= vector;
+	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+}
+
 static struct irq_chip mpic_irq_chip = {
 	.mask		= mpic_mask_irq,
 	.unmask		= mpic_unmask_irq,
@@ -1230,6 +1248,8 @@ void __init mpic_init(struct mpic *mpic)
 		mpic_u3msi_init(mpic);
 	}
 
+	mpic_pasemi_msi_init(mpic);
+
 	for (i = 0; i < mpic->num_sources; i++) {
 		/* start with vector = source number, and masked */
 		u32 vecpri = MPIC_VECPRI_MASK | i |
arch/powerpc/sysdev/mpic.h +7 -0
index 1cb6bd8..4783c6e 100644
@@ -17,6 +17,7 @@ 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);
+extern int mpic_pasemi_msi_init(struct mpic *mpic);
 #else
 static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
 					  irq_hw_number_t hwirq)
@@ -28,9 +29,15 @@ static inline int mpic_u3msi_init(struct mpic *mpic)
 {
 	return -1;
 }
+
+static inline int mpic_pasemi_msi_init(struct mpic *mpic)
+{
+	return -1;
+}
 #endif
 
 extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern void mpic_set_vector(unsigned int virq, unsigned int vector);
 extern void mpic_end_irq(unsigned int irq);
 extern void mpic_mask_irq(unsigned int irq);
 extern void mpic_unmask_irq(unsigned int irq);
arch/powerpc/sysdev/mpic_pasemi_msi.c new file +172 -0

172 lines not on this page · raw message

#2 lore raw
Quoted 168 lines · Olof Johansson

[POWERPC] pasemi: Implement MSI support

Implement MSI support for PA Semi PWRficient platforms. MSI is done through a special range of sources on the openpic controller, and they're unfortunately breaking the usual concepts of how sources are programmed:

* The source is calculated as 512 + the value written into the MSI register
* The vector for this source is added to the source and reported through IACK

This means that for simplicity, it makes much more sense to just set the vector to 0 for the source, since that's really the vector we expect to see from IACK.

Also, the affinity/priority registers will affect 16 sources at a time. To avoid most (simple) users from being limited by this, allocate 16 sources per device but use only one. This means that there's a total of 32 sources.

If we get usage scenarions that need more sources, the allocator should probably be revised to take an alignment argument and size, not just do natural alignment.

Finally, since I'm already touching the MPIC names on pasemi, rename the base one from the somewhat odd " PAS-OPIC " to "PASEMI-OPIC".

---

Oops, fixed the CONFIG_PCI_MSI=n prototype to be static inline instead of extern.

 arch/powerpc/platforms/pasemi/setup.c |    2 
 arch/powerpc/sysdev/Makefile          |    2 
 arch/powerpc/sysdev/mpic.c            |   20 +++
 arch/powerpc/sysdev/mpic.h            |    7 +
 arch/powerpc/sysdev/mpic_pasemi_msi.c |  172 ++++++++++++++++++++++++++++++++++
 5 files changed, 201 insertions(+), 2 deletions(-)
arch/powerpc/platforms/pasemi/setup.c +1 -1
index 6d7d068..b5dfd42 100644
@@ -223,7 +223,7 @@ static __init void pas_init_IRQ(void)
 
 	mpic = mpic_alloc(mpic_node, openpic_addr,
 			  MPIC_PRIMARY|MPIC_LARGE_VECTORS,
-			  0, 0, " PAS-OPIC  ");
+			  0, 0, "PASEMI-OPIC");
 	BUG_ON(!mpic);
 
 	mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
arch/powerpc/sysdev/Makefile +1 -1
index 99a77d7..85cf8c6 100644
@@ -2,7 +2,7 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o
+mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
arch/powerpc/sysdev/mpic.c +20 -0
index e479388..aebf025 100644
@@ -842,6 +842,24 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 	return 0;
 }
 
+void mpic_set_vector(unsigned int virq, unsigned int vector)
+{
+	struct mpic *mpic = mpic_from_irq(virq);
+	unsigned int src = mpic_irq_to_hw(virq);
+	unsigned int vecpri;
+
+	DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
+	    mpic, virq, src, vector);
+
+	if (src >= mpic->irq_count)
+		return;
+
+	vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
+	vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK);
+	vecpri |= vector;
+	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+}
+
 static struct irq_chip mpic_irq_chip = {
 	.mask		= mpic_mask_irq,
 	.unmask		= mpic_unmask_irq,
@@ -1230,6 +1248,8 @@ void __init mpic_init(struct mpic *mpic)
 		mpic_u3msi_init(mpic);
 	}
 
+	mpic_pasemi_msi_init(mpic);
+
 	for (i = 0; i < mpic->num_sources; i++) {
 		/* start with vector = source number, and masked */
 		u32 vecpri = MPIC_VECPRI_MASK | i |
arch/powerpc/sysdev/mpic.h +7 -0
index 1cb6bd8..4783c6e 100644
@@ -17,6 +17,7 @@ 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);
+extern int mpic_pasemi_msi_init(struct mpic *mpic);
 #else
 static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
 					  irq_hw_number_t hwirq)
@@ -28,9 +29,15 @@ static inline int mpic_u3msi_init(struct mpic *mpic)
 {
 	return -1;
 }
+
+static inline int mpic_pasemi_msi_init(struct mpic *mpic)
+{
+	return -1;
+}
 #endif
 
 extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern void mpic_set_vector(unsigned int virq, unsigned int vector);
 extern void mpic_end_irq(unsigned int irq);
 extern void mpic_mask_irq(unsigned int irq);
 extern void mpic_unmask_irq(unsigned int irq);
arch/powerpc/sysdev/mpic_pasemi_msi.c new file +28 -0
new file mode 100644
index 0000000..d6bfda3
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2007, Olof Johansson, PA Semi
+ *
+ * Based on arch/powerpc/sysdev/mpic_u3msi.c:
+ *
+ * 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.
+ *
+ */
+
+#undef DEBUG
+
+#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"
+
+/* Allocate 16 interrupts per device, to give an alignment of 16,

arch/powerpc/sysdev/mpic_pasemi_msi.c line 38

Quoted 10 lines
arch/powerpc/sysdev/mpic_pasemi_msi.c new file +10 -0
+ * since that's the size of the grouping w.r.t. affinity. If someone
+ * needs more than 32 MSI's down the road we'll have to rethink this,
+ * but it should be OK for now.
+ */
+#define ALLOC_CHUNK 16
+
+#define PASEMI_MSI_ADDR 0xfc080000
+
+/* A bit ugly, can we get this from the pci_dev somehow? */
+static struct mpic *msi_mpic;

Before the ugliness spreads .. I'm pretty sure we can get this from the chip_data of the virq - I haven't fixed it though because I wasn't sure if using chip_data was kosher or not.

cheers

Signature · 8 lines
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
#3 lore raw
Quoted 3 lines · Michael Ellerman

Before the ugliness spreads .. I'm pretty sure we can get this from the chip_data of the virq - I haven't fixed it though because I wasn't sure if using chip_data was kosher or not.

Hmm, maybe.

I can forsee MSI and legacy interrupts being handled by different irq hosts on systems where they are cascaded, so I'm not 100% sure that's a workable way to do it (I assume you'd look it up through the pci_dev's legacy irq field, right?).

-Olof

#4 lore raw
Quoted 11 lines · Olof Johansson
Quoted 3 lines · Michael Ellerman

Before the ugliness spreads .. I'm pretty sure we can get this from the chip_data of the virq - I haven't fixed it though because I wasn't sure if using chip_data was kosher or not.

Hmm, maybe.

I can forsee MSI and legacy interrupts being handled by different irq hosts on systems where they are cascaded, so I'm not 100% sure that's a workable way to do it (I assume you'd look it up through the pci_dev's legacy irq field, right?).

No you're right that won't work, what I had in mind would work for teardown, we could get the mpic from the chip_data of each virq.

But for setup we need to know which mpic to create the mapping on _before_ it's mapped (obviously) so using chip_data doesn't work. And yeah, guessing based on the legacy irq of the pci_dev would not be safe.

The only safe way to do it I think would be to walk up the interrupt tree and find the interrupt controller node, then do an irq_find_host(), but that's a lot of fuss to save one static variable :)

Patch looks good otherwise.

cheers

Signature · 8 lines
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
#5 lore raw
Quoted 3 lines · Michael Ellerman

On Wed, 2007-12-12 at 01:23 -0600, Olof Johansson wrote:

Patch looks good otherwise.

By which I mean:

This patch is double-plus-good!

cheers

Signature · 8 lines
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