From 8a50c841cf1d05f2d954ae4cbee402ebfd690148 Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Mon, 16 Oct 2023 16:38:31 +0200 Subject: [PATCH] v3d,v3dv: fix MMU error from hardware prefetch after ldunifa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ldunifa works exactly the same as ldunif: the hw will prefetch the next 4 bytes after a read, so if a buffer is exactly a multiple of a page size and a shader uses ldunifa to read exactly the last 4 bytes the prefetch will read out of bounds and spam the error on the kernel log. Avoid that by allocating extra bytes in this scenario. Reviewed-by: Alejandro PiƱeiro Cc: mesa-stable Part-of: (cherry picked from commit 82bef62c17c79b298601fd565ce558c5282a88b7) --- .pick_status.json | 2 +- src/broadcom/vulkan/v3dv_device.c | 12 ++++++++++++ src/gallium/drivers/v3d/v3d_resource.c | 12 +++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 81fcd593d0a..edf59ed67a6 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -224,7 +224,7 @@ "description": "v3d,v3dv: fix MMU error from hardware prefetch after ldunifa", "nominated": true, "nomination_type": 0, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/broadcom/vulkan/v3dv_device.c b/src/broadcom/vulkan/v3dv_device.c index 48aa967e56f..60c55120fe6 100644 --- a/src/broadcom/vulkan/v3dv_device.c +++ b/src/broadcom/vulkan/v3dv_device.c @@ -2766,6 +2766,18 @@ get_buffer_memory_requirements(struct v3dv_buffer *buffer, .size = align64(buffer->size, buffer->alignment), }; + /* UBO and SSBO may be read using ldunifa, which prefetches the next + * 4 bytes after a read. If the buffer's size is exactly a multiple + * of a page size and the shader reads the last 4 bytes with ldunifa + * the prefetching would read out of bounds and cause an MMU error, + * so we allocate extra space to avoid kernel error spamming. + */ + bool can_ldunifa = buffer->usage & + (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + if (can_ldunifa && (buffer->size % 4096 == 0)) + pMemoryRequirements->memoryRequirements.size += buffer->alignment; + vk_foreach_struct(ext, pMemoryRequirements->pNext) { switch (ext->sType) { case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: { diff --git a/src/gallium/drivers/v3d/v3d_resource.c b/src/gallium/drivers/v3d/v3d_resource.c index a0a210ccad5..d9a79614dd1 100644 --- a/src/gallium/drivers/v3d/v3d_resource.c +++ b/src/gallium/drivers/v3d/v3d_resource.c @@ -99,7 +99,17 @@ v3d_resource_bo_alloc(struct v3d_resource *rsc) struct pipe_screen *pscreen = prsc->screen; struct v3d_bo *bo; - bo = v3d_bo_alloc(v3d_screen(pscreen), rsc->size, "resource"); + /* Buffers may be read using ldunifa, which prefetches the next + * 4 bytes after a read. If the buffer's size is exactly a multiple + * of a page size and the shader reads the last 4 bytes with ldunifa + * the prefetching would read out of bounds and cause an MMU error, + * so we allocate extra space to avoid kernel error spamming. + */ + uint32_t size = rsc->size; + if (rsc->base.target == PIPE_BUFFER && (size % 4096 == 0)) + size += 4; + + bo = v3d_bo_alloc(v3d_screen(pscreen), size, "resource"); if (bo) { v3d_bo_unreference(&rsc->bo); rsc->bo = bo;