1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12
13#include <config.h>
14#include <mode/smp/ipi.h>
15#include <smp/lock.h>
16#include <util.h>
17
18#ifdef ENABLE_SMP_SUPPORT
19
20static IpiModeRemoteCall_t remoteCall;   /* the remote call being requested */
21
22static inline void init_ipi_args(IpiModeRemoteCall_t func,
23                                 word_t data1, word_t data2, word_t data3,
24                                 word_t mask)
25{
26    remoteCall = func;
27    ipi_args[0] = data1;
28    ipi_args[1] = data2;
29    ipi_args[2] = data3;
30
31    /* get number of cores involved in this IPI */
32    totalCoreBarrier = popcountl(mask);
33}
34
35static void handleRemoteCall(IpiModeRemoteCall_t call, word_t arg0,
36                             word_t arg1, word_t arg2, bool_t irqPath)
37{
38    /* we gets spurious irq_remote_call_ipi calls, e.g. when handling IPI
39     * in lock while hardware IPI is pending. Guard against spurious IPIs! */
40    if (clh_is_ipi_pending(getCurrentCPUIndex())) {
41        switch ((IpiRemoteCall_t)call) {
42        case IpiRemoteCall_Stall:
43            ipiStallCoreCallback(irqPath);
44            break;
45
46#ifdef CONFIG_HAVE_FPU
47        case IpiRemoteCall_switchFpuOwner:
48            switchLocalFpuOwner((user_fpu_state_t *)arg0);
49            break;
50#endif /* CONFIG_HAVE_FPU */
51
52        case IpiRemoteCall_InvalidateTranslationSingle:
53            invalidateTranslationSingleLocal(arg0);
54            break;
55
56        case IpiRemoteCall_InvalidateTranslationASID:
57            invalidateTranslationASIDLocal(arg0);
58            break;
59
60        case IpiRemoteCall_InvalidateTranslationAll:
61            invalidateTranslationAllLocal();
62            break;
63
64        default:
65            fail("Invalid remote call");
66            break;
67        }
68
69        big_kernel_lock.node_owners[getCurrentCPUIndex()].ipi = 0;
70        ipi_wait(totalCoreBarrier);
71    }
72}
73
74void ipi_send_mask(irq_t ipi, word_t mask, bool_t isBlocking)
75{
76    generic_ipi_send_mask(ipi, mask, isBlocking);
77}
78#endif /* ENABLE_SMP_SUPPORT */
79