RTAS MSI
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.
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
@@ -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 * pdevelse 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
Re: [PATCH][1/2] export msi symbols
Quoted 3 lines
Forgot to export symbols for MSI.
Signed-off-by Jake Moilanen <[email protected]>
PATCH 2/2 RTAS MSI
In reply to Jake MoilanenRebased 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -526,11 +526,12 @@ static int xics_host_map_lpar(struct irqpr_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 ; }
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
-3obj-$(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
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.oThese two lines don't need the msi.o and msi-altix.o AFAICS.
s/altix/apic/. Duh.
Segher
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.oThese 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.oI think this file should live in
arch/powerpc, and so should thisMakefilefragment.
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.cMaybe
msi-papr.cis 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -526,11 +526,12 @@ static int xics_host_map_lpar(struct irqpr_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 ; }
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 thisMakefilefragment.I'm following the current MSI methodologies where arch specific MSI code lives in
drivers/pci. This is just likemsi-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.cMaybe
msi-papr.cis 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
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.
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.oDoesn'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.
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, asirq_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" , ®len); +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
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_numto 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 howseq_numbeing static is going to work, a different cpu could stomp on theseq_numvalue 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_callfor 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" , ®len); +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.
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -526,11 +526,12 @@ static int xics_host_map_lpar(struct irqpr_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 ; }
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
Quoted 3 lines
I'm not sure what disable really needs to do, but I think drivers might expect it to set
dev->irqback to the LSI value, even if we don't free anything internally. Not sure.
Yes, that's required by the MSI API.
Segher
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
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 AFAICTirq_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 controllerBut 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.
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 AFAICTirq_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
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.
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.
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
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
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
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
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
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
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 thenpci_enable_multi_msi(dev, num_irqs)which would give the drivernum_irqsMSI 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.
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 thenpci_enable_multi_msi(dev, num_irqs)which would give the drivernum_irqsMSI 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
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.
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.