1a1d2a633SQiang Yu // SPDX-License-Identifier: GPL-2.0 OR MIT
2a1d2a633SQiang Yu /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
3a1d2a633SQiang Yu
4a1d2a633SQiang Yu #include <linux/interrupt.h>
5a1d2a633SQiang Yu #include <linux/iopoll.h>
6a1d2a633SQiang Yu #include <linux/device.h>
7a1d2a633SQiang Yu #include <linux/slab.h>
8a1d2a633SQiang Yu
9a1d2a633SQiang Yu #include <drm/lima_drm.h>
10a1d2a633SQiang Yu
11a1d2a633SQiang Yu #include "lima_device.h"
12a1d2a633SQiang Yu #include "lima_gp.h"
13a1d2a633SQiang Yu #include "lima_regs.h"
142081e8dcSQiang Yu #include "lima_gem.h"
152081e8dcSQiang Yu #include "lima_vm.h"
16a1d2a633SQiang Yu
17a1d2a633SQiang Yu #define gp_write(reg, data) writel(data, ip->iomem + reg)
18a1d2a633SQiang Yu #define gp_read(reg) readl(ip->iomem + reg)
19a1d2a633SQiang Yu
lima_gp_irq_handler(int irq,void * data)20a1d2a633SQiang Yu static irqreturn_t lima_gp_irq_handler(int irq, void *data)
21a1d2a633SQiang Yu {
22a1d2a633SQiang Yu struct lima_ip *ip = data;
23a1d2a633SQiang Yu struct lima_device *dev = ip->dev;
24a1d2a633SQiang Yu struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
252081e8dcSQiang Yu struct lima_sched_task *task = pipe->current_task;
26a1d2a633SQiang Yu u32 state = gp_read(LIMA_GP_INT_STAT);
27a1d2a633SQiang Yu u32 status = gp_read(LIMA_GP_STATUS);
28a1d2a633SQiang Yu bool done = false;
29a1d2a633SQiang Yu
30a1d2a633SQiang Yu /* for shared irq case */
31a1d2a633SQiang Yu if (!state)
32a1d2a633SQiang Yu return IRQ_NONE;
33a1d2a633SQiang Yu
34a1d2a633SQiang Yu if (state & LIMA_GP_IRQ_MASK_ERROR) {
352081e8dcSQiang Yu if ((state & LIMA_GP_IRQ_MASK_ERROR) ==
362081e8dcSQiang Yu LIMA_GP_IRQ_PLBU_OUT_OF_MEM) {
372081e8dcSQiang Yu dev_dbg(dev->dev, "gp out of heap irq status=%x\n",
382081e8dcSQiang Yu status);
392081e8dcSQiang Yu } else {
40a1d2a633SQiang Yu dev_err(dev->dev, "gp error irq state=%x status=%x\n",
41a1d2a633SQiang Yu state, status);
422081e8dcSQiang Yu if (task)
432081e8dcSQiang Yu task->recoverable = false;
442081e8dcSQiang Yu }
45a1d2a633SQiang Yu
46a1d2a633SQiang Yu /* mask all interrupts before hard reset */
47a1d2a633SQiang Yu gp_write(LIMA_GP_INT_MASK, 0);
48a1d2a633SQiang Yu
49a1d2a633SQiang Yu pipe->error = true;
50a1d2a633SQiang Yu done = true;
51a1d2a633SQiang Yu } else {
52a1d2a633SQiang Yu bool valid = state & (LIMA_GP_IRQ_VS_END_CMD_LST |
53a1d2a633SQiang Yu LIMA_GP_IRQ_PLBU_END_CMD_LST);
54a1d2a633SQiang Yu bool active = status & (LIMA_GP_STATUS_VS_ACTIVE |
55a1d2a633SQiang Yu LIMA_GP_STATUS_PLBU_ACTIVE);
56a1d2a633SQiang Yu done = valid && !active;
572081e8dcSQiang Yu pipe->error = false;
58a1d2a633SQiang Yu }
59a1d2a633SQiang Yu
60a1d2a633SQiang Yu gp_write(LIMA_GP_INT_CLEAR, state);
61a1d2a633SQiang Yu
62a1d2a633SQiang Yu if (done)
63a1d2a633SQiang Yu lima_sched_pipe_task_done(pipe);
64a1d2a633SQiang Yu
65a1d2a633SQiang Yu return IRQ_HANDLED;
66a1d2a633SQiang Yu }
67a1d2a633SQiang Yu
lima_gp_soft_reset_async(struct lima_ip * ip)68a1d2a633SQiang Yu static void lima_gp_soft_reset_async(struct lima_ip *ip)
69a1d2a633SQiang Yu {
70a1d2a633SQiang Yu if (ip->data.async_reset)
71a1d2a633SQiang Yu return;
72a1d2a633SQiang Yu
73a1d2a633SQiang Yu gp_write(LIMA_GP_INT_MASK, 0);
74a1d2a633SQiang Yu gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_RESET_COMPLETED);
75a1d2a633SQiang Yu gp_write(LIMA_GP_CMD, LIMA_GP_CMD_SOFT_RESET);
76a1d2a633SQiang Yu ip->data.async_reset = true;
77a1d2a633SQiang Yu }
78a1d2a633SQiang Yu
lima_gp_soft_reset_async_wait(struct lima_ip * ip)79a1d2a633SQiang Yu static int lima_gp_soft_reset_async_wait(struct lima_ip *ip)
80a1d2a633SQiang Yu {
81a1d2a633SQiang Yu struct lima_device *dev = ip->dev;
82a1d2a633SQiang Yu int err;
83a1d2a633SQiang Yu u32 v;
84a1d2a633SQiang Yu
85a1d2a633SQiang Yu if (!ip->data.async_reset)
86a1d2a633SQiang Yu return 0;
87a1d2a633SQiang Yu
88a1d2a633SQiang Yu err = readl_poll_timeout(ip->iomem + LIMA_GP_INT_RAWSTAT, v,
89a1d2a633SQiang Yu v & LIMA_GP_IRQ_RESET_COMPLETED,
90a1d2a633SQiang Yu 0, 100);
91a1d2a633SQiang Yu if (err) {
92a1d2a633SQiang Yu dev_err(dev->dev, "gp soft reset time out\n");
93a1d2a633SQiang Yu return err;
94a1d2a633SQiang Yu }
95a1d2a633SQiang Yu
96a1d2a633SQiang Yu gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL);
97a1d2a633SQiang Yu gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
98a1d2a633SQiang Yu
99a1d2a633SQiang Yu ip->data.async_reset = false;
100a1d2a633SQiang Yu return 0;
101a1d2a633SQiang Yu }
102a1d2a633SQiang Yu
lima_gp_task_validate(struct lima_sched_pipe * pipe,struct lima_sched_task * task)103a1d2a633SQiang Yu static int lima_gp_task_validate(struct lima_sched_pipe *pipe,
104a1d2a633SQiang Yu struct lima_sched_task *task)
105a1d2a633SQiang Yu {
106a1d2a633SQiang Yu struct drm_lima_gp_frame *frame = task->frame;
107a1d2a633SQiang Yu u32 *f = frame->frame;
108a1d2a633SQiang Yu (void)pipe;
109a1d2a633SQiang Yu
110a1d2a633SQiang Yu if (f[LIMA_GP_VSCL_START_ADDR >> 2] >
111a1d2a633SQiang Yu f[LIMA_GP_VSCL_END_ADDR >> 2] ||
112a1d2a633SQiang Yu f[LIMA_GP_PLBUCL_START_ADDR >> 2] >
113a1d2a633SQiang Yu f[LIMA_GP_PLBUCL_END_ADDR >> 2] ||
114a1d2a633SQiang Yu f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] >
115a1d2a633SQiang Yu f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2])
116a1d2a633SQiang Yu return -EINVAL;
117a1d2a633SQiang Yu
118a1d2a633SQiang Yu if (f[LIMA_GP_VSCL_START_ADDR >> 2] ==
119a1d2a633SQiang Yu f[LIMA_GP_VSCL_END_ADDR >> 2] &&
120a1d2a633SQiang Yu f[LIMA_GP_PLBUCL_START_ADDR >> 2] ==
121a1d2a633SQiang Yu f[LIMA_GP_PLBUCL_END_ADDR >> 2])
122a1d2a633SQiang Yu return -EINVAL;
123a1d2a633SQiang Yu
124a1d2a633SQiang Yu return 0;
125a1d2a633SQiang Yu }
126a1d2a633SQiang Yu
lima_gp_task_run(struct lima_sched_pipe * pipe,struct lima_sched_task * task)127a1d2a633SQiang Yu static void lima_gp_task_run(struct lima_sched_pipe *pipe,
128a1d2a633SQiang Yu struct lima_sched_task *task)
129a1d2a633SQiang Yu {
130a1d2a633SQiang Yu struct lima_ip *ip = pipe->processor[0];
131a1d2a633SQiang Yu struct drm_lima_gp_frame *frame = task->frame;
132a1d2a633SQiang Yu u32 *f = frame->frame;
133a1d2a633SQiang Yu u32 cmd = 0;
134a1d2a633SQiang Yu int i;
135a1d2a633SQiang Yu
1362081e8dcSQiang Yu /* update real heap buffer size for GP */
1372081e8dcSQiang Yu for (i = 0; i < task->num_bos; i++) {
1382081e8dcSQiang Yu struct lima_bo *bo = task->bos[i];
1392081e8dcSQiang Yu
1402081e8dcSQiang Yu if (bo->heap_size &&
1412081e8dcSQiang Yu lima_vm_get_va(task->vm, bo) ==
1422081e8dcSQiang Yu f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]) {
1432081e8dcSQiang Yu f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
1442081e8dcSQiang Yu f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] +
1452081e8dcSQiang Yu bo->heap_size;
1462081e8dcSQiang Yu task->recoverable = true;
1472081e8dcSQiang Yu task->heap = bo;
1482081e8dcSQiang Yu break;
1492081e8dcSQiang Yu }
1502081e8dcSQiang Yu }
1512081e8dcSQiang Yu
152a1d2a633SQiang Yu if (f[LIMA_GP_VSCL_START_ADDR >> 2] !=
153a1d2a633SQiang Yu f[LIMA_GP_VSCL_END_ADDR >> 2])
154a1d2a633SQiang Yu cmd |= LIMA_GP_CMD_START_VS;
155a1d2a633SQiang Yu if (f[LIMA_GP_PLBUCL_START_ADDR >> 2] !=
156a1d2a633SQiang Yu f[LIMA_GP_PLBUCL_END_ADDR >> 2])
157a1d2a633SQiang Yu cmd |= LIMA_GP_CMD_START_PLBU;
158a1d2a633SQiang Yu
159a1d2a633SQiang Yu /* before any hw ops, wait last success task async soft reset */
160a1d2a633SQiang Yu lima_gp_soft_reset_async_wait(ip);
161a1d2a633SQiang Yu
162a1d2a633SQiang Yu for (i = 0; i < LIMA_GP_FRAME_REG_NUM; i++)
163a1d2a633SQiang Yu writel(f[i], ip->iomem + LIMA_GP_VSCL_START_ADDR + i * 4);
164a1d2a633SQiang Yu
165a1d2a633SQiang Yu gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
166a1d2a633SQiang Yu gp_write(LIMA_GP_CMD, cmd);
167a1d2a633SQiang Yu }
168a1d2a633SQiang Yu
lima_gp_bus_stop_poll(struct lima_ip * ip)169*93249026SErico Nunes static int lima_gp_bus_stop_poll(struct lima_ip *ip)
170*93249026SErico Nunes {
171*93249026SErico Nunes return !!(gp_read(LIMA_GP_STATUS) & LIMA_GP_STATUS_BUS_STOPPED);
172*93249026SErico Nunes }
173*93249026SErico Nunes
lima_gp_hard_reset_poll(struct lima_ip * ip)174a1d2a633SQiang Yu static int lima_gp_hard_reset_poll(struct lima_ip *ip)
175a1d2a633SQiang Yu {
176a1d2a633SQiang Yu gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000);
177a1d2a633SQiang Yu return gp_read(LIMA_GP_PERF_CNT_0_LIMIT) == 0xC01A0000;
178a1d2a633SQiang Yu }
179a1d2a633SQiang Yu
lima_gp_hard_reset(struct lima_ip * ip)180a1d2a633SQiang Yu static int lima_gp_hard_reset(struct lima_ip *ip)
181a1d2a633SQiang Yu {
182a1d2a633SQiang Yu struct lima_device *dev = ip->dev;
183a1d2a633SQiang Yu int ret;
184a1d2a633SQiang Yu
185a1d2a633SQiang Yu gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000);
186a1d2a633SQiang Yu gp_write(LIMA_GP_INT_MASK, 0);
187*93249026SErico Nunes
188*93249026SErico Nunes gp_write(LIMA_GP_CMD, LIMA_GP_CMD_STOP_BUS);
189*93249026SErico Nunes ret = lima_poll_timeout(ip, lima_gp_bus_stop_poll, 10, 100);
190*93249026SErico Nunes if (ret) {
191*93249026SErico Nunes dev_err(dev->dev, "%s bus stop timeout\n", lima_ip_name(ip));
192*93249026SErico Nunes return ret;
193*93249026SErico Nunes }
194a1d2a633SQiang Yu gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET);
195a1d2a633SQiang Yu ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100);
196a1d2a633SQiang Yu if (ret) {
197a1d2a633SQiang Yu dev_err(dev->dev, "gp hard reset timeout\n");
198a1d2a633SQiang Yu return ret;
199a1d2a633SQiang Yu }
200a1d2a633SQiang Yu
201a1d2a633SQiang Yu gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0);
202a1d2a633SQiang Yu gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL);
203a1d2a633SQiang Yu gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
204a1d2a633SQiang Yu return 0;
205a1d2a633SQiang Yu }
206a1d2a633SQiang Yu
lima_gp_task_fini(struct lima_sched_pipe * pipe)207a1d2a633SQiang Yu static void lima_gp_task_fini(struct lima_sched_pipe *pipe)
208a1d2a633SQiang Yu {
209a1d2a633SQiang Yu lima_gp_soft_reset_async(pipe->processor[0]);
210a1d2a633SQiang Yu }
211a1d2a633SQiang Yu
lima_gp_task_error(struct lima_sched_pipe * pipe)212a1d2a633SQiang Yu static void lima_gp_task_error(struct lima_sched_pipe *pipe)
213a1d2a633SQiang Yu {
214a1d2a633SQiang Yu struct lima_ip *ip = pipe->processor[0];
215a1d2a633SQiang Yu
216a1d2a633SQiang Yu dev_err(ip->dev->dev, "gp task error int_state=%x status=%x\n",
217a1d2a633SQiang Yu gp_read(LIMA_GP_INT_STAT), gp_read(LIMA_GP_STATUS));
218a1d2a633SQiang Yu
219a1d2a633SQiang Yu lima_gp_hard_reset(ip);
220a1d2a633SQiang Yu }
221a1d2a633SQiang Yu
lima_gp_task_mmu_error(struct lima_sched_pipe * pipe)222a1d2a633SQiang Yu static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe)
223a1d2a633SQiang Yu {
224a1d2a633SQiang Yu lima_sched_pipe_task_done(pipe);
225a1d2a633SQiang Yu }
226a1d2a633SQiang Yu
lima_gp_task_mask_irq(struct lima_sched_pipe * pipe)227022db5d6SErico Nunes static void lima_gp_task_mask_irq(struct lima_sched_pipe *pipe)
228022db5d6SErico Nunes {
229022db5d6SErico Nunes struct lima_ip *ip = pipe->processor[0];
230022db5d6SErico Nunes
231022db5d6SErico Nunes gp_write(LIMA_GP_INT_MASK, 0);
232022db5d6SErico Nunes }
233022db5d6SErico Nunes
lima_gp_task_recover(struct lima_sched_pipe * pipe)2342081e8dcSQiang Yu static int lima_gp_task_recover(struct lima_sched_pipe *pipe)
2352081e8dcSQiang Yu {
2362081e8dcSQiang Yu struct lima_ip *ip = pipe->processor[0];
2372081e8dcSQiang Yu struct lima_sched_task *task = pipe->current_task;
2382081e8dcSQiang Yu struct drm_lima_gp_frame *frame = task->frame;
2392081e8dcSQiang Yu u32 *f = frame->frame;
2402081e8dcSQiang Yu size_t fail_size =
2412081e8dcSQiang Yu f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] -
2422081e8dcSQiang Yu f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2];
2432081e8dcSQiang Yu
2442081e8dcSQiang Yu if (fail_size == task->heap->heap_size) {
2452081e8dcSQiang Yu int ret;
2462081e8dcSQiang Yu
2472081e8dcSQiang Yu ret = lima_heap_alloc(task->heap, task->vm);
2482081e8dcSQiang Yu if (ret < 0)
2492081e8dcSQiang Yu return ret;
2502081e8dcSQiang Yu }
2512081e8dcSQiang Yu
2522081e8dcSQiang Yu gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
2536707b755SVasily Khoruzhick /* Resume from where we stopped, i.e. new start is old end */
2546707b755SVasily Khoruzhick gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR,
2556707b755SVasily Khoruzhick f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
2566707b755SVasily Khoruzhick f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
2576707b755SVasily Khoruzhick f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size;
2582081e8dcSQiang Yu gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR,
2596707b755SVasily Khoruzhick f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
2602081e8dcSQiang Yu gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
2612081e8dcSQiang Yu return 0;
2622081e8dcSQiang Yu }
2632081e8dcSQiang Yu
lima_gp_print_version(struct lima_ip * ip)264a1d2a633SQiang Yu static void lima_gp_print_version(struct lima_ip *ip)
265a1d2a633SQiang Yu {
266a1d2a633SQiang Yu u32 version, major, minor;
267a1d2a633SQiang Yu char *name;
268a1d2a633SQiang Yu
269a1d2a633SQiang Yu version = gp_read(LIMA_GP_VERSION);
270a1d2a633SQiang Yu major = (version >> 8) & 0xFF;
271a1d2a633SQiang Yu minor = version & 0xFF;
272a1d2a633SQiang Yu switch (version >> 16) {
273a1d2a633SQiang Yu case 0xA07:
274a1d2a633SQiang Yu name = "mali200";
275a1d2a633SQiang Yu break;
276a1d2a633SQiang Yu case 0xC07:
277a1d2a633SQiang Yu name = "mali300";
278a1d2a633SQiang Yu break;
279a1d2a633SQiang Yu case 0xB07:
280a1d2a633SQiang Yu name = "mali400";
281a1d2a633SQiang Yu break;
282a1d2a633SQiang Yu case 0xD07:
283a1d2a633SQiang Yu name = "mali450";
284a1d2a633SQiang Yu break;
285a1d2a633SQiang Yu default:
286a1d2a633SQiang Yu name = "unknown";
287a1d2a633SQiang Yu break;
288a1d2a633SQiang Yu }
289a1d2a633SQiang Yu dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n",
290a1d2a633SQiang Yu lima_ip_name(ip), name, major, minor);
291a1d2a633SQiang Yu }
292a1d2a633SQiang Yu
293a1d2a633SQiang Yu static struct kmem_cache *lima_gp_task_slab;
294a1d2a633SQiang Yu static int lima_gp_task_slab_refcnt;
295a1d2a633SQiang Yu
lima_gp_hw_init(struct lima_ip * ip)2963446d7e9SQiang Yu static int lima_gp_hw_init(struct lima_ip *ip)
2973446d7e9SQiang Yu {
2983446d7e9SQiang Yu ip->data.async_reset = false;
2993446d7e9SQiang Yu lima_gp_soft_reset_async(ip);
3003446d7e9SQiang Yu return lima_gp_soft_reset_async_wait(ip);
3013446d7e9SQiang Yu }
3023446d7e9SQiang Yu
lima_gp_resume(struct lima_ip * ip)3033446d7e9SQiang Yu int lima_gp_resume(struct lima_ip *ip)
3043446d7e9SQiang Yu {
3053446d7e9SQiang Yu return lima_gp_hw_init(ip);
3063446d7e9SQiang Yu }
3073446d7e9SQiang Yu
lima_gp_suspend(struct lima_ip * ip)3083446d7e9SQiang Yu void lima_gp_suspend(struct lima_ip *ip)
3093446d7e9SQiang Yu {
3103446d7e9SQiang Yu
3113446d7e9SQiang Yu }
3123446d7e9SQiang Yu
lima_gp_init(struct lima_ip * ip)313a1d2a633SQiang Yu int lima_gp_init(struct lima_ip *ip)
314a1d2a633SQiang Yu {
315a1d2a633SQiang Yu struct lima_device *dev = ip->dev;
316a1d2a633SQiang Yu int err;
317a1d2a633SQiang Yu
318a1d2a633SQiang Yu lima_gp_print_version(ip);
319a1d2a633SQiang Yu
3203446d7e9SQiang Yu err = lima_gp_hw_init(ip);
321a1d2a633SQiang Yu if (err)
322a1d2a633SQiang Yu return err;
323a1d2a633SQiang Yu
324a1d2a633SQiang Yu err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler,
325a1d2a633SQiang Yu IRQF_SHARED, lima_ip_name(ip), ip);
326a1d2a633SQiang Yu if (err) {
327a1d2a633SQiang Yu dev_err(dev->dev, "gp %s fail to request irq\n",
328a1d2a633SQiang Yu lima_ip_name(ip));
329a1d2a633SQiang Yu return err;
330a1d2a633SQiang Yu }
331a1d2a633SQiang Yu
332a1d2a633SQiang Yu dev->gp_version = gp_read(LIMA_GP_VERSION);
333a1d2a633SQiang Yu
334a1d2a633SQiang Yu return 0;
335a1d2a633SQiang Yu }
336a1d2a633SQiang Yu
lima_gp_fini(struct lima_ip * ip)337a1d2a633SQiang Yu void lima_gp_fini(struct lima_ip *ip)
338a1d2a633SQiang Yu {
33904d531b9SErico Nunes struct lima_device *dev = ip->dev;
340a1d2a633SQiang Yu
34104d531b9SErico Nunes devm_free_irq(dev->dev, ip->irq, ip);
342a1d2a633SQiang Yu }
343a1d2a633SQiang Yu
lima_gp_pipe_init(struct lima_device * dev)344a1d2a633SQiang Yu int lima_gp_pipe_init(struct lima_device *dev)
345a1d2a633SQiang Yu {
346a1d2a633SQiang Yu int frame_size = sizeof(struct drm_lima_gp_frame);
347a1d2a633SQiang Yu struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
348a1d2a633SQiang Yu
349a1d2a633SQiang Yu if (!lima_gp_task_slab) {
350a1d2a633SQiang Yu lima_gp_task_slab = kmem_cache_create_usercopy(
351a1d2a633SQiang Yu "lima_gp_task", sizeof(struct lima_sched_task) + frame_size,
352a1d2a633SQiang Yu 0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task),
353a1d2a633SQiang Yu frame_size, NULL);
354a1d2a633SQiang Yu if (!lima_gp_task_slab)
355a1d2a633SQiang Yu return -ENOMEM;
356a1d2a633SQiang Yu }
357a1d2a633SQiang Yu lima_gp_task_slab_refcnt++;
358a1d2a633SQiang Yu
359a1d2a633SQiang Yu pipe->frame_size = frame_size;
360a1d2a633SQiang Yu pipe->task_slab = lima_gp_task_slab;
361a1d2a633SQiang Yu
362a1d2a633SQiang Yu pipe->task_validate = lima_gp_task_validate;
363a1d2a633SQiang Yu pipe->task_run = lima_gp_task_run;
364a1d2a633SQiang Yu pipe->task_fini = lima_gp_task_fini;
365a1d2a633SQiang Yu pipe->task_error = lima_gp_task_error;
366a1d2a633SQiang Yu pipe->task_mmu_error = lima_gp_task_mmu_error;
3672081e8dcSQiang Yu pipe->task_recover = lima_gp_task_recover;
368022db5d6SErico Nunes pipe->task_mask_irq = lima_gp_task_mask_irq;
369a1d2a633SQiang Yu
370a1d2a633SQiang Yu return 0;
371a1d2a633SQiang Yu }
372a1d2a633SQiang Yu
lima_gp_pipe_fini(struct lima_device * dev)373a1d2a633SQiang Yu void lima_gp_pipe_fini(struct lima_device *dev)
374a1d2a633SQiang Yu {
375a1d2a633SQiang Yu if (!--lima_gp_task_slab_refcnt) {
376a1d2a633SQiang Yu kmem_cache_destroy(lima_gp_task_slab);
377a1d2a633SQiang Yu lima_gp_task_slab = NULL;
378a1d2a633SQiang Yu }
379a1d2a633SQiang Yu }
380