1251881Speter/*
2251881Speter * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3251881Speter *
4251881Speter * SPDX-License-Identifier: GPL-2.0-only
5251881Speter */
6251881Speter
7251881Speter#include <config.h>
8251881Speter#include <mode/smp/ipi.h>
9251881Speter#include <smp/lock.h>
10251881Speter#include <util.h>
11251881Speter
12251881Speter#ifdef ENABLE_SMP_SUPPORT
13251881Speter
14251881Speter/* the remote call being requested */
15251881Speterstatic volatile IpiRemoteCall_t  remoteCall;
16251881Speterstatic volatile irq_t            ipiIrq[CONFIG_MAX_NUM_NODES];
17251881Speter
18251881Speterstatic inline void init_ipi_args(IpiRemoteCall_t func,
19251881Speter                                 word_t data1, word_t data2, word_t data3,
20251881Speter                                 word_t mask)
21251881Speter{
22251881Speter    remoteCall = func;
23251881Speter    ipi_args[0] = data1;
24251881Speter    ipi_args[1] = data2;
25251881Speter    ipi_args[2] = data3;
26251881Speter
27251881Speter    /* get number of cores involved in this IPI */
28251881Speter    totalCoreBarrier = popcountl(mask);
29251881Speter}
30251881Speter
31251881Speterstatic void handleRemoteCall(IpiRemoteCall_t call, word_t arg0,
32251881Speter                             word_t arg1, word_t arg2, bool_t irqPath)
33251881Speter{
34251881Speter    /* we gets spurious irq_remote_call_ipi calls, e.g. when handling IPI
35251881Speter     * in lock while hardware IPI is pending. Guard against spurious IPIs! */
36251881Speter    if (clh_is_ipi_pending(getCurrentCPUIndex())) {
37251881Speter        switch ((IpiRemoteCall_t)call) {
38251881Speter        case IpiRemoteCall_Stall:
39251881Speter            ipiStallCoreCallback(irqPath);
40251881Speter            break;
41251881Speter
42251881Speter#ifdef CONFIG_HAVE_FPU
43251881Speter        case IpiRemoteCall_switchFpuOwner:
44251881Speter            switchLocalFpuOwner((user_fpu_state_t *)arg0);
45251881Speter            break;
46251881Speter#endif /* CONFIG_HAVE_FPU */
47251881Speter
48251881Speter        default:
49251881Speter            fail("Invalid remote call");
50251881Speter            break;
51251881Speter        }
52251881Speter
53251881Speter        big_kernel_lock.node_owners[getCurrentCPUIndex()].ipi = 0;
54251881Speter        ipiIrq[getCurrentCPUIndex()] = irqInvalid;
55251881Speter        ipi_wait(totalCoreBarrier);
56251881Speter    }
57251881Speter}
58251881Speter
59251881Spetervoid ipi_send_mask(irq_t ipi, word_t mask, bool_t isBlocking)
60251881Speter{
61251881Speter
62251881Speter    generic_ipi_send_mask(ipi, mask, isBlocking);
63251881Speter}
64251881Speter
65251881Speterirq_t ipi_get_irq(void)
66251881Speter{
67251881Speter    assert(!(ipiIrq[getCurrentCPUIndex()] == irqInvalid && big_kernel_lock.node_owners[getCurrentCPUIndex()].ipi == 1));
68251881Speter    return ipiIrq[getCurrentCPUIndex()];
69251881Speter}
70251881Speter
71251881Spetervoid ipi_clear_irq(irq_t irq)
72251881Speter{
73251881Speter    ipiIrq[getCurrentCPUIndex()] = irqInvalid;
74251881Speter    return;
75251881Speter}
76251881Speter
77251881Speter/* this function is called with a single hart id. */
78251881Spetervoid ipi_send_target(irq_t irq, word_t hart_id)
79251881Speter{
80251881Speter    unsigned long hart_mask;
81251881Speter    word_t core_id = hartIDToCoreID(hart_id);
82251881Speter    assert(core_id < CONFIG_MAX_NUM_NODES);
83251881Speter    hart_mask = BIT(hart_id);
84251881Speter
85251881Speter    assert((ipiIrq[core_id] == irqInvalid) || (ipiIrq[core_id] == irq_reschedule_ipi) ||
86251881Speter           (ipiIrq[core_id] == irq_remote_call_ipi && big_kernel_lock.node_owners[core_id].ipi == 0));
87251881Speter
88251881Speter    ipiIrq[core_id] = irq;
89251881Speter    asm volatile("fence rw,rw");
90251881Speter    sbi_send_ipi(&hart_mask);
91251881Speter}
92251881Speter
93251881Speter#endif
94251881Speter