1 /*
2  * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #include <config.h>
8 #include <mode/smp/ipi.h>
9 #include <smp/lock.h>
10 #include <util.h>
11 
12 #ifdef ENABLE_SMP_SUPPORT
13 
14 static IpiModeRemoteCall_t remoteCall;   /* the remote call being requested */
15 
init_ipi_args(IpiRemoteCall_t func,word_t data1,word_t data2,word_t data3,word_t mask)16 static inline void init_ipi_args(IpiRemoteCall_t func,
17                                  word_t data1, word_t data2, word_t data3,
18                                  word_t mask)
19 {
20     remoteCall = (IpiModeRemoteCall_t)func;
21     ipi_args[0] = data1;
22     ipi_args[1] = data2;
23     ipi_args[2] = data3;
24 
25     /* get number of cores involved in this IPI */
26     totalCoreBarrier = popcountl(mask);
27 }
28 
handleRemoteCall(IpiModeRemoteCall_t call,word_t arg0,word_t arg1,word_t arg2,bool_t irqPath)29 static void handleRemoteCall(IpiModeRemoteCall_t call, word_t arg0,
30                              word_t arg1, word_t arg2, bool_t irqPath)
31 {
32     /* we gets spurious irq_remote_call_ipi calls, e.g. when handling IPI
33      * in lock while hardware IPI is pending. Guard against spurious IPIs! */
34     if (clh_is_ipi_pending(getCurrentCPUIndex())) {
35         switch ((IpiRemoteCall_t)call) {
36         case IpiRemoteCall_Stall:
37             ipiStallCoreCallback(irqPath);
38             break;
39 
40 #ifdef CONFIG_HAVE_FPU
41         case IpiRemoteCall_switchFpuOwner:
42             switchLocalFpuOwner((user_fpu_state_t *)arg0);
43             break;
44 #endif /* CONFIG_HAVE_FPU */
45 
46         case IpiRemoteCall_InvalidateTranslationSingle:
47             invalidateTranslationSingleLocal(arg0);
48             break;
49 
50         case IpiRemoteCall_InvalidateTranslationASID:
51             invalidateTranslationASIDLocal(arg0);
52             break;
53 
54         case IpiRemoteCall_InvalidateTranslationAll:
55             invalidateTranslationAllLocal();
56             break;
57 
58         case IpiRemoteCall_MaskPrivateInterrupt:
59             maskInterrupt(arg0, IDX_TO_IRQT(arg1));
60             break;
61 
62 #if defined CONFIG_ARM_HYPERVISOR_SUPPORT && defined ENABLE_SMP_SUPPORT
63         case IpiRemoteCall_VCPUInjectInterrupt: {
64             virq_t virq;
65             virq.words[0] = arg2;
66             handleVCPUInjectInterruptIPI((vcpu_t *) arg0, arg1, virq);
67             break;
68         }
69 #endif
70 
71         default:
72             fail("Invalid remote call");
73             break;
74         }
75 
76         big_kernel_lock.node_owners[getCurrentCPUIndex()].ipi = 0;
77         ipi_wait(totalCoreBarrier);
78     }
79 }
80 
ipi_send_mask(irq_t ipi,word_t mask,bool_t isBlocking)81 void ipi_send_mask(irq_t ipi, word_t mask, bool_t isBlocking)
82 {
83     generic_ipi_send_mask(ipi, mask, isBlocking);
84 }
85 #endif /* ENABLE_SMP_SUPPORT */
86