1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2014-2016, 2018-2021 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include <mali_kbase.h>
23 #include <mali_kbase_hwaccess_time.h>
24 #include <device/mali_kbase_device.h>
25 #include <backend/gpu/mali_kbase_pm_internal.h>
26 #include <mali_kbase_config_defaults.h>
27
kbase_backend_get_gpu_time_norequest(struct kbase_device * kbdev,u64 * cycle_counter,u64 * system_time,struct timespec64 * ts)28 void kbase_backend_get_gpu_time_norequest(struct kbase_device *kbdev,
29 u64 *cycle_counter,
30 u64 *system_time,
31 struct timespec64 *ts)
32 {
33 u32 hi1, hi2;
34
35 if (cycle_counter)
36 *cycle_counter = kbase_backend_get_cycle_cnt(kbdev);
37
38 if (system_time) {
39 /* Read hi, lo, hi to ensure a coherent u64 */
40 do {
41 hi1 = kbase_reg_read(kbdev,
42 GPU_CONTROL_REG(TIMESTAMP_HI));
43 *system_time = kbase_reg_read(kbdev,
44 GPU_CONTROL_REG(TIMESTAMP_LO));
45 hi2 = kbase_reg_read(kbdev,
46 GPU_CONTROL_REG(TIMESTAMP_HI));
47 } while (hi1 != hi2);
48 *system_time |= (((u64) hi1) << 32);
49 }
50
51 /* Record the CPU's idea of current time */
52 if (ts != NULL)
53 #if (KERNEL_VERSION(4, 17, 0) > LINUX_VERSION_CODE)
54 *ts = ktime_to_timespec64(ktime_get_raw());
55 #else
56 ktime_get_raw_ts64(ts);
57 #endif
58 }
59
60 #if !MALI_USE_CSF
61 /**
62 * timedwait_cycle_count_active() - Timed wait till CYCLE_COUNT_ACTIVE is active
63 *
64 * @kbdev: Kbase device
65 *
66 * Return: true if CYCLE_COUNT_ACTIVE is active within the timeout.
67 */
timedwait_cycle_count_active(struct kbase_device * kbdev)68 static bool timedwait_cycle_count_active(struct kbase_device *kbdev)
69 {
70 #if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI)
71 return true;
72 #else
73 bool success = false;
74 const unsigned int timeout = 100;
75 const unsigned long remaining = jiffies + msecs_to_jiffies(timeout);
76
77 while (time_is_after_jiffies(remaining)) {
78 if ((kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_STATUS)) &
79 GPU_STATUS_CYCLE_COUNT_ACTIVE)) {
80 success = true;
81 break;
82 }
83 }
84 return success;
85 #endif
86 }
87 #endif
88
kbase_backend_get_gpu_time(struct kbase_device * kbdev,u64 * cycle_counter,u64 * system_time,struct timespec64 * ts)89 void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter,
90 u64 *system_time, struct timespec64 *ts)
91 {
92 #if !MALI_USE_CSF
93 kbase_pm_request_gpu_cycle_counter(kbdev);
94 WARN_ONCE(kbdev->pm.backend.l2_state != KBASE_L2_ON,
95 "L2 not powered up");
96 WARN_ONCE((!timedwait_cycle_count_active(kbdev)),
97 "Timed out on CYCLE_COUNT_ACTIVE");
98 #endif
99 kbase_backend_get_gpu_time_norequest(kbdev, cycle_counter, system_time,
100 ts);
101 #if !MALI_USE_CSF
102 kbase_pm_release_gpu_cycle_counter(kbdev);
103 #endif
104 }
105
kbase_get_timeout_ms(struct kbase_device * kbdev,enum kbase_timeout_selector selector)106 unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev,
107 enum kbase_timeout_selector selector)
108 {
109 /* Timeout calculation:
110 * dividing number of cycles by freq in KHz automatically gives value
111 * in milliseconds. nr_cycles will have to be multiplied by 1e3 to
112 * get result in microseconds, and 1e6 to get result in nanoseconds.
113 */
114
115 u64 timeout, nr_cycles = 0;
116 u64 freq_khz = kbdev->lowest_gpu_freq_khz;
117
118 WARN_ON(!freq_khz);
119
120 switch (selector) {
121 /* use Firmware timeout if invalid selection */
122 default:
123 #if !MALI_USE_CSF
124 WARN(1, "Invalid timeout selector used! Using default value");
125 timeout = JM_DEFAULT_TIMEOUT_CYCLES;
126 CSTD_UNUSED(nr_cycles);
127 #else
128 WARN(1,
129 "Invalid timeout selector used! Using CSF Firmware timeout");
130 fallthrough;
131 case CSF_FIRMWARE_TIMEOUT:
132 nr_cycles = CSF_FIRMWARE_TIMEOUT_CYCLES;
133 timeout = div_u64(nr_cycles, freq_khz);
134 /* cap CSF FW timeout to FIRMWARE_PING_INTERVAL_MS
135 * if calculated timeout exceeds it. This should be adapted to a
136 * direct timeout comparison once the FIRMWARE_PING_INTERVAL_MS
137 * option is added to this timeout function. A compile-time check
138 * such as BUILD_BUG_ON can also be done once the firmware ping
139 * interval in cycles becomes available as a macro.
140 */
141 if (timeout > FIRMWARE_PING_INTERVAL_MS) {
142 dev_dbg(kbdev->dev, "Capped CSF_FIRMWARE_TIMEOUT %llu to %d",
143 timeout, FIRMWARE_PING_INTERVAL_MS);
144 timeout = FIRMWARE_PING_INTERVAL_MS;
145 }
146 #endif
147 break;
148 }
149 return (unsigned int)timeout;
150 }
151
kbase_backend_get_cycle_cnt(struct kbase_device * kbdev)152 u64 kbase_backend_get_cycle_cnt(struct kbase_device *kbdev)
153 {
154 u32 hi1, hi2, lo;
155
156 /* Read hi, lo, hi to ensure a coherent u64 */
157 do {
158 hi1 = kbase_reg_read(kbdev,
159 GPU_CONTROL_REG(CYCLE_COUNT_HI));
160 lo = kbase_reg_read(kbdev,
161 GPU_CONTROL_REG(CYCLE_COUNT_LO));
162 hi2 = kbase_reg_read(kbdev,
163 GPU_CONTROL_REG(CYCLE_COUNT_HI));
164 } while (hi1 != hi2);
165
166 return lo | (((u64) hi1) << 32);
167 }
168