gpu: nvgpu: ensure coherency in sema wait ioctl

The semaphore dmabuf supplied in NVGPU_IOCTL_CHANNEL_WAIT is not
necessarily always cache coherent with the GPU. Call
dma_buf_begin_cpu_access() and dma_buf_end_cpu_access() around the sema
read to make sure we see updated values after the interrupt.

Jira NVGPU-5387
Bug 3028497

Change-Id: I09d23c8a679621c86bdfe609d454199e05fa2987
Signed-off-by: Konsta Hölttä <kholtta@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2359002
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Alex Waterman <alexw@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Konsta Hölttä
2020-07-01 14:42:38 +03:00
committed by Alex Waterman
parent 530381ee86
commit d660a5d0e8

View File

@@ -629,13 +629,41 @@ static void nvgpu_get_fence_args(
fence_args_out->value = fence_args_in->value; fence_args_out->value = fence_args_in->value;
} }
static bool channel_test_user_semaphore(struct dma_buf *dmabuf, void *data,
u32 offset, u32 payload)
{
u32 *semaphore;
bool ret;
int err;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
err = dma_buf_begin_cpu_access(dmabuf, offset, sizeof(u32), DMA_FROM_DEVICE);
#else
err = dma_buf_begin_cpu_access(dmabuf, DMA_FROM_DEVICE);
#endif
if (err != 0) {
pr_err("nvgpu: sema begin cpu access failed\n");
return false;
}
semaphore = (u32 *)((uintptr_t)data + offset);
ret = *semaphore == payload;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
dma_buf_end_cpu_access(dmabuf, offset, sizeof(u32), DMA_FROM_DEVICE);
#else
dma_buf_end_cpu_access(dmabuf, DMA_FROM_DEVICE);
#endif
return ret;
}
static int gk20a_channel_wait_semaphore(struct nvgpu_channel *ch, static int gk20a_channel_wait_semaphore(struct nvgpu_channel *ch,
ulong id, u32 offset, ulong id, u32 offset,
u32 payload, u32 timeout) u32 payload, u32 timeout)
{ {
struct dma_buf *dmabuf; struct dma_buf *dmabuf;
void *data; void *data;
u32 *semaphore;
int ret = 0; int ret = 0;
/* do not wait if channel has timed out */ /* do not wait if channel has timed out */
@@ -669,11 +697,9 @@ static int gk20a_channel_wait_semaphore(struct nvgpu_channel *ch,
goto cleanup_put; goto cleanup_put;
} }
semaphore = (u32 *)((uintptr_t)data + offset);
ret = NVGPU_COND_WAIT_INTERRUPTIBLE( ret = NVGPU_COND_WAIT_INTERRUPTIBLE(
&ch->semaphore_wq, &ch->semaphore_wq,
*semaphore == payload || channel_test_user_semaphore(dmabuf, data, offset, payload) ||
nvgpu_channel_check_unserviceable(ch), nvgpu_channel_check_unserviceable(ch),
timeout); timeout);