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/* the remote call being requested */
15static volatile IpiRemoteCall_t  remoteCall;
16static volatile irq_t            ipiIrq[CONFIG_MAX_NUM_NODES];
17
18static inline void init_ipi_args(IpiRemoteCall_t func,
19                                 word_t data1, word_t data2, word_t data3,
20                                 word_t mask)
21{
22    remoteCall = func;
23    ipi_args[0] = data1;
24    ipi_args[1] = data2;
25    ipi_args[2] = data3;
26
27    /* get number of cores involved in this IPI */
28    totalCoreBarrier = popcountl(mask);
29}
30
31static void handleRemoteCall(IpiRemoteCall_t call, word_t arg0,
32                             word_t arg1, word_t arg2, bool_t irqPath)
33{
34    /* we gets spurious irq_remote_call_ipi calls, e.g. when handling IPI
35     * in lock while hardware IPI is pending. Guard against spurious IPIs! */
36    if (clh_is_ipi_pending(getCurrentCPUIndex())) {
37        switch ((IpiRemoteCall_t)call) {
38        case IpiRemoteCall_Stall:
39            ipiStallCoreCallback(irqPath);
40            break;
41
42#ifdef CONFIG_HAVE_FPU
43        case IpiRemoteCall_switchFpuOwner:
44            switchLocalFpuOwner((user_fpu_state_t *)arg0);
45            break;
46#endif /* CONFIG_HAVE_FPU */
47
48        default:
49            fail("Invalid remote call");
50            break;
51        }
52
53        big_kernel_lock.node_owners[getCurrentCPUIndex()].ipi = 0;
54        ipiIrq[getCurrentCPUIndex()] = irqInvalid;
55        ipi_wait(totalCoreBarrier);
56    }
57}
58
59void ipi_send_mask(irq_t ipi, word_t mask, bool_t isBlocking)
60{
61
62    generic_ipi_send_mask(ipi, mask, isBlocking);
63}
64
65irq_t ipi_get_irq(void)
66{
67    assert(!(ipiIrq[getCurrentCPUIndex()] == irqInvalid && big_kernel_lock.node_owners[getCurrentCPUIndex()].ipi == 1));
68    return ipiIrq[getCurrentCPUIndex()];
69}
70
71void ipi_clear_irq(irq_t irq)
72{
73    ipiIrq[getCurrentCPUIndex()] = irqInvalid;
74    return;
75}
76
77/* this function is called with a single hart id. */
78void ipi_send_target(irq_t irq, word_t hart_id)
79{
80    unsigned long hart_mask;
81    word_t core_id = hartIDToCoreID(hart_id);
82    assert(core_id < CONFIG_MAX_NUM_NODES);
83    hart_mask = BIT(hart_id);
84
85    assert((ipiIrq[core_id] == irqInvalid) || (ipiIrq[core_id] == irq_reschedule_ipi) ||
86           (ipiIrq[core_id] == irq_remote_call_ipi && big_kernel_lock.node_owners[core_id].ipi == 0));
87
88    ipiIrq[core_id] = irq;
89    asm volatile("fence rw,rw");
90    sbi_send_ipi(&hart_mask);
91}
92
93#endif
94