[Mesa-dev] [PATCH 16/20] intel/error2aub: write GGTT buffers into the aub file

Lionel Landwerlin lionel.g.landwerlin at intel.com
Tue Sep 25 08:23:55 UTC 2018


Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
---
 src/intel/tools/aub_write.c | 69 +++++++++++++++++++++++++++++++
 src/intel/tools/aub_write.h |  5 +++
 src/intel/tools/error2aub.c | 82 +++++++++++++++++++++++++++++++------
 3 files changed, 144 insertions(+), 12 deletions(-)

diff --git a/src/intel/tools/aub_write.c b/src/intel/tools/aub_write.c
index fe759a40204..ee6b92fe15b 100644
--- a/src/intel/tools/aub_write.c
+++ b/src/intel/tools/aub_write.c
@@ -543,6 +543,66 @@ aub_write_default_setup(struct aub_file *aub)
       write_execlists_default_setup(aub);
    else
       write_legacy_default_setup(aub);
+
+   aub->has_default_setup = true;
+}
+
+void
+aub_write_ggtt(struct aub_file *aub, uint64_t virt_addr, uint64_t size, const void *data)
+{
+   if (aub->verbose_log_file) {
+      fprintf(aub->verbose_log_file,
+              " Writting GGTT address: 0x%" PRIx64 ", size: %" PRIu64"\n",
+              virt_addr, size);
+   }
+
+   /* Default setup assumes a 1 to 1 mapping between physical and virtual GGTT
+    * addresses. This is somewhat incompatible with the aub_write_ggtt()
+    * function. In practice it doesn't matter as the GGTT writes are used to
+    * replace the default setup and we've taken care to setup the PML4 as the
+    * top of the GGTT.
+    */
+   assert(!aub->has_default_setup);
+
+   /* Makes the code below a bit simpler. In practice all of the write we
+    * receive from error2aub are page aligned.
+    */
+   assert(virt_addr % 4096 == 0);
+   assert((aub->phys_addrs_allocator + size) < (1UL << 32));
+
+   /* GGTT PT */
+   uint32_t ggtt_ptes = DIV_ROUND_UP(size, 4096);
+   uint64_t phys_addr = aub->phys_addrs_allocator << 12;
+   aub->phys_addrs_allocator += ggtt_ptes;
+
+   if (aub->verbose_log_file) {
+      fprintf(aub->verbose_log_file,
+              " Writting GGTT address: 0x%" PRIx64 ", size: %" PRIu64" phys_addr=0x%lx entries=%u\n",
+              virt_addr, size, phys_addr, ggtt_ptes);
+   }
+
+   mem_trace_memory_write_header_out(aub,
+                                     (virt_addr >> 12) * GEN8_PTE_SIZE,
+                                     ggtt_ptes * GEN8_PTE_SIZE,
+                                     AUB_MEM_TRACE_MEMORY_ADDRESS_SPACE_GGTT_ENTRY,
+                                     "GGTT PT");
+   for (uint32_t i = 0; i < ggtt_ptes; i++) {
+      dword_out(aub, 1 + phys_addr + i * 4096);
+      dword_out(aub, 0);
+   }
+
+   static const char null_block[8 * 4096];
+   for (uint64_t offset = 0; offset < size; offset += 4096) {
+      uint32_t block_size = min(4096, size - offset);
+
+      mem_trace_memory_write_header_out(aub, virt_addr + offset, block_size,
+                                        AUB_MEM_TRACE_MEMORY_ADDRESS_SPACE_GGTT,
+                                        "GGTT buffer");
+      data_out(aub, (char *) data + offset, block_size);
+
+      /* Pad to a multiple of 4 bytes. */
+      data_out(aub, null_block, -block_size & 3);
+   }
 }
 
 /**
@@ -693,3 +753,12 @@ aub_write_exec(struct aub_file *aub, uint64_t batch_addr,
    }
    fflush(aub->file);
 }
+
+void
+aub_write_context_execlists(struct aub_file *aub, uint64_t context_addr,
+                            enum drm_i915_gem_engine_class engine_class)
+{
+   const struct engine *cs = engine_from_ring_flag(engine_class);
+   uint64_t descriptor = ((uint64_t)1 << 62 | context_addr  | CONTEXT_FLAGS);
+   aub_dump_execlist(aub, cs, descriptor);
+}
diff --git a/src/intel/tools/aub_write.h b/src/intel/tools/aub_write.h
index 51a252b7834..97d2820ef52 100644
--- a/src/intel/tools/aub_write.h
+++ b/src/intel/tools/aub_write.h
@@ -45,6 +45,8 @@ struct aub_ppgtt_table {
 struct aub_file {
    FILE *file;
 
+   bool has_default_setup;
+
    /* Set if you want extra logging */
    FILE *verbose_log_file;
 
@@ -85,11 +87,14 @@ aub_write_reloc(const struct gen_device_info *devinfo, void *p, uint64_t v)
 
 void aub_write_default_setup(struct aub_file *aub);
 void aub_map_ppgtt(struct aub_file *aub, uint64_t start, uint64_t size);
+void aub_write_ggtt(struct aub_file *aub, uint64_t virt_addr, uint64_t size, const void *data);
 void aub_write_trace_block(struct aub_file *aub,
                            uint32_t type, void *virtual,
                            uint32_t size, uint64_t gtt_offset);
 void aub_write_exec(struct aub_file *aub, uint64_t batch_addr,
                     uint64_t offset, enum drm_i915_gem_engine_class engine_class);
+void aub_write_context_execlists(struct aub_file *aub, uint64_t context_addr,
+                                 enum drm_i915_gem_engine_class engine_class);
 
 #ifdef __cplusplus
 }
diff --git a/src/intel/tools/error2aub.c b/src/intel/tools/error2aub.c
index 72531a97b18..354e4e00924 100644
--- a/src/intel/tools/error2aub.c
+++ b/src/intel/tools/error2aub.c
@@ -307,8 +307,6 @@ main(int argc, char *argv[])
                        NULL, pci_id, "error_state");
          fail_if(!aub_use_execlists(&aub),
                  "%s currently only works on gen8+\n", argv[0]);
-
-         aub_write_default_setup(&aub);
          continue;
       }
 
@@ -424,7 +422,18 @@ main(int argc, char *argv[])
       }
    }
 
+   /* Find the batch that trigger the hang */
+   struct bo *batch_bo = NULL;
+   list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
+      if (bo_entry->type == BO_TYPE_BATCH) {
+         batch_bo = bo_entry;
+         break;
+      }
+   }
+   fail_if(!batch_bo, "Failed to find batch buffer.\n");
+
    /* Add all the BOs to the aub file */
+   struct bo *hwsp_bo = NULL;
    list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
       switch (bo_entry->type) {
       case BO_TYPE_BATCH:
@@ -436,21 +445,70 @@ main(int argc, char *argv[])
          aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
          aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
                                bo_entry->data, bo_entry->size, bo_entry->addr);
-      default:
          break;
-      }
-   }
+      case BO_TYPE_CONTEXT:
+         if (bo_entry->engine_class == batch_bo->engine_class &&
+             bo_entry->engine_instance == batch_bo->engine_instance) {
+            hwsp_bo = bo_entry;
+
+            uint32_t *context = (uint32_t *) (bo_entry->data + 4096 /* GuC */ + 4096 /* HWSP */);
+
+            if (context[1] == 0) {
+               fprintf(stderr,
+                       "Invalid context image data.\n"
+                       "This is likely a kernel issue : https://bugs.freedesktop.org/show_bug.cgi?id=107691\n");
+            }
+
+            /* Update the ring buffer at the last known location. */
+            context[5] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_head;
+            context[7] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_tail;
+            fprintf(stdout, "engine start=0x%x head/tail=0x%x/0x%x\n",
+                    context[9], context[5], context[7]);
+
+            /* The error state doesn't provide a dump of the page tables, so
+             * we have to provide our own, that's easy enough.
+             */
+            context[49] = aub.pml4.phys_addr >> 32;
+            context[51] = aub.pml4.phys_addr & 0xffffffff;
+
+            fprintf(stdout, "context dump:\n");
+            for (int i = 0; i < 60; i++) {
+               if (i % 4 == 0)
+                  fprintf(stdout, "\n 0x%08lx: ", bo_entry->addr + 8192 + i * 4);
+               fprintf(stdout, "0x%08x ", context[i]);
+            }
+            fprintf(stdout, "\n");
 
-   /* Finally exec the batch BO */
-   bool batch_found = false;
-   list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
-      if (bo_entry->type == BO_TYPE_BATCH) {
-         aub_write_exec(&aub, bo_entry->addr, aub_gtt_size(&aub), bo_entry->engine_class);
-         batch_found = true;
+         }
+         aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
+         break;
+      case BO_TYPE_RINGBUFFER:
+      case BO_TYPE_STATUS:
+      case BO_TYPE_CONTEXT_WA:
+         aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
+         break;
+      case BO_TYPE_UNKNOWN:
+         if (bo_entry->gtt == PPGTT) {
+            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
+            if (bo_entry->data) {
+               aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
+                                     bo_entry->data, bo_entry->size, bo_entry->addr);
+            }
+         } else {
+            if (bo_entry->size > 0) {
+               void *zero_data = calloc(1, bo_entry->size);
+               aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, zero_data);
+               free(zero_data);
+            }
+         }
+         break;
+      default:
          break;
       }
    }
-   fail_if(!batch_found, "Failed to find batch buffer.\n");
+
+   fail_if(!hwsp_bo, "Failed to find Context buffer.\n");
+   aub_write_context_execlists(&aub, hwsp_bo->addr + 4096 /* skip GuC page */, hwsp_bo->engine_class);
 
    /* Cleanup */
    list_for_each_entry_safe(struct bo, bo_entry, &bo_list, link) {
-- 
2.19.0



More information about the mesa-dev mailing list