Commit | Line | Data |
---|---|---|
5d7422cf JL |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * Copyright (C) 2020-2023 Intel Corporation | |
4 | */ | |
5 | ||
6 | #include <linux/genalloc.h> | |
7 | #include <linux/highmem.h> | |
8 | #include <linux/kthread.h> | |
9 | #include <linux/wait.h> | |
10 | ||
11 | #include "ivpu_drv.h" | |
12 | #include "ivpu_gem.h" | |
13 | #include "ivpu_hw.h" | |
14 | #include "ivpu_hw_reg_io.h" | |
15 | #include "ivpu_ipc.h" | |
16 | #include "ivpu_jsm_msg.h" | |
852be13f | 17 | #include "ivpu_pm.h" |
5d7422cf JL |
18 | |
19 | #define IPC_MAX_RX_MSG 128 | |
20 | #define IS_KTHREAD() (get_current()->flags & PF_KTHREAD) | |
21 | ||
22 | struct ivpu_ipc_tx_buf { | |
23 | struct ivpu_ipc_hdr ipc; | |
24 | struct vpu_jsm_msg jsm; | |
25 | }; | |
26 | ||
27 | struct ivpu_ipc_rx_msg { | |
28 | struct list_head link; | |
29 | struct ivpu_ipc_hdr *ipc_hdr; | |
30 | struct vpu_jsm_msg *jsm_msg; | |
31 | }; | |
32 | ||
33 | static void ivpu_ipc_msg_dump(struct ivpu_device *vdev, char *c, | |
34 | struct ivpu_ipc_hdr *ipc_hdr, u32 vpu_addr) | |
35 | { | |
36 | ivpu_dbg(vdev, IPC, | |
37 | "%s: vpu:0x%x (data_addr:0x%08x, data_size:0x%x, channel:0x%x, src_node:0x%x, dst_node:0x%x, status:0x%x)", | |
38 | c, vpu_addr, ipc_hdr->data_addr, ipc_hdr->data_size, ipc_hdr->channel, | |
39 | ipc_hdr->src_node, ipc_hdr->dst_node, ipc_hdr->status); | |
40 | } | |
41 | ||
42 | static void ivpu_jsm_msg_dump(struct ivpu_device *vdev, char *c, | |
43 | struct vpu_jsm_msg *jsm_msg, u32 vpu_addr) | |
44 | { | |
45 | u32 *payload = (u32 *)&jsm_msg->payload; | |
46 | ||
47 | ivpu_dbg(vdev, JSM, | |
48 | "%s: vpu:0x%08x (type:0x%x, status:0x%x, id: 0x%x, result: 0x%x, payload:0x%x 0x%x 0x%x 0x%x 0x%x)\n", | |
49 | c, vpu_addr, jsm_msg->type, jsm_msg->status, jsm_msg->request_id, jsm_msg->result, | |
50 | payload[0], payload[1], payload[2], payload[3], payload[4]); | |
51 | } | |
52 | ||
53 | static void | |
54 | ivpu_ipc_rx_mark_free(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr, | |
55 | struct vpu_jsm_msg *jsm_msg) | |
56 | { | |
57 | ipc_hdr->status = IVPU_IPC_HDR_FREE; | |
58 | if (jsm_msg) | |
59 | jsm_msg->status = VPU_JSM_MSG_FREE; | |
60 | wmb(); /* Flush WC buffers for message statuses */ | |
61 | } | |
62 | ||
63 | static void ivpu_ipc_mem_fini(struct ivpu_device *vdev) | |
64 | { | |
65 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
66 | ||
67 | ivpu_bo_free_internal(ipc->mem_rx); | |
68 | ivpu_bo_free_internal(ipc->mem_tx); | |
69 | } | |
70 | ||
71 | static int | |
72 | ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, | |
73 | struct vpu_jsm_msg *req) | |
74 | { | |
75 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
76 | struct ivpu_ipc_tx_buf *tx_buf; | |
77 | u32 tx_buf_vpu_addr; | |
78 | u32 jsm_vpu_addr; | |
79 | ||
80 | tx_buf_vpu_addr = gen_pool_alloc(ipc->mm_tx, sizeof(*tx_buf)); | |
81 | if (!tx_buf_vpu_addr) { | |
82 | ivpu_err(vdev, "Failed to reserve IPC buffer, size %ld\n", | |
83 | sizeof(*tx_buf)); | |
84 | return -ENOMEM; | |
85 | } | |
86 | ||
87 | tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr); | |
88 | if (drm_WARN_ON(&vdev->drm, !tx_buf)) { | |
89 | gen_pool_free(ipc->mm_tx, tx_buf_vpu_addr, sizeof(*tx_buf)); | |
90 | return -EIO; | |
91 | } | |
92 | ||
93 | jsm_vpu_addr = tx_buf_vpu_addr + offsetof(struct ivpu_ipc_tx_buf, jsm); | |
94 | ||
95 | if (tx_buf->ipc.status != IVPU_IPC_HDR_FREE) | |
96 | ivpu_warn(vdev, "IPC message vpu:0x%x not released by firmware\n", | |
97 | tx_buf_vpu_addr); | |
98 | ||
99 | if (tx_buf->jsm.status != VPU_JSM_MSG_FREE) | |
100 | ivpu_warn(vdev, "JSM message vpu:0x%x not released by firmware\n", | |
101 | jsm_vpu_addr); | |
102 | ||
103 | memset(tx_buf, 0, sizeof(*tx_buf)); | |
104 | tx_buf->ipc.data_addr = jsm_vpu_addr; | |
105 | /* TODO: Set data_size to actual JSM message size, not union of all messages */ | |
106 | tx_buf->ipc.data_size = sizeof(*req); | |
107 | tx_buf->ipc.channel = cons->channel; | |
108 | tx_buf->ipc.src_node = 0; | |
109 | tx_buf->ipc.dst_node = 1; | |
110 | tx_buf->ipc.status = IVPU_IPC_HDR_ALLOCATED; | |
111 | tx_buf->jsm.type = req->type; | |
112 | tx_buf->jsm.status = VPU_JSM_MSG_ALLOCATED; | |
113 | tx_buf->jsm.payload = req->payload; | |
114 | ||
115 | req->request_id = atomic_inc_return(&ipc->request_id); | |
116 | tx_buf->jsm.request_id = req->request_id; | |
117 | cons->request_id = req->request_id; | |
118 | wmb(); /* Flush WC buffers for IPC, JSM msgs */ | |
119 | ||
120 | cons->tx_vpu_addr = tx_buf_vpu_addr; | |
121 | ||
122 | ivpu_jsm_msg_dump(vdev, "TX", &tx_buf->jsm, jsm_vpu_addr); | |
123 | ivpu_ipc_msg_dump(vdev, "TX", &tx_buf->ipc, tx_buf_vpu_addr); | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static void ivpu_ipc_tx_release(struct ivpu_device *vdev, u32 vpu_addr) | |
129 | { | |
130 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
131 | ||
132 | if (vpu_addr) | |
133 | gen_pool_free(ipc->mm_tx, vpu_addr, sizeof(struct ivpu_ipc_tx_buf)); | |
134 | } | |
135 | ||
136 | static void ivpu_ipc_tx(struct ivpu_device *vdev, u32 vpu_addr) | |
137 | { | |
138 | ivpu_hw_reg_ipc_tx_set(vdev, vpu_addr); | |
139 | } | |
140 | ||
141 | void | |
142 | ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, u32 channel) | |
143 | { | |
144 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
145 | ||
146 | INIT_LIST_HEAD(&cons->link); | |
147 | cons->channel = channel; | |
148 | cons->tx_vpu_addr = 0; | |
149 | cons->request_id = 0; | |
150 | spin_lock_init(&cons->rx_msg_lock); | |
151 | INIT_LIST_HEAD(&cons->rx_msg_list); | |
152 | init_waitqueue_head(&cons->rx_msg_wq); | |
153 | ||
154 | spin_lock_irq(&ipc->cons_list_lock); | |
155 | list_add_tail(&cons->link, &ipc->cons_list); | |
156 | spin_unlock_irq(&ipc->cons_list_lock); | |
157 | } | |
158 | ||
159 | void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons) | |
160 | { | |
161 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
162 | struct ivpu_ipc_rx_msg *rx_msg, *r; | |
163 | ||
164 | spin_lock_irq(&ipc->cons_list_lock); | |
165 | list_del(&cons->link); | |
166 | spin_unlock_irq(&ipc->cons_list_lock); | |
167 | ||
168 | spin_lock_irq(&cons->rx_msg_lock); | |
169 | list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) { | |
170 | list_del(&rx_msg->link); | |
171 | ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); | |
172 | atomic_dec(&ipc->rx_msg_count); | |
173 | kfree(rx_msg); | |
174 | } | |
175 | spin_unlock_irq(&cons->rx_msg_lock); | |
176 | ||
177 | ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr); | |
178 | } | |
179 | ||
180 | static int | |
181 | ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct vpu_jsm_msg *req) | |
182 | { | |
183 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
184 | int ret; | |
185 | ||
186 | ret = mutex_lock_interruptible(&ipc->lock); | |
187 | if (ret) | |
188 | return ret; | |
189 | ||
190 | if (!ipc->on) { | |
191 | ret = -EAGAIN; | |
192 | goto unlock; | |
193 | } | |
194 | ||
195 | ret = ivpu_ipc_tx_prepare(vdev, cons, req); | |
196 | if (ret) | |
197 | goto unlock; | |
198 | ||
199 | ivpu_ipc_tx(vdev, cons->tx_vpu_addr); | |
200 | ||
201 | unlock: | |
202 | mutex_unlock(&ipc->lock); | |
203 | return ret; | |
204 | } | |
205 | ||
206 | int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, | |
207 | struct ivpu_ipc_hdr *ipc_buf, | |
208 | struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms) | |
209 | { | |
210 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
211 | struct ivpu_ipc_rx_msg *rx_msg; | |
212 | int wait_ret, ret = 0; | |
213 | ||
214 | wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq, | |
215 | (IS_KTHREAD() && kthread_should_stop()) || | |
216 | !list_empty(&cons->rx_msg_list), | |
217 | msecs_to_jiffies(timeout_ms)); | |
218 | ||
219 | if (IS_KTHREAD() && kthread_should_stop()) | |
220 | return -EINTR; | |
221 | ||
222 | if (wait_ret == 0) | |
223 | return -ETIMEDOUT; | |
224 | ||
225 | if (wait_ret < 0) | |
226 | return -ERESTARTSYS; | |
227 | ||
228 | spin_lock_irq(&cons->rx_msg_lock); | |
229 | rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link); | |
230 | if (!rx_msg) { | |
231 | spin_unlock_irq(&cons->rx_msg_lock); | |
232 | return -EAGAIN; | |
233 | } | |
234 | list_del(&rx_msg->link); | |
235 | spin_unlock_irq(&cons->rx_msg_lock); | |
236 | ||
237 | if (ipc_buf) | |
238 | memcpy(ipc_buf, rx_msg->ipc_hdr, sizeof(*ipc_buf)); | |
239 | if (rx_msg->jsm_msg) { | |
240 | u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*ipc_payload)); | |
241 | ||
242 | if (rx_msg->jsm_msg->result != VPU_JSM_STATUS_SUCCESS) { | |
243 | ivpu_dbg(vdev, IPC, "IPC resp result error: %d\n", rx_msg->jsm_msg->result); | |
244 | ret = -EBADMSG; | |
245 | } | |
246 | ||
247 | if (ipc_payload) | |
248 | memcpy(ipc_payload, rx_msg->jsm_msg, size); | |
249 | } | |
250 | ||
251 | ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); | |
252 | atomic_dec(&ipc->rx_msg_count); | |
253 | kfree(rx_msg); | |
254 | ||
255 | return ret; | |
256 | } | |
257 | ||
258 | static int | |
259 | ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req, | |
260 | enum vpu_ipc_msg_type expected_resp_type, | |
261 | struct vpu_jsm_msg *resp, u32 channel, | |
262 | unsigned long timeout_ms) | |
263 | { | |
264 | struct ivpu_ipc_consumer cons; | |
265 | int ret; | |
266 | ||
267 | ivpu_ipc_consumer_add(vdev, &cons, channel); | |
268 | ||
269 | ret = ivpu_ipc_send(vdev, &cons, req); | |
270 | if (ret) { | |
271 | ivpu_warn(vdev, "IPC send failed: %d\n", ret); | |
272 | goto consumer_del; | |
273 | } | |
274 | ||
275 | ret = ivpu_ipc_receive(vdev, &cons, NULL, resp, timeout_ms); | |
276 | if (ret) { | |
277 | ivpu_warn(vdev, "IPC receive failed: type 0x%x, ret %d\n", req->type, ret); | |
278 | goto consumer_del; | |
279 | } | |
280 | ||
281 | if (resp->type != expected_resp_type) { | |
282 | ivpu_warn(vdev, "Invalid JSM response type: 0x%x\n", resp->type); | |
283 | ret = -EBADE; | |
284 | } | |
285 | ||
286 | consumer_del: | |
287 | ivpu_ipc_consumer_del(vdev, &cons); | |
288 | return ret; | |
289 | } | |
290 | ||
291 | int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, | |
292 | enum vpu_ipc_msg_type expected_resp_type, | |
293 | struct vpu_jsm_msg *resp, u32 channel, | |
294 | unsigned long timeout_ms) | |
295 | { | |
296 | struct vpu_jsm_msg hb_req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB }; | |
297 | struct vpu_jsm_msg hb_resp; | |
852be13f JL |
298 | int ret, hb_ret; |
299 | ||
300 | ret = ivpu_rpm_get(vdev); | |
301 | if (ret < 0) | |
302 | return ret; | |
5d7422cf JL |
303 | |
304 | ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp_type, resp, | |
305 | channel, timeout_ms); | |
306 | if (ret != -ETIMEDOUT) | |
852be13f | 307 | goto rpm_put; |
5d7422cf | 308 | |
852be13f JL |
309 | hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, |
310 | &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, | |
311 | vdev->timeout.jsm); | |
312 | if (hb_ret == -ETIMEDOUT) { | |
5d7422cf | 313 | ivpu_hw_diagnose_failure(vdev); |
852be13f JL |
314 | ivpu_pm_schedule_recovery(vdev); |
315 | } | |
5d7422cf | 316 | |
852be13f JL |
317 | rpm_put: |
318 | ivpu_rpm_put(vdev); | |
5d7422cf JL |
319 | return ret; |
320 | } | |
321 | ||
322 | static bool | |
323 | ivpu_ipc_match_consumer(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, | |
324 | struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg) | |
325 | { | |
326 | if (cons->channel != ipc_hdr->channel) | |
327 | return false; | |
328 | ||
329 | if (!jsm_msg || jsm_msg->request_id == cons->request_id) | |
330 | return true; | |
331 | ||
332 | return false; | |
333 | } | |
334 | ||
335 | static void | |
336 | ivpu_ipc_dispatch(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, | |
337 | struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg) | |
338 | { | |
339 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
340 | struct ivpu_ipc_rx_msg *rx_msg; | |
341 | unsigned long flags; | |
342 | ||
343 | lockdep_assert_held(&ipc->cons_list_lock); | |
344 | ||
345 | rx_msg = kzalloc(sizeof(*rx_msg), GFP_ATOMIC); | |
346 | if (!rx_msg) { | |
347 | ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg); | |
348 | return; | |
349 | } | |
350 | ||
351 | atomic_inc(&ipc->rx_msg_count); | |
352 | ||
353 | rx_msg->ipc_hdr = ipc_hdr; | |
354 | rx_msg->jsm_msg = jsm_msg; | |
355 | ||
356 | spin_lock_irqsave(&cons->rx_msg_lock, flags); | |
357 | list_add_tail(&rx_msg->link, &cons->rx_msg_list); | |
358 | spin_unlock_irqrestore(&cons->rx_msg_lock, flags); | |
359 | ||
360 | wake_up(&cons->rx_msg_wq); | |
361 | } | |
362 | ||
363 | int ivpu_ipc_irq_handler(struct ivpu_device *vdev) | |
364 | { | |
365 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
366 | struct ivpu_ipc_consumer *cons; | |
367 | struct ivpu_ipc_hdr *ipc_hdr; | |
368 | struct vpu_jsm_msg *jsm_msg; | |
369 | unsigned long flags; | |
370 | bool dispatched; | |
371 | u32 vpu_addr; | |
372 | ||
373 | /* | |
374 | * Driver needs to purge all messages from IPC FIFO to clear IPC interrupt. | |
375 | * Without purge IPC FIFO to 0 next IPC interrupts won't be generated. | |
376 | */ | |
377 | while (ivpu_hw_reg_ipc_rx_count_get(vdev)) { | |
378 | vpu_addr = ivpu_hw_reg_ipc_rx_addr_get(vdev); | |
379 | if (vpu_addr == REG_IO_ERROR) { | |
380 | ivpu_err(vdev, "Failed to read IPC rx addr register\n"); | |
381 | return -EIO; | |
382 | } | |
383 | ||
384 | ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr); | |
385 | if (!ipc_hdr) { | |
386 | ivpu_warn(vdev, "IPC msg 0x%x out of range\n", vpu_addr); | |
387 | continue; | |
388 | } | |
389 | ivpu_ipc_msg_dump(vdev, "RX", ipc_hdr, vpu_addr); | |
390 | ||
391 | jsm_msg = NULL; | |
392 | if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) { | |
393 | jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr); | |
394 | if (!jsm_msg) { | |
395 | ivpu_warn(vdev, "JSM msg 0x%x out of range\n", ipc_hdr->data_addr); | |
396 | ivpu_ipc_rx_mark_free(vdev, ipc_hdr, NULL); | |
397 | continue; | |
398 | } | |
399 | ivpu_jsm_msg_dump(vdev, "RX", jsm_msg, ipc_hdr->data_addr); | |
400 | } | |
401 | ||
402 | if (atomic_read(&ipc->rx_msg_count) > IPC_MAX_RX_MSG) { | |
403 | ivpu_warn(vdev, "IPC RX msg dropped, msg count %d\n", IPC_MAX_RX_MSG); | |
404 | ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg); | |
405 | continue; | |
406 | } | |
407 | ||
408 | dispatched = false; | |
409 | spin_lock_irqsave(&ipc->cons_list_lock, flags); | |
410 | list_for_each_entry(cons, &ipc->cons_list, link) { | |
411 | if (ivpu_ipc_match_consumer(vdev, cons, ipc_hdr, jsm_msg)) { | |
412 | ivpu_ipc_dispatch(vdev, cons, ipc_hdr, jsm_msg); | |
413 | dispatched = true; | |
414 | break; | |
415 | } | |
416 | } | |
417 | spin_unlock_irqrestore(&ipc->cons_list_lock, flags); | |
418 | ||
419 | if (!dispatched) { | |
420 | ivpu_dbg(vdev, IPC, "IPC RX msg 0x%x dropped (no consumer)\n", vpu_addr); | |
421 | ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg); | |
422 | } | |
423 | } | |
424 | ||
425 | return 0; | |
426 | } | |
427 | ||
428 | int ivpu_ipc_init(struct ivpu_device *vdev) | |
429 | { | |
430 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
431 | int ret = -ENOMEM; | |
432 | ||
433 | ipc->mem_tx = ivpu_bo_alloc_internal(vdev, 0, SZ_16K, DRM_IVPU_BO_WC); | |
434 | if (!ipc->mem_tx) | |
435 | return ret; | |
436 | ||
437 | ipc->mem_rx = ivpu_bo_alloc_internal(vdev, 0, SZ_16K, DRM_IVPU_BO_WC); | |
438 | if (!ipc->mem_rx) | |
439 | goto err_free_tx; | |
440 | ||
441 | ipc->mm_tx = devm_gen_pool_create(vdev->drm.dev, __ffs(IVPU_IPC_ALIGNMENT), | |
442 | -1, "TX_IPC_JSM"); | |
443 | if (IS_ERR(ipc->mm_tx)) { | |
444 | ret = PTR_ERR(ipc->mm_tx); | |
445 | ivpu_err(vdev, "Failed to create gen pool, %pe\n", ipc->mm_tx); | |
446 | goto err_free_rx; | |
447 | } | |
448 | ||
449 | ret = gen_pool_add(ipc->mm_tx, ipc->mem_tx->vpu_addr, ipc->mem_tx->base.size, -1); | |
450 | if (ret) { | |
451 | ivpu_err(vdev, "gen_pool_add failed, ret %d\n", ret); | |
452 | goto err_free_rx; | |
453 | } | |
454 | ||
455 | INIT_LIST_HEAD(&ipc->cons_list); | |
456 | spin_lock_init(&ipc->cons_list_lock); | |
457 | drmm_mutex_init(&vdev->drm, &ipc->lock); | |
458 | ||
459 | ivpu_ipc_reset(vdev); | |
460 | return 0; | |
461 | ||
462 | err_free_rx: | |
463 | ivpu_bo_free_internal(ipc->mem_rx); | |
464 | err_free_tx: | |
465 | ivpu_bo_free_internal(ipc->mem_tx); | |
466 | return ret; | |
467 | } | |
468 | ||
469 | void ivpu_ipc_fini(struct ivpu_device *vdev) | |
470 | { | |
471 | ivpu_ipc_mem_fini(vdev); | |
472 | } | |
473 | ||
474 | void ivpu_ipc_enable(struct ivpu_device *vdev) | |
475 | { | |
476 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
477 | ||
478 | mutex_lock(&ipc->lock); | |
479 | ipc->on = true; | |
480 | mutex_unlock(&ipc->lock); | |
481 | } | |
482 | ||
483 | void ivpu_ipc_disable(struct ivpu_device *vdev) | |
484 | { | |
485 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
486 | struct ivpu_ipc_consumer *cons, *c; | |
487 | unsigned long flags; | |
488 | ||
489 | mutex_lock(&ipc->lock); | |
490 | ipc->on = false; | |
491 | mutex_unlock(&ipc->lock); | |
492 | ||
493 | spin_lock_irqsave(&ipc->cons_list_lock, flags); | |
494 | list_for_each_entry_safe(cons, c, &ipc->cons_list, link) | |
495 | wake_up(&cons->rx_msg_wq); | |
496 | spin_unlock_irqrestore(&ipc->cons_list_lock, flags); | |
497 | } | |
498 | ||
499 | void ivpu_ipc_reset(struct ivpu_device *vdev) | |
500 | { | |
501 | struct ivpu_ipc_info *ipc = vdev->ipc; | |
502 | ||
503 | mutex_lock(&ipc->lock); | |
504 | ||
505 | memset(ipc->mem_tx->kvaddr, 0, ipc->mem_tx->base.size); | |
506 | memset(ipc->mem_rx->kvaddr, 0, ipc->mem_rx->base.size); | |
507 | wmb(); /* Flush WC buffers for TX and RX rings */ | |
508 | ||
509 | mutex_unlock(&ipc->lock); | |
510 | } |