Line data Source code
1 : // SPDX-License-Identifier: MIT 2 : /* 3 : * Copyright 2021 Advanced Micro Devices, Inc. 4 : * 5 : * Permission is hereby granted, free of charge, to any person obtaining a 6 : * copy of this software and associated documentation files (the "Software"), 7 : * to deal in the Software without restriction, including without limitation 8 : * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 : * and/or sell copies of the Software, and to permit persons to whom the 10 : * Software is furnished to do so, subject to the following conditions: 11 : * 12 : * The above copyright notice and this permission notice shall be included in 13 : * all copies or substantial portions of the Software. 14 : * 15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 : * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 : * OTHER DEALINGS IN THE SOFTWARE. 22 : * 23 : * Authors: AMD 24 : * 25 : */ 26 : 27 : #include "dc_trace.h" 28 : 29 : #if defined(CONFIG_X86) 30 : #include <asm/fpu/api.h> 31 : #elif defined(CONFIG_PPC64) 32 : #include <asm/switch_to.h> 33 : #include <asm/cputable.h> 34 : #endif 35 : 36 : /** 37 : * DOC: DC FPU manipulation overview 38 : * 39 : * DC core uses FPU operations in multiple parts of the code, which requires a 40 : * more specialized way to manage these areas' entrance. To fulfill this 41 : * requirement, we created some wrapper functions that encapsulate 42 : * kernel_fpu_begin/end to better fit our need in the display component. In 43 : * summary, in this file, you can find functions related to FPU operation 44 : * management. 45 : */ 46 : 47 : static DEFINE_PER_CPU(int, fpu_recursion_depth); 48 : 49 : /** 50 : * dc_assert_fp_enabled - Check if FPU protection is enabled 51 : * 52 : * This function tells if the code is already under FPU protection or not. A 53 : * function that works as an API for a set of FPU operations can use this 54 : * function for checking if the caller invoked it after DC_FP_START(). For 55 : * example, take a look at dcn20_fpu.c file. 56 : */ 57 4 : inline void dc_assert_fp_enabled(void) 58 : { 59 4 : int *pcpu, depth = 0; 60 : 61 4 : pcpu = get_cpu_ptr(&fpu_recursion_depth); 62 4 : depth = *pcpu; 63 4 : put_cpu_ptr(&fpu_recursion_depth); 64 : 65 4 : ASSERT(depth >= 1); 66 4 : } 67 : 68 : /** 69 : * dc_fpu_begin - Enables FPU protection 70 : * @function_name: A string containing the function name for debug purposes 71 : * (usually __func__) 72 : * 73 : * @line: A line number where DC_FP_START was invoked for debug purpose 74 : * (usually __LINE__) 75 : * 76 : * This function is responsible for managing the use of kernel_fpu_begin() with 77 : * the advantage of providing an event trace for debugging. 78 : * 79 : * Note: Do not call this function directly; always use DC_FP_START(). 80 : */ 81 45 : void dc_fpu_begin(const char *function_name, const int line) 82 : { 83 : int *pcpu; 84 : 85 45 : pcpu = get_cpu_ptr(&fpu_recursion_depth); 86 45 : *pcpu += 1; 87 : 88 : if (*pcpu == 1) { 89 : #if defined(CONFIG_X86) 90 : kernel_fpu_begin(); 91 : #elif defined(CONFIG_PPC64) 92 : if (cpu_has_feature(CPU_FTR_VSX_COMP)) { 93 : preempt_disable(); 94 : enable_kernel_vsx(); 95 : } else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) { 96 : preempt_disable(); 97 : enable_kernel_altivec(); 98 : } else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) { 99 : preempt_disable(); 100 : enable_kernel_fp(); 101 : } 102 : #endif 103 : } 104 : 105 45 : TRACE_DCN_FPU(true, function_name, line, *pcpu); 106 45 : put_cpu_ptr(&fpu_recursion_depth); 107 45 : } 108 : 109 : /** 110 : * dc_fpu_end - Disable FPU protection 111 : * @function_name: A string containing the function name for debug purposes 112 : * @line: A-line number where DC_FP_END was invoked for debug purpose 113 : * 114 : * This function is responsible for managing the use of kernel_fpu_end() with 115 : * the advantage of providing an event trace for debugging. 116 : * 117 : * Note: Do not call this function directly; always use DC_FP_END(). 118 : */ 119 45 : void dc_fpu_end(const char *function_name, const int line) 120 : { 121 : int *pcpu; 122 : 123 45 : pcpu = get_cpu_ptr(&fpu_recursion_depth); 124 45 : *pcpu -= 1; 125 : if (*pcpu <= 0) { 126 : #if defined(CONFIG_X86) 127 : kernel_fpu_end(); 128 : #elif defined(CONFIG_PPC64) 129 : if (cpu_has_feature(CPU_FTR_VSX_COMP)) { 130 : disable_kernel_vsx(); 131 : preempt_enable(); 132 : } else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) { 133 : disable_kernel_altivec(); 134 : preempt_enable(); 135 : } else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) { 136 : disable_kernel_fp(); 137 : preempt_enable(); 138 : } 139 : #endif 140 : } 141 : 142 45 : TRACE_DCN_FPU(false, function_name, line, *pcpu); 143 45 : put_cpu_ptr(&fpu_recursion_depth); 144 45 : }