1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <config.h>
10#include <object/structures.h>
11#include <model/statedata.h>
12#include <arch/machine/fpu.h>
13
14#ifdef CONFIG_HAVE_FPU
15
16/* Perform any actions required for the deletion of the given thread. */
17void fpuThreadDelete(tcb_t *thread);
18
19/* Handle an FPU exception. */
20exception_t handleFPUFault(void);
21
22void switchLocalFpuOwner(user_fpu_state_t *new_owner);
23
24/* Switch the current owner of the FPU state on the core specified by 'cpu'. */
25void switchFpuOwner(user_fpu_state_t *new_owner, word_t cpu);
26
27/* Returns whether or not the passed thread is using the current active fpu state */
28static inline bool_t nativeThreadUsingFPU(tcb_t *thread)
29{
30    return &thread->tcbArch.tcbContext.fpuState ==
31           NODE_STATE_ON_CORE(ksActiveFPUState, thread->tcbAffinity);
32}
33
34static inline void FORCE_INLINE lazyFPURestore(tcb_t *thread)
35{
36    if (unlikely(NODE_STATE(ksActiveFPUState))) {
37        /* If we have enabled/disabled the FPU too many times without
38         * someone else trying to use it, we assume it is no longer
39         * in use and switch out its state. */
40        if (unlikely(NODE_STATE(ksFPURestoresSinceSwitch) > CONFIG_FPU_MAX_RESTORES_SINCE_SWITCH)) {
41            switchLocalFpuOwner(NULL);
42            NODE_STATE(ksFPURestoresSinceSwitch) = 0;
43        } else {
44            if (likely(nativeThreadUsingFPU(thread))) {
45                /* We are using the FPU, make sure it is enabled */
46                enableFpu();
47            } else {
48                /* Someone is using the FPU and it might be enabled */
49                disableFpu();
50            }
51            NODE_STATE(ksFPURestoresSinceSwitch)++;
52        }
53    } else {
54        /* No-one (including us) is using the FPU, so we assume it
55         * is currently disabled */
56    }
57}
58
59#endif /* CONFIG_HAVE_FPU */
60
61