1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This program is free software and is provided to you under the terms of the
7*4882a593Smuzhiyun * GNU General Public License version 2 as published by the Free Software
8*4882a593Smuzhiyun * Foundation, and any use by you of this program is subject to the terms
9*4882a593Smuzhiyun * of such GNU license.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*4882a593Smuzhiyun * GNU General Public License for more details.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
17*4882a593Smuzhiyun * along with this program; if not, you can access it online at
18*4882a593Smuzhiyun * http://www.gnu.org/licenses/gpl-2.0.html.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <mali_kbase.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <linux/dma-buf.h>
25*4882a593Smuzhiyun #include <asm/cacheflush.h>
26*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SYNC_FILE)
27*4882a593Smuzhiyun #include <mali_kbase_sync.h>
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun #include <linux/dma-mapping.h>
30*4882a593Smuzhiyun #include <uapi/gpu/arm/bifrost/mali_base_kernel.h>
31*4882a593Smuzhiyun #include <mali_kbase_hwaccess_time.h>
32*4882a593Smuzhiyun #include <mali_kbase_kinstr_jm.h>
33*4882a593Smuzhiyun #include <mali_kbase_mem_linux.h>
34*4882a593Smuzhiyun #include <tl/mali_kbase_tracepoints.h>
35*4882a593Smuzhiyun #include <mali_linux_trace.h>
36*4882a593Smuzhiyun #include <linux/version.h>
37*4882a593Smuzhiyun #include <linux/ktime.h>
38*4882a593Smuzhiyun #include <linux/pfn.h>
39*4882a593Smuzhiyun #include <linux/sched.h>
40*4882a593Smuzhiyun #include <linux/kernel.h>
41*4882a593Smuzhiyun #include <linux/cache.h>
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #if !MALI_USE_CSF
44*4882a593Smuzhiyun /**
45*4882a593Smuzhiyun * DOC: This file implements the logic behind software only jobs that are
46*4882a593Smuzhiyun * executed within the driver rather than being handed over to the GPU.
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun
kbasep_add_waiting_soft_job(struct kbase_jd_atom * katom)49*4882a593Smuzhiyun static void kbasep_add_waiting_soft_job(struct kbase_jd_atom *katom)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
52*4882a593Smuzhiyun unsigned long lflags;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags);
55*4882a593Smuzhiyun list_add_tail(&katom->queue, &kctx->waiting_soft_jobs);
56*4882a593Smuzhiyun spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
kbasep_remove_waiting_soft_job(struct kbase_jd_atom * katom)59*4882a593Smuzhiyun void kbasep_remove_waiting_soft_job(struct kbase_jd_atom *katom)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
62*4882a593Smuzhiyun unsigned long lflags;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags);
65*4882a593Smuzhiyun list_del(&katom->queue);
66*4882a593Smuzhiyun spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
kbasep_add_waiting_with_timeout(struct kbase_jd_atom * katom)69*4882a593Smuzhiyun static void kbasep_add_waiting_with_timeout(struct kbase_jd_atom *katom)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Record the start time of this atom so we could cancel it at
74*4882a593Smuzhiyun * the right time.
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun katom->start_timestamp = ktime_get_raw();
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* Add the atom to the waiting list before the timer is
79*4882a593Smuzhiyun * (re)started to make sure that it gets processed.
80*4882a593Smuzhiyun */
81*4882a593Smuzhiyun kbasep_add_waiting_soft_job(katom);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* Schedule timeout of this atom after a period if it is not active */
84*4882a593Smuzhiyun if (!timer_pending(&kctx->soft_job_timeout)) {
85*4882a593Smuzhiyun int timeout_ms = atomic_read(
86*4882a593Smuzhiyun &kctx->kbdev->js_data.soft_job_timeout_ms);
87*4882a593Smuzhiyun mod_timer(&kctx->soft_job_timeout,
88*4882a593Smuzhiyun jiffies + msecs_to_jiffies(timeout_ms));
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
kbasep_read_soft_event_status(struct kbase_context * kctx,u64 evt,unsigned char * status)92*4882a593Smuzhiyun static int kbasep_read_soft_event_status(
93*4882a593Smuzhiyun struct kbase_context *kctx, u64 evt, unsigned char *status)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun unsigned char *mapped_evt;
96*4882a593Smuzhiyun struct kbase_vmap_struct map;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun mapped_evt = kbase_vmap_prot(kctx, evt, sizeof(*mapped_evt),
99*4882a593Smuzhiyun KBASE_REG_CPU_RD, &map);
100*4882a593Smuzhiyun if (!mapped_evt)
101*4882a593Smuzhiyun return -EFAULT;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun *status = *mapped_evt;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun kbase_vunmap(kctx, &map);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
kbasep_write_soft_event_status(struct kbase_context * kctx,u64 evt,unsigned char new_status)110*4882a593Smuzhiyun static int kbasep_write_soft_event_status(
111*4882a593Smuzhiyun struct kbase_context *kctx, u64 evt, unsigned char new_status)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun unsigned char *mapped_evt;
114*4882a593Smuzhiyun struct kbase_vmap_struct map;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if ((new_status != BASE_JD_SOFT_EVENT_SET) &&
117*4882a593Smuzhiyun (new_status != BASE_JD_SOFT_EVENT_RESET))
118*4882a593Smuzhiyun return -EINVAL;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun mapped_evt = kbase_vmap_prot(kctx, evt, sizeof(*mapped_evt),
121*4882a593Smuzhiyun KBASE_REG_CPU_WR, &map);
122*4882a593Smuzhiyun if (!mapped_evt)
123*4882a593Smuzhiyun return -EFAULT;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun *mapped_evt = new_status;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun kbase_vunmap(kctx, &map);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun return 0;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
kbase_dump_cpu_gpu_time(struct kbase_jd_atom * katom)132*4882a593Smuzhiyun static int kbase_dump_cpu_gpu_time(struct kbase_jd_atom *katom)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun struct kbase_vmap_struct map;
135*4882a593Smuzhiyun void *user_result;
136*4882a593Smuzhiyun struct timespec64 ts;
137*4882a593Smuzhiyun struct base_dump_cpu_gpu_counters data;
138*4882a593Smuzhiyun u64 system_time = 0ULL;
139*4882a593Smuzhiyun u64 cycle_counter;
140*4882a593Smuzhiyun u64 jc = katom->jc;
141*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
142*4882a593Smuzhiyun int pm_active_err;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun memset(&data, 0, sizeof(data));
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* Take the PM active reference as late as possible - otherwise, it could
147*4882a593Smuzhiyun * delay suspend until we process the atom (which may be at the end of a
148*4882a593Smuzhiyun * long chain of dependencies
149*4882a593Smuzhiyun */
150*4882a593Smuzhiyun #ifdef CONFIG_MALI_ARBITER_SUPPORT
151*4882a593Smuzhiyun atomic_inc(&kctx->kbdev->pm.gpu_users_waiting);
152*4882a593Smuzhiyun #endif /* CONFIG_MALI_ARBITER_SUPPORT */
153*4882a593Smuzhiyun pm_active_err = kbase_pm_context_active_handle_suspend(kctx->kbdev, KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE);
154*4882a593Smuzhiyun if (pm_active_err) {
155*4882a593Smuzhiyun struct kbasep_js_device_data *js_devdata = &kctx->kbdev->js_data;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* We're suspended - queue this on the list of suspended jobs
158*4882a593Smuzhiyun * Use dep_item[1], because dep_item[0] was previously in use
159*4882a593Smuzhiyun * for 'waiting_soft_jobs'.
160*4882a593Smuzhiyun */
161*4882a593Smuzhiyun mutex_lock(&js_devdata->runpool_mutex);
162*4882a593Smuzhiyun list_add_tail(&katom->dep_item[1], &js_devdata->suspended_soft_jobs_list);
163*4882a593Smuzhiyun mutex_unlock(&js_devdata->runpool_mutex);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* Also adding this to the list of waiting soft job */
166*4882a593Smuzhiyun kbasep_add_waiting_soft_job(katom);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun return pm_active_err;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun #ifdef CONFIG_MALI_ARBITER_SUPPORT
171*4882a593Smuzhiyun else
172*4882a593Smuzhiyun atomic_dec(&kctx->kbdev->pm.gpu_users_waiting);
173*4882a593Smuzhiyun #endif /* CONFIG_MALI_ARBITER_SUPPORT */
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun kbase_backend_get_gpu_time(kctx->kbdev, &cycle_counter, &system_time,
176*4882a593Smuzhiyun &ts);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun kbase_pm_context_idle(kctx->kbdev);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun data.sec = ts.tv_sec;
181*4882a593Smuzhiyun data.usec = ts.tv_nsec / 1000;
182*4882a593Smuzhiyun data.system_time = system_time;
183*4882a593Smuzhiyun data.cycle_counter = cycle_counter;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /* Assume this atom will be cancelled until we know otherwise */
186*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* GPU_WR access is checked on the range for returning the result to
189*4882a593Smuzhiyun * userspace for the following reasons:
190*4882a593Smuzhiyun * - security, this is currently how imported user bufs are checked.
191*4882a593Smuzhiyun * - userspace ddk guaranteed to assume region was mapped as GPU_WR
192*4882a593Smuzhiyun */
193*4882a593Smuzhiyun user_result = kbase_vmap_prot(kctx, jc, sizeof(data), KBASE_REG_GPU_WR, &map);
194*4882a593Smuzhiyun if (!user_result)
195*4882a593Smuzhiyun return 0;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun memcpy(user_result, &data, sizeof(data));
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun kbase_vunmap(kctx, &map);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* Atom was fine - mark it as done */
202*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_DONE;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SYNC_FILE)
208*4882a593Smuzhiyun /* Called by the explicit fence mechanism when a fence wait has completed */
kbase_soft_event_wait_callback(struct kbase_jd_atom * katom)209*4882a593Smuzhiyun void kbase_soft_event_wait_callback(struct kbase_jd_atom *katom)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun mutex_lock(&kctx->jctx.lock);
214*4882a593Smuzhiyun kbasep_remove_waiting_soft_job(katom);
215*4882a593Smuzhiyun kbase_finish_soft_job(katom);
216*4882a593Smuzhiyun if (kbase_jd_done_nolock(katom, true))
217*4882a593Smuzhiyun kbase_js_sched_all(kctx->kbdev);
218*4882a593Smuzhiyun mutex_unlock(&kctx->jctx.lock);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun #endif
221*4882a593Smuzhiyun
kbasep_soft_event_complete_job(struct work_struct * work)222*4882a593Smuzhiyun static void kbasep_soft_event_complete_job(struct work_struct *work)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun struct kbase_jd_atom *katom = container_of(work, struct kbase_jd_atom,
225*4882a593Smuzhiyun work);
226*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
227*4882a593Smuzhiyun int resched;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun mutex_lock(&kctx->jctx.lock);
230*4882a593Smuzhiyun resched = kbase_jd_done_nolock(katom, true);
231*4882a593Smuzhiyun mutex_unlock(&kctx->jctx.lock);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (resched)
234*4882a593Smuzhiyun kbase_js_sched_all(kctx->kbdev);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
kbasep_complete_triggered_soft_events(struct kbase_context * kctx,u64 evt)237*4882a593Smuzhiyun void kbasep_complete_triggered_soft_events(struct kbase_context *kctx, u64 evt)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun int cancel_timer = 1;
240*4882a593Smuzhiyun struct list_head *entry, *tmp;
241*4882a593Smuzhiyun unsigned long lflags;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags);
244*4882a593Smuzhiyun list_for_each_safe(entry, tmp, &kctx->waiting_soft_jobs) {
245*4882a593Smuzhiyun struct kbase_jd_atom *katom = list_entry(
246*4882a593Smuzhiyun entry, struct kbase_jd_atom, queue);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) {
249*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_WAIT:
250*4882a593Smuzhiyun if (katom->jc == evt) {
251*4882a593Smuzhiyun list_del(&katom->queue);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_DONE;
254*4882a593Smuzhiyun INIT_WORK(&katom->work,
255*4882a593Smuzhiyun kbasep_soft_event_complete_job);
256*4882a593Smuzhiyun queue_work(kctx->jctx.job_done_wq,
257*4882a593Smuzhiyun &katom->work);
258*4882a593Smuzhiyun } else {
259*4882a593Smuzhiyun /* There are still other waiting jobs, we cannot
260*4882a593Smuzhiyun * cancel the timer yet.
261*4882a593Smuzhiyun */
262*4882a593Smuzhiyun cancel_timer = 0;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun break;
265*4882a593Smuzhiyun #ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG
266*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_WAIT:
267*4882a593Smuzhiyun /* Keep the timer running if fence debug is enabled and
268*4882a593Smuzhiyun * there are waiting fence jobs.
269*4882a593Smuzhiyun */
270*4882a593Smuzhiyun cancel_timer = 0;
271*4882a593Smuzhiyun break;
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (cancel_timer)
277*4882a593Smuzhiyun del_timer(&kctx->soft_job_timeout);
278*4882a593Smuzhiyun spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun #ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG
kbase_fence_debug_check_atom(struct kbase_jd_atom * katom)282*4882a593Smuzhiyun static void kbase_fence_debug_check_atom(struct kbase_jd_atom *katom)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
285*4882a593Smuzhiyun struct device *dev = kctx->kbdev->dev;
286*4882a593Smuzhiyun int i;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun for (i = 0; i < 2; i++) {
289*4882a593Smuzhiyun struct kbase_jd_atom *dep;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun list_for_each_entry(dep, &katom->dep_head[i], dep_item[i]) {
292*4882a593Smuzhiyun if (dep->status == KBASE_JD_ATOM_STATE_UNUSED ||
293*4882a593Smuzhiyun dep->status == KBASE_JD_ATOM_STATE_COMPLETED)
294*4882a593Smuzhiyun continue;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if ((dep->core_req & BASE_JD_REQ_SOFT_JOB_TYPE)
297*4882a593Smuzhiyun == BASE_JD_REQ_SOFT_FENCE_TRIGGER) {
298*4882a593Smuzhiyun /* Found blocked trigger fence. */
299*4882a593Smuzhiyun struct kbase_sync_fence_info info;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (!kbase_sync_fence_in_info_get(dep, &info)) {
302*4882a593Smuzhiyun dev_warn(dev,
303*4882a593Smuzhiyun "\tVictim trigger atom %d fence [%pK] %s: %s\n",
304*4882a593Smuzhiyun kbase_jd_atom_id(kctx, dep),
305*4882a593Smuzhiyun info.fence,
306*4882a593Smuzhiyun info.name,
307*4882a593Smuzhiyun kbase_sync_status_string(info.status));
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun kbase_fence_debug_check_atom(dep);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
kbase_fence_debug_wait_timeout(struct kbase_jd_atom * katom)316*4882a593Smuzhiyun static void kbase_fence_debug_wait_timeout(struct kbase_jd_atom *katom)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
319*4882a593Smuzhiyun struct device *dev = katom->kctx->kbdev->dev;
320*4882a593Smuzhiyun int timeout_ms = atomic_read(&kctx->kbdev->js_data.soft_job_timeout_ms);
321*4882a593Smuzhiyun unsigned long lflags;
322*4882a593Smuzhiyun struct kbase_sync_fence_info info;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun if (kbase_sync_fence_in_info_get(katom, &info)) {
327*4882a593Smuzhiyun /* Fence must have signaled just after timeout. */
328*4882a593Smuzhiyun spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags);
329*4882a593Smuzhiyun return;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun dev_warn(dev, "ctx %d_%d: Atom %d still waiting for fence [%pK] after %dms\n",
333*4882a593Smuzhiyun kctx->tgid, kctx->id,
334*4882a593Smuzhiyun kbase_jd_atom_id(kctx, katom),
335*4882a593Smuzhiyun info.fence, timeout_ms);
336*4882a593Smuzhiyun dev_warn(dev, "\tGuilty fence [%pK] %s: %s\n",
337*4882a593Smuzhiyun info.fence, info.name,
338*4882a593Smuzhiyun kbase_sync_status_string(info.status));
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* Search for blocked trigger atoms */
341*4882a593Smuzhiyun kbase_fence_debug_check_atom(katom);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun kbase_sync_fence_in_dump(katom);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun struct kbase_fence_debug_work {
349*4882a593Smuzhiyun struct kbase_jd_atom *katom;
350*4882a593Smuzhiyun struct work_struct work;
351*4882a593Smuzhiyun };
352*4882a593Smuzhiyun
kbase_fence_debug_wait_timeout_worker(struct work_struct * work)353*4882a593Smuzhiyun static void kbase_fence_debug_wait_timeout_worker(struct work_struct *work)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct kbase_fence_debug_work *w = container_of(work,
356*4882a593Smuzhiyun struct kbase_fence_debug_work, work);
357*4882a593Smuzhiyun struct kbase_jd_atom *katom = w->katom;
358*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun mutex_lock(&kctx->jctx.lock);
361*4882a593Smuzhiyun kbase_fence_debug_wait_timeout(katom);
362*4882a593Smuzhiyun mutex_unlock(&kctx->jctx.lock);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun kfree(w);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
kbase_fence_debug_timeout(struct kbase_jd_atom * katom)367*4882a593Smuzhiyun static void kbase_fence_debug_timeout(struct kbase_jd_atom *katom)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct kbase_fence_debug_work *work;
370*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /* Enqueue fence debug worker. Use job_done_wq to get
373*4882a593Smuzhiyun * debug print ordered with job completion.
374*4882a593Smuzhiyun */
375*4882a593Smuzhiyun work = kzalloc(sizeof(struct kbase_fence_debug_work), GFP_ATOMIC);
376*4882a593Smuzhiyun /* Ignore allocation failure. */
377*4882a593Smuzhiyun if (work) {
378*4882a593Smuzhiyun work->katom = katom;
379*4882a593Smuzhiyun INIT_WORK(&work->work, kbase_fence_debug_wait_timeout_worker);
380*4882a593Smuzhiyun queue_work(kctx->jctx.job_done_wq, &work->work);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun #endif /* CONFIG_MALI_BIFROST_FENCE_DEBUG */
384*4882a593Smuzhiyun
kbasep_soft_job_timeout_worker(struct timer_list * timer)385*4882a593Smuzhiyun void kbasep_soft_job_timeout_worker(struct timer_list *timer)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun struct kbase_context *kctx = container_of(timer, struct kbase_context,
388*4882a593Smuzhiyun soft_job_timeout);
389*4882a593Smuzhiyun u32 timeout_ms = (u32)atomic_read(
390*4882a593Smuzhiyun &kctx->kbdev->js_data.soft_job_timeout_ms);
391*4882a593Smuzhiyun ktime_t cur_time = ktime_get_raw();
392*4882a593Smuzhiyun bool restarting = false;
393*4882a593Smuzhiyun unsigned long lflags;
394*4882a593Smuzhiyun struct list_head *entry, *tmp;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags);
397*4882a593Smuzhiyun list_for_each_safe(entry, tmp, &kctx->waiting_soft_jobs) {
398*4882a593Smuzhiyun struct kbase_jd_atom *katom = list_entry(entry,
399*4882a593Smuzhiyun struct kbase_jd_atom, queue);
400*4882a593Smuzhiyun s64 elapsed_time = ktime_to_ms(ktime_sub(cur_time,
401*4882a593Smuzhiyun katom->start_timestamp));
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (elapsed_time < (s64)timeout_ms) {
404*4882a593Smuzhiyun restarting = true;
405*4882a593Smuzhiyun continue;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) {
409*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_WAIT:
410*4882a593Smuzhiyun /* Take it out of the list to ensure that it
411*4882a593Smuzhiyun * will be cancelled in all cases
412*4882a593Smuzhiyun */
413*4882a593Smuzhiyun list_del(&katom->queue);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
416*4882a593Smuzhiyun INIT_WORK(&katom->work, kbasep_soft_event_complete_job);
417*4882a593Smuzhiyun queue_work(kctx->jctx.job_done_wq, &katom->work);
418*4882a593Smuzhiyun break;
419*4882a593Smuzhiyun #ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG
420*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_WAIT:
421*4882a593Smuzhiyun kbase_fence_debug_timeout(katom);
422*4882a593Smuzhiyun break;
423*4882a593Smuzhiyun #endif
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun if (restarting)
428*4882a593Smuzhiyun mod_timer(timer, jiffies + msecs_to_jiffies(timeout_ms));
429*4882a593Smuzhiyun spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags);
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
kbasep_soft_event_wait(struct kbase_jd_atom * katom)432*4882a593Smuzhiyun static int kbasep_soft_event_wait(struct kbase_jd_atom *katom)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
435*4882a593Smuzhiyun unsigned char status;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* The status of this soft-job is stored in jc */
438*4882a593Smuzhiyun if (kbasep_read_soft_event_status(kctx, katom->jc, &status)) {
439*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
440*4882a593Smuzhiyun return 0;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun if (status == BASE_JD_SOFT_EVENT_SET)
444*4882a593Smuzhiyun return 0; /* Event already set, nothing to do */
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun kbasep_add_waiting_with_timeout(katom);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun return 1;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
kbasep_soft_event_update_locked(struct kbase_jd_atom * katom,unsigned char new_status)451*4882a593Smuzhiyun static void kbasep_soft_event_update_locked(struct kbase_jd_atom *katom,
452*4882a593Smuzhiyun unsigned char new_status)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun /* Complete jobs waiting on the same event */
455*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun if (kbasep_write_soft_event_status(kctx, katom->jc, new_status) != 0) {
458*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
459*4882a593Smuzhiyun return;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if (new_status == BASE_JD_SOFT_EVENT_SET)
463*4882a593Smuzhiyun kbasep_complete_triggered_soft_events(kctx, katom->jc);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /**
467*4882a593Smuzhiyun * kbase_soft_event_update() - Update soft event state
468*4882a593Smuzhiyun * @kctx: Pointer to context
469*4882a593Smuzhiyun * @event: Event to update
470*4882a593Smuzhiyun * @new_status: New status value of event
471*4882a593Smuzhiyun *
472*4882a593Smuzhiyun * Update the event, and wake up any atoms waiting for the event.
473*4882a593Smuzhiyun *
474*4882a593Smuzhiyun * Return: 0 on success, a negative error code on failure.
475*4882a593Smuzhiyun */
kbase_soft_event_update(struct kbase_context * kctx,u64 event,unsigned char new_status)476*4882a593Smuzhiyun int kbase_soft_event_update(struct kbase_context *kctx,
477*4882a593Smuzhiyun u64 event,
478*4882a593Smuzhiyun unsigned char new_status)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun int err = 0;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun mutex_lock(&kctx->jctx.lock);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun if (kbasep_write_soft_event_status(kctx, event, new_status)) {
485*4882a593Smuzhiyun err = -ENOENT;
486*4882a593Smuzhiyun goto out;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (new_status == BASE_JD_SOFT_EVENT_SET)
490*4882a593Smuzhiyun kbasep_complete_triggered_soft_events(kctx, event);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun out:
493*4882a593Smuzhiyun mutex_unlock(&kctx->jctx.lock);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun return err;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
kbasep_soft_event_cancel_job(struct kbase_jd_atom * katom)498*4882a593Smuzhiyun static void kbasep_soft_event_cancel_job(struct kbase_jd_atom *katom)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
501*4882a593Smuzhiyun if (kbase_jd_done_nolock(katom, true))
502*4882a593Smuzhiyun kbase_js_sched_all(katom->kctx->kbdev);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST
kbase_debug_copy_finish(struct kbase_jd_atom * katom)506*4882a593Smuzhiyun static void kbase_debug_copy_finish(struct kbase_jd_atom *katom)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun struct kbase_debug_copy_buffer *buffers = katom->softjob_data;
509*4882a593Smuzhiyun unsigned int i;
510*4882a593Smuzhiyun unsigned int nr = katom->nr_extres;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun if (!buffers)
513*4882a593Smuzhiyun return;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun kbase_gpu_vm_lock(katom->kctx);
516*4882a593Smuzhiyun for (i = 0; i < nr; i++) {
517*4882a593Smuzhiyun int p;
518*4882a593Smuzhiyun struct kbase_mem_phy_alloc *gpu_alloc = buffers[i].gpu_alloc;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun if (!buffers[i].pages)
521*4882a593Smuzhiyun break;
522*4882a593Smuzhiyun for (p = 0; p < buffers[i].nr_pages; p++) {
523*4882a593Smuzhiyun struct page *pg = buffers[i].pages[p];
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (pg)
526*4882a593Smuzhiyun put_page(pg);
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun if (buffers[i].is_vmalloc)
529*4882a593Smuzhiyun vfree(buffers[i].pages);
530*4882a593Smuzhiyun else
531*4882a593Smuzhiyun kfree(buffers[i].pages);
532*4882a593Smuzhiyun if (gpu_alloc) {
533*4882a593Smuzhiyun switch (gpu_alloc->type) {
534*4882a593Smuzhiyun case KBASE_MEM_TYPE_IMPORTED_USER_BUF:
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun kbase_free_user_buffer(&buffers[i]);
537*4882a593Smuzhiyun break;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun default:
540*4882a593Smuzhiyun /* Nothing to be done. */
541*4882a593Smuzhiyun break;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun kbase_mem_phy_alloc_put(gpu_alloc);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun kbase_gpu_vm_unlock(katom->kctx);
547*4882a593Smuzhiyun kfree(buffers);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun katom->softjob_data = NULL;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
kbase_debug_copy_prepare(struct kbase_jd_atom * katom)552*4882a593Smuzhiyun static int kbase_debug_copy_prepare(struct kbase_jd_atom *katom)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun struct kbase_debug_copy_buffer *buffers;
555*4882a593Smuzhiyun struct base_jd_debug_copy_buffer *user_buffers = NULL;
556*4882a593Smuzhiyun unsigned int i;
557*4882a593Smuzhiyun unsigned int nr = katom->nr_extres;
558*4882a593Smuzhiyun int ret = 0;
559*4882a593Smuzhiyun void __user *user_structs = (void __user *)(uintptr_t)katom->jc;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun if (!user_structs)
562*4882a593Smuzhiyun return -EINVAL;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun buffers = kcalloc(nr, sizeof(*buffers), GFP_KERNEL);
565*4882a593Smuzhiyun if (!buffers) {
566*4882a593Smuzhiyun ret = -ENOMEM;
567*4882a593Smuzhiyun goto out_cleanup;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun katom->softjob_data = buffers;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun user_buffers = kmalloc_array(nr, sizeof(*user_buffers), GFP_KERNEL);
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun if (!user_buffers) {
574*4882a593Smuzhiyun ret = -ENOMEM;
575*4882a593Smuzhiyun goto out_cleanup;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun ret = copy_from_user(user_buffers, user_structs,
579*4882a593Smuzhiyun sizeof(*user_buffers)*nr);
580*4882a593Smuzhiyun if (ret) {
581*4882a593Smuzhiyun ret = -EFAULT;
582*4882a593Smuzhiyun goto out_cleanup;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun for (i = 0; i < nr; i++) {
586*4882a593Smuzhiyun u64 addr = user_buffers[i].address;
587*4882a593Smuzhiyun u64 page_addr = addr & PAGE_MASK;
588*4882a593Smuzhiyun u64 end_page_addr = addr + user_buffers[i].size - 1;
589*4882a593Smuzhiyun u64 last_page_addr = end_page_addr & PAGE_MASK;
590*4882a593Smuzhiyun int nr_pages = (last_page_addr-page_addr)/PAGE_SIZE+1;
591*4882a593Smuzhiyun int pinned_pages;
592*4882a593Smuzhiyun struct kbase_va_region *reg;
593*4882a593Smuzhiyun struct base_external_resource user_extres;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun if (!addr)
596*4882a593Smuzhiyun continue;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun if (last_page_addr < page_addr) {
599*4882a593Smuzhiyun ret = -EINVAL;
600*4882a593Smuzhiyun goto out_cleanup;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun buffers[i].nr_pages = nr_pages;
604*4882a593Smuzhiyun buffers[i].offset = addr & ~PAGE_MASK;
605*4882a593Smuzhiyun if (buffers[i].offset >= PAGE_SIZE) {
606*4882a593Smuzhiyun ret = -EINVAL;
607*4882a593Smuzhiyun goto out_cleanup;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun buffers[i].size = user_buffers[i].size;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun if (nr_pages > (KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD /
612*4882a593Smuzhiyun sizeof(struct page *))) {
613*4882a593Smuzhiyun buffers[i].is_vmalloc = true;
614*4882a593Smuzhiyun buffers[i].pages = vzalloc(nr_pages *
615*4882a593Smuzhiyun sizeof(struct page *));
616*4882a593Smuzhiyun } else {
617*4882a593Smuzhiyun buffers[i].is_vmalloc = false;
618*4882a593Smuzhiyun buffers[i].pages = kcalloc(nr_pages,
619*4882a593Smuzhiyun sizeof(struct page *), GFP_KERNEL);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun if (!buffers[i].pages) {
623*4882a593Smuzhiyun ret = -ENOMEM;
624*4882a593Smuzhiyun goto out_cleanup;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun pinned_pages = get_user_pages_fast(page_addr,
628*4882a593Smuzhiyun nr_pages,
629*4882a593Smuzhiyun 1, /* Write */
630*4882a593Smuzhiyun buffers[i].pages);
631*4882a593Smuzhiyun if (pinned_pages < 0) {
632*4882a593Smuzhiyun /* get_user_pages_fast has failed - page array is not
633*4882a593Smuzhiyun * valid. Don't try to release any pages.
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun buffers[i].nr_pages = 0;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun ret = pinned_pages;
638*4882a593Smuzhiyun goto out_cleanup;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun if (pinned_pages != nr_pages) {
641*4882a593Smuzhiyun /* Adjust number of pages, so that we only attempt to
642*4882a593Smuzhiyun * release pages in the array that we know are valid.
643*4882a593Smuzhiyun */
644*4882a593Smuzhiyun buffers[i].nr_pages = pinned_pages;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun ret = -EINVAL;
647*4882a593Smuzhiyun goto out_cleanup;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun user_extres = user_buffers[i].extres;
651*4882a593Smuzhiyun if (user_extres.ext_resource == 0ULL) {
652*4882a593Smuzhiyun ret = -EINVAL;
653*4882a593Smuzhiyun goto out_cleanup;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun kbase_gpu_vm_lock(katom->kctx);
657*4882a593Smuzhiyun reg = kbase_region_tracker_find_region_enclosing_address(
658*4882a593Smuzhiyun katom->kctx, user_extres.ext_resource &
659*4882a593Smuzhiyun ~BASE_EXT_RES_ACCESS_EXCLUSIVE);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (kbase_is_region_invalid_or_free(reg) ||
662*4882a593Smuzhiyun reg->gpu_alloc == NULL) {
663*4882a593Smuzhiyun ret = -EINVAL;
664*4882a593Smuzhiyun goto out_unlock;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun buffers[i].gpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc);
668*4882a593Smuzhiyun buffers[i].nr_extres_pages = reg->nr_pages;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (reg->nr_pages*PAGE_SIZE != buffers[i].size)
671*4882a593Smuzhiyun dev_warn(katom->kctx->kbdev->dev, "Copy buffer is not of same size as the external resource to copy.\n");
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun switch (reg->gpu_alloc->type) {
674*4882a593Smuzhiyun case KBASE_MEM_TYPE_IMPORTED_USER_BUF:
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc;
677*4882a593Smuzhiyun const unsigned long nr_pages = alloc->imported.user_buf.nr_pages;
678*4882a593Smuzhiyun const unsigned long start = alloc->imported.user_buf.address;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun if (alloc->imported.user_buf.mm != current->mm) {
681*4882a593Smuzhiyun ret = -EINVAL;
682*4882a593Smuzhiyun goto out_unlock;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun buffers[i].extres_pages = kcalloc(nr_pages,
685*4882a593Smuzhiyun sizeof(struct page *), GFP_KERNEL);
686*4882a593Smuzhiyun if (!buffers[i].extres_pages) {
687*4882a593Smuzhiyun ret = -ENOMEM;
688*4882a593Smuzhiyun goto out_unlock;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun kbase_gpu_vm_unlock(katom->kctx);
691*4882a593Smuzhiyun ret = get_user_pages_fast(start, nr_pages, 0, buffers[i].extres_pages);
692*4882a593Smuzhiyun kbase_gpu_vm_lock(katom->kctx);
693*4882a593Smuzhiyun if (ret != nr_pages) {
694*4882a593Smuzhiyun /* Adjust number of pages, so that we only
695*4882a593Smuzhiyun * attempt to release pages in the array that we
696*4882a593Smuzhiyun * know are valid.
697*4882a593Smuzhiyun */
698*4882a593Smuzhiyun if (ret < 0)
699*4882a593Smuzhiyun buffers[i].nr_extres_pages = 0;
700*4882a593Smuzhiyun else
701*4882a593Smuzhiyun buffers[i].nr_extres_pages = ret;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun goto out_unlock;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun ret = 0;
706*4882a593Smuzhiyun break;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun default:
709*4882a593Smuzhiyun /* Nothing to be done. */
710*4882a593Smuzhiyun break;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun kbase_gpu_vm_unlock(katom->kctx);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun kfree(user_buffers);
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun return ret;
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun out_unlock:
719*4882a593Smuzhiyun kbase_gpu_vm_unlock(katom->kctx);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun out_cleanup:
722*4882a593Smuzhiyun /* Frees allocated memory for kbase_debug_copy_job struct, including
723*4882a593Smuzhiyun * members, and sets jc to 0
724*4882a593Smuzhiyun */
725*4882a593Smuzhiyun kbase_debug_copy_finish(katom);
726*4882a593Smuzhiyun kfree(user_buffers);
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun return ret;
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun #if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE
dma_buf_kmap_page(struct kbase_mem_phy_alloc * gpu_alloc,unsigned long page_num,struct page ** page)732*4882a593Smuzhiyun static void *dma_buf_kmap_page(struct kbase_mem_phy_alloc *gpu_alloc,
733*4882a593Smuzhiyun unsigned long page_num, struct page **page)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun struct sg_table *sgt = gpu_alloc->imported.umm.sgt;
736*4882a593Smuzhiyun struct sg_page_iter sg_iter;
737*4882a593Smuzhiyun unsigned long page_index = 0;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun if (WARN_ON(gpu_alloc->type != KBASE_MEM_TYPE_IMPORTED_UMM))
740*4882a593Smuzhiyun return NULL;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun if (!sgt)
743*4882a593Smuzhiyun return NULL;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun if (WARN_ON(page_num >= gpu_alloc->nents))
746*4882a593Smuzhiyun return NULL;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun for_each_sg_page(sgt->sgl, &sg_iter, sgt->nents, 0) {
749*4882a593Smuzhiyun if (page_index == page_num) {
750*4882a593Smuzhiyun *page = sg_page_iter_page(&sg_iter);
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun return kmap(*page);
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun page_index++;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun return NULL;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun #endif
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun /**
762*4882a593Smuzhiyun * kbase_mem_copy_from_extres() - Copy from external resources.
763*4882a593Smuzhiyun *
764*4882a593Smuzhiyun * @kctx: kbase context within which the copying is to take place.
765*4882a593Smuzhiyun * @buf_data: Pointer to the information about external resources:
766*4882a593Smuzhiyun * pages pertaining to the external resource, number of
767*4882a593Smuzhiyun * pages to copy.
768*4882a593Smuzhiyun *
769*4882a593Smuzhiyun * Return: 0 on success, error code otherwise.
770*4882a593Smuzhiyun */
kbase_mem_copy_from_extres(struct kbase_context * kctx,struct kbase_debug_copy_buffer * buf_data)771*4882a593Smuzhiyun static int kbase_mem_copy_from_extres(struct kbase_context *kctx,
772*4882a593Smuzhiyun struct kbase_debug_copy_buffer *buf_data)
773*4882a593Smuzhiyun {
774*4882a593Smuzhiyun unsigned int i;
775*4882a593Smuzhiyun unsigned int target_page_nr = 0;
776*4882a593Smuzhiyun struct page **pages = buf_data->pages;
777*4882a593Smuzhiyun u64 offset = buf_data->offset;
778*4882a593Smuzhiyun size_t extres_size = buf_data->nr_extres_pages*PAGE_SIZE;
779*4882a593Smuzhiyun size_t to_copy = min(extres_size, buf_data->size);
780*4882a593Smuzhiyun struct kbase_mem_phy_alloc *gpu_alloc = buf_data->gpu_alloc;
781*4882a593Smuzhiyun int ret = 0;
782*4882a593Smuzhiyun size_t dma_to_copy;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun KBASE_DEBUG_ASSERT(pages != NULL);
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun kbase_gpu_vm_lock(kctx);
787*4882a593Smuzhiyun if (!gpu_alloc) {
788*4882a593Smuzhiyun ret = -EINVAL;
789*4882a593Smuzhiyun goto out_unlock;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun switch (gpu_alloc->type) {
793*4882a593Smuzhiyun case KBASE_MEM_TYPE_IMPORTED_USER_BUF:
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun for (i = 0; i < buf_data->nr_extres_pages &&
796*4882a593Smuzhiyun target_page_nr < buf_data->nr_pages; i++) {
797*4882a593Smuzhiyun struct page *pg = buf_data->extres_pages[i];
798*4882a593Smuzhiyun void *extres_page = kmap(pg);
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun if (extres_page) {
801*4882a593Smuzhiyun ret = kbase_mem_copy_to_pinned_user_pages(
802*4882a593Smuzhiyun pages, extres_page, &to_copy,
803*4882a593Smuzhiyun buf_data->nr_pages,
804*4882a593Smuzhiyun &target_page_nr, offset);
805*4882a593Smuzhiyun kunmap(pg);
806*4882a593Smuzhiyun if (ret)
807*4882a593Smuzhiyun goto out_unlock;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun break;
812*4882a593Smuzhiyun case KBASE_MEM_TYPE_IMPORTED_UMM: {
813*4882a593Smuzhiyun struct dma_buf *dma_buf = gpu_alloc->imported.umm.dma_buf;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun KBASE_DEBUG_ASSERT(dma_buf != NULL);
816*4882a593Smuzhiyun if (dma_buf->size > buf_data->nr_extres_pages * PAGE_SIZE)
817*4882a593Smuzhiyun dev_warn(kctx->kbdev->dev, "External resources buffer size mismatch");
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun dma_to_copy = min(dma_buf->size,
820*4882a593Smuzhiyun (size_t)(buf_data->nr_extres_pages * PAGE_SIZE));
821*4882a593Smuzhiyun ret = dma_buf_begin_cpu_access(dma_buf, DMA_FROM_DEVICE);
822*4882a593Smuzhiyun if (ret)
823*4882a593Smuzhiyun goto out_unlock;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun for (i = 0; i < dma_to_copy/PAGE_SIZE &&
826*4882a593Smuzhiyun target_page_nr < buf_data->nr_pages; i++) {
827*4882a593Smuzhiyun #if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE
828*4882a593Smuzhiyun struct page *pg;
829*4882a593Smuzhiyun void *extres_page = dma_buf_kmap_page(gpu_alloc, i, &pg);
830*4882a593Smuzhiyun #else
831*4882a593Smuzhiyun void *extres_page = dma_buf_kmap(dma_buf, i);
832*4882a593Smuzhiyun #endif
833*4882a593Smuzhiyun if (extres_page) {
834*4882a593Smuzhiyun ret = kbase_mem_copy_to_pinned_user_pages(
835*4882a593Smuzhiyun pages, extres_page, &to_copy,
836*4882a593Smuzhiyun buf_data->nr_pages,
837*4882a593Smuzhiyun &target_page_nr, offset);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun #if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE
840*4882a593Smuzhiyun kunmap(pg);
841*4882a593Smuzhiyun #else
842*4882a593Smuzhiyun dma_buf_kunmap(dma_buf, i, extres_page);
843*4882a593Smuzhiyun #endif
844*4882a593Smuzhiyun if (ret)
845*4882a593Smuzhiyun break;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun dma_buf_end_cpu_access(dma_buf, DMA_FROM_DEVICE);
849*4882a593Smuzhiyun break;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun default:
852*4882a593Smuzhiyun ret = -EINVAL;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun out_unlock:
855*4882a593Smuzhiyun kbase_gpu_vm_unlock(kctx);
856*4882a593Smuzhiyun return ret;
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun
kbase_debug_copy(struct kbase_jd_atom * katom)859*4882a593Smuzhiyun static int kbase_debug_copy(struct kbase_jd_atom *katom)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun struct kbase_debug_copy_buffer *buffers = katom->softjob_data;
862*4882a593Smuzhiyun unsigned int i;
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun if (WARN_ON(!buffers))
865*4882a593Smuzhiyun return -EINVAL;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun for (i = 0; i < katom->nr_extres; i++) {
868*4882a593Smuzhiyun int res = kbase_mem_copy_from_extres(katom->kctx, &buffers[i]);
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun if (res)
871*4882a593Smuzhiyun return res;
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun return 0;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun #endif /* IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST */
877*4882a593Smuzhiyun #endif /* !MALI_USE_CSF */
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun #define KBASEP_JIT_ALLOC_GPU_ADDR_ALIGNMENT ((u32)0x7)
880*4882a593Smuzhiyun
kbasep_jit_alloc_validate(struct kbase_context * kctx,struct base_jit_alloc_info * info)881*4882a593Smuzhiyun int kbasep_jit_alloc_validate(struct kbase_context *kctx,
882*4882a593Smuzhiyun struct base_jit_alloc_info *info)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun int j;
885*4882a593Smuzhiyun /* If the ID is zero, then fail the job */
886*4882a593Smuzhiyun if (info->id == 0)
887*4882a593Smuzhiyun return -EINVAL;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun /* Sanity check that the PA fits within the VA */
890*4882a593Smuzhiyun if (info->va_pages < info->commit_pages)
891*4882a593Smuzhiyun return -EINVAL;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun /* Ensure the GPU address is correctly aligned */
894*4882a593Smuzhiyun if ((info->gpu_alloc_addr & KBASEP_JIT_ALLOC_GPU_ADDR_ALIGNMENT) != 0)
895*4882a593Smuzhiyun return -EINVAL;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun /* Interface version 2 (introduced with kernel driver version 11.5)
898*4882a593Smuzhiyun * onward has padding and a flags member to validate.
899*4882a593Smuzhiyun *
900*4882a593Smuzhiyun * Note: To support earlier versions the extra bytes will have been set
901*4882a593Smuzhiyun * to 0 by the caller.
902*4882a593Smuzhiyun */
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun /* Check padding is all zeroed */
905*4882a593Smuzhiyun for (j = 0; j < sizeof(info->padding); j++) {
906*4882a593Smuzhiyun if (info->padding[j] != 0)
907*4882a593Smuzhiyun return -EINVAL;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun /* Only valid flags shall be set */
911*4882a593Smuzhiyun if (info->flags & ~(BASE_JIT_ALLOC_VALID_FLAGS))
912*4882a593Smuzhiyun return -EINVAL;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun #if !MALI_JIT_PRESSURE_LIMIT_BASE
915*4882a593Smuzhiyun /* If just-in-time memory allocation pressure limit feature is disabled,
916*4882a593Smuzhiyun * heap_info_gpu_addr must be zeroed-out
917*4882a593Smuzhiyun */
918*4882a593Smuzhiyun if (info->heap_info_gpu_addr)
919*4882a593Smuzhiyun return -EINVAL;
920*4882a593Smuzhiyun #endif
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun #if !MALI_USE_CSF
923*4882a593Smuzhiyun /* If BASE_JIT_ALLOC_HEAP_INFO_IS_SIZE is set, heap_info_gpu_addr
924*4882a593Smuzhiyun * cannot be 0
925*4882a593Smuzhiyun */
926*4882a593Smuzhiyun if ((info->flags & BASE_JIT_ALLOC_HEAP_INFO_IS_SIZE) &&
927*4882a593Smuzhiyun !info->heap_info_gpu_addr)
928*4882a593Smuzhiyun return -EINVAL;
929*4882a593Smuzhiyun #endif /* !MALI_USE_CSF */
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun return 0;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun #if !MALI_USE_CSF
935*4882a593Smuzhiyun
kbase_jit_allocate_prepare(struct kbase_jd_atom * katom)936*4882a593Smuzhiyun static int kbase_jit_allocate_prepare(struct kbase_jd_atom *katom)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun __user u8 *data = (__user u8 *)(uintptr_t) katom->jc;
939*4882a593Smuzhiyun struct base_jit_alloc_info *info;
940*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
941*4882a593Smuzhiyun struct kbase_device *kbdev = kctx->kbdev;
942*4882a593Smuzhiyun u32 count;
943*4882a593Smuzhiyun int ret;
944*4882a593Smuzhiyun u32 i;
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun if (!kbase_mem_allow_alloc(kctx)) {
947*4882a593Smuzhiyun dev_dbg(kbdev->dev, "Invalid attempt to allocate JIT memory by %s/%d for ctx %d_%d",
948*4882a593Smuzhiyun current->comm, current->pid, kctx->tgid, kctx->id);
949*4882a593Smuzhiyun ret = -EINVAL;
950*4882a593Smuzhiyun goto fail;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun /* For backwards compatibility, and to prevent reading more than 1 jit
954*4882a593Smuzhiyun * info struct on jit version 1
955*4882a593Smuzhiyun */
956*4882a593Smuzhiyun if (katom->nr_extres == 0)
957*4882a593Smuzhiyun katom->nr_extres = 1;
958*4882a593Smuzhiyun count = katom->nr_extres;
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun /* Sanity checks */
961*4882a593Smuzhiyun if (!data || count > kctx->jit_max_allocations ||
962*4882a593Smuzhiyun count > ARRAY_SIZE(kctx->jit_alloc)) {
963*4882a593Smuzhiyun ret = -EINVAL;
964*4882a593Smuzhiyun goto fail;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun /* Copy the information for safe access and future storage */
968*4882a593Smuzhiyun info = kmalloc_array(count, sizeof(*info), GFP_KERNEL);
969*4882a593Smuzhiyun if (!info) {
970*4882a593Smuzhiyun ret = -ENOMEM;
971*4882a593Smuzhiyun goto fail;
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun katom->softjob_data = info;
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun for (i = 0; i < count; i++, info++, data += sizeof(*info)) {
977*4882a593Smuzhiyun if (copy_from_user(info, data, sizeof(*info)) != 0) {
978*4882a593Smuzhiyun ret = -EINVAL;
979*4882a593Smuzhiyun goto free_info;
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun ret = kbasep_jit_alloc_validate(kctx, info);
983*4882a593Smuzhiyun if (ret)
984*4882a593Smuzhiyun goto free_info;
985*4882a593Smuzhiyun KBASE_TLSTREAM_TL_ATTRIB_ATOM_JITALLOCINFO(
986*4882a593Smuzhiyun kbdev, katom, info->va_pages, info->commit_pages,
987*4882a593Smuzhiyun info->extension, info->id, info->bin_id,
988*4882a593Smuzhiyun info->max_allocations, info->flags, info->usage_id);
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun katom->jit_blocked = false;
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun lockdep_assert_held(&kctx->jctx.lock);
994*4882a593Smuzhiyun list_add_tail(&katom->jit_node, &kctx->jctx.jit_atoms_head);
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun /*
997*4882a593Smuzhiyun * Note:
998*4882a593Smuzhiyun * The provided info->gpu_alloc_addr isn't validated here as
999*4882a593Smuzhiyun * userland can cache allocations which means that even
1000*4882a593Smuzhiyun * though the region is valid it doesn't represent the
1001*4882a593Smuzhiyun * same thing it used to.
1002*4882a593Smuzhiyun *
1003*4882a593Smuzhiyun * Complete validation of va_pages, commit_pages and extension
1004*4882a593Smuzhiyun * isn't done here as it will be done during the call to
1005*4882a593Smuzhiyun * kbase_mem_alloc.
1006*4882a593Smuzhiyun */
1007*4882a593Smuzhiyun return 0;
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun free_info:
1010*4882a593Smuzhiyun kfree(katom->softjob_data);
1011*4882a593Smuzhiyun katom->softjob_data = NULL;
1012*4882a593Smuzhiyun fail:
1013*4882a593Smuzhiyun return ret;
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
kbase_jit_free_get_ids(struct kbase_jd_atom * katom)1016*4882a593Smuzhiyun static u8 *kbase_jit_free_get_ids(struct kbase_jd_atom *katom)
1017*4882a593Smuzhiyun {
1018*4882a593Smuzhiyun if (WARN_ON((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) !=
1019*4882a593Smuzhiyun BASE_JD_REQ_SOFT_JIT_FREE))
1020*4882a593Smuzhiyun return NULL;
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun return (u8 *) katom->softjob_data;
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun
kbase_jit_add_to_pending_alloc_list(struct kbase_jd_atom * katom)1025*4882a593Smuzhiyun static void kbase_jit_add_to_pending_alloc_list(struct kbase_jd_atom *katom)
1026*4882a593Smuzhiyun {
1027*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1028*4882a593Smuzhiyun struct list_head *target_list_head = NULL;
1029*4882a593Smuzhiyun struct kbase_jd_atom *entry;
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun list_for_each_entry(entry, &kctx->jctx.jit_pending_alloc, queue) {
1032*4882a593Smuzhiyun if (katom->age < entry->age) {
1033*4882a593Smuzhiyun target_list_head = &entry->queue;
1034*4882a593Smuzhiyun break;
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun if (target_list_head == NULL)
1039*4882a593Smuzhiyun target_list_head = &kctx->jctx.jit_pending_alloc;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun list_add_tail(&katom->queue, target_list_head);
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun
kbase_jit_allocate_process(struct kbase_jd_atom * katom)1044*4882a593Smuzhiyun static int kbase_jit_allocate_process(struct kbase_jd_atom *katom)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1047*4882a593Smuzhiyun struct kbase_device *kbdev = kctx->kbdev;
1048*4882a593Smuzhiyun struct base_jit_alloc_info *info;
1049*4882a593Smuzhiyun struct kbase_va_region *reg;
1050*4882a593Smuzhiyun struct kbase_vmap_struct mapping;
1051*4882a593Smuzhiyun u64 *ptr, new_addr;
1052*4882a593Smuzhiyun u32 count = katom->nr_extres;
1053*4882a593Smuzhiyun u32 i;
1054*4882a593Smuzhiyun bool ignore_pressure_limit = false;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun trace_sysgraph(SGR_SUBMIT, kctx->id,
1057*4882a593Smuzhiyun kbase_jd_atom_id(kctx, katom));
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun if (katom->jit_blocked) {
1060*4882a593Smuzhiyun list_del(&katom->queue);
1061*4882a593Smuzhiyun katom->jit_blocked = false;
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun info = katom->softjob_data;
1065*4882a593Smuzhiyun if (WARN_ON(!info)) {
1066*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1067*4882a593Smuzhiyun return 0;
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun for (i = 0; i < count; i++, info++) {
1071*4882a593Smuzhiyun /* The JIT ID is still in use so fail the allocation */
1072*4882a593Smuzhiyun if (kctx->jit_alloc[info->id]) {
1073*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_MEM_GROWTH_FAILED;
1074*4882a593Smuzhiyun return 0;
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun #if MALI_JIT_PRESSURE_LIMIT_BASE
1079*4882a593Smuzhiyun /*
1080*4882a593Smuzhiyun * If this is the only JIT_ALLOC atom in-flight or if JIT pressure limit
1081*4882a593Smuzhiyun * is disabled at the context scope, then bypass JIT pressure limit
1082*4882a593Smuzhiyun * logic in kbase_jit_allocate().
1083*4882a593Smuzhiyun */
1084*4882a593Smuzhiyun if (!kbase_ctx_flag(kctx, KCTX_JPL_ENABLED)
1085*4882a593Smuzhiyun || (kctx->jit_current_allocations == 0)) {
1086*4882a593Smuzhiyun ignore_pressure_limit = true;
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun #else
1089*4882a593Smuzhiyun ignore_pressure_limit = true;
1090*4882a593Smuzhiyun #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun for (i = 0, info = katom->softjob_data; i < count; i++, info++) {
1093*4882a593Smuzhiyun if (kctx->jit_alloc[info->id]) {
1094*4882a593Smuzhiyun /* The JIT ID is duplicated in this atom. Roll back
1095*4882a593Smuzhiyun * previous allocations and fail.
1096*4882a593Smuzhiyun */
1097*4882a593Smuzhiyun u32 j;
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun info = katom->softjob_data;
1100*4882a593Smuzhiyun for (j = 0; j < i; j++, info++) {
1101*4882a593Smuzhiyun kbase_jit_free(kctx, kctx->jit_alloc[info->id]);
1102*4882a593Smuzhiyun kctx->jit_alloc[info->id] =
1103*4882a593Smuzhiyun KBASE_RESERVED_REG_JIT_ALLOC;
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_MEM_GROWTH_FAILED;
1107*4882a593Smuzhiyun return 0;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun /* Create a JIT allocation */
1111*4882a593Smuzhiyun reg = kbase_jit_allocate(kctx, info, ignore_pressure_limit);
1112*4882a593Smuzhiyun if (!reg) {
1113*4882a593Smuzhiyun struct kbase_jd_atom *jit_atom;
1114*4882a593Smuzhiyun bool can_block = false;
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun lockdep_assert_held(&kctx->jctx.lock);
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun list_for_each_entry(jit_atom, &kctx->jctx.jit_atoms_head, jit_node) {
1119*4882a593Smuzhiyun if (jit_atom == katom)
1120*4882a593Smuzhiyun break;
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun if ((jit_atom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) ==
1123*4882a593Smuzhiyun BASE_JD_REQ_SOFT_JIT_FREE) {
1124*4882a593Smuzhiyun u8 *free_ids = kbase_jit_free_get_ids(jit_atom);
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun if (free_ids && *free_ids &&
1127*4882a593Smuzhiyun kctx->jit_alloc[*free_ids]) {
1128*4882a593Smuzhiyun /* A JIT free which is active and
1129*4882a593Smuzhiyun * submitted before this atom
1130*4882a593Smuzhiyun */
1131*4882a593Smuzhiyun can_block = true;
1132*4882a593Smuzhiyun break;
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun }
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun if (!can_block) {
1138*4882a593Smuzhiyun /* Mark the failed allocation as well as the
1139*4882a593Smuzhiyun * other un-attempted allocations in the set,
1140*4882a593Smuzhiyun * so we know they are in use even if the
1141*4882a593Smuzhiyun * allocation itself failed.
1142*4882a593Smuzhiyun */
1143*4882a593Smuzhiyun for (; i < count; i++, info++) {
1144*4882a593Smuzhiyun kctx->jit_alloc[info->id] =
1145*4882a593Smuzhiyun KBASE_RESERVED_REG_JIT_ALLOC;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_MEM_GROWTH_FAILED;
1149*4882a593Smuzhiyun dev_warn_ratelimited(kbdev->dev, "JIT alloc softjob failed: atom id %d\n",
1150*4882a593Smuzhiyun kbase_jd_atom_id(kctx, katom));
1151*4882a593Smuzhiyun return 0;
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun /* There are pending frees for an active allocation
1155*4882a593Smuzhiyun * so we should wait to see whether they free the
1156*4882a593Smuzhiyun * memory. Add to the list of atoms for which JIT
1157*4882a593Smuzhiyun * allocation is pending.
1158*4882a593Smuzhiyun */
1159*4882a593Smuzhiyun kbase_jit_add_to_pending_alloc_list(katom);
1160*4882a593Smuzhiyun katom->jit_blocked = true;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun /* Rollback, the whole set will be re-attempted */
1163*4882a593Smuzhiyun while (i-- > 0) {
1164*4882a593Smuzhiyun info--;
1165*4882a593Smuzhiyun kbase_jit_free(kctx, kctx->jit_alloc[info->id]);
1166*4882a593Smuzhiyun kctx->jit_alloc[info->id] = NULL;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun return 1;
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun /* Bind it to the user provided ID. */
1173*4882a593Smuzhiyun kctx->jit_alloc[info->id] = reg;
1174*4882a593Smuzhiyun }
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun for (i = 0, info = katom->softjob_data; i < count; i++, info++) {
1177*4882a593Smuzhiyun u64 entry_mmu_flags = 0;
1178*4882a593Smuzhiyun /*
1179*4882a593Smuzhiyun * Write the address of the JIT allocation to the user provided
1180*4882a593Smuzhiyun * GPU allocation.
1181*4882a593Smuzhiyun */
1182*4882a593Smuzhiyun ptr = kbase_vmap_prot(kctx, info->gpu_alloc_addr, sizeof(*ptr),
1183*4882a593Smuzhiyun KBASE_REG_CPU_WR, &mapping);
1184*4882a593Smuzhiyun if (!ptr) {
1185*4882a593Smuzhiyun /*
1186*4882a593Smuzhiyun * Leave the allocations "live" as the JIT free atom
1187*4882a593Smuzhiyun * will be submitted anyway.
1188*4882a593Smuzhiyun */
1189*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1190*4882a593Smuzhiyun return 0;
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun reg = kctx->jit_alloc[info->id];
1194*4882a593Smuzhiyun new_addr = reg->start_pfn << PAGE_SHIFT;
1195*4882a593Smuzhiyun *ptr = new_addr;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun #if defined(CONFIG_MALI_VECTOR_DUMP)
1198*4882a593Smuzhiyun /*
1199*4882a593Smuzhiyun * Retrieve the mmu flags for JIT allocation
1200*4882a593Smuzhiyun * only if dumping is enabled
1201*4882a593Smuzhiyun */
1202*4882a593Smuzhiyun entry_mmu_flags = kbase_mmu_create_ate(kbdev,
1203*4882a593Smuzhiyun (struct tagged_addr){ 0 }, reg->flags,
1204*4882a593Smuzhiyun MIDGARD_MMU_BOTTOMLEVEL, kctx->jit_group_id);
1205*4882a593Smuzhiyun #endif
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun KBASE_TLSTREAM_TL_ATTRIB_ATOM_JIT(
1208*4882a593Smuzhiyun kbdev, katom, info->gpu_alloc_addr, new_addr,
1209*4882a593Smuzhiyun info->flags, entry_mmu_flags, info->id,
1210*4882a593Smuzhiyun info->commit_pages, info->extension, info->va_pages);
1211*4882a593Smuzhiyun kbase_vunmap(kctx, &mapping);
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun kbase_trace_jit_report_gpu_mem(kctx, reg,
1214*4882a593Smuzhiyun KBASE_JIT_REPORT_ON_ALLOC_OR_FREE);
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_DONE;
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun return 0;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun
kbase_jit_allocate_finish(struct kbase_jd_atom * katom)1222*4882a593Smuzhiyun static void kbase_jit_allocate_finish(struct kbase_jd_atom *katom)
1223*4882a593Smuzhiyun {
1224*4882a593Smuzhiyun struct base_jit_alloc_info *info;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun lockdep_assert_held(&katom->kctx->jctx.lock);
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun if (WARN_ON(!katom->softjob_data))
1229*4882a593Smuzhiyun return;
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun /* Remove atom from jit_atoms_head list */
1232*4882a593Smuzhiyun list_del(&katom->jit_node);
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun if (katom->jit_blocked) {
1235*4882a593Smuzhiyun list_del(&katom->queue);
1236*4882a593Smuzhiyun katom->jit_blocked = false;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun info = katom->softjob_data;
1240*4882a593Smuzhiyun /* Free the info structure */
1241*4882a593Smuzhiyun kfree(info);
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
kbase_jit_free_prepare(struct kbase_jd_atom * katom)1244*4882a593Smuzhiyun static int kbase_jit_free_prepare(struct kbase_jd_atom *katom)
1245*4882a593Smuzhiyun {
1246*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1247*4882a593Smuzhiyun struct kbase_device *kbdev = kctx->kbdev;
1248*4882a593Smuzhiyun __user void *data = (__user void *)(uintptr_t) katom->jc;
1249*4882a593Smuzhiyun u8 *ids;
1250*4882a593Smuzhiyun u32 count = MAX(katom->nr_extres, 1);
1251*4882a593Smuzhiyun u32 i;
1252*4882a593Smuzhiyun int ret;
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun /* Sanity checks */
1255*4882a593Smuzhiyun if (count > ARRAY_SIZE(kctx->jit_alloc)) {
1256*4882a593Smuzhiyun ret = -EINVAL;
1257*4882a593Smuzhiyun goto fail;
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun /* Copy the information for safe access and future storage */
1261*4882a593Smuzhiyun ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL);
1262*4882a593Smuzhiyun if (!ids) {
1263*4882a593Smuzhiyun ret = -ENOMEM;
1264*4882a593Smuzhiyun goto fail;
1265*4882a593Smuzhiyun }
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun lockdep_assert_held(&kctx->jctx.lock);
1268*4882a593Smuzhiyun katom->softjob_data = ids;
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun /* For backwards compatibility */
1271*4882a593Smuzhiyun if (katom->nr_extres) {
1272*4882a593Smuzhiyun /* Fail the job if there is no list of ids */
1273*4882a593Smuzhiyun if (!data) {
1274*4882a593Smuzhiyun ret = -EINVAL;
1275*4882a593Smuzhiyun goto free_info;
1276*4882a593Smuzhiyun }
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun if (copy_from_user(ids, data, sizeof(*ids)*count) != 0) {
1279*4882a593Smuzhiyun ret = -EINVAL;
1280*4882a593Smuzhiyun goto free_info;
1281*4882a593Smuzhiyun }
1282*4882a593Smuzhiyun } else {
1283*4882a593Smuzhiyun katom->nr_extres = 1;
1284*4882a593Smuzhiyun *ids = (u8)katom->jc;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun for (i = 0; i < count; i++)
1287*4882a593Smuzhiyun KBASE_TLSTREAM_TL_ATTRIB_ATOM_JITFREEINFO(kbdev, katom, ids[i]);
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun list_add_tail(&katom->jit_node, &kctx->jctx.jit_atoms_head);
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun return 0;
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun free_info:
1294*4882a593Smuzhiyun kfree(katom->softjob_data);
1295*4882a593Smuzhiyun katom->softjob_data = NULL;
1296*4882a593Smuzhiyun fail:
1297*4882a593Smuzhiyun return ret;
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun
kbase_jit_free_process(struct kbase_jd_atom * katom)1300*4882a593Smuzhiyun static void kbase_jit_free_process(struct kbase_jd_atom *katom)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1303*4882a593Smuzhiyun u8 *ids = kbase_jit_free_get_ids(katom);
1304*4882a593Smuzhiyun u32 count = katom->nr_extres;
1305*4882a593Smuzhiyun u32 i;
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun if (ids == NULL) {
1308*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1309*4882a593Smuzhiyun return;
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun for (i = 0; i < count; i++, ids++) {
1313*4882a593Smuzhiyun /*
1314*4882a593Smuzhiyun * If the ID is zero or it is not in use yet then fail the job.
1315*4882a593Smuzhiyun */
1316*4882a593Smuzhiyun if ((*ids == 0) || (kctx->jit_alloc[*ids] == NULL)) {
1317*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1318*4882a593Smuzhiyun return;
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun }
1322*4882a593Smuzhiyun
kbasep_jit_finish_worker(struct work_struct * work)1323*4882a593Smuzhiyun static void kbasep_jit_finish_worker(struct work_struct *work)
1324*4882a593Smuzhiyun {
1325*4882a593Smuzhiyun struct kbase_jd_atom *katom = container_of(work, struct kbase_jd_atom,
1326*4882a593Smuzhiyun work);
1327*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1328*4882a593Smuzhiyun int resched;
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun mutex_lock(&kctx->jctx.lock);
1331*4882a593Smuzhiyun kbase_finish_soft_job(katom);
1332*4882a593Smuzhiyun resched = kbase_jd_done_nolock(katom, true);
1333*4882a593Smuzhiyun mutex_unlock(&kctx->jctx.lock);
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun if (resched)
1336*4882a593Smuzhiyun kbase_js_sched_all(kctx->kbdev);
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun
kbase_jit_retry_pending_alloc(struct kbase_context * kctx)1339*4882a593Smuzhiyun void kbase_jit_retry_pending_alloc(struct kbase_context *kctx)
1340*4882a593Smuzhiyun {
1341*4882a593Smuzhiyun LIST_HEAD(jit_pending_alloc_list);
1342*4882a593Smuzhiyun struct list_head *i, *tmp;
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun list_splice_tail_init(&kctx->jctx.jit_pending_alloc,
1345*4882a593Smuzhiyun &jit_pending_alloc_list);
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun list_for_each_safe(i, tmp, &jit_pending_alloc_list) {
1348*4882a593Smuzhiyun struct kbase_jd_atom *pending_atom = list_entry(i,
1349*4882a593Smuzhiyun struct kbase_jd_atom, queue);
1350*4882a593Smuzhiyun KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTJOB_START(kctx->kbdev, pending_atom);
1351*4882a593Smuzhiyun kbase_kinstr_jm_atom_sw_start(pending_atom);
1352*4882a593Smuzhiyun if (kbase_jit_allocate_process(pending_atom) == 0) {
1353*4882a593Smuzhiyun /* Atom has completed */
1354*4882a593Smuzhiyun INIT_WORK(&pending_atom->work,
1355*4882a593Smuzhiyun kbasep_jit_finish_worker);
1356*4882a593Smuzhiyun queue_work(kctx->jctx.job_done_wq, &pending_atom->work);
1357*4882a593Smuzhiyun }
1358*4882a593Smuzhiyun KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTJOB_END(kctx->kbdev, pending_atom);
1359*4882a593Smuzhiyun kbase_kinstr_jm_atom_sw_stop(pending_atom);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun
kbase_jit_free_finish(struct kbase_jd_atom * katom)1363*4882a593Smuzhiyun static void kbase_jit_free_finish(struct kbase_jd_atom *katom)
1364*4882a593Smuzhiyun {
1365*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1366*4882a593Smuzhiyun u8 *ids;
1367*4882a593Smuzhiyun size_t j;
1368*4882a593Smuzhiyun
1369*4882a593Smuzhiyun lockdep_assert_held(&kctx->jctx.lock);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun ids = kbase_jit_free_get_ids(katom);
1372*4882a593Smuzhiyun if (WARN_ON(ids == NULL))
1373*4882a593Smuzhiyun return;
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /* Remove this atom from the jit_atoms_head list */
1376*4882a593Smuzhiyun list_del(&katom->jit_node);
1377*4882a593Smuzhiyun
1378*4882a593Smuzhiyun for (j = 0; j != katom->nr_extres; ++j) {
1379*4882a593Smuzhiyun if ((ids[j] != 0) && (kctx->jit_alloc[ids[j]] != NULL)) {
1380*4882a593Smuzhiyun /*
1381*4882a593Smuzhiyun * If the ID is valid but the allocation request failed
1382*4882a593Smuzhiyun * still succeed this soft job but don't try and free
1383*4882a593Smuzhiyun * the allocation.
1384*4882a593Smuzhiyun */
1385*4882a593Smuzhiyun if (kctx->jit_alloc[ids[j]] !=
1386*4882a593Smuzhiyun KBASE_RESERVED_REG_JIT_ALLOC) {
1387*4882a593Smuzhiyun KBASE_TLSTREAM_TL_JIT_USEDPAGES(kctx->kbdev,
1388*4882a593Smuzhiyun kctx->jit_alloc[ids[j]]->
1389*4882a593Smuzhiyun gpu_alloc->nents, ids[j]);
1390*4882a593Smuzhiyun kbase_jit_free(kctx, kctx->jit_alloc[ids[j]]);
1391*4882a593Smuzhiyun }
1392*4882a593Smuzhiyun kctx->jit_alloc[ids[j]] = NULL;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun }
1395*4882a593Smuzhiyun /* Free the list of ids */
1396*4882a593Smuzhiyun kfree(ids);
1397*4882a593Smuzhiyun
1398*4882a593Smuzhiyun kbase_jit_retry_pending_alloc(kctx);
1399*4882a593Smuzhiyun }
1400*4882a593Smuzhiyun
kbase_ext_res_prepare(struct kbase_jd_atom * katom)1401*4882a593Smuzhiyun static int kbase_ext_res_prepare(struct kbase_jd_atom *katom)
1402*4882a593Smuzhiyun {
1403*4882a593Smuzhiyun __user struct base_external_resource_list *user_ext_res;
1404*4882a593Smuzhiyun struct base_external_resource_list *ext_res;
1405*4882a593Smuzhiyun u64 count = 0;
1406*4882a593Smuzhiyun size_t copy_size;
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun user_ext_res = (__user struct base_external_resource_list *)
1409*4882a593Smuzhiyun (uintptr_t) katom->jc;
1410*4882a593Smuzhiyun
1411*4882a593Smuzhiyun /* Fail the job if there is no info structure */
1412*4882a593Smuzhiyun if (!user_ext_res)
1413*4882a593Smuzhiyun return -EINVAL;
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun if (copy_from_user(&count, &user_ext_res->count, sizeof(u64)) != 0)
1416*4882a593Smuzhiyun return -EINVAL;
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun /* Is the number of external resources in range? */
1419*4882a593Smuzhiyun if (!count || count > BASE_EXT_RES_COUNT_MAX)
1420*4882a593Smuzhiyun return -EINVAL;
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun /* Copy the information for safe access and future storage */
1423*4882a593Smuzhiyun copy_size = sizeof(*ext_res);
1424*4882a593Smuzhiyun copy_size += sizeof(struct base_external_resource) * (count - 1);
1425*4882a593Smuzhiyun ext_res = memdup_user(user_ext_res, copy_size);
1426*4882a593Smuzhiyun if (IS_ERR(ext_res))
1427*4882a593Smuzhiyun return PTR_ERR(ext_res);
1428*4882a593Smuzhiyun
1429*4882a593Smuzhiyun /*
1430*4882a593Smuzhiyun * Overwrite the count with the first value incase it was changed
1431*4882a593Smuzhiyun * after the fact.
1432*4882a593Smuzhiyun */
1433*4882a593Smuzhiyun ext_res->count = count;
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun katom->softjob_data = ext_res;
1436*4882a593Smuzhiyun
1437*4882a593Smuzhiyun return 0;
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun
kbase_ext_res_process(struct kbase_jd_atom * katom,bool map)1440*4882a593Smuzhiyun static void kbase_ext_res_process(struct kbase_jd_atom *katom, bool map)
1441*4882a593Smuzhiyun {
1442*4882a593Smuzhiyun struct base_external_resource_list *ext_res;
1443*4882a593Smuzhiyun int i;
1444*4882a593Smuzhiyun bool failed = false;
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun ext_res = katom->softjob_data;
1447*4882a593Smuzhiyun if (!ext_res)
1448*4882a593Smuzhiyun goto failed_jc;
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun kbase_gpu_vm_lock(katom->kctx);
1451*4882a593Smuzhiyun
1452*4882a593Smuzhiyun for (i = 0; i < ext_res->count; i++) {
1453*4882a593Smuzhiyun u64 gpu_addr;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun gpu_addr = ext_res->ext_res[i].ext_resource &
1456*4882a593Smuzhiyun ~BASE_EXT_RES_ACCESS_EXCLUSIVE;
1457*4882a593Smuzhiyun if (map) {
1458*4882a593Smuzhiyun if (!kbase_sticky_resource_acquire(katom->kctx,
1459*4882a593Smuzhiyun gpu_addr))
1460*4882a593Smuzhiyun goto failed_loop;
1461*4882a593Smuzhiyun } else {
1462*4882a593Smuzhiyun if (!kbase_sticky_resource_release_force(katom->kctx, NULL,
1463*4882a593Smuzhiyun gpu_addr))
1464*4882a593Smuzhiyun failed = true;
1465*4882a593Smuzhiyun }
1466*4882a593Smuzhiyun }
1467*4882a593Smuzhiyun
1468*4882a593Smuzhiyun /*
1469*4882a593Smuzhiyun * In the case of unmap we continue unmapping other resources in the
1470*4882a593Smuzhiyun * case of failure but will always report failure if _any_ unmap
1471*4882a593Smuzhiyun * request fails.
1472*4882a593Smuzhiyun */
1473*4882a593Smuzhiyun if (failed)
1474*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1475*4882a593Smuzhiyun else
1476*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_DONE;
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun kbase_gpu_vm_unlock(katom->kctx);
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun return;
1481*4882a593Smuzhiyun
1482*4882a593Smuzhiyun failed_loop:
1483*4882a593Smuzhiyun while (i > 0) {
1484*4882a593Smuzhiyun u64 const gpu_addr = ext_res->ext_res[i - 1].ext_resource &
1485*4882a593Smuzhiyun ~BASE_EXT_RES_ACCESS_EXCLUSIVE;
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun kbase_sticky_resource_release_force(katom->kctx, NULL, gpu_addr);
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun --i;
1490*4882a593Smuzhiyun }
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1493*4882a593Smuzhiyun kbase_gpu_vm_unlock(katom->kctx);
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun failed_jc:
1496*4882a593Smuzhiyun return;
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun
kbase_ext_res_finish(struct kbase_jd_atom * katom)1499*4882a593Smuzhiyun static void kbase_ext_res_finish(struct kbase_jd_atom *katom)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun struct base_external_resource_list *ext_res;
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun ext_res = katom->softjob_data;
1504*4882a593Smuzhiyun /* Free the info structure */
1505*4882a593Smuzhiyun kfree(ext_res);
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun
kbase_process_soft_job(struct kbase_jd_atom * katom)1508*4882a593Smuzhiyun int kbase_process_soft_job(struct kbase_jd_atom *katom)
1509*4882a593Smuzhiyun {
1510*4882a593Smuzhiyun int ret = 0;
1511*4882a593Smuzhiyun struct kbase_context *kctx = katom->kctx;
1512*4882a593Smuzhiyun struct kbase_device *kbdev = kctx->kbdev;
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTJOB_START(kbdev, katom);
1515*4882a593Smuzhiyun kbase_kinstr_jm_atom_sw_start(katom);
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun trace_sysgraph(SGR_SUBMIT, kctx->id,
1518*4882a593Smuzhiyun kbase_jd_atom_id(kctx, katom));
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) {
1521*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME:
1522*4882a593Smuzhiyun ret = kbase_dump_cpu_gpu_time(katom);
1523*4882a593Smuzhiyun break;
1524*4882a593Smuzhiyun
1525*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SYNC_FILE)
1526*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_TRIGGER:
1527*4882a593Smuzhiyun katom->event_code = kbase_sync_fence_out_trigger(katom,
1528*4882a593Smuzhiyun katom->event_code == BASE_JD_EVENT_DONE ?
1529*4882a593Smuzhiyun 0 : -EFAULT);
1530*4882a593Smuzhiyun break;
1531*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_WAIT:
1532*4882a593Smuzhiyun {
1533*4882a593Smuzhiyun ret = kbase_sync_fence_in_wait(katom);
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun if (ret == 1) {
1536*4882a593Smuzhiyun #ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG
1537*4882a593Smuzhiyun kbasep_add_waiting_with_timeout(katom);
1538*4882a593Smuzhiyun #else
1539*4882a593Smuzhiyun kbasep_add_waiting_soft_job(katom);
1540*4882a593Smuzhiyun #endif
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun break;
1543*4882a593Smuzhiyun }
1544*4882a593Smuzhiyun #endif
1545*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_WAIT:
1546*4882a593Smuzhiyun ret = kbasep_soft_event_wait(katom);
1547*4882a593Smuzhiyun break;
1548*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_SET:
1549*4882a593Smuzhiyun kbasep_soft_event_update_locked(katom, BASE_JD_SOFT_EVENT_SET);
1550*4882a593Smuzhiyun break;
1551*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_RESET:
1552*4882a593Smuzhiyun kbasep_soft_event_update_locked(katom, BASE_JD_SOFT_EVENT_RESET);
1553*4882a593Smuzhiyun break;
1554*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST
1555*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_DEBUG_COPY:
1556*4882a593Smuzhiyun {
1557*4882a593Smuzhiyun int res = kbase_debug_copy(katom);
1558*4882a593Smuzhiyun
1559*4882a593Smuzhiyun if (res)
1560*4882a593Smuzhiyun katom->event_code = BASE_JD_EVENT_JOB_INVALID;
1561*4882a593Smuzhiyun break;
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun #endif /* IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST */
1564*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_JIT_ALLOC:
1565*4882a593Smuzhiyun ret = kbase_jit_allocate_process(katom);
1566*4882a593Smuzhiyun break;
1567*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_JIT_FREE:
1568*4882a593Smuzhiyun kbase_jit_free_process(katom);
1569*4882a593Smuzhiyun break;
1570*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EXT_RES_MAP:
1571*4882a593Smuzhiyun kbase_ext_res_process(katom, true);
1572*4882a593Smuzhiyun break;
1573*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EXT_RES_UNMAP:
1574*4882a593Smuzhiyun kbase_ext_res_process(katom, false);
1575*4882a593Smuzhiyun break;
1576*4882a593Smuzhiyun }
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun /* Atom is complete */
1579*4882a593Smuzhiyun KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTJOB_END(kbdev, katom);
1580*4882a593Smuzhiyun kbase_kinstr_jm_atom_sw_stop(katom);
1581*4882a593Smuzhiyun return ret;
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun
kbase_cancel_soft_job(struct kbase_jd_atom * katom)1584*4882a593Smuzhiyun void kbase_cancel_soft_job(struct kbase_jd_atom *katom)
1585*4882a593Smuzhiyun {
1586*4882a593Smuzhiyun switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) {
1587*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SYNC_FILE)
1588*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_WAIT:
1589*4882a593Smuzhiyun kbase_sync_fence_in_cancel_wait(katom);
1590*4882a593Smuzhiyun break;
1591*4882a593Smuzhiyun #endif
1592*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_WAIT:
1593*4882a593Smuzhiyun kbasep_soft_event_cancel_job(katom);
1594*4882a593Smuzhiyun break;
1595*4882a593Smuzhiyun default:
1596*4882a593Smuzhiyun /* This soft-job doesn't support cancellation! */
1597*4882a593Smuzhiyun KBASE_DEBUG_ASSERT(0);
1598*4882a593Smuzhiyun }
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun
kbase_prepare_soft_job(struct kbase_jd_atom * katom)1601*4882a593Smuzhiyun int kbase_prepare_soft_job(struct kbase_jd_atom *katom)
1602*4882a593Smuzhiyun {
1603*4882a593Smuzhiyun switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) {
1604*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME:
1605*4882a593Smuzhiyun {
1606*4882a593Smuzhiyun if (!IS_ALIGNED(katom->jc, cache_line_size()))
1607*4882a593Smuzhiyun return -EINVAL;
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun break;
1610*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SYNC_FILE)
1611*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_TRIGGER:
1612*4882a593Smuzhiyun {
1613*4882a593Smuzhiyun struct base_fence fence;
1614*4882a593Smuzhiyun int fd;
1615*4882a593Smuzhiyun
1616*4882a593Smuzhiyun if (copy_from_user(&fence,
1617*4882a593Smuzhiyun (__user void *)(uintptr_t)katom->jc,
1618*4882a593Smuzhiyun sizeof(fence)) != 0)
1619*4882a593Smuzhiyun return -EINVAL;
1620*4882a593Smuzhiyun
1621*4882a593Smuzhiyun fd = kbase_sync_fence_out_create(katom,
1622*4882a593Smuzhiyun fence.basep.stream_fd);
1623*4882a593Smuzhiyun if (fd < 0)
1624*4882a593Smuzhiyun return -EINVAL;
1625*4882a593Smuzhiyun
1626*4882a593Smuzhiyun fence.basep.fd = fd;
1627*4882a593Smuzhiyun if (copy_to_user((__user void *)(uintptr_t)katom->jc,
1628*4882a593Smuzhiyun &fence, sizeof(fence)) != 0) {
1629*4882a593Smuzhiyun kbase_sync_fence_out_remove(katom);
1630*4882a593Smuzhiyun /* fd should have been closed here, but there's
1631*4882a593Smuzhiyun * no good way of doing that. Since
1632*4882a593Smuzhiyun * copy_to_user() very rarely fails, and the fd
1633*4882a593Smuzhiyun * will get closed on process termination this
1634*4882a593Smuzhiyun * won't be a problem.
1635*4882a593Smuzhiyun */
1636*4882a593Smuzhiyun fence.basep.fd = -EINVAL;
1637*4882a593Smuzhiyun return -EINVAL;
1638*4882a593Smuzhiyun }
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun break;
1641*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_WAIT:
1642*4882a593Smuzhiyun {
1643*4882a593Smuzhiyun struct base_fence fence;
1644*4882a593Smuzhiyun int ret;
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyun if (copy_from_user(&fence,
1647*4882a593Smuzhiyun (__user void *)(uintptr_t)katom->jc,
1648*4882a593Smuzhiyun sizeof(fence)) != 0)
1649*4882a593Smuzhiyun return -EINVAL;
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun /* Get a reference to the fence object */
1652*4882a593Smuzhiyun ret = kbase_sync_fence_in_from_fd(katom,
1653*4882a593Smuzhiyun fence.basep.fd);
1654*4882a593Smuzhiyun if (ret < 0)
1655*4882a593Smuzhiyun return ret;
1656*4882a593Smuzhiyun }
1657*4882a593Smuzhiyun break;
1658*4882a593Smuzhiyun #endif /* CONFIG_SYNC_FILE */
1659*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_JIT_ALLOC:
1660*4882a593Smuzhiyun return kbase_jit_allocate_prepare(katom);
1661*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_JIT_FREE:
1662*4882a593Smuzhiyun return kbase_jit_free_prepare(katom);
1663*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_WAIT:
1664*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_SET:
1665*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EVENT_RESET:
1666*4882a593Smuzhiyun if (katom->jc == 0)
1667*4882a593Smuzhiyun return -EINVAL;
1668*4882a593Smuzhiyun break;
1669*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST
1670*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_DEBUG_COPY:
1671*4882a593Smuzhiyun return kbase_debug_copy_prepare(katom);
1672*4882a593Smuzhiyun #endif /* IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST */
1673*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EXT_RES_MAP:
1674*4882a593Smuzhiyun return kbase_ext_res_prepare(katom);
1675*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EXT_RES_UNMAP:
1676*4882a593Smuzhiyun return kbase_ext_res_prepare(katom);
1677*4882a593Smuzhiyun default:
1678*4882a593Smuzhiyun /* Unsupported soft-job */
1679*4882a593Smuzhiyun return -EINVAL;
1680*4882a593Smuzhiyun }
1681*4882a593Smuzhiyun return 0;
1682*4882a593Smuzhiyun }
1683*4882a593Smuzhiyun
kbase_finish_soft_job(struct kbase_jd_atom * katom)1684*4882a593Smuzhiyun void kbase_finish_soft_job(struct kbase_jd_atom *katom)
1685*4882a593Smuzhiyun {
1686*4882a593Smuzhiyun trace_sysgraph(SGR_COMPLETE, katom->kctx->id,
1687*4882a593Smuzhiyun kbase_jd_atom_id(katom->kctx, katom));
1688*4882a593Smuzhiyun
1689*4882a593Smuzhiyun switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) {
1690*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME:
1691*4882a593Smuzhiyun /* Nothing to do */
1692*4882a593Smuzhiyun break;
1693*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SYNC_FILE)
1694*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_TRIGGER:
1695*4882a593Smuzhiyun /* If fence has not yet been signaled, do it now */
1696*4882a593Smuzhiyun kbase_sync_fence_out_trigger(katom, katom->event_code ==
1697*4882a593Smuzhiyun BASE_JD_EVENT_DONE ? 0 : -EFAULT);
1698*4882a593Smuzhiyun break;
1699*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_FENCE_WAIT:
1700*4882a593Smuzhiyun /* Release katom's reference to fence object */
1701*4882a593Smuzhiyun kbase_sync_fence_in_remove(katom);
1702*4882a593Smuzhiyun break;
1703*4882a593Smuzhiyun #endif /* CONFIG_SYNC_FILE */
1704*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST
1705*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_DEBUG_COPY:
1706*4882a593Smuzhiyun kbase_debug_copy_finish(katom);
1707*4882a593Smuzhiyun break;
1708*4882a593Smuzhiyun #endif /* IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST */
1709*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_JIT_ALLOC:
1710*4882a593Smuzhiyun kbase_jit_allocate_finish(katom);
1711*4882a593Smuzhiyun break;
1712*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EXT_RES_MAP:
1713*4882a593Smuzhiyun kbase_ext_res_finish(katom);
1714*4882a593Smuzhiyun break;
1715*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_EXT_RES_UNMAP:
1716*4882a593Smuzhiyun kbase_ext_res_finish(katom);
1717*4882a593Smuzhiyun break;
1718*4882a593Smuzhiyun case BASE_JD_REQ_SOFT_JIT_FREE:
1719*4882a593Smuzhiyun kbase_jit_free_finish(katom);
1720*4882a593Smuzhiyun break;
1721*4882a593Smuzhiyun }
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun
kbase_resume_suspended_soft_jobs(struct kbase_device * kbdev)1724*4882a593Smuzhiyun void kbase_resume_suspended_soft_jobs(struct kbase_device *kbdev)
1725*4882a593Smuzhiyun {
1726*4882a593Smuzhiyun LIST_HEAD(local_suspended_soft_jobs);
1727*4882a593Smuzhiyun struct kbase_jd_atom *tmp_iter;
1728*4882a593Smuzhiyun struct kbase_jd_atom *katom_iter;
1729*4882a593Smuzhiyun struct kbasep_js_device_data *js_devdata;
1730*4882a593Smuzhiyun bool resched = false;
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun KBASE_DEBUG_ASSERT(kbdev);
1733*4882a593Smuzhiyun
1734*4882a593Smuzhiyun js_devdata = &kbdev->js_data;
1735*4882a593Smuzhiyun
1736*4882a593Smuzhiyun /* Move out the entire list */
1737*4882a593Smuzhiyun mutex_lock(&js_devdata->runpool_mutex);
1738*4882a593Smuzhiyun list_splice_init(&js_devdata->suspended_soft_jobs_list,
1739*4882a593Smuzhiyun &local_suspended_soft_jobs);
1740*4882a593Smuzhiyun mutex_unlock(&js_devdata->runpool_mutex);
1741*4882a593Smuzhiyun
1742*4882a593Smuzhiyun /*
1743*4882a593Smuzhiyun * Each atom must be detached from the list and ran separately -
1744*4882a593Smuzhiyun * it could be re-added to the old list, but this is unlikely
1745*4882a593Smuzhiyun */
1746*4882a593Smuzhiyun list_for_each_entry_safe(katom_iter, tmp_iter,
1747*4882a593Smuzhiyun &local_suspended_soft_jobs, dep_item[1]) {
1748*4882a593Smuzhiyun struct kbase_context *kctx = katom_iter->kctx;
1749*4882a593Smuzhiyun
1750*4882a593Smuzhiyun mutex_lock(&kctx->jctx.lock);
1751*4882a593Smuzhiyun
1752*4882a593Smuzhiyun /* Remove from the global list */
1753*4882a593Smuzhiyun list_del(&katom_iter->dep_item[1]);
1754*4882a593Smuzhiyun /* Remove from the context's list of waiting soft jobs */
1755*4882a593Smuzhiyun kbasep_remove_waiting_soft_job(katom_iter);
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun if (kbase_process_soft_job(katom_iter) == 0) {
1758*4882a593Smuzhiyun kbase_finish_soft_job(katom_iter);
1759*4882a593Smuzhiyun resched |= kbase_jd_done_nolock(katom_iter, true);
1760*4882a593Smuzhiyun #ifdef CONFIG_MALI_ARBITER_SUPPORT
1761*4882a593Smuzhiyun atomic_dec(&kbdev->pm.gpu_users_waiting);
1762*4882a593Smuzhiyun #endif /* CONFIG_MALI_ARBITER_SUPPORT */
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun mutex_unlock(&kctx->jctx.lock);
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun
1767*4882a593Smuzhiyun if (resched)
1768*4882a593Smuzhiyun kbase_js_sched_all(kbdev);
1769*4882a593Smuzhiyun }
1770*4882a593Smuzhiyun #endif /* !MALI_USE_CSF */
1771