Module: Mesa
Branch: main
Commit: 82bef62c17c79b298601fd565ce558c5282a88b7
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=82bef62c17c79b298601fd565ce558c5282a88b7

Author: Iago Toral Quiroga <ito...@igalia.com>
Date:   Mon Oct 16 16:38:31 2023 +0200

v3d,v3dv: fix MMU error from hardware prefetch after ldunifa

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 <apinhe...@igalia.com>
Cc: mesa-stable
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25752>

---

 src/broadcom/vulkan/v3dv_device.c      | 12 ++++++++++++
 src/gallium/drivers/v3d/v3d_resource.c | 12 +++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

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;

Reply via email to