anv/batch_chain: Improve write_reloc
authorJason Ekstrand <jason.ekstrand@intel.com>
Wed, 2 Nov 2016 17:42:45 +0000 (10:42 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Wed, 9 Nov 2016 19:31:06 +0000 (11:31 -0800)
The old version wasn't properly handling large addresses where we have to
sign-extend to get it into the "canonical form" expected by the hardware.
Also, the new version is capable of doing a clflush of the newly written
reloc if requested.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
Cc: "13.0" <mesa-stable@lists.freedesktop.org>
src/intel/vulkan/anv_batch_chain.c

index e8485286ecc17df9e3e709348224590837a82fa3..1610a4a93c2c51f3766f7d05819af1e55c65c4be 100644 (file)
@@ -1016,12 +1016,29 @@ anv_cmd_buffer_process_relocs(struct anv_cmd_buffer *cmd_buffer,
 }
 
 static void
-write_reloc(const struct anv_device *device, void *p, uint64_t v)
+write_reloc(const struct anv_device *device, void *p, uint64_t v, bool flush)
 {
-   if (device->info.gen >= 8)
-      *(uint64_t *)p = v;
-   else
+   unsigned reloc_size = 0;
+   if (device->info.gen >= 8) {
+      /* From the Broadwell PRM Vol. 2a, MI_LOAD_REGISTER_MEM::MemoryAddress:
+       *
+       *    "This field specifies the address of the memory location where the
+       *    register value specified in the DWord above will read from. The
+       *    address specifies the DWord location of the data. Range =
+       *    GraphicsVirtualAddress[63:2] for a DWord register GraphicsAddress
+       *    [63:48] are ignored by the HW and assumed to be in correct
+       *    canonical form [63:48] == [47]."
+       */
+      const int shift = 63 - 47;
+      reloc_size = sizeof(uint64_t);
+      *(uint64_t *)p = (((int64_t)v) << shift) >> shift;
+   } else {
+      reloc_size = sizeof(uint32_t);
       *(uint32_t *)p = v;
+   }
+
+   if (flush && !device->info.has_llc)
+      anv_clflush_range(p, reloc_size);
 }
 
 static void
@@ -1070,7 +1087,7 @@ adjust_relocations_to_state_pool(struct anv_block_pool *pool,
          assert(relocs->relocs[i].offset < from_bo->size);
          write_reloc(pool->device, from_bo->map + relocs->relocs[i].offset,
                      relocs->relocs[i].presumed_offset +
-                     relocs->relocs[i].delta);
+                     relocs->relocs[i].delta, false);
       }
    }