• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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