Skip to contentSkip to conversation

RTAS MSI

PATCH In review Jake Moilanen 5 participants 30 messages Jul 27, 2006 – Aug 10, 2006

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover RTAS MSI

Here is a rebased RTAS MSI which uses the IRQ layer rewrite. Please try getting it into 2.6.18.

I mistakenly forgot to export the MSI symbols. So modules weren't too happy...

The RTAS patch skips the intel-centric MSI layer and uses pci_enable/disable_msi() calls directly. It does not correctly handle multi-vector MSI either.

#1 lore raw

PATCH 1/2 export msi symbols

Forgot to export symbols for MSI.

 arch/powerpc/kernel/irq.c |    5 +++++
 1 files changed, 5 insertions(+)
arch/powerpc/kernel/irq.c +3 -0
Index: 2.6-msi/arch/powerpc/kernel/irq.c
===================================================================
@@ -52,6 +52,7 @@
 #include <linux/radix-tree.h>
 #include <linux/mutex.h>
 #include <linux/bootmem.h>
+#include <linux/pci.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -818,12 +819,14 @@ int pci_enable_msi(struct pci_dev * 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;}
@@ -831,6 +834,8 @@ void pci_disable_msix(struct pci_dev *de
void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} void disable_msi_mode(struct pci_dev *dev, int pos, int type) {} void pci_no_msi(void) {}
+EXPORT_SYMBOL(pci_enable_msix); +EXPORT_SYMBOL(pci_disable_msix);

#endif

#3 lore raw

PATCH 2/2 RTAS MSI

In reply to Jake Moilanen

Rebased with the IRQ layer rewrite. The code is not deallocating the vectors on a pci_disable_msi(). This is to work around a firmware vector release bug. Plus it is really not needed, as irq_create_mapping() just returns mappings to irqs that it knows of.

Additionally, the patch includes the client architecture bit for MSI, and correctly identifying that MSI is edge triggered.

 arch/powerpc/kernel/prom_init.c        |    8 ++
 arch/powerpc/platforms/pseries/setup.c |    4 +
 arch/powerpc/platforms/pseries/xics.c  |    5 -
 drivers/pci/Kconfig                    |    2 
 drivers/pci/Makefile                   |    9 +-
 drivers/pci/msi-rtas.c                 |  111
+++++++++++++++++++++++++++++++++
 include/asm-powerpc/rtas.h             |    4 +
 7 files changed, 136 insertions(+), 7 deletions(-)
drivers/pci/Makefile +6 -3
Index: 2.6-msi/drivers/pci/Makefile
===================================================================
@@ -27,9 +27,12 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
drivers/pci/msi-rtas.c new file +111 -0

111 lines not on this page · raw message

drivers/pci/Kconfig +1 -1
Index: 2.6-msi/drivers/pci/Kconfig
===================================================================
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC_PSERIES
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
arch/powerpc/platforms/pseries/setup.c +4 -0
Index: 2.6-msi/arch/powerpc/platforms/pseries/setup.c
===================================================================
@@ -267,6 +267,10 @@ static void __init pseries_discover_pic(
 			return;
 		} else if (strstr(typep, "ppc-xicp")) {
 			ppc_md.init_IRQ       = xics_init_IRQ;
+#ifdef CONFIG_PCI_MSI
+			ppc_md.enable_msi	= rtas_enable_msi;
+			ppc_md.disable_msi	= rtas_disable_msi;
+#endif
 #ifdef CONFIG_KEXEC
 			ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
 #endif
include/asm-powerpc/rtas.h +1 -0
Index: 2.6-msi/include/asm-powerpc/rtas.h
===================================================================
@@ -4,6 +4,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
+#include <linux/pci.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -186,6 +187,9 @@ extern int early_init_dt_scan_rtas(unsig
 
 extern void pSeries_log_error(char *buf, unsigned int err_type, int

fatal);

+extern int rtas_enable_msi(struct pci_dev* pdev); +extern void rtas_disable_msi(struct pci_dev * pdev); +
/* Error types logged. */
#define ERR_FLAG_ALREADY_LOGGED 0x0
#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */

arch/powerpc/kernel/prom_init.c +7 -1
Index: 2.6-msi/arch/powerpc/kernel/prom_init.c
===================================================================
@@ -632,6 +632,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,
@@ -675,7 +681,7 @@ static unsigned char ibm_architecture_ve
 	/* option vector 5: PAPR/OF options */
 	3 - 1,				/* length */
 	0,				/* don't ignore, don't halt */
-	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
arch/powerpc/platforms/pseries/xics.c +3 -2
Index: 2.6-msi/arch/powerpc/platforms/pseries/xics.c
===================================================================
@@ -526,11 +526,12 @@ static int xics_host_map_lpar(struct irq
 	pr_debug("xics: map_lpar virq %d, hwirq 0x%lx, flags: 0x%x\n",
 		 virq, hw, flags);
 
-	if (sense && sense != IRQ_TYPE_LEVEL_LOW)
+	if (sense && !(sense & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_RISING)))
 		printk(KERN_WARNING "xics: using unsupported sense 0x%x"
 		       " for irq %d (h: 0x%lx)\n", flags, virq, hw);
 
-	get_irq_desc(virq)->status |= IRQ_LEVEL;
+	if (sense && sense & IRQ_TYPE_LEVEL_LOW)
+		get_irq_desc(virq)->status |= IRQ_LEVEL;
 	set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq);
 	return 0;
 }
#4 lore raw
Quoted 6 lines

Index: 2.6-msi/drivers/pci/Makefile
===================================================================

drivers/pci/Makefile +0 -0
@@ -27,9 +27,12 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 34

Quoted 10 lines
drivers/pci/Makefile +4 -3
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
 
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-apic.o msi-altix.o

These two lines don't need the msi.o and msi-altix.o AFAICS.

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 34

Quoted 1 line
drivers/pci/Makefile +1 -0
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o

I think this file should live in arch/powerpc, and so should this Makefile fragment.

Quoted 4 lines
drivers/pci/Makefile +1 -0
+
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 

#

Other than that, can we please have the part that doesn't build the "generic" MSI stuff included ASAP?

Quoted 1 line

Index: 2.6-msi/drivers/pci/msi-rtas.c

Maybe msi-papr.c is a better name btw? Not that I care :-)

No comments on your actual code, sorry.

Segher

#5 lore raw
Quoted 4 lines

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 33

Quoted 2 lines
drivers/pci/Makefile +2 -0
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-apic.o msi-altix.o

These two lines don't need the msi.o and msi-altix.o AFAICS.

s/altix/apic/. Duh.

Segher

#6 lore raw
In reply to Segher Boessenkool
Quoted 14 lines · Segher Boessenkool
Quoted 13 lines

Index: 2.6-msi/drivers/pci/Makefile
===================================================================

drivers/pci/Makefile +2 -3
@@ -27,9 +27,12 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
Quoted 4 lines

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 33

Quoted 2 lines
drivers/pci/Makefile +2 -0
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-apic.o msi-altix.o

These two lines don't need the msi.o and msi-altix.o AFAICS.

Yup, you are right...updated patch included below.

Quoted 4 lines

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 34

Quoted 1 line
drivers/pci/Makefile +1 -0
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o

I think this file should live in arch/powerpc, and so should this Makefile fragment.

I'm following the current MSI methodologies where arch specific MSI code lives in drivers/pci. This is just like msi-altix.c.

Quoted 11 lines

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 38

Quoted 4 lines
drivers/pci/Makefile +1 -0
+
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #

Other than that, can we please have the part that doesn't build the "generic" MSI stuff included ASAP?

Quoted 1 line

Index: 2.6-msi/drivers/pci/msi-rtas.c

Maybe msi-papr.c is a better name btw? Not that I care :-)

IMHO I don't like PAPR names because they like changing them on a whim. RTAS is a bit more persistent.

I don't really care...If anyone feels real strongly about it, I'll change it.

 arch/powerpc/kernel/prom_init.c        |    8 ++
 arch/powerpc/platforms/pseries/setup.c |    4 +
 arch/powerpc/platforms/pseries/xics.c  |    5 -
 drivers/pci/Kconfig                    |    2 
 drivers/pci/Makefile                   |    5 +
 drivers/pci/msi-rtas.c                 |  111
+++++++++++++++++++++++++++++++++
 include/asm-powerpc/rtas.h             |    4 +
 7 files changed, 134 insertions(+), 5 deletions(-)
drivers/pci/Makefile +4 -1
Index: 2.6-msi/drivers/pci/Makefile
===================================================================
@@ -27,9 +27,12 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
 msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
 msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
drivers/pci/msi-rtas.c new file +111 -0

111 lines not on this page · raw message

drivers/pci/Kconfig +1 -1
Index: 2.6-msi/drivers/pci/Kconfig
===================================================================
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC_PSERIES
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
arch/powerpc/platforms/pseries/setup.c +4 -0
Index: 2.6-msi/arch/powerpc/platforms/pseries/setup.c
===================================================================
@@ -267,6 +267,10 @@ static void __init pseries_discover_pic(
 			return;
 		} else if (strstr(typep, "ppc-xicp")) {
 			ppc_md.init_IRQ       = xics_init_IRQ;
+#ifdef CONFIG_PCI_MSI
+			ppc_md.enable_msi	= rtas_enable_msi;
+			ppc_md.disable_msi	= rtas_disable_msi;
+#endif
 #ifdef CONFIG_KEXEC
 			ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
 #endif
include/asm-powerpc/rtas.h +1 -0
Index: 2.6-msi/include/asm-powerpc/rtas.h
===================================================================
@@ -4,6 +4,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
+#include <linux/pci.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -186,6 +187,9 @@ extern int early_init_dt_scan_rtas(unsig
 
 extern void pSeries_log_error(char *buf, unsigned int err_type, int

fatal);

+extern int rtas_enable_msi(struct pci_dev* pdev); +extern void rtas_disable_msi(struct pci_dev * pdev); +
/* Error types logged. */
#define ERR_FLAG_ALREADY_LOGGED 0x0
#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */

arch/powerpc/kernel/prom_init.c +7 -1
Index: 2.6-msi/arch/powerpc/kernel/prom_init.c
===================================================================
@@ -632,6 +632,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,
@@ -675,7 +681,7 @@ static unsigned char ibm_architecture_ve
 	/* option vector 5: PAPR/OF options */
 	3 - 1,				/* length */
 	0,				/* don't ignore, don't halt */
-	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
arch/powerpc/platforms/pseries/xics.c +3 -2
Index: 2.6-msi/arch/powerpc/platforms/pseries/xics.c
===================================================================
@@ -526,11 +526,12 @@ static int xics_host_map_lpar(struct irq
 	pr_debug("xics: map_lpar virq %d, hwirq 0x%lx, flags: 0x%x\n",
 		 virq, hw, flags);
 
-	if (sense && sense != IRQ_TYPE_LEVEL_LOW)
+	if (sense && !(sense & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_RISING)))
 		printk(KERN_WARNING "xics: using unsupported sense 0x%x"
 		       " for irq %d (h: 0x%lx)\n", flags, virq, hw);
 
-	get_irq_desc(virq)->status |= IRQ_LEVEL;
+	if (sense && sense & IRQ_TYPE_LEVEL_LOW)
+		get_irq_desc(virq)->status |= IRQ_LEVEL;
 	set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq);
 	return 0;
 }
#7 lore raw
Quoted 3 lines
Quoted 1 line

These two lines don't need the msi.o and msi-altix.o AFAICS.

Yup, you are right...updated patch included below.

Looks fine now, thanks.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o

I think this file should live in arch/powerpc, and so should this Makefile fragment.

I'm following the current MSI methodologies where arch specific MSI code lives in drivers/pci. This is just like msi-altix.c.

True, but our core support lives in arch/. The same is true for PHB code etc.; if Altix messed this up, that doesn't mean we need to :-)

Quoted 2 lines
Quoted 2 lines

Other than that, can we please have the part that doesn't build the "generic" MSI stuff included ASAP?

This would naturally fall out as a separate patch then, as well.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Index: 2.6-msi/drivers/pci/msi-rtas.c

Maybe msi-papr.c is a better name btw? Not that I care :-)

IMHO I don't like PAPR names because they like changing them on a whim. RTAS is a bit more persistent.

Maybe msi-pseries then? Oh wait, they changed that name too ;-)

Quoted 2 lines

I don't really care...If anyone feels real strongly about it, I'll change it.

If you move this code to arch/powerpc/platforms/pseries/, you could just call it "msi.c". I don't like the msi-rtas name -- but, I don't feel that strongly about it, just a suggestion.

Segher

#8 lore raw
In reply to Jake Moilanen

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 33

Quoted 7 lines · Jake Moilanen
drivers/pci/Makefile +4 -3
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-apic.o msi-altix.o

Doesn't this mean that ia64 configs might now get msi.o and msi-apic.o listed twice? Why did you need to change the msiobj-$(CONFIG_IA64_GENERIC) and msiobj-$(CONFIG_IA64_SGI_SN2) lines at all?

Paul.

#9 lore raw
Quoted 14 lines · Paul Mackerras

drivers/pci/Makefile obj-$(CONFIG_PPC64) += setup-bus.o · line 33

Quoted 7 lines · Jake Moilanen
drivers/pci/Makefile +4 -3
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-apic.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-apic.o msi-altix.o

Doesn't this mean that ia64 configs might now get msi.o and msi-apic.o listed twice? Why did you need to change the msiobj-$(CONFIG_IA64_GENERIC) and msiobj-$(CONFIG_IA64_SGI_SN2) lines at all?

Yup...see the second patch I posted where I fixed up the ia64 configs so msi.o and msi-apic.o are listed once and msiobj-$(CONFIG_IA64_GENERIC) and msiobj-$(CONFIG_IA64_SGI_SN2) are not changed.

In a few, I'll be posting another version of the patch which address Michael's concerns.

#10 lore raw
In reply to Jake Moilanen
Quoted 7 lines · Jake Moilanen

Rebased with the IRQ layer rewrite. The code is not deallocating the vectors on a pci_disable_msi(). This is to work around a firmware vector release bug. Plus it is really not needed, as irq_create_mapping() just returns mappings to irqs that it knows of.

Additionally, the patch includes the client architecture bit for MSI, and correctly identifying that MSI is edge triggered.

Hey Jake, just a few niggles below ..

Quoted 15 lines

Index: 2.6-msi/drivers/pci/msi-rtas.c
===================================================================

drivers/pci/msi-rtas.c new file +10 -0
@@ -0,0 +1,111 @@
+/*
+ * Jake Moilanen <[email protected]>
+ * Copyright (C) 2006 IBM
+ *
+ * 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.
+ *
+ */

drivers/pci/msi-rtas.c line 20

Quoted 10 lines
drivers/pci/msi-rtas.c new file +10 -0
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+int rtas_enable_msi(struct pci_dev* pdev)
+{
+	static int seq_num = 1;

Do we really want seq_num to be static? By my reading of PAPR we only need to maintain the seq number across calls that return -2/990x, and we handle that all inside this function. If it does need to be unique for _all_ calls, then I don't see how seq_num being static is going to work, a different cpu could stomp on the seq_num value between calls, which presumably would make firmware mad.

drivers/pci/msi-rtas.c line 28

Quoted 8 lines
drivers/pci/msi-rtas.c new file +8 -0
+	int i;
+	int rc;
+	int query_token = rtas_token("ibm,query-interrupt-source-number");
+	int devfn;
+	int busno;
+	u32 *reg;
+	int reglen;
+	int ret[3];

You only need ret[2] I think, the first return value (status) is handled inside rtas_call for you.

drivers/pci/msi-rtas.c line 34

Quoted 6 lines
drivers/pci/msi-rtas.c new file +6 -0
+	int dummy;
+	int n_intr;
+	int last_virq = NO_IRQ;
+	int virq;
+	unsigned int addr;
+	unsigned long buid = -1;

No need to set buid to -1 as you unconditionally assign to it later.

drivers/pci/msi-rtas.c line 40

Quoted 6 lines
drivers/pci/msi-rtas.c new file +6 -0
+	struct device_node * dn;
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", &dummy))
+		return -ENOENT;

You don't need dummy, just pass NULL.

drivers/pci/msi-rtas.c line 50

Quoted 10 lines
drivers/pci/msi-rtas.c new file +10 -0
+
+	reg = (u32 *) get_property(dn, "reg", &reglen);
+	if (reg == NULL || reglen < 20)
+		return -ENXIO;
+
+	devfn = (reg[0] >> 8) & 0xff;
+	busno = (reg[0] >> 16) & 0xff;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (busno << 16) | (devfn << 8);

Why do we need to read the reg here, can't we just use the existing fields? ie:

        addr = (pdev->bus->number << 16) | (pdev->devfn << 8);

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#11 lore raw
Quoted 11 lines

drivers/pci/msi-rtas.c line 20

Quoted 4 lines
drivers/pci/msi-rtas.c new file +3 -0
+int rtas_enable_msi(struct pci_dev* pdev)
+{
+	static int seq_num = 1;

Do we really want seq_num to be static? By my reading of PAPR we only need to maintain the seq number across calls that return -2/990x, and we handle that all inside this function. If it does need to be unique for _all_ calls, then I don't see how seq_num being static is going to work, a different cpu could stomp on the seq_num value between calls, which presumably would make firmware mad.

Bah...I thought I fixed this a long time ago....must have gotten dropped somewhere in the mix.

Quoted 5 lines

drivers/pci/msi-rtas.c line 28

Quoted 2 lines
drivers/pci/msi-rtas.c new file +2 -0
+	int reglen;
+	int ret[3];

You only need ret[2] I think, the first return value (status) is handled inside rtas_call for you.

Yup...

Quoted 8 lines

drivers/pci/msi-rtas.c line 34

Quoted 6 lines
drivers/pci/msi-rtas.c new file +6 -0
+	int dummy;
+	int n_intr;
+	int last_virq = NO_IRQ;
+	int virq;
+	unsigned int addr;
+	unsigned long buid = -1;

No need to set buid to -1 as you unconditionally assign to it later.

Agreed

Quoted 8 lines

drivers/pci/msi-rtas.c line 40

Quoted 6 lines
drivers/pci/msi-rtas.c new file +6 -0
+	struct device_node * dn;
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", &dummy))
+		return -ENOENT;

You don't need dummy, just pass NULL.

Yup.

Quoted 14 lines

drivers/pci/msi-rtas.c line 50

Quoted 10 lines
drivers/pci/msi-rtas.c new file +10 -0
+
+	reg = (u32 *) get_property(dn, "reg", &reglen);
+	if (reg == NULL || reglen < 20)
+		return -ENXIO;
+
+	devfn = (reg[0] >> 8) & 0xff;
+	busno = (reg[0] >> 16) & 0xff;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (busno << 16) | (devfn << 8);

Why do we need to read the reg here, can't we just use the existing fields? ie:

Quoted 1 line
        addr = (pdev->bus->number << 16) | (pdev->devfn << 8);

Patch coming w/ all these fixes.

#12 lore raw
In reply to Michael Ellerman

Here's version 3 which addresses all of Michael's comments.

 arch/powerpc/kernel/prom_init.c        |    8 ++
 arch/powerpc/platforms/pseries/setup.c |    4 +
 arch/powerpc/platforms/pseries/xics.c  |    5 +
 drivers/pci/Kconfig                    |    2 
 drivers/pci/Makefile                   |    5 +
 drivers/pci/msi-rtas.c                 |   99
+++++++++++++++++++++++++++++++++
 include/asm-powerpc/rtas.h             |    4 +
 7 files changed, 122 insertions(+), 5 deletions(-)
drivers/pci/Makefile +4 -1
Index: 2.6-msi/drivers/pci/Makefile
===================================================================
@@ -27,9 +27,12 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o
 msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
 msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
drivers/pci/msi-rtas.c new file +99 -0

99 lines not on this page · raw message

drivers/pci/Kconfig +1 -1
Index: 2.6-msi/drivers/pci/Kconfig
===================================================================
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC_PSERIES
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
arch/powerpc/platforms/pseries/setup.c +4 -0
Index: 2.6-msi/arch/powerpc/platforms/pseries/setup.c
===================================================================
@@ -267,6 +267,10 @@ static void __init pseries_discover_pic(
 			return;
 		} else if (strstr(typep, "ppc-xicp")) {
 			ppc_md.init_IRQ       = xics_init_IRQ;
+#ifdef CONFIG_PCI_MSI
+			ppc_md.enable_msi	= rtas_enable_msi;
+			ppc_md.disable_msi	= rtas_disable_msi;
+#endif
 #ifdef CONFIG_KEXEC
 			ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
 #endif
include/asm-powerpc/rtas.h +1 -0
Index: 2.6-msi/include/asm-powerpc/rtas.h
===================================================================
@@ -4,6 +4,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
+#include <linux/pci.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -186,6 +187,9 @@ extern int early_init_dt_scan_rtas(unsig
 
 extern void pSeries_log_error(char *buf, unsigned int err_type, int

fatal);

+extern int rtas_enable_msi(struct pci_dev* pdev); +extern void rtas_disable_msi(struct pci_dev * pdev); +
/* Error types logged. */
#define ERR_FLAG_ALREADY_LOGGED 0x0
#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */

arch/powerpc/kernel/prom_init.c +7 -1
Index: 2.6-msi/arch/powerpc/kernel/prom_init.c
===================================================================
@@ -632,6 +632,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,
@@ -675,7 +681,7 @@ static unsigned char ibm_architecture_ve
 	/* option vector 5: PAPR/OF options */
 	3 - 1,				/* length */
 	0,				/* don't ignore, don't halt */
-	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
arch/powerpc/platforms/pseries/xics.c +3 -2
Index: 2.6-msi/arch/powerpc/platforms/pseries/xics.c
===================================================================
@@ -526,11 +526,12 @@ static int xics_host_map_lpar(struct irq
 	pr_debug("xics: map_lpar virq %d, hwirq 0x%lx, flags: 0x%x\n",
 		 virq, hw, flags);
 
-	if (sense && sense != IRQ_TYPE_LEVEL_LOW)
+	if (sense && !(sense & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_RISING)))
 		printk(KERN_WARNING "xics: using unsupported sense 0x%x"
 		       " for irq %d (h: 0x%lx)\n", flags, virq, hw);
 
-	get_irq_desc(virq)->status |= IRQ_LEVEL;
+	if (sense && sense & IRQ_TYPE_LEVEL_LOW)
+		get_irq_desc(virq)->status |= IRQ_LEVEL;
 	set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq);
 	return 0;
 }
#13 lore raw
Quoted 1 line · Jake Moilanen

Here's version 3 which addresses all of Michael's comments.

Looks good, nice one.

I was thinking about disable, can you give us any more details on the firmware bug that is blocking that?

I'm not sure what disable really needs to do, but I think drivers might expect it to set dev->irq back to the LSI value, even if we don't free anything internally. Not sure.

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#14 lore raw
Quoted 3 lines

I'm not sure what disable really needs to do, but I think drivers might expect it to set dev->irq back to the LSI value, even if we don't free anything internally. Not sure.

Yes, that's required by the MSI API.

Segher

#15 lore raw
In reply to Jake Moilanen
Quoted 1 line · Jake Moilanen

Here's version 3 which addresses all of Michael's comments.

Sorry, more questions :)

Quoted 64 lines

Index: 2.6-msi/drivers/pci/msi-rtas.c
===================================================================

drivers/pci/msi-rtas.c new file +59 -0
@@ -0,0 +1,99 @@
+/*
+ * Jake Moilanen <[email protected]>
+ * Copyright (C) 2006 IBM
+ *
+ * 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/pci.h>
+#include <linux/irq.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+int rtas_enable_msi(struct pci_dev* pdev)
+{
+	int seq_num = 1;
+	int i;
+	int rc;
+	int query_token = rtas_token("ibm,query-interrupt-source-number");
+	int ret[2];
+	int n_intr;
+	int last_virq = NO_IRQ;
+	int virq;
+	unsigned int addr;
+	unsigned long buid;
+	struct device_node * dn;
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", NULL))
+		return -ENOENT;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (pdev->bus->number << 16) | (pdev->devfn << 8);
+
+	do {
+		rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
+			       buid >> 32, buid & 0xffffffff,
+			       0, 0, seq_num);
+
+		seq_num = ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc)	{
+		printk(KERN_WARNING "error[%d]: getting the number of "
+		       "MSI interrupts for %s\n", rc, dn->name);
+		return -EIO;
+	}
+
+	/* Return if there's no MSI interrupts */
+	if (!ret[0])
+		return -ENOENT;
+
+	n_intr = ret[0];
+

drivers/pci/msi-rtas.c line 69

Quoted 10 lines
drivers/pci/msi-rtas.c new file +10 -0
+	for (i = 0; i < n_intr; i++) {
+		do {
+			rc = rtas_call(query_token, 4, 3, ret, addr,
+				       buid >> 32, buid & 0xffffffff, i);
+		} while (rtas_busy_delay(rc));
+
+		if (!rc) {
+			virq = irq_create_mapping(irq_find_host(dn), ret[0],
+						ret[1] ? IRQ_TYPE_EDGE_RISING :
+						IRQ_TYPE_LEVEL_LOW);

I'm only just starting to get benh's new irq code, but I think irq_find_host(dn) isn't doing what we want here. It's probably harmless, but AFAICT irq_find_host() is only meant to be called when you have the node of the irq controller, not for an arbitrary dn. The doco's a bit ambiguous:

* irq_find_host - Locates a host for a given device node
* @node: device-tree node of the interrupt controller

But looking at the implementation, it doesn't do a search up the tree or anything, it just checks node against each host.

Also, since's benh's latest patch went in we'll have to split this into two calls, I think we want:

virq = irq_create_mapping(NULL ???, ret[0]); set_irq_type(virq, ret[1] ? IRQ_TYPE_EDGE_RISING : IRQ_TYPE_LEVEL_LOW);

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#16 lore raw
Quoted 7 lines

I'm only just starting to get benh's new irq code, but I think irq_find_host(dn) isn't doing what we want here. It's probably harmless, but AFAICT irq_find_host() is only meant to be called when you have the node of the irq controller, not for an arbitrary dn. The doco's a bit ambiguous:

Quoted 5 lines

* irq_find_host - Locates a host for a given device node
* @node: device-tree node of the interrupt controller

But looking at the implementation, it doesn't do a search up the tree or anything, it just checks node against each host.

For pSeries, passing NULL is fine for host anyway as there is only one domain that is relevant for MSIs (there might be a 8259 legacy domain too but it's not relevant) and that domain is set to be the default host.

Quoted 5 lines

Also, since's benh's latest patch went in we'll have to split this into two calls, I think we want:

virq = irq_create_mapping(NULL ???, ret[0]); set_irq_type(virq, ret[1] ? IRQ_TYPE_EDGE_RISING : IRQ_TYPE_LEVEL_LOW);

MSIs are always edge (though there might be an issue with some P5IOC errata lurking here...). The xics code doesn't care much at this point though.

Ben.

#17 lore raw
Quoted 9 lines · Benjamin Herrenschmidt
Quoted 9 lines

I'm only just starting to get benh's new irq code, but I think irq_find_host(dn) isn't doing what we want here. It's probably harmless, but AFAICT irq_find_host() is only meant to be called when you have the node of the irq controller, not for an arbitrary dn. The doco's a bit ambiguous:

* irq_find_host - Locates a host for a given device node
* @node: device-tree node of the interrupt controller

Quoted 7 lines
Quoted 2 lines

But looking at the implementation, it doesn't do a search up the tree or anything, it just checks node against each host.

For pSeries, passing NULL is fine for host anyway as there is only one domain that is relevant for MSIs (there might be a 8259 legacy domain too but it's not relevant) and that domain is set to be the default host.

OK, will fix it. In the long run we probably want a function that takes any dn and finds the host for it.

Quoted 10 lines
Quoted 6 lines

Also, since's benh's latest patch went in we'll have to split this into two calls, I think we want:

virq = irq_create_mapping(NULL ???, ret[0]); set_irq_type(virq, ret[1] ? IRQ_TYPE_EDGE_RISING : IRQ_TYPE_LEVEL_LOW);

MSIs are always edge (though there might be an issue with some P5IOC errata lurking here...). The xics code doesn't care much at this point though.

Err, great. Anymore info? I'll just set it to EDGE for now.

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#18 lore raw
Quoted 2 lines · Michael Ellerman

OK, will fix it. In the long run we probably want a function that takes any dn and finds the host for it.

That's what the OF irq parsing functions do... You can't just walk up the device-tree for interrupts, you have to walk up the interrupt tree...

Quoted 1 line

Err, great. Anymore info? I'll just set it to EDGE for now.

Or just don't call set_irq_type()... xics doesn't care.

Ben.

#19 lore raw
In reply to Jake Moilanen
Quoted 9 lines · Jake Moilanen

Here is a rebased RTAS MSI which uses the IRQ layer rewrite. Please try getting it into 2.6.18.

I mistakenly forgot to export the MSI symbols. So modules weren't too happy...

The RTAS patch skips the intel-centric MSI layer and uses pci_enable/disable_msi() calls directly. It does not correctly handle multi-vector MSI either.

Multi-vector MSIs aren't handled by the linux API anyway it seems (the doc says pci_enable_msi() only ever enables one MSI) so that's fine if you don't handle them :) The word on the street is that multivector MSIs aren't useful, MSI-X are.

Ben.

#20 lore raw
Quoted 8 lines
Quoted 3 lines

The RTAS patch skips the intel-centric MSI layer and uses pci_enable/disable_msi() calls directly. It does not correctly handle multi-vector MSI either.

Multi-vector MSIs aren't handled by the linux API anyway it seems (the doc says pci_enable_msi() only ever enables one MSI) so that's fine if you don't handle them :) The word on the street is that multivector MSIs aren't useful, MSI-X are.

pci_enable_msi() should always enable exactly one or zero MSIs. Maybe Jake's patch doesn't follow this rule, and that is what he alluded to?

Segher

#21 lore raw
Quoted 5 lines · Segher Boessenkool
Quoted 5 lines
Quoted 4 lines

The RTAS patch skips the intel-centric MSI layer and uses pci_enable/disable_msi() calls directly. It does not correctly handle
multi-vector MSI either.

Quoted 8 lines
Quoted 5 lines

Multi-vector MSIs aren't handled by the linux API anyway it seems (the doc says pci_enable_msi() only ever enables one MSI) so that's fine if you don't handle them :) The word on the street is that multivector MSIs
aren't useful, MSI-X are.

pci_enable_msi() should always enable exactly one or zero MSIs. Maybe Jake's patch doesn't follow this rule, and that is what he alluded to?

Sorry, I was less-than-clear. I was going to use this same framework for MSI-X, and I was saying that it is not being correctly handled at this point.

Jake

#22 lore raw
Quoted 3 lines

Sorry, I was less-than-clear. I was going to use this same framework for MSI-X, and I was saying that it is not being correctly handled at this point.

Well it's _correct_ -- pci_enable_msix() always returns failure, that's fine from a correctness perspective (although suboptimal from a performance or functionality perspective, heh).

Segher

#23 lore raw
In reply to Segher Boessenkool
Quoted 5 lines · Segher Boessenkool
Quoted 5 lines
Quoted 4 lines

The RTAS patch skips the intel-centric MSI layer and uses pci_enable/disable_msi() calls directly. It does not correctly handle
multi-vector MSI either.

Quoted 8 lines
Quoted 5 lines

Multi-vector MSIs aren't handled by the linux API anyway it seems (the doc says pci_enable_msi() only ever enables one MSI) so that's fine if you don't handle them :) The word on the street is that multivector MSIs
aren't useful, MSI-X are.

pci_enable_msi() should always enable exactly one or zero MSIs. Maybe Jake's patch doesn't follow this rule, and that is what he alluded to?

I was just re-reading this thread and this got me thinking. I think the current code does violate this rule if firmware has allocated more than one MSI to the device.

In rtas_enable_msi() we ask firmware how many MSIs the device has been given (by firmware), we then return one to the driver, but leave any extras configured.

So this might lead to the state where the card has been configured to use x MSIs, but we only tell the driver about 1 of them. I don't know enough PCI to grok if that's going to be a problem.

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#24 lore raw
Quoted 11 lines

I was just re-reading this thread and this got me thinking. I think the current code does violate this rule if firmware has allocated more than one MSI to the device.

In rtas_enable_msi() we ask firmware how many MSIs the device has been given (by firmware), we then return one to the driver, but leave any extras configured.

So this might lead to the state where the card has been configured to use x MSIs, but we only tell the driver about 1 of them. I don't know enough PCI to grok if that's going to be a problem.

A device could in principle happily start using all MSIs it has been assigned as soon as its global interrupt enable bit is set. So lying to the driver about what MSIs are enabled can in principle cause nasty problems.

In reality however, on any (recent) device, every interrupt cause also has its own enable bits that the driver needs to set. So we're sort-of safe here.

Eventually, we should change the API for pci_enable_msi() so that it can enable multiple MSIs as well; an arch implementation can always choose to do just one. This lets us roll the APIs for MSI and MSI-X into one as well btw -- always a good thing!

Segher

#25 lore raw
Quoted 14 lines · Segher Boessenkool
Quoted 6 lines

I was just re-reading this thread and this got me thinking. I think the
current code does violate this rule if firmware has allocated more than
one MSI to the device.

Quoted 7 lines

In rtas_enable_msi() we ask firmware how many MSIs the device has been given (by firmware), we then return one to the driver, but leave any extras configured.

So this might lead to the state where the card has been configured to use x MSIs, but we only tell the driver about 1 of them. I don't know enough PCI to grok if that's going to be a problem.

Quoted 8 lines

A device could in principle happily start using all MSIs it has been assigned as soon as its global interrupt enable bit is set. So lying to the driver about what MSIs are enabled can in principle cause nasty problems.

In reality however, on any (recent) device, every interrupt cause also has its own enable bits that the driver needs to set. So we're sort-of safe here.

Yeah ok, I thought that was probably the answer - it's possible, but probably not a problem IRL.

Quoted 4 lines

Eventually, we should change the API for pci_enable_msi() so that it can enable multiple MSIs as well; an arch implementation can always choose to do just one. This lets us roll the APIs for MSI and MSI-X into one as well btw -- always a good thing!

Yeah. Looking at the way drivers use the current API (and there's only a few), they generally seem to try to enable n MSI-X vectors, then fallback to a single MSI then LSI. And then there's some that just want a single MSI as a drop-in replacement for LSI.

So I think we could have pci_enable_msi(dev), which would enable a single MSI _or_ MSI-X vector, depending on what's available. That'd be used by drivers that just want a simple replacement for LSI. And then pci_enable_multi_msi(dev, num_irqs) which would give the driver num_irqs MSI or MSI-X vectors.

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#26 lore raw
Quoted 5 lines

So I think we could have pci_enable_msi(dev), which would enable a single MSI _or_ MSI-X vector, depending on what's available. That'd be used by drivers that just want a simple replacement for LSI. And then pci_enable_multi_msi(dev, num_irqs) which would give the driver num_irqs MSI or MSI-X vectors.

You cannot lie and have pci_enable_msi() enable an MSI-X vector. Some cards need additional tweaking when enabling MSI or MSI-X and if the system enables MSI-X while the driver thinks it's MSI, bad things might happen.

pci_enable_msi() should call the firmware to reconfigure for only one MSI and enable just that. MSI-X is the only really sexy thing anyway (that and a way to spread MSI-X accross CPUs from the kernel but that's another topic)

Ben.

#27 lore raw
Quoted 10 lines · Benjamin Herrenschmidt
Quoted 5 lines

So I think we could have pci_enable_msi(dev), which would enable a single MSI _or_ MSI-X vector, depending on what's available. That'd be used by drivers that just want a simple replacement for LSI. And then pci_enable_multi_msi(dev, num_irqs) which would give the driver num_irqs MSI or MSI-X vectors.

You cannot lie and have pci_enable_msi() enable an MSI-X vector. Some cards need additional tweaking when enabling MSI or MSI-X and if the system enables MSI-X while the driver thinks it's MSI, bad things might happen.

Hmm. As I read the PAPR the firmware calls may do just that (pp 122). ie. it doesn't differentiate between MSIs and MSI-Xs as far as I can tell. So if we implement pci_enable_msi() via the RTAS calls we might be violating that constraint.

Quoted 4 lines

pci_enable_msi() should call the firmware to reconfigure for only one MSI and enable just that. MSI-X is the only really sexy thing anyway (that and a way to spread MSI-X accross CPUs from the kernel but that's another topic)

And the current implementation doesn't do that either, so we should fix it to only allocate 1 MSI, regardless of what firmware has set.

cheers

Signature · 8 lines
Michael Ellerman
IBM OzLabs

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
#28 lore raw
Quoted 5 lines

Hmm. As I read the PAPR the firmware calls may do just that (pp 122). ie. it doesn't differentiate between MSIs and MSI-Xs as far as I can tell. So if we implement pci_enable_msi() via the RTAS calls we might be violating that constraint.

It's pretty screwed up .... I don't know what is a proper way out there.

Quoted 7 lines
Quoted 4 lines

pci_enable_msi() should call the firmware to reconfigure for only one MSI and enable just that. MSI-X is the only really sexy thing anyway (that and a way to spread MSI-X accross CPUs from the kernel but that's another topic)

And the current implementation doesn't do that either, so we should fix it to only allocate 1 MSI, regardless of what firmware has set.

Yes.

Ben.

#29 lore raw
In reply to Michael Ellerman
Quoted 4 lines

So this might lead to the state where the card has been configured to use x MSIs, but we only tell the driver about 1 of them. I don't know enough PCI to grok if that's going to be a problem.

It probably will

Ben.