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
14static IpiModeRemoteCall_t remoteCall;   /* the remote call being requested */
15
16static 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
29static 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
81void 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