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