• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3  *
4  * (C) COPYRIGHT 2019-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 <linux/kernel.h>
23 #include <linux/device.h>
24 #include <linux/mutex.h>
25 #include <linux/sysfs.h>
26 #include <linux/of.h>
27 
28 #include "mali_kbase.h"
29 #include "mali_kbase_config_defaults.h"
30 #include "mali_kbase_csf_firmware.h"
31 #include "mali_kbase_csf_timeout.h"
32 #include "mali_kbase_reset_gpu.h"
33 #include "backend/gpu/mali_kbase_pm_internal.h"
34 
35 /**
36  * set_timeout - set a new global progress timeout.
37  *
38  * @kbdev:   Instance of a GPU platform device that implements a CSF interface.
39  * @timeout: the maximum number of GPU cycles without forward progress to allow
40  *           to elapse before terminating a GPU command queue group.
41  *
42  * Return:   0 on success, or negative on failure
43  *           (e.g. -ERANGE if the requested timeout is too large).
44  */
set_timeout(struct kbase_device * const kbdev,u64 const timeout)45 static int set_timeout(struct kbase_device *const kbdev, u64 const timeout)
46 {
47 	if (timeout > GLB_PROGRESS_TIMER_TIMEOUT_MAX) {
48 		dev_err(kbdev->dev, "Timeout %llu is too large.\n", timeout);
49 		return -ERANGE;
50 	}
51 
52 	dev_dbg(kbdev->dev, "New progress timeout: %llu cycles\n", timeout);
53 
54 	atomic64_set(&kbdev->csf.progress_timeout, timeout);
55 
56 	return 0;
57 }
58 
59 /**
60  * progress_timeout_store - Store the progress_timeout device attribute.
61  * @dev:   The device that has the attribute.
62  * @attr:  The attributes of the sysfs file.
63  * @buf:   The value written to the sysfs file.
64  * @count: The number of bytes written to the sysfs file.
65  *
66  * This function is called when the progress_timeout sysfs file is written to.
67  * It checks the data written, and if valid updates the progress timeout value.
68  * The function also checks gpu reset status, if the gpu is in reset process,
69  * the function will return an error code (-EBUSY), and no change for timeout
70  * value.
71  *
72  * Return: @count if the function succeeded. An error code on failure.
73  */
progress_timeout_store(struct device * const dev,struct device_attribute * const attr,const char * const buf,size_t const count)74 static ssize_t progress_timeout_store(struct device * const dev,
75 		struct device_attribute * const attr, const char * const buf,
76 		size_t const count)
77 {
78 	struct kbase_device *const kbdev = dev_get_drvdata(dev);
79 	int err;
80 	u64 timeout;
81 
82 	if (!kbdev)
83 		return -ENODEV;
84 
85 	err = kbase_reset_gpu_try_prevent(kbdev);
86 	if (err) {
87 		dev_warn(kbdev->dev,
88 			 "Couldn't process progress_timeout write operation for GPU reset.\n");
89 		return -EBUSY;
90 	}
91 
92 	err = kstrtou64(buf, 0, &timeout);
93 	if (err)
94 		dev_err(kbdev->dev,
95 			"Couldn't process progress_timeout write operation.\n"
96 			"Use format <progress_timeout>\n");
97 	else
98 		err = set_timeout(kbdev, timeout);
99 
100 	if (!err) {
101 		kbase_csf_scheduler_pm_active(kbdev);
102 
103 		err = kbase_csf_scheduler_wait_mcu_active(kbdev);
104 		if (!err)
105 			err = kbase_csf_firmware_set_timeout(kbdev, timeout);
106 
107 		kbase_csf_scheduler_pm_idle(kbdev);
108 	}
109 
110 	kbase_reset_gpu_allow(kbdev);
111 	if (err)
112 		return err;
113 
114 	return count;
115 }
116 
117 /**
118  * progress_timeout_show - Show the progress_timeout device attribute.
119  * @dev: The device that has the attribute.
120  * @attr: The attributes of the sysfs file.
121  * @buf:  The output buffer to receive the global timeout.
122  *
123  * This function is called to get the progress timeout value.
124  *
125  * Return: The number of bytes output to @buf.
126  */
progress_timeout_show(struct device * const dev,struct device_attribute * const attr,char * const buf)127 static ssize_t progress_timeout_show(struct device * const dev,
128 		struct device_attribute * const attr, char * const buf)
129 {
130 	struct kbase_device *const kbdev = dev_get_drvdata(dev);
131 	int err;
132 
133 	if (!kbdev)
134 		return -ENODEV;
135 
136 	err = scnprintf(buf, PAGE_SIZE, "%llu\n", kbase_csf_timeout_get(kbdev));
137 
138 	return err;
139 
140 }
141 
142 static DEVICE_ATTR(progress_timeout, 0644, progress_timeout_show,
143 	progress_timeout_store);
144 
kbase_csf_timeout_init(struct kbase_device * const kbdev)145 int kbase_csf_timeout_init(struct kbase_device *const kbdev)
146 {
147 	u64 timeout = DEFAULT_PROGRESS_TIMEOUT;
148 	int err;
149 
150 #if IS_ENABLED(CONFIG_OF)
151 	err = of_property_read_u64(kbdev->dev->of_node,
152 		"progress_timeout", &timeout);
153 	if (!err)
154 		dev_info(kbdev->dev, "Found progress_timeout = %llu in Devicetree\n",
155 			timeout);
156 #endif
157 
158 	err = set_timeout(kbdev, timeout);
159 	if (err)
160 		return err;
161 
162 	err = sysfs_create_file(&kbdev->dev->kobj,
163 		&dev_attr_progress_timeout.attr);
164 	if (err)
165 		dev_err(kbdev->dev, "SysFS file creation failed\n");
166 
167 	return err;
168 }
169 
kbase_csf_timeout_term(struct kbase_device * const kbdev)170 void kbase_csf_timeout_term(struct kbase_device * const kbdev)
171 {
172 	sysfs_remove_file(&kbdev->dev->kobj, &dev_attr_progress_timeout.attr);
173 }
174 
kbase_csf_timeout_get(struct kbase_device * const kbdev)175 u64 kbase_csf_timeout_get(struct kbase_device *const kbdev)
176 {
177 	return atomic64_read(&kbdev->csf.progress_timeout);
178 }
179