Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Change the doorbell IPI calling convention

Change the doorbell callers to know about their msgsnd addressing,
rather than have them set a per-cpu target data tag at boot that gets
sent to the cause_ipi functions. The data is only used for doorbell IPI
functions, no other IPI types, so it makes sense to keep that detail
local to doorbell.

Have the platform code understand doorbell IPIs, rather than the
interrupt controller code understand them. Platform code can look at
capabilities it has available and decide which to use.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Nicholas Piggin and committed by
Michael Ellerman
b866cc21 9b7ff0c6

+95 -82
+3 -6
arch/powerpc/include/asm/dbell.h
··· 35 35 #ifdef CONFIG_PPC_BOOK3S 36 36 37 37 #define PPC_DBELL_MSGTYPE PPC_DBELL_SERVER 38 - #define SPRN_DOORBELL_CPUTAG SPRN_TIR 39 - #define PPC_DBELL_TAG_MASK 0x7f 40 38 41 39 static inline void _ppc_msgsnd(u32 msg) 42 40 { ··· 47 49 #else /* CONFIG_PPC_BOOK3S */ 48 50 49 51 #define PPC_DBELL_MSGTYPE PPC_DBELL 50 - #define SPRN_DOORBELL_CPUTAG SPRN_PIR 51 - #define PPC_DBELL_TAG_MASK 0x3fff 52 52 53 53 static inline void _ppc_msgsnd(u32 msg) 54 54 { ··· 55 59 56 60 #endif /* CONFIG_PPC_BOOK3S */ 57 61 58 - extern void doorbell_cause_ipi(int cpu, unsigned long data); 62 + extern void doorbell_global_ipi(int cpu); 63 + extern void doorbell_core_ipi(int cpu); 64 + extern int doorbell_try_core_ipi(int cpu); 59 65 extern void doorbell_exception(struct pt_regs *regs); 60 - extern void doorbell_setup_this_cpu(void); 61 66 62 67 static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag) 63 68 {
+1 -2
arch/powerpc/include/asm/smp.h
··· 40 40 struct smp_ops_t { 41 41 void (*message_pass)(int cpu, int msg); 42 42 #ifdef CONFIG_PPC_SMP_MUXED_IPI 43 - void (*cause_ipi)(int cpu, unsigned long data); 43 + void (*cause_ipi)(int cpu); 44 44 #endif 45 45 void (*probe)(void); 46 46 int (*kick_cpu)(int nr); ··· 125 125 extern const char *smp_ipi_name[]; 126 126 127 127 /* for irq controllers with only a single ipi */ 128 - extern void smp_muxed_ipi_set_data(int cpu, unsigned long data); 129 128 extern void smp_muxed_ipi_message_pass(int cpu, int msg); 130 129 extern void smp_muxed_ipi_set_message(int cpu, int msg); 131 130 extern irqreturn_t smp_ipi_demux(void);
+1 -1
arch/powerpc/include/asm/xics.h
··· 57 57 void (*teardown_cpu)(void); 58 58 void (*flush_ipi)(void); 59 59 #ifdef CONFIG_SMP 60 - void (*cause_ipi)(int cpu, unsigned long data); 60 + void (*cause_ipi)(int cpu); 61 61 irq_handler_t ipi_action; 62 62 #endif 63 63 };
+50 -8
arch/powerpc/kernel/dbell.c
··· 20 20 #include <asm/kvm_ppc.h> 21 21 22 22 #ifdef CONFIG_SMP 23 - void doorbell_setup_this_cpu(void) 24 - { 25 - unsigned long tag = mfspr(SPRN_DOORBELL_CPUTAG) & PPC_DBELL_TAG_MASK; 26 23 27 - smp_muxed_ipi_set_data(smp_processor_id(), tag); 28 - } 29 - 30 - void doorbell_cause_ipi(int cpu, unsigned long data) 24 + /* 25 + * Doorbells must only be used if CPU_FTR_DBELL is available. 26 + * msgsnd is used in HV, and msgsndp is used in !HV. 27 + * 28 + * These should be used by platform code that is aware of restrictions. 29 + * Other arch code should use ->cause_ipi. 30 + * 31 + * doorbell_global_ipi() sends a dbell to any target CPU. 32 + * Must be used only by architectures that address msgsnd target 33 + * by PIR/get_hard_smp_processor_id. 34 + */ 35 + void doorbell_global_ipi(int cpu) 31 36 { 37 + u32 tag = get_hard_smp_processor_id(cpu); 38 + 39 + kvmppc_set_host_ipi(cpu, 1); 32 40 /* Order previous accesses vs. msgsnd, which is treated as a store */ 33 41 mb(); 34 - ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, data); 42 + ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); 43 + } 44 + 45 + /* 46 + * doorbell_core_ipi() sends a dbell to a target CPU in the same core. 47 + * Must be used only by architectures that address msgsnd target 48 + * by TIR/cpu_thread_in_core. 49 + */ 50 + void doorbell_core_ipi(int cpu) 51 + { 52 + u32 tag = cpu_thread_in_core(cpu); 53 + 54 + kvmppc_set_host_ipi(cpu, 1); 55 + /* Order previous accesses vs. msgsnd, which is treated as a store */ 56 + mb(); 57 + ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); 58 + } 59 + 60 + /* 61 + * Attempt to cause a core doorbell if destination is on the same core. 62 + * Returns 1 on success, 0 on failure. 63 + */ 64 + int doorbell_try_core_ipi(int cpu) 65 + { 66 + int this_cpu = get_cpu(); 67 + int ret = 0; 68 + 69 + if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) { 70 + doorbell_core_ipi(cpu); 71 + ret = 1; 72 + } 73 + 74 + put_cpu(); 75 + 76 + return ret; 35 77 } 36 78 37 79 void doorbell_exception(struct pt_regs *regs)
+5 -12
arch/powerpc/kernel/smp.c
··· 39 39 #include <asm/irq.h> 40 40 #include <asm/hw_irq.h> 41 41 #include <asm/kvm_ppc.h> 42 + #include <asm/dbell.h> 42 43 #include <asm/page.h> 43 44 #include <asm/pgtable.h> 44 45 #include <asm/prom.h> ··· 212 211 #ifdef CONFIG_PPC_SMP_MUXED_IPI 213 212 struct cpu_messages { 214 213 long messages; /* current messages */ 215 - unsigned long data; /* data for cause ipi */ 216 214 }; 217 215 static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); 218 - 219 - void smp_muxed_ipi_set_data(int cpu, unsigned long data) 220 - { 221 - struct cpu_messages *info = &per_cpu(ipi_message, cpu); 222 - 223 - info->data = data; 224 - } 225 216 226 217 void smp_muxed_ipi_set_message(int cpu, int msg) 227 218 { ··· 229 236 230 237 void smp_muxed_ipi_message_pass(int cpu, int msg) 231 238 { 232 - struct cpu_messages *info = &per_cpu(ipi_message, cpu); 233 - 234 239 smp_muxed_ipi_set_message(cpu, msg); 240 + 235 241 /* 236 242 * cause_ipi functions are required to include a full barrier 237 243 * before doing whatever causes the IPI. 238 244 */ 239 - smp_ops->cause_ipi(cpu, info->data); 245 + smp_ops->cause_ipi(cpu); 240 246 } 241 247 242 248 #ifdef __BIG_ENDIAN__ ··· 246 254 247 255 irqreturn_t smp_ipi_demux(void) 248 256 { 249 - struct cpu_messages *info = this_cpu_ptr(&ipi_message); 257 + struct cpu_messages *info; 250 258 unsigned long all; 251 259 252 260 mb(); /* order any irq clear */ 253 261 262 + info = this_cpu_ptr(&ipi_message); 254 263 do { 255 264 all = xchg(&info->messages, 0); 256 265 #if defined(CONFIG_KVM_XICS) && defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
+2 -9
arch/powerpc/platforms/85xx/smp.c
··· 461 461 } 462 462 #endif /* CONFIG_KEXEC_CORE */ 463 463 464 - static void smp_85xx_basic_setup(int cpu_nr) 465 - { 466 - if (cpu_has_feature(CPU_FTR_DBELL)) 467 - doorbell_setup_this_cpu(); 468 - } 469 - 470 464 static void smp_85xx_setup_cpu(int cpu_nr) 471 465 { 472 466 mpic_setup_this_cpu(); 473 - smp_85xx_basic_setup(cpu_nr); 474 467 } 475 468 476 469 void __init mpc85xx_smp_init(void) ··· 477 484 smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; 478 485 smp_85xx_ops.message_pass = smp_mpic_message_pass; 479 486 } else 480 - smp_85xx_ops.setup_cpu = smp_85xx_basic_setup; 487 + smp_85xx_ops.setup_cpu = NULL; 481 488 482 489 if (cpu_has_feature(CPU_FTR_DBELL)) { 483 490 /* ··· 485 492 * smp_muxed_ipi_message_pass 486 493 */ 487 494 smp_85xx_ops.message_pass = NULL; 488 - smp_85xx_ops.cause_ipi = doorbell_cause_ipi; 495 + smp_85xx_ops.cause_ipi = doorbell_global_ipi; 489 496 smp_85xx_ops.probe = NULL; 490 497 } 491 498
+1 -1
arch/powerpc/platforms/powermac/smp.c
··· 172 172 return IRQ_HANDLED; 173 173 } 174 174 175 - static void smp_psurge_cause_ipi(int cpu, unsigned long data) 175 + static void smp_psurge_cause_ipi(int cpu) 176 176 { 177 177 psurge_set_ipi(cpu); 178 178 }
+16 -7
arch/powerpc/platforms/powernv/smp.c
··· 53 53 xive_smp_setup_cpu(); 54 54 else if (cpu != boot_cpuid) 55 55 xics_setup_cpu(); 56 - 57 - #ifdef CONFIG_PPC_DOORBELL 58 - if (cpu_has_feature(CPU_FTR_DBELL)) 59 - doorbell_setup_this_cpu(); 60 - #endif 61 56 } 62 57 63 58 static int pnv_smp_kick_cpu(int nr) ··· 249 254 return 0; 250 255 } 251 256 257 + static void pnv_cause_ipi(int cpu) 258 + { 259 + if (doorbell_try_core_ipi(cpu)) 260 + return; 261 + 262 + icp_ops->cause_ipi(cpu); 263 + } 264 + 252 265 static void __init pnv_smp_probe(void) 253 266 { 254 267 if (xive_enabled()) 255 268 xive_smp_probe(); 256 269 else 257 270 xics_smp_probe(); 271 + 272 + if (cpu_has_feature(CPU_FTR_DBELL) && !cpu_has_feature(CPU_FTR_ARCH_300)) { 273 + smp_ops->cause_ipi = pnv_cause_ipi; 274 + } else { 275 + smp_ops->cause_ipi = icp_ops->cause_ipi; 276 + } 258 277 } 259 278 260 279 static struct smp_ops_t pnv_smp_ops = { 261 - .message_pass = smp_muxed_ipi_message_pass, 262 - .cause_ipi = NULL, /* Filled at runtime by xi{cs,ve}_smp_probe() */ 280 + .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */ 281 + .cause_ipi = NULL, /* Filled at runtime by pnv_smp_probe() */ 263 282 .probe = pnv_smp_probe, 264 283 .prepare_cpu = pnv_smp_prepare_cpu, 265 284 .kick_cpu = pnv_smp_kick_cpu,
+10 -17
arch/powerpc/platforms/pseries/smp.c
··· 55 55 */ 56 56 static cpumask_var_t of_spin_mask; 57 57 58 - /* 59 - * If we multiplex IPI mechanisms, store the appropriate XICS IPI mechanism here 60 - */ 61 - static void (*xics_cause_ipi)(int cpu, unsigned long data); 62 - 63 58 /* Query where a cpu is now. Return codes #defined in plpar_wrappers.h */ 64 59 int smp_query_cpu_stopped(unsigned int pcpu) 65 60 { ··· 138 143 { 139 144 if (cpu != boot_cpuid) 140 145 xics_setup_cpu(); 141 - if (cpu_has_feature(CPU_FTR_DBELL)) 142 - doorbell_setup_this_cpu(); 143 146 144 147 if (firmware_has_feature(FW_FEATURE_SPLPAR)) 145 148 vpa_init(cpu); ··· 180 187 return 0; 181 188 } 182 189 183 - /* Only used on systems that support multiple IPI mechanisms */ 184 - static void pSeries_cause_ipi_mux(int cpu, unsigned long data) 190 + static void smp_pseries_cause_ipi(int cpu) 185 191 { 186 - if (cpumask_test_cpu(cpu, cpu_sibling_mask(smp_processor_id()))) 187 - doorbell_cause_ipi(cpu, data); 188 - else 189 - xics_cause_ipi(cpu, data); 192 + /* POWER9 should not use this handler */ 193 + if (doorbell_try_core_ipi(cpu)) 194 + return; 195 + 196 + icp_ops->cause_ipi(cpu); 190 197 } 191 198 192 199 static __init void pSeries_smp_probe(void) 193 200 { 194 201 xics_smp_probe(); 195 202 196 - if (cpu_has_feature(CPU_FTR_DBELL)) { 197 - xics_cause_ipi = smp_ops->cause_ipi; 198 - smp_ops->cause_ipi = pSeries_cause_ipi_mux; 199 - } 203 + if (cpu_has_feature(CPU_FTR_DBELL)) 204 + smp_ops->cause_ipi = smp_pseries_cause_ipi; 205 + else 206 + smp_ops->cause_ipi = icp_ops->cause_ipi; 200 207 } 201 208 202 209 static struct smp_ops_t pseries_smp_ops = {
+1 -1
arch/powerpc/sysdev/xics/icp-hv.c
··· 138 138 139 139 #ifdef CONFIG_SMP 140 140 141 - static void icp_hv_cause_ipi(int cpu, unsigned long data) 141 + static void icp_hv_cause_ipi(int cpu) 142 142 { 143 143 icp_hv_set_qirr(cpu, IPI_PRIORITY); 144 144 }
+1 -11
arch/powerpc/sysdev/xics/icp-native.c
··· 143 143 144 144 #ifdef CONFIG_SMP 145 145 146 - static void icp_native_cause_ipi(int cpu, unsigned long data) 146 + static void icp_native_cause_ipi(int cpu) 147 147 { 148 148 kvmppc_set_host_ipi(cpu, 1); 149 - #ifdef CONFIG_PPC_DOORBELL 150 - if (cpu_has_feature(CPU_FTR_DBELL)) { 151 - if (cpumask_test_cpu(cpu, cpu_sibling_mask(get_cpu()))) { 152 - doorbell_cause_ipi(cpu, data); 153 - put_cpu(); 154 - return; 155 - } 156 - put_cpu(); 157 - } 158 - #endif 159 149 icp_native_set_qirr(cpu, IPI_PRIORITY); 160 150 } 161 151
+1 -1
arch/powerpc/sysdev/xics/icp-opal.c
··· 126 126 127 127 #ifdef CONFIG_SMP 128 128 129 - static void icp_opal_cause_ipi(int cpu, unsigned long data) 129 + static void icp_opal_cause_ipi(int cpu) 130 130 { 131 131 int hw_cpu = get_hard_smp_processor_id(cpu); 132 132
-3
arch/powerpc/sysdev/xics/xics-common.c
··· 143 143 144 144 void __init xics_smp_probe(void) 145 145 { 146 - /* Setup cause_ipi callback based on which ICP is used */ 147 - smp_ops->cause_ipi = icp_ops->cause_ipi; 148 - 149 146 /* Register all the IPIs */ 150 147 xics_request_ipi(); 151 148 }
+3 -3
arch/powerpc/sysdev/xive/common.c
··· 834 834 835 835 #ifdef CONFIG_SMP 836 836 837 - static void xive_cause_ipi(int cpu, unsigned long msg) 837 + static void xive_cause_ipi(int cpu) 838 838 { 839 839 struct xive_cpu *xc; 840 840 struct xive_irq_data *xd; 841 841 842 842 xc = per_cpu(xive_cpu, cpu); 843 843 844 - DBG_VERBOSE("IPI msg#%ld CPU %d -> %d (HW IRQ 0x%x)\n", 845 - msg, smp_processor_id(), cpu, xc->hw_ipi); 844 + DBG_VERBOSE("IPI CPU %d -> %d (HW IRQ 0x%x)\n", 845 + smp_processor_id(), cpu, xc->hw_ipi); 846 846 847 847 xd = &xc->ipi_data; 848 848 if (WARN_ON(!xd->trig_mmio))