powerpc/powernv: Add XICS emulation APIs
PATCH 1/14 powerpc/powernv: Add XICS emulation APIs
OPAL provides an emulated XICS interrupt controller to use as a fallback on newer processors that don't have a XICS. It's meant as a way to provide backward compatibility with future processors. Add the corresponding interfaces.
--- arch/powerpc/include/asm/opal-api.h | 6 +++++- arch/powerpc/include/asm/opal.h | 5 +++++ arch/powerpc/platforms/powernv/opal-wrappers.S | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-)
arch/powerpc/include/asm/opal-api.h +5 -1
@@ -162,7 +162,11 @@#define OPAL_PCI_GET_PRESENCE_STATE 119#define OPAL_PCI_GET_POWER_STATE 120#define OPAL_PCI_SET_POWER_STATE 121 -#define OPAL_LAST 121 +#define OPAL_INT_GET_XIRR 122 +#define OPAL_INT_SET_CPPR 123 +#define OPAL_INT_EOI 124 +#define OPAL_INT_SET_MFRR 125 +#define OPAL_LAST 125/* Device tree flags */
arch/powerpc/include/asm/opal.h +5 -0
@@ -218,6 +218,11 @@ int64_t opal_pci_set_power_state(uint64_t async_token, uint64_t id, uint64_t data);int64_t opal_pci_poll2 (uint64_t id,uint64_t data); +int64_t opal_int_get_xirr (uint32_t *out_xirr,bool just_poll); +int64_t opal_int_set_cppr (uint8_t cppr); +int64_t opal_int_eoi (uint32_t xirr); +int64_t opal_int_set_mfrr (uint32_t cpu,uint8_t mfrr); +/* Internal functions */ extern int early_init_dt_scan_opal (unsigned long node,const char *uname,int depth,void *data);
arch/powerpc/platforms/powernv/opal-wrappers.S +4 -0
@@ -307,3 +307,7 @@ OPAL_CALL(opal_get_device_tree, OPAL_GET_DEVICE_TREE); OPAL_CALL(opal_pci_get_presence_state, OPAL_PCI_GET_PRESENCE_STATE); OPAL_CALL(opal_pci_get_power_state, OPAL_PCI_GET_POWER_STATE); OPAL_CALL(opal_pci_set_power_state, OPAL_PCI_SET_POWER_STATE); +OPAL_CALL(opal_int_get_xirr, OPAL_INT_GET_XIRR); +OPAL_CALL(opal_int_set_cppr, OPAL_INT_SET_CPPR); +OPAL_CALL(opal_int_eoi, OPAL_INT_EOI); +OPAL_CALL(opal_int_set_mfrr, OPAL_INT_SET_MFRR);
Signature · 1 line
2.7.4
PATCH 2/14 powerpc/irq: Add support for HV virtualization interrupts
This will be delivering external interrupts from the XIVE to the Hypervisor. We treat it as a normal external interrupt for the lazy irq disable code (so it will be replayed as a 0x500) and route it to do_IRQ.
--- arch/powerpc/include/asm/exception-64s.h | 2 ++ arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/kernel/cpu_setup_power.S | 2 ++ arch/powerpc/kernel/exceptions-64s.S | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+)
arch/powerpc/include/asm/exception-64s.h +2 -0
@@ -403,6 +403,8 @@ label##_relon_hv: \#define SOFTEN_VALUE_0xe82 PACA_IRQ_DBELL#define SOFTEN_VALUE_0xe60 PACA_IRQ_HMI#define SOFTEN_VALUE_0xe62 PACA_IRQ_HMI +#define SOFTEN_VALUE_0xea0 PACA_IRQ_EE +#define SOFTEN_VALUE_0xea2 PACA_IRQ_EE#define __SOFTEN_TEST (h, vec) \ lbz r10,PACASOFTIRQEN(r13); \
arch/powerpc/include/asm/reg.h +1 -0
@@ -352,6 +352,7 @@#define LPCR_LPES1 0x00000004/* LPAR Env selector 1 */ #define LPCR_LPES_SH 2#define LPCR_RMI 0x00000002/* real mode is cache inhibit */ +#define LPCR_HVICE 0x00000002/* P9: HV interrupt enable */ #define LPCR_HDICE 0x00000001/* Hyp Decr enable (HV,PR,EE) */ #define LPCR_UPRT 0x00400000/* Use Process Table (ISA 3) */ #ifndef SPRN_LPID
arch/powerpc/kernel/cpu_setup_power.S +2 -0
@@ -99,6 +99,7 @@ _GLOBAL(__setup_cpu_power9) mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH + ori r3, r3, LPCR_HVICE bl __init_LPCR bl __init_HFSCR bl __init_tlb_power9
@@ -118,6 +119,7 @@ _GLOBAL(__restore_cpu_power9) mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH + ori r3, r3, LPCR_HVICE bl __init_LPCR bl __init_HFSCR bl __init_tlb_power9
arch/powerpc/kernel/exceptions-64s.S +19 -0
@@ -351,6 +351,12 @@ hv_doorbell_trampoline: EXCEPTION_PROLOG_0(PACA_EXGEN) b h_doorbell_hv + . = 0xea0 +hv_virt_irq_trampoline: + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_0(PACA_EXGEN) + b h_virt_irq_hv + /* We need to deal with the Altivec unavailable exception * here which is at 0xf20, thus in the middle of the * prolog code of the PerformanceMonitor one. A little
@@ -601,6 +607,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell) KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82) + MASKABLE_EXCEPTION_HV_OOL(0xea2, h_virt_irq) + KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xea2) + /* moved from 0xf00 */ STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor) KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf00)
@@ -680,6 +689,8 @@ _GLOBAL(__replay_interrupt) BEGIN_FTR_SECTION cmpwi r3,0xe80 beq h_doorbell_common + cmpwi r3,0xea0 + beq h_virt_irq_common FTR_SECTION_ELSE cmpwi r3,0xa00 beq doorbell_super_common
@@ -754,6 +765,7 @@ kvmppc_skip_Hinterrupt: #else STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, unknown_exception) #endif + STD_EXCEPTION_COMMON_ASYNC(0xea0, h_virt_irq, do_IRQ) STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, instruction_breakpoint_exception) STD_EXCEPTION_COMMON(0x1502, denorm, unknown_exception)
@@ -877,6 +889,12 @@ h_doorbell_relon_trampoline: EXCEPTION_PROLOG_0(PACA_EXGEN) b h_doorbell_relon_hv + . = 0x4ea0 +h_virt_irq_relon_trampoline: + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_0(PACA_EXGEN) + b h_virt_irq_relon_hv + . = 0x4f00 performance_monitor_relon_pseries_trampoline: SET_SCRATCH0(r13)
@@ -1137,6 +1155,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) /* Equivalents to the above handlers for relocation-on interrupt vectors */ STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist) MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell) + MASKABLE_RELON_EXCEPTION_HV_OOL(0xea0, h_virt_irq) STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor) STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
Signature · 1 line
2.7.4
Michael Ellerman
reviewerRe: [PATCH 02/14] powerpc/irq: Add support for HV virtualization interrupts
Quoted 5 lines · Benjamin Herrenschmidt
This will be delivering external interrupts from the XIVE to the Hypervisor. We treat it as a normal external interrupt for the lazy irq disable code (so it will be replayed as a
0x500) and route it todo_IRQ.
Quoted 7 lines
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- arch/powerpc/include/asm/exception-64s.h | 2 ++ arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/kernel/cpu_setup_power.S | 2 ++ arch/powerpc/kernel/exceptions-64s.S | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+)
This is breaking allmodconfig with:
arch/powerpc/kernel/exceptions-64s.S:778: Error: attempt to move .org backwards arch/powerpc/kernel/exceptions-64s.S:779: Error: attempt to move .org backwards arch/powerpc/kernel/exceptions-64s.S:803: Error: attempt to move .org backwards arch/powerpc/kernel/exceptions-64s.S:804: Error: attempt to move .org backwards arch/powerpc/kernel/exceptions-64s.S:823: Error: attempt to move .org backwards arch/powerpc/kernel/exceptions-64s.S:833: Error: attempt to move .org backwards
http://kisskb.ozlabs.ibm.com/kisskb/buildresult/12746513/
cheers
Re: [PATCH 02/14] powerpc/irq: Add support for HV virtualization interrupts
Quoted 10 lines · Michael Ellerman
This is breaking allmodconfig with:
arch/powerpc/kernel/exceptions-64s.S:778: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:779: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:803: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:804: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:823: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:833: Error: attempt to move .org backwards
Yuck. Is that even fixable without completely shuffling all the IRQ stuff ? We really need to find a way to sort that shit once and for all...
Cheers,
Ben.
Re: [PATCH 02/14] powerpc/irq: Add support for HV virtualization interrupts
Quoted 16 lines · Benjamin Herrenschmidt
On Sat, 2016-07-16 at 20:40 +1000, Michael Ellerman wrote:s
Quoted 15 lines
This is breaking allmodconfig with:
arch/powerpc/kernel/exceptions-64s.S:778: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:779: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:803: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:804: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:823: Error: attempt to move .org backwardsarch/powerpc/kernel/exceptions-64s.S:833: Error: attempt to move .org backwards
Quoted 5 lines
Yuck. Is that even fixable without completely shuffling all the IRQ stuff ? We really need to find a way to sort that shit once and for all...
I reproduced... We need to move more of the "common" ones out of the way, without making the conditional branches lose it. Ugh....
Another quick and easy option: Get rid of Cell :-) There is 3 cell ones right there we could get rid of ;-)
... except that's not enough. Now the OOL handlers are bumping into the FWNMI page. Argh. Moved a couple more, seems to work,
I'm sending you a patch in the next few monites to test that needs to be added *before* the HV virtualization interrupts one. It works with the few variants of allmodconfigs I managed to try on the laptop (basically with and without RELOCATABLE).
Let me know how it goes in kisskb.
Cheers,
Ben.
PATCH 3/14 powerpc/irq: Add mechanism to force a replay of interrupts
In reply to Benjamin HerrenschmidtCalling this function with interrupts soft-disabled will cause a replay of the external interrupt vector when they are re-enabled.
This will be used by the OPAL XICS backend (and latter by the native XIVE code) to handle EOI signaling that there are more interrupts to fetch from the hardware since the hardware won't issue another HW interrupt in that case.
--- arch/powerpc/include/asm/hw_irq.h | 2 ++ arch/powerpc/kernel/irq.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+)
arch/powerpc/include/asm/hw_irq.h +2 -0
@@ -130,6 +130,8 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)extern bool prep_irq_for_idle (void ); +extern void force_external_irq_replay (void ); +#else /* CONFIG_PPC64 */ #define SET_MSR_EE (x) mtmsr(x)
arch/powerpc/kernel/irq.c +14 -0
@@ -342,6 +342,20 @@ bool prep_irq_for_idle(void) return true; } +/* Force a replay of the external interrupt handler on this +* CPU. +*/ +void force_external_irq_replay (void ) +{ +/* This must only be called with interrupts soft-disabled, +* the replay will happen when re-enabling +*/ +WARN_ON (!arch_irqs_disabled ()); + +/* Indicate in the PACA that we have an interrupt to replay */ + local_paca->irq_happened |=PACA_IRQ_EE ; +} +#endif /* CONFIG_PPC64 */ int arch_show_interrupts (struct seq_file *p,int prec)
Signature · 1 line
2.7.4
PATCH 4/14 powerpc/xics: Add ICP OPAL backend
In reply to Benjamin HerrenschmidtThis adds a new XICS backend that uses OPAL calls, which can be used when we don't have native support for the platform interrupt controller.
--- arch/powerpc/include/asm/xics.h | 8 +- arch/powerpc/sysdev/xics/Makefile | 2 +- arch/powerpc/sysdev/xics/icp-opal.c | 144 +++++++++++++++++++++++++++++++++ arch/powerpc/sysdev/xics/xics-common.c | 5 +- 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 arch/powerpc/sysdev/xics/icp-opal.c
arch/powerpc/include/asm/xics.h +7 -1
@@ -42,6 +42,12 @@ extern int icp_hv_init(void);static inline int icp_hv_init (void ) {return -ENODEV ; }#endif +#ifdef CONFIG_PPC_POWERNV +extern int icp_opal_init (void ); +#else +static inline int icp_opal_init (void ) {return -ENODEV ; } +#endif +/* ICP ops */ struct icp_ops {unsigned int (*get_irq)(void );
@@ -135,7 +141,7 @@ static inline void xics_set_base_cppr(unsigned char cppr)static inline unsigned char xics_cppr_top (void ) {struct xics_cppr *os_cppr =this_cpu_ptr (&xics_cppr); - +return os_cppr->stack[os_cppr->index]; }
arch/powerpc/sysdev/xics/Makefile +1 -1
@@ -4,4 +4,4 @@ obj-y += xics-common.o obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o -obj-$(CONFIG_PPC_POWERNV) += ics-opal.o +obj-$(CONFIG_PPC_POWERNV) += ics-opal.o icp-opal.o
arch/powerpc/sysdev/xics/icp-opal.c new file +144 -0
144 lines not on this page · raw message
arch/powerpc/sysdev/xics/xics-common.c +4 -1
@@ -404,8 +404,11 @@ void __init xics_init(void)/* Fist locate ICP */ if (firmware_has_feature (FW_FEATURE_LPAR )) rc =icp_hv_init (); -if (rc <0 ) +if (rc <0 ) { rc =icp_native_init (); +if (rc == -ENODEV ) + rc =icp_opal_init (); + }if (rc <0 ) {pr_warning ("XICS: Cannot find a Presentation Controller !\n" );return ;
Signature · 1 line
2.7.4
PATCH 5/14 powerpc/powernv: Discover IODA3 PHBs
In reply to Benjamin HerrenschmidtWe instanciate them as IODA2. We also change the MSI EOI hack to only kick on PHB3 since it will not be needed on any new implementation.
--- arch/powerpc/platforms/powernv/pci-ioda.c | 3 ++- arch/powerpc/platforms/powernv/pci.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-)
arch/powerpc/platforms/powernv/pci-ioda.c +2 -1
@@ -2711,7 +2711,8 @@ static void set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq)struct irq_data *idata;struct irq_chip *ichip; -if (phb->type !=PNV_PHB_IODA2 ) +/* The MSI EOI OPAL call is only needed on PHB3 */ +if (phb->model !=PNV_PHB_MODEL_PHB3 )return ;if (!phb->ioda.irq_chip_init) {
arch/powerpc/platforms/powernv/pci.c +4 -0
@@ -932,6 +932,10 @@ void __init pnv_pci_init(void)for_each_compatible_node (np,NULL ,"ibm,ioda2-phb" )pnv_pci_init_ioda2_phb (np); +/* Look for ioda3 built-in PHB4's, we treat them as IODA2 */ +for_each_compatible_node (np,NULL ,"ibm,ioda3-phb" ) +pnv_pci_init_ioda2_phb (np); +/* Look for NPU PHBs */ for_each_compatible_node (np,NULL ,"ibm,ioda2-npu-phb" )pnv_pci_init_npu_phb (np);
Signature · 1 line
2.7.4
PATCH 6/14 powerpc/pseries/pci: Remove obsolete SW invalidate
In reply to Benjamin HerrenschmidtThat was used by some old IBM internal bringup tools and is no longer relevant.
--- arch/powerpc/platforms/pseries/iommu.c | 53 +--------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-)
arch/powerpc/platforms/pseries/iommu.c +1 -52
@@ -120,35 +120,6 @@ static void iommu_pseries_free_group(struct iommu_table_group *table_group,kfree (table_group); } -static void tce_invalidate_pSeries_sw (struct iommu_table *tbl, -__be64 *startp,__be64 *endp) -{ -u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; -unsigned long start, end, inc; - - start =__pa (startp); - end =__pa (endp); - inc =L1_CACHE_BYTES ;/* invalidate a cacheline of TCEs at a time */ - -/* If this is non-zero, change the format. We shift the -* address and or in the magic from the device tree. */ -if (tbl->it_busno) { - start <<=12 ; - end <<=12 ; - inc <<=12 ; - start |= tbl->it_busno; - end |= tbl->it_busno; - } - - end |= inc -1 ;/* round up end to be different than start */ - -mb ();/* Make sure TCEs in memory are written */ -while (start <= end) { -out_be64 (invalidate, start); - start += inc; - } -} - static int tce_build_pSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, enum dma_data_direction direction,
@@ -173,9 +144,6 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, uaddr +=TCE_PAGE_SIZE ; tcep++; } - -if (tbl->it_type &TCE_PCI_SWINV_CREATE ) -tce_invalidate_pSeries_sw (tbl, tces, tcep -1 );return 0 ; }
@@ -188,9 +156,6 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)while (npages--) *(tcep++) =0 ; - -if (tbl->it_type &TCE_PCI_SWINV_FREE ) -tce_invalidate_pSeries_sw (tbl, tces, tcep -1 ); }static unsigned long tce_get_pseries (struct iommu_table *tbl,long index)
@@ -537,7 +502,7 @@ static void iommu_table_setparms(struct pci_controller *phb, struct iommu_table *tbl) {struct device_node *node; -const unsigned long *basep, *sw_inval; +const unsigned long *basep;const u32 *sizep; node = phb->dn;
@@ -575,22 +540,6 @@ static void iommu_table_setparms(struct pci_controller *phb, tbl->it_index =0 ; tbl->it_blocksize =16 ; tbl->it_type =TCE_PCI ; - - sw_inval =of_get_property (node,"linux,tce-sw-invalidate-info" ,NULL ); -if (sw_inval) { -/* -* This property contains information on how to -* invalidate the TCE entry. The first property is -* the base MMIO address used to invalidate entries. -* The second property tells us the format of the TCE -* invalidate (whether it needs to be shifted) and -* some magic routing info to add to our invalidate -* command. -*/ - tbl->it_index = (unsigned long )ioremap (sw_inval[0 ],8 ); - tbl->it_busno = sw_inval[1 ];/* overload this with magic */ - tbl->it_type =TCE_PCI_SWINV_CREATE |TCE_PCI_SWINV_FREE ; - } }/*
Signature · 1 line
2.7.4
PATCH 7/14 powerpc/opal: Add real mode call wrappers
In reply to Benjamin HerrenschmidtReplace the old generic opal_call_realmode() with proper per-call wrappers similar to the normal ones and convert callers.
--- arch/powerpc/include/asm/opal-api.h | 10 +++- arch/powerpc/include/asm/opal.h | 6 +++ arch/powerpc/kernel/idle_power7.S | 16 ++----- arch/powerpc/platforms/powernv/opal-wrappers.S | 63 +++++++++++++------------- 4 files changed, 51 insertions(+), 44 deletions(-)
arch/powerpc/include/asm/opal-api.h +9 -1
@@ -166,7 +166,8 @@#define OPAL_INT_SET_CPPR 123#define OPAL_INT_EOI 124#define OPAL_INT_SET_MFRR 125 -#define OPAL_LAST 125 +#define OPAL_PCI_TCE_KILL 126 +#define OPAL_LAST 126/* Device tree flags */
@@ -912,6 +913,13 @@ enum { OPAL_REBOOT_PLATFORM_ERROR = 1, }; +/* Argument to OPAL_PCI_TCE_KILL */ +enum { +OPAL_PCI_TCE_KILL_PAGES , +OPAL_PCI_TCE_KILL_PE , +OPAL_PCI_TCE_KILL_ALL , +}; +#endif /* __ASSEMBLY__ */ #endif /* __OPAL_API_H */
arch/powerpc/include/asm/opal.h +6 -0
@@ -222,6 +222,12 @@ int64_t opal_int_get_xirr(uint32_t *out_xirr, bool just_poll);int64_t opal_int_set_cppr (uint8_t cppr);int64_t opal_int_eoi (uint32_t xirr);int64_t opal_int_set_mfrr (uint32_t cpu,uint8_t mfrr); +int64_t opal_pci_tce_kill (uint64_t phb_id,uint32_t kill_type, +uint32_t pe_num,uint32_t tce_size, +uint64_t dma_addr,uint32_t npages); +int64_t opal_rm_pci_tce_kill (uint64_t phb_id,uint32_t kill_type, +uint32_t pe_num,uint32_t tce_size, +uint64_t dma_addr,uint32_t npages);/* Internal functions */ extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
arch/powerpc/kernel/idle_power7.S +5 -11
@@ -196,8 +196,7 @@ fastsleep_workaround_at_entry: /* Fast sleep workaround */ li r3,1 li r4,1 - li r0,OPAL_CONFIG_CPU_IDLE_STATE - bl opal_call_realmode + bl opal_rm_config_cpu_idle_state /* Clear Lock bit */ li r0,0
@@ -270,8 +269,7 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); \ ld r2,PACATOC(r13); \ ld r1,PACAR1(r13); \ std r3,ORIG_GPR3(r1); /* Save original r3 */ \ - li r0,OPAL_HANDLE_HMI; /* Pass opal token argument*/ \ - bl opal_call_realmode; \ + bl opal_rm_handle_hmi; \ ld r3,ORIG_GPR3(r1); /* Restore original r3 */ \ 20: nop;
@@ -284,7 +282,7 @@ _GLOBAL(power7_wakeup_tb_loss) * and they are restored before switching to the process context. Hence * until they are restored, they are free to be used. * - * Save SRR1 in a NVGPR as it might be clobbered in opal_call_realmode + * Save SRR1 in a NVGPR as it might be clobbered in opal call * (called in CHECK_HMI_INTERRUPT). SRR1 is required to determine the * wakeup reason if we branch to kvm_start_guest. */
@@ -378,10 +376,7 @@ timebase_resync: * set in exceptions-64s.S */ ble cr3,clear_lock /* Time base re-sync */ - li r0,OPAL_RESYNC_TIMEBASE - bl opal_call_realmode; - /* TODO: Check r3 for failure */ - + bl opal_rm_resync_timebase; /* * If waking up from sleep, per core state is not lost, skip to * clear_lock.
@@ -469,8 +464,7 @@ hypervisor_state_restored: fastsleep_workaround_at_exit: li r3,1 li r4,0 - li r0,OPAL_CONFIG_CPU_IDLE_STATE - bl opal_call_realmode + bl opal_rm_config_cpu_idle_state b timebase_resync /*
arch/powerpc/platforms/powernv/opal-wrappers.S +31 -32
104 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH 8/14 powerpc/powernv/pci: Rename TCE invalidation calls
In reply to Benjamin HerrenschmidtThe TCE invalidation functions are fairly implementation specific, and while the IODA specs more/less describe the register, in practice various implementation workarounds may be required. So name the functions after the target PHB.
Note today and for the foreseeable future, there's a 1:1 relationship between an IODA version and a PHB implementation. There exist another variant of IODA1 (Torrent) but we never supported in with OPAL and never will.
--- arch/powerpc/platforms/powernv/npu-dma.c | 8 +++---- arch/powerpc/platforms/powernv/pci-ioda.c | 36 +++++++++++++++---------------- arch/powerpc/platforms/powernv/pci.h | 4 +--- 3 files changed, 23 insertions(+), 25 deletions(-)
arch/powerpc/platforms/powernv/npu-dma.c +4 -4
@@ -180,7 +180,7 @@ long pnv_npu_set_window(struct pnv_ioda_pe *npe, int num,pe_err (npe,"Failed to configure TCE table, err %lld\n" , rc);return rc; } -pnv_pci_ioda2_tce_invalidate_entire (phb, false); +pnv_pci_phb3_tce_invalidate_entire (phb, false);/* Add the table to the list so its TCE cache will get invalidated */ pnv_pci_link_table_and_group(phb->hose->node, num,
@@ -204,7 +204,7 @@ long pnv_npu_unset_window(struct pnv_ioda_pe *npe, int num)pe_err (npe,"Unmapping failed, ret = %lld\n" , rc);return rc; } -pnv_pci_ioda2_tce_invalidate_entire (phb, false); +pnv_pci_phb3_tce_invalidate_entire (phb, false);pnv_pci_unlink_table_and_group (npe->table_group.tables[num], &npe->table_group);
@@ -270,7 +270,7 @@ static int pnv_npu_dma_set_bypass(struct pnv_ioda_pe *npe) 0 /* bypass base */, top);if (rc ==OPAL_SUCCESS ) -pnv_pci_ioda2_tce_invalidate_entire (phb, false); +pnv_pci_phb3_tce_invalidate_entire (phb, false);return rc; }
@@ -334,7 +334,7 @@ void pnv_npu_take_ownership(struct pnv_ioda_pe *npe)pe_err (npe,"Failed to disable bypass, err %lld\n" , rc);return ; } -pnv_pci_ioda2_tce_invalidate_entire (npe->phb, false); +pnv_pci_phb3_tce_invalidate_entire (npe->phb, false); }struct pnv_ioda_pe *pnv_pci_npu_setup_iommu (struct pnv_ioda_pe *npe)
arch/powerpc/platforms/powernv/pci-ioda.c +18 -18
@@ -1727,7 +1727,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, } } -static void pnv_pci_ioda1_tce_invalidate (struct iommu_table *tbl, +static void pnv_pci_p7ioc_tce_invalidate (struct iommu_table *tbl,unsigned long index,unsigned long npages,bool rm) { struct iommu_table_group_link *tgl = list_first_entry_or_null(
@@ -1788,7 +1788,7 @@ static int pnv_ioda1_tce_build(struct iommu_table *tbl, long index, attrs);if (!ret && (tbl->it_type &TCE_PCI_SWINV_CREATE )) -pnv_pci_ioda1_tce_invalidate (tbl, index, npages, false); +pnv_pci_p7ioc_tce_invalidate (tbl, index, npages, false);return ret; }
@@ -1801,7 +1801,7 @@ static int pnv_ioda1_tce_xchg(struct iommu_table *tbl, long index,if (!ret && (tbl->it_type & (TCE_PCI_SWINV_CREATE |TCE_PCI_SWINV_FREE ))) -pnv_pci_ioda1_tce_invalidate (tbl, index,1 , false); +pnv_pci_p7ioc_tce_invalidate (tbl, index,1 , false);return ret; }
@@ -1813,7 +1813,7 @@ static void pnv_ioda1_tce_free(struct iommu_table *tbl, long index,pnv_tce_free (tbl, index, npages);if (tbl->it_type &TCE_PCI_SWINV_FREE ) -pnv_pci_ioda1_tce_invalidate (tbl, index, npages, false); +pnv_pci_p7ioc_tce_invalidate (tbl, index, npages, false); }static struct iommu_table_ops pnv_ioda1_iommu_ops = {
@@ -1825,13 +1825,13 @@ static struct iommu_table_ops pnv_ioda1_iommu_ops = { .get = pnv_tce_get, }; -#define TCE_KILL_INVAL_ALL PPC_BIT(0) -#define TCE_KILL_INVAL_PE PPC_BIT(1) -#define TCE_KILL_INVAL_TCE PPC_BIT(2) +#define PHB3_TCE_KILL_INVAL_ALL PPC_BIT(0) +#define PHB3_TCE_KILL_INVAL_PE PPC_BIT(1) +#define PHB3_TCE_KILL_INVAL_ONE PPC_BIT(2) -void pnv_pci_ioda2_tce_invalidate_entire (struct pnv_phb *phb,bool rm) +void pnv_pci_phb3_tce_invalidate_entire (struct pnv_phb *phb,bool rm) { -const unsigned long val =TCE_KILL_INVAL_ALL ; +const unsigned long val =PHB3_TCE_KILL_INVAL_ALL ;mb ();/* Ensure previous TCE table stores are visible */ if (rm)
@@ -1842,10 +1842,10 @@ void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_phb *phb, bool rm)__raw_writeq (cpu_to_be64 (val), phb->ioda.tce_inval_reg); } -static inline void pnv_pci_ioda2_tce_invalidate_pe (struct pnv_ioda_pe *pe) +static inline void pnv_pci_phb3_tce_invalidate_pe (struct pnv_ioda_pe *pe) {/* 01xb - invalidate TCEs that match the specified PE# */ -unsigned long val =TCE_KILL_INVAL_PE | (pe->pe_number &0xFF ); +unsigned long val =PHB3_TCE_KILL_INVAL_PE | (pe->pe_number &0xFF );struct pnv_phb *phb = pe->phb;if (!phb->ioda.tce_inval_reg)
@@ -1855,14 +1855,14 @@ static inline void pnv_pci_ioda2_tce_invalidate_pe(struct pnv_ioda_pe *pe)__raw_writeq (cpu_to_be64 (val), phb->ioda.tce_inval_reg); } -static void pnv_pci_ioda2_do_tce_invalidate (unsigned pe_number,bool rm, +static void pnv_pci_phb3_tce_invalidate (unsigned pe_number,bool rm,__be64 __iomem *invalidate,unsigned shift,unsigned long index,unsigned long npages) {unsigned long start, end, inc;/* We'll invalidate DMA address in PE scope */ - start =TCE_KILL_INVAL_TCE ; + start =PHB3_TCE_KILL_INVAL_ONE ; start |= (pe_number &0xFF ); end = start;
@@ -1899,10 +1899,10 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,* per TCE entry so we have to invalidate * the entire cache for it. */ -pnv_pci_ioda2_tce_invalidate_entire (pe->phb, rm); +pnv_pci_phb3_tce_invalidate_entire (pe->phb, rm);continue ; } -pnv_pci_ioda2_do_tce_invalidate (pe->pe_number, rm, +pnv_pci_phb3_tce_invalidate (pe->pe_number, rm, invalidate, tbl->it_page_shift, index, npages); }
@@ -2178,7 +2178,7 @@ static long pnv_pci_ioda2_set_window(struct iommu_table_group *table_group,pnv_pci_link_table_and_group (phb->hose->node, num, tbl, &pe->table_group); -pnv_pci_ioda2_tce_invalidate_pe (pe); +pnv_pci_phb3_tce_invalidate_pe (pe);return 0 ; }
@@ -2322,7 +2322,7 @@ static long pnv_pci_ioda2_unset_window(struct iommu_table_group *table_group,if (ret)pe_warn (pe,"Unmapping failed, ret = %ld\n" , ret);else -pnv_pci_ioda2_tce_invalidate_pe (pe); +pnv_pci_phb3_tce_invalidate_pe (pe);pnv_pci_unlink_table_and_group (table_group->tables[num], table_group);
@@ -3447,7 +3447,7 @@ static void pnv_pci_ioda1_release_pe_dma(struct pnv_ioda_pe *pe)if (rc !=OPAL_SUCCESS )return ; -pnv_pci_ioda1_tce_invalidate (tbl, tbl->it_offset, tbl->it_size, false); +pnv_pci_p7ioc_tce_invalidate (tbl, tbl->it_offset, tbl->it_size, false);if (pe->table_group.group) {iommu_group_put (pe->table_group.group);WARN_ON (pe->table_group.group);
arch/powerpc/platforms/powernv/pci.h +1 -3
@@ -203,8 +203,6 @@ extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,extern void pnv_pci_init_ioda_hub (struct device_node *np);extern void pnv_pci_init_ioda2_phb (struct device_node *np);extern void pnv_pci_init_npu_phb (struct device_node *np); -extern void pnv_pci_ioda_tce_invalidate (struct iommu_table *tbl, -__be64 *startp,__be64 *endp,bool rm);extern void pnv_pci_reset_secondary_bus (struct pci_dev *dev);extern int pnv_eeh_phb_reset (struct pci_controller *hose,int option);
@@ -224,7 +222,7 @@ extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,/* Nvlink functions */ extern void pnv_npu_try_dma_set_bypass (struct pci_dev *gpdev,bool bypass); -extern void pnv_pci_ioda2_tce_invalidate_entire (struct pnv_phb *phb,bool rm); +extern void pnv_pci_phb3_tce_invalidate_entire (struct pnv_phb *phb,bool rm);extern struct pnv_ioda_pe *pnv_pci_npu_setup_iommu (struct pnv_ioda_pe *npe);extern long pnv_npu_set_window (struct pnv_ioda_pe *npe,int num,struct iommu_table *tbl);
Signature · 1 line
2.7.4
PATCH 9/14 powerpc/powernv/pci: Remove SWINV constants and obsolete TCE code
In reply to Benjamin HerrenschmidtWe have some obsolete code in pnv_pci_p7ioc_tce_invalidate() to handle some internal lab tools that have stopped being useful a long time ago. Remove that along with the definition and test for the TCE_PCI_SWINV_* flags whose value is basically always the same.
--- arch/powerpc/include/asm/tce.h | 3 -- arch/powerpc/platforms/powernv/pci-ioda.c | 50 +++++++------------------------ 2 files changed, 10 insertions(+), 43 deletions(-)
arch/powerpc/include/asm/tce.h +0 -3
@@ -31,9 +31,6 @@*/ #define TCE_VB 0#define TCE_PCI 1 -#define TCE_PCI_SWINV_CREATE 2 -#define TCE_PCI_SWINV_FREE 4 -#define TCE_PCI_SWINV_PAIR 8/* TCE page size is 4096 bytes (1 << 12) */
arch/powerpc/platforms/powernv/pci-ioda.c +10 -40
115 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH 10/14 powerpc/powernv/pci: Rework accessing the TCE invalidate register
In reply to Benjamin HerrenschmidtIt's architected, always in a known place, so there is no need to keep a separate pointer to it, we use the existing "regs", and we complement it with a real mode variant.
# Conflicts:
# arch/powerpc/platforms/powernv/pci-ioda.c
# arch/powerpc/platforms/powernv/pci.h
--- arch/powerpc/platforms/powernv/pci-ioda.c | 69 ++++++++++++------------------- arch/powerpc/platforms/powernv/pci.h | 7 +--- 2 files changed, 28 insertions(+), 48 deletions(-)
arch/powerpc/platforms/powernv/pci-ioda.c +27 -42
@@ -1727,6 +1727,13 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, } } +static inline __be64 __iomem *pnv_ioda_get_inval_reg (struct pnv_phb *phb, +bool real_mode) +{ +return real_mode ? (__be64 __iomem *)(phb->regs_phys +0x210 ) : + (phb->regs +0x210 ); +} +static void pnv_pci_p7ioc_tce_invalidate (struct iommu_table *tbl,unsigned long index,unsigned long npages,bool rm) {
@@ -1735,9 +1742,7 @@ static void pnv_pci_p7ioc_tce_invalidate(struct iommu_table *tbl, next);struct pnv_ioda_pe *pe =container_of (tgl->table_group, struct pnv_ioda_pe, table_group); -__be64 __iomem *invalidate = rm ? - (__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys : - pe->phb->ioda.tce_inval_reg; +__be64 __iomem *invalidate =pnv_ioda_get_inval_reg (pe->phb, rm);unsigned long start, end, inc; start =__pa (((__be64 *)tbl->it_base) + index - tbl->it_offset);
@@ -1815,39 +1820,36 @@ static struct iommu_table_ops pnv_ioda1_iommu_ops = {void pnv_pci_phb3_tce_invalidate_entire (struct pnv_phb *phb,bool rm) { +__be64 __iomem *invalidate =pnv_ioda_get_inval_reg (phb, rm);const unsigned long val =PHB3_TCE_KILL_INVAL_ALL ;mb ();/* Ensure previous TCE table stores are visible */ if (rm) -__raw_rm_writeq (cpu_to_be64 (val), - (__be64 __iomem *) - phb->ioda.tce_inval_reg_phys); +__raw_rm_writeq (cpu_to_be64 (val), invalidate);else -__raw_writeq (cpu_to_be64 (val), phb->ioda.tce_inval_reg); +__raw_writeq (cpu_to_be64 (val), invalidate); }static inline void pnv_pci_phb3_tce_invalidate_pe (struct pnv_ioda_pe *pe) {/* 01xb - invalidate TCEs that match the specified PE# */ +__be64 __iomem *invalidate =pnv_ioda_get_inval_reg (pe->phb, false);unsigned long val =PHB3_TCE_KILL_INVAL_PE | (pe->pe_number &0xFF ); -struct pnv_phb *phb = pe->phb; - -if (!phb->ioda.tce_inval_reg) -return ;mb ();/* Ensure above stores are visible */ -__raw_writeq (cpu_to_be64 (val), phb->ioda.tce_inval_reg); +__raw_writeq (cpu_to_be64 (val), invalidate); } -static void pnv_pci_phb3_tce_invalidate (unsigned pe_number,bool rm, -__be64 __iomem *invalidate,unsigned shift, -unsigned long index,unsigned long npages) +static void pnv_pci_phb3_tce_invalidate (struct pnv_ioda_pe *pe,bool rm, +unsigned shift,unsigned long index, +unsigned long npages) { +__be64 __iomem *invalidate =pnv_ioda_get_inval_reg (pe->phb, false);unsigned long start, end, inc;/* We'll invalidate DMA address in PE scope */ start =PHB3_TCE_KILL_INVAL_ONE ; - start |= (pe_number &0xFF ); + start |= (pe->pe_number &0xFF ); end = start;/* Figure out the start, end and step */
@@ -1873,10 +1875,6 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,list_for_each_entry_rcu (tgl, &tbl->it_group_list, next) {struct pnv_ioda_pe *pe =container_of (tgl->table_group, struct pnv_ioda_pe, table_group); -__be64 __iomem *invalidate = rm ? - (__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys : - pe->phb->ioda.tce_inval_reg; -if (pe->phb->type ==PNV_PHB_NPU ) {/* * The NVLink hardware does not support TCE kill
@@ -1886,9 +1884,8 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,pnv_pci_phb3_tce_invalidate_entire (pe->phb, rm);continue ; } -pnv_pci_phb3_tce_invalidate (pe->pe_number, rm, - invalidate, tbl->it_page_shift, - index, npages); +pnv_pci_phb3_tce_invalidate (pe, rm, tbl->it_page_shift, + index, npages); } }
@@ -2473,19 +2470,6 @@ static void pnv_pci_ioda_setup_iommu_api(void)static void pnv_pci_ioda_setup_iommu_api (void ) { };#endif -static void pnv_pci_ioda_setup_opal_tce_kill (struct pnv_phb *phb) -{ -const __be64 *swinvp; - -/* OPAL variant of PHB3 invalidated TCEs */ - swinvp =of_get_property (phb->hose->dn,"ibm,opal-tce-kill" ,NULL ); -if (!swinvp) -return ; - - phb->ioda.tce_inval_reg_phys =be64_to_cpup (swinvp); - phb->ioda.tce_inval_reg =ioremap (phb->ioda.tce_inval_reg_phys,8 ); -} -static __be64 *pnv_pci_ioda2_table_do_alloc_pages (int nid,unsigned shift,unsigned levels,unsigned long limit,unsigned long *current_offset,unsigned long *total_allocated)
@@ -3600,6 +3584,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,struct pnv_phb *phb;unsigned long size, m64map_off, m32map_off, pemap_off;unsigned long iomap_off =0 , dma32map_off =0 ; +struct resource r;const __be64 *prop64;const __be32 *prop32;int len;
@@ -3660,12 +3645,12 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,pci_process_bridge_OF_ranges (hose, np, !hose->global_number);/* Get registers */ - phb->regs =of_iomap (np,0 ); -if (phb->regs ==NULL ) -pr_err (" Failed to map registers !\n" ); - -/* Initialize TCE kill register */ -pnv_pci_ioda_setup_opal_tce_kill (phb); +if (!of_address_to_resource (np,0 , &r)) { + phb->regs_phys = r.start; + phb->regs =ioremap (r.start,resource_size (&r)); +if (phb->regs ==NULL ) +pr_err (" Failed to map registers !\n" ); + }/* Initialize more IODA stuff */ phb->ioda.total_pe_num =1 ;
arch/powerpc/platforms/powernv/pci.h +1 -6
@@ -81,6 +81,7 @@ struct pnv_phb {u64 opal_id;int flags;void __iomem *regs; +u64 regs_phys;int initialized;spinlock_t lock;
@@ -157,12 +158,6 @@ struct pnv_phb {/* Reverse map of PEs, indexed by {bus, devfn} */ unsigned int pe_rmap[0x10000 ]; - -/* TCE cache invalidate registers (physical and -* remapped) -*/ -phys_addr_t tce_inval_reg_phys; -__be64 __iomem *tce_inval_reg; } ioda;/* PHB and hub status structure */
Signature · 1 line
2.7.4
PATCH 11/14 powerpc/powernv/pci: Fallback to OPAL for TCE invalidations
In reply to Benjamin HerrenschmidtIf we don't find registers for the PHB or don't know the model specific invalidation method, use OPAL calls instead.
--- arch/powerpc/platforms/powernv/pci-ioda.c | 33 +++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
arch/powerpc/platforms/powernv/pci-ioda.c +29 -4
@@ -1867,6 +1867,17 @@ static void pnv_pci_phb3_tce_invalidate(struct pnv_ioda_pe *pe, bool rm, } } +static inline void pnv_pci_ioda2_tce_invalidate_pe (struct pnv_ioda_pe *pe) +{ +struct pnv_phb *phb = pe->phb; + +if (phb->model ==PNV_PHB_MODEL_PHB3 && phb->regs) +pnv_pci_phb3_tce_invalidate_pe (pe); +else +opal_pci_tce_kill (phb->opal_id,OPAL_PCI_TCE_KILL_PE , + pe->pe_number,0 ,0 ,0 ); +} +static void pnv_pci_ioda2_tce_invalidate (struct iommu_table *tbl,unsigned long index,unsigned long npages,bool rm) {
@@ -1875,17 +1886,31 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,list_for_each_entry_rcu (tgl, &tbl->it_group_list, next) {struct pnv_ioda_pe *pe =container_of (tgl->table_group, struct pnv_ioda_pe, table_group); -if (pe->phb->type ==PNV_PHB_NPU ) { +struct pnv_phb *phb = pe->phb; +unsigned int shift = tbl->it_page_shift; + +if (phb->type ==PNV_PHB_NPU ) {/* * The NVLink hardware does not support TCE kill * per TCE entry so we have to invalidate * the entire cache for it. */ -pnv_pci_phb3_tce_invalidate_entire (pe->phb, rm); +pnv_pci_phb3_tce_invalidate_entire (phb, rm);continue ; } -pnv_pci_phb3_tce_invalidate (pe, rm, tbl->it_page_shift, - index, npages); +if (phb->model ==PNV_PHB_MODEL_PHB3 && phb->regs) +pnv_pci_phb3_tce_invalidate (pe, rm, shift, + index, npages); +else if (rm) +opal_rm_pci_tce_kill (phb->opal_id, +OPAL_PCI_TCE_KILL_PAGES , + pe->pe_number,1u << shift, + index << shift, npages); +else +opal_pci_tce_kill (phb->opal_id, +OPAL_PCI_TCE_KILL_PAGES , + pe->pe_number,1u << shift, + index << shift, npages); } }
Signature · 1 line
2.7.4
PATCH v2 11/14 powerpc/powernv/pci: Fallback to OPAL for TCE invalidations
If we don't find registers for the PHB or don't know the model specific invalidation method, use OPAL calls instead.
---
v2. Missed some new invalidation calls that went upstream since I
wrote the original patch.
arch/powerpc/platforms/powernv/pci-ioda.c | 37 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-)
arch/powerpc/platforms/powernv/pci-ioda.c +31 -6
@@ -1867,6 +1867,17 @@ static void pnv_pci_phb3_tce_invalidate(struct pnv_ioda_pe *pe, bool rm, } } +static inline void pnv_pci_ioda2_tce_invalidate_pe (struct pnv_ioda_pe *pe) +{ +struct pnv_phb *phb = pe->phb; + +if (phb->model ==PNV_PHB_MODEL_PHB3 && phb->regs) +pnv_pci_phb3_tce_invalidate_pe (pe); +else +opal_pci_tce_kill (phb->opal_id,OPAL_PCI_TCE_KILL_PE , + pe->pe_number,0 ,0 ,0 ); +} +static void pnv_pci_ioda2_tce_invalidate (struct iommu_table *tbl,unsigned long index,unsigned long npages,bool rm) {
@@ -1875,17 +1886,31 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,list_for_each_entry_rcu (tgl, &tbl->it_group_list, next) {struct pnv_ioda_pe *pe =container_of (tgl->table_group, struct pnv_ioda_pe, table_group); -if (pe->phb->type ==PNV_PHB_NPU ) { +struct pnv_phb *phb = pe->phb; +unsigned int shift = tbl->it_page_shift; + +if (phb->type ==PNV_PHB_NPU ) {/* * The NVLink hardware does not support TCE kill * per TCE entry so we have to invalidate * the entire cache for it. */ -pnv_pci_phb3_tce_invalidate_entire (pe->phb, rm); +pnv_pci_phb3_tce_invalidate_entire (phb, rm);continue ; } -pnv_pci_phb3_tce_invalidate (pe, rm, tbl->it_page_shift, - index, npages); +if (phb->model ==PNV_PHB_MODEL_PHB3 && phb->regs) +pnv_pci_phb3_tce_invalidate (pe, rm, shift, + index, npages); +else if (rm) +opal_rm_pci_tce_kill (phb->opal_id, +OPAL_PCI_TCE_KILL_PAGES , + pe->pe_number,1u << shift, + index << shift, npages); +else +opal_pci_tce_kill (phb->opal_id, +OPAL_PCI_TCE_KILL_PAGES , + pe->pe_number,1u << shift, + index << shift, npages); } }
@@ -2151,7 +2176,7 @@ static long pnv_pci_ioda2_set_window(struct iommu_table_group *table_group,pnv_pci_link_table_and_group (phb->hose->node, num, tbl, &pe->table_group); -pnv_pci_phb3_tce_invalidate_pe (pe); +pnv_pci_ioda2_tce_invalidate_pe (pe);return 0 ; }
@@ -2289,7 +2314,7 @@ static long pnv_pci_ioda2_unset_window(struct iommu_table_group *table_group,if (ret)pe_warn (pe,"Unmapping failed, ret = %ld\n" , ret);else -pnv_pci_phb3_tce_invalidate_pe (pe); +pnv_pci_ioda2_tce_invalidate_pe (pe);pnv_pci_unlink_table_and_group (table_group->tables[num], table_group);
PATCH 12/14 powerpc/powernv/pci: Use the device-tree to get available range of M64's
In reply to Benjamin HerrenschmidtM64's are the configurable 64-bit windows that cover the 64-bit MMIO space. We used to hard code 16 windows. Newer chips might have a variable number and might need to reserve some as well (for example on PHB4/POWER9, M32 and M64 are actually unified and we use M64#0 to map the 32-bit space).
So newer OPALs will provide a property we can use to know what range of windows is available. The property is named so that it can eventually support multiple ranges but we only use the first one for now.
--- arch/powerpc/platforms/powernv/pci-ioda.c | 49 +++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-)
arch/powerpc/platforms/powernv/pci-ioda.c +43 -6
@@ -197,9 +197,6 @@ static int pnv_ioda2_init_m64(struct pnv_phb *phb) goto fail; } -/* Mark the M64 BAR assigned */ -set_bit (phb->ioda.m64_bar_idx, &phb->ioda.m64_bar_alloc); -/* * Exclude the segments for reserved and root bus PE, which * are first or last two PEs.
@@ -410,6 +407,7 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)struct pci_controller *hose = phb->hose;struct device_node *dn = hose->dn;struct resource *res; +u32 m64_range[2 ], i;const u32 *r;u64 pci_addr;
@@ -430,6 +428,29 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)return ; } +/* Find the available M64 BAR range and pickup the last one for +* covering the whole 64-bits space. We support only one range. +*/ +if (of_property_read_u32_array (dn,"ibm,opal-available-m64-ranges" , + m64_range,2 )) { +/* In absence of the property, assume 0..15 */ + m64_range[0 ] =0 ; + m64_range[1 ] =16 ; + } +/* We only support 64 bits in our allocator */ +if (m64_range[1 ] >63 ) { +pr_warn ("%s: Limiting M64 range to 63 (from %d) on PHB#%x\n" , + __func__, m64_range[1 ], phb->hose->global_number); + m64_range[1 ] =63 ; + } +/* Empty range, no m64 */ +if (m64_range[1 ] <= m64_range[0 ]) { +pr_warn ("%s: M64 empty, disabling M64 usage on PHB#%x\n" , + __func__, phb->hose->global_number); +return ; + } + +/* Configure M64 informations */ res = &hose->mem_resources[1 ]; res->name = dn->full_name; res->start =of_translate_address (dn, r +2 );
@@ -442,11 +463,27 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb) phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe_num; phb->ioda.m64_base = pci_addr; -pr_info (" MEM64 0x%016llx..0x%016llx -> 0x%016llx\n" , - res->start, res->end, pci_addr); +/* This lines up nicely with the display from processing OF ranges */ +pr_info (" MEM 0x%016llx..0x%016llx -> 0x%016llx (M64 #%d..%d)\n" , + res->start, res->end, pci_addr, m64_range[0 ], + m64_range[0 ] + m64_range[1 ] -1 ); + +/* Mark all M64 used up by default */ + phb->ioda.m64_bar_alloc = (unsigned long )-1 ;/* Use last M64 BAR to cover M64 window */ - phb->ioda.m64_bar_idx =15 ; + m64_range[1 ]--; + phb->ioda.m64_bar_idx = m64_range[0 ] + m64_range[1 ]; + +pr_info (" Using M64 #%d as default window\n" , phb->ioda.m64_bar_idx); + +/* Mark remaining ones free */ +for (i = m64_range[0 ]; i < m64_range[1 ]; i++) +clear_bit (i, &phb->ioda.m64_bar_alloc); + +/* Setup init functions for M64 based on IODA version, IODA3 uses +* the IODA2 code +*/ if (phb->type ==PNV_PHB_IODA1 ) phb->init_m64 = pnv_ioda1_init_m64;else
Signature · 1 line
2.7.4
PATCH 13/14 powerpc/powernv/pci: Check status of a PHB before using it
In reply to Benjamin HerrenschmidtIf the firmware encounters an error (internal or HW) during initialization of a PHB, it might leave the device-node in the tree but mark it disabled using the "status" property. We should check it.
--- arch/powerpc/platforms/powernv/pci-ioda.c | 3 +++ 1 file changed, 3 insertions(+)
arch/powerpc/platforms/powernv/pci-ioda.c +3 -0
@@ -3655,6 +3655,9 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,void *aux;long rc; +if (!of_device_is_available (np)) +return ; +pr_info ("Initializing %s PHB (%s)\n" , pnv_phb_names[ioda_type],of_node_full_name (np));
Signature · 1 line
2.7.4
PATCH 14/14 powerpc/pci: Don't try to allocate resources that will be reassigned
In reply to Benjamin HerrenschmidtWhen we know we will reassign all resources, trying (and failing) to allocate them initially is fairly pointless and leads to a lot of scary messages in the kernel log
--- arch/powerpc/kernel/pci-common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/powerpc/kernel/pci-common.c +4 -2
@@ -1370,8 +1370,10 @@ void __init pcibios_resource_survey(void)/* Allocate and assign resources */ list_for_each_entry (b, &pci_root_buses, node)pcibios_allocate_bus_resources (b); -pcibios_allocate_resources (0 ); -pcibios_allocate_resources (1 ); +if (!pci_has_flag (PCI_REASSIGN_ALL_RSRC )) { +pcibios_allocate_resources (0 ); +pcibios_allocate_resources (1 ); + }/* Before we start assigning unassigned resource, we try to reserve * the low IO area and the VGA memory area if they intersect the
Signature · 1 line
2.7.4
Quoted 6 lines · Benjamin Herrenschmidt
OPAL provides an emulated XICS interrupt controller to use as a fallback on newer processors that don't have a XICS. It's meant as a way to provide backward compatibility with future processors. Add the corresponding interfaces.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
These OPAL calls have the correct OPAL API numbers and they've been assigned upstream in skiboot.
Signature · 2 lines
Stewart Smith OPAL Architect, IBM.
Michael Ellerman
reviewerQuoted 7 lines · Benjamin Herrenschmidt
OPAL provides an emulated XICS interrupt controller to use as a fallback on newer processors that don't have a XICS. It's meant as a way to provide backward compatibility with future processors. Add the corresponding interfaces.
Signed-off-by Benjamin Herrenschmidt <[email protected]>Acked-by Stewart Smith <[email protected]>
Series applied to powerpc next, thanks.
https://git.kernel.org/powerpc/c/9fedd3f8804af87be608310aac
cheers