drm/i915/guc: Make GuC log sizes runtime configurable
authorJohn Harrison <John.C.Harrison@Intel.com>
Thu, 28 Jul 2022 02:20:27 +0000 (19:20 -0700)
committerJohn Harrison <John.C.Harrison@Intel.com>
Wed, 17 Aug 2022 17:07:04 +0000 (10:07 -0700)
The GuC log buffer sizes had to be configured statically at compile
time. This can be quite troublesome when needing to get larger logs
out of a released driver. So re-organise the code to allow a boot time
module parameter override.

Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Reviewed-by: Alan Previn <alan.previn.teres.alexis@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220728022028.2190627-7-John.C.Harrison@Intel.com
drivers/gpu/drm/i915/gt/uc/intel_guc.c
drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_params.h

index ab4aacc..01f2705 100644 (file)
@@ -224,53 +224,22 @@ static u32 guc_ctl_feature_flags(struct intel_guc *guc)
 
 static u32 guc_ctl_log_params_flags(struct intel_guc *guc)
 {
-       u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT;
-       u32 flags;
-
-       #if (((CRASH_BUFFER_SIZE) % SZ_1M) == 0)
-       #define LOG_UNIT SZ_1M
-       #define LOG_FLAG GUC_LOG_LOG_ALLOC_UNITS
-       #else
-       #define LOG_UNIT SZ_4K
-       #define LOG_FLAG 0
-       #endif
-
-       #if (((CAPTURE_BUFFER_SIZE) % SZ_1M) == 0)
-       #define CAPTURE_UNIT SZ_1M
-       #define CAPTURE_FLAG GUC_LOG_CAPTURE_ALLOC_UNITS
-       #else
-       #define CAPTURE_UNIT SZ_4K
-       #define CAPTURE_FLAG 0
-       #endif
-
-       BUILD_BUG_ON(!CRASH_BUFFER_SIZE);
-       BUILD_BUG_ON(!IS_ALIGNED(CRASH_BUFFER_SIZE, LOG_UNIT));
-       BUILD_BUG_ON(!DEBUG_BUFFER_SIZE);
-       BUILD_BUG_ON(!IS_ALIGNED(DEBUG_BUFFER_SIZE, LOG_UNIT));
-       BUILD_BUG_ON(!CAPTURE_BUFFER_SIZE);
-       BUILD_BUG_ON(!IS_ALIGNED(CAPTURE_BUFFER_SIZE, CAPTURE_UNIT));
-
-       BUILD_BUG_ON((CRASH_BUFFER_SIZE / LOG_UNIT - 1) >
-                       (GUC_LOG_CRASH_MASK >> GUC_LOG_CRASH_SHIFT));
-       BUILD_BUG_ON((DEBUG_BUFFER_SIZE / LOG_UNIT - 1) >
-                       (GUC_LOG_DEBUG_MASK >> GUC_LOG_DEBUG_SHIFT));
-       BUILD_BUG_ON((CAPTURE_BUFFER_SIZE / CAPTURE_UNIT - 1) >
-                       (GUC_LOG_CAPTURE_MASK >> GUC_LOG_CAPTURE_SHIFT));
+       struct intel_guc_log *log = &guc->log;
+       u32 offset, flags;
+
+       GEM_BUG_ON(!log->sizes_initialised);
+
+       offset = intel_guc_ggtt_offset(guc, log->vma) >> PAGE_SHIFT;
 
        flags = GUC_LOG_VALID |
                GUC_LOG_NOTIFY_ON_HALF_FULL |
-               CAPTURE_FLAG |
-               LOG_FLAG |
-               ((CRASH_BUFFER_SIZE / LOG_UNIT - 1) << GUC_LOG_CRASH_SHIFT) |
-               ((DEBUG_BUFFER_SIZE / LOG_UNIT - 1) << GUC_LOG_DEBUG_SHIFT) |
-               ((CAPTURE_BUFFER_SIZE / CAPTURE_UNIT - 1) << GUC_LOG_CAPTURE_SHIFT) |
+               log->sizes[GUC_LOG_SECTIONS_DEBUG].flag |
+               log->sizes[GUC_LOG_SECTIONS_CAPTURE].flag |
+               (log->sizes[GUC_LOG_SECTIONS_CRASH].count << GUC_LOG_CRASH_SHIFT) |
+               (log->sizes[GUC_LOG_SECTIONS_DEBUG].count << GUC_LOG_DEBUG_SHIFT) |
+               (log->sizes[GUC_LOG_SECTIONS_CAPTURE].count << GUC_LOG_CAPTURE_SHIFT) |
                (offset << GUC_LOG_BUF_ADDR_SHIFT);
 
-       #undef LOG_UNIT
-       #undef LOG_FLAG
-       #undef CAPTURE_UNIT
-       #undef CAPTURE_FLAG
-
        return flags;
 }
 
index b54b788..d2ac53d 100644 (file)
@@ -656,16 +656,17 @@ static void check_guc_capture_size(struct intel_guc *guc)
        struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
        int min_size = guc_capture_output_min_size_est(guc);
        int spare_size = min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;
+       u32 buffer_size = intel_guc_log_section_size_capture(&guc->log);
 
        if (min_size < 0)
                drm_warn(&i915->drm, "Failed to calculate GuC error state capture buffer minimum size: %d!\n",
                         min_size);
-       else if (min_size > CAPTURE_BUFFER_SIZE)
+       else if (min_size > buffer_size)
                drm_warn(&i915->drm, "GuC error state capture buffer is too small: %d < %d\n",
-                        CAPTURE_BUFFER_SIZE, min_size);
-       else if (spare_size > CAPTURE_BUFFER_SIZE)
+                        buffer_size, min_size);
+       else if (spare_size > buffer_size)
                drm_notice(&i915->drm, "GuC error state capture buffer maybe too small: %d < %d (min = %d)\n",
-                          CAPTURE_BUFFER_SIZE, spare_size, min_size);
+                          buffer_size, spare_size, min_size);
 }
 
 /*
@@ -1294,7 +1295,8 @@ static void __guc_capture_process_output(struct intel_guc *guc)
 
        log_buf_state = guc->log.buf_addr +
                        (sizeof(struct guc_log_buffer_state) * GUC_CAPTURE_LOG_BUFFER);
-       src_data = guc->log.buf_addr + intel_guc_get_log_buffer_offset(GUC_CAPTURE_LOG_BUFFER);
+       src_data = guc->log.buf_addr +
+                  intel_guc_get_log_buffer_offset(&guc->log, GUC_CAPTURE_LOG_BUFFER);
 
        /*
         * Make a copy of the state structure, inside GuC log buffer
@@ -1302,7 +1304,7 @@ static void __guc_capture_process_output(struct intel_guc *guc)
         * from it multiple times.
         */
        memcpy(&log_buf_state_local, log_buf_state, sizeof(struct guc_log_buffer_state));
-       buffer_size = intel_guc_get_log_buffer_size(GUC_CAPTURE_LOG_BUFFER);
+       buffer_size = intel_guc_get_log_buffer_size(&guc->log, GUC_CAPTURE_LOG_BUFFER);
        read_offset = log_buf_state_local.read_ptr;
        write_offset = log_buf_state_local.sampled_write_ptr;
        full_count = log_buf_state_local.buffer_full_cnt;
index 44e6e68..3a2243b 100644 (file)
 #include "intel_guc_capture.h"
 #include "intel_guc_log.h"
 
+#if defined(CONFIG_DRM_I915_DEBUG_GUC)
+#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE      SZ_2M
+#define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE      SZ_16M
+#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE    SZ_4M
+#elif defined(CONFIG_DRM_I915_DEBUG_GEM)
+#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE      SZ_1M
+#define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE      SZ_2M
+#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE    SZ_4M
+#else
+#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE      SZ_8K
+#define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE      SZ_64K
+#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE    SZ_2M
+#endif
+
 static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log);
 
+struct guc_log_section {
+       u32 max;
+       u32 flag;
+       u32 default_val;
+       const char *name;
+};
+
+static s32 scale_log_param(struct intel_guc_log *log, const struct guc_log_section *section,
+                          s32 param)
+{
+       /* -1 means default */
+       if (param < 0)
+               return section->default_val;
+
+       /* Check for 32-bit overflow */
+       if (param >= SZ_4K) {
+               drm_err(&guc_to_gt(log_to_guc(log))->i915->drm, "Size too large for GuC %s log: %dMB!",
+                       section->name, param);
+               return section->default_val;
+       }
+
+       /* Param units are 1MB */
+       return param * SZ_1M;
+}
+
+static void _guc_log_init_sizes(struct intel_guc_log *log)
+{
+       struct intel_guc *guc = log_to_guc(log);
+       struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+       static const struct guc_log_section sections[GUC_LOG_SECTIONS_LIMIT] = {
+               {
+                       GUC_LOG_CRASH_MASK >> GUC_LOG_CRASH_SHIFT,
+                       GUC_LOG_LOG_ALLOC_UNITS,
+                       GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE,
+                       "crash dump"
+               },
+               {
+                       GUC_LOG_DEBUG_MASK >> GUC_LOG_DEBUG_SHIFT,
+                       GUC_LOG_LOG_ALLOC_UNITS,
+                       GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE,
+                       "debug",
+               },
+               {
+                       GUC_LOG_CAPTURE_MASK >> GUC_LOG_CAPTURE_SHIFT,
+                       GUC_LOG_CAPTURE_ALLOC_UNITS,
+                       GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE,
+                       "capture",
+               }
+       };
+       s32 params[GUC_LOG_SECTIONS_LIMIT] = {
+               i915->params.guc_log_size_crash,
+               i915->params.guc_log_size_debug,
+               i915->params.guc_log_size_capture,
+       };
+       int i;
+
+       for (i = 0; i < GUC_LOG_SECTIONS_LIMIT; i++)
+               log->sizes[i].bytes = scale_log_param(log, sections + i, params[i]);
+
+       /* If debug size > 1MB then bump default crash size to keep the same units */
+       if (log->sizes[GUC_LOG_SECTIONS_DEBUG].bytes >= SZ_1M &&
+           (i915->params.guc_log_size_crash == -1) &&
+           GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE < SZ_1M)
+               log->sizes[GUC_LOG_SECTIONS_CRASH].bytes = SZ_1M;
+
+       /* Prepare the GuC API structure fields: */
+       for (i = 0; i < GUC_LOG_SECTIONS_LIMIT; i++) {
+               /* Convert to correct units */
+               if ((log->sizes[i].bytes % SZ_1M) == 0) {
+                       log->sizes[i].units = SZ_1M;
+                       log->sizes[i].flag = sections[i].flag;
+               } else {
+                       log->sizes[i].units = SZ_4K;
+                       log->sizes[i].flag = 0;
+               }
+
+               if (!IS_ALIGNED(log->sizes[i].bytes, log->sizes[i].units))
+                       drm_err(&i915->drm, "Mis-aligned GuC log %s size: 0x%X vs 0x%X!",
+                               sections[i].name, log->sizes[i].bytes, log->sizes[i].units);
+               log->sizes[i].count = log->sizes[i].bytes / log->sizes[i].units;
+
+               if (!log->sizes[i].count) {
+                       drm_err(&i915->drm, "Zero GuC log %s size!", sections[i].name);
+               } else {
+                       /* Size is +1 unit */
+                       log->sizes[i].count--;
+               }
+
+               /* Clip to field size */
+               if (log->sizes[i].count > sections[i].max) {
+                       drm_err(&i915->drm, "GuC log %s size too large: %d vs %d!",
+                               sections[i].name, log->sizes[i].count + 1, sections[i].max + 1);
+                       log->sizes[i].count = sections[i].max;
+               }
+       }
+
+       if (log->sizes[GUC_LOG_SECTIONS_CRASH].units != log->sizes[GUC_LOG_SECTIONS_DEBUG].units) {
+               drm_err(&i915->drm, "Unit mis-match for GuC log crash and debug sections: %d vs %d!",
+                       log->sizes[GUC_LOG_SECTIONS_CRASH].units,
+                       log->sizes[GUC_LOG_SECTIONS_DEBUG].units);
+               log->sizes[GUC_LOG_SECTIONS_CRASH].units = log->sizes[GUC_LOG_SECTIONS_DEBUG].units;
+               log->sizes[GUC_LOG_SECTIONS_CRASH].count = 0;
+       }
+
+       log->sizes_initialised = true;
+}
+
+static void guc_log_init_sizes(struct intel_guc_log *log)
+{
+       if (log->sizes_initialised)
+               return;
+
+       _guc_log_init_sizes(log);
+}
+
+static u32 intel_guc_log_section_size_crash(struct intel_guc_log *log)
+{
+       guc_log_init_sizes(log);
+
+       return log->sizes[GUC_LOG_SECTIONS_CRASH].bytes;
+}
+
+static u32 intel_guc_log_section_size_debug(struct intel_guc_log *log)
+{
+       guc_log_init_sizes(log);
+
+       return log->sizes[GUC_LOG_SECTIONS_DEBUG].bytes;
+}
+
+u32 intel_guc_log_section_size_capture(struct intel_guc_log *log)
+{
+       guc_log_init_sizes(log);
+
+       return log->sizes[GUC_LOG_SECTIONS_CAPTURE].bytes;
+}
+
 static u32 intel_guc_log_size(struct intel_guc_log *log)
 {
        /*
@@ -38,7 +188,10 @@ static u32 intel_guc_log_size(struct intel_guc_log *log)
         *  |         Capture logs          |
         *  +===============================+ + CAPTURE_SIZE
         */
-       return PAGE_SIZE + CRASH_BUFFER_SIZE + DEBUG_BUFFER_SIZE + CAPTURE_BUFFER_SIZE;
+       return PAGE_SIZE +
+               intel_guc_log_section_size_crash(log) +
+               intel_guc_log_section_size_debug(log) +
+               intel_guc_log_section_size_capture(log);
 }
 
 /**
@@ -165,7 +318,8 @@ static void guc_move_to_next_buf(struct intel_guc_log *log)
        smp_wmb();
 
        /* All data has been written, so now move the offset of sub buffer. */
-       relay_reserve(log->relay.channel, log->vma->obj->base.size - CAPTURE_BUFFER_SIZE);
+       relay_reserve(log->relay.channel, log->vma->obj->base.size -
+                                         intel_guc_log_section_size_capture(log));
 
        /* Switch to the next sub buffer */
        relay_flush(log->relay.channel);
@@ -210,15 +364,16 @@ bool intel_guc_check_log_buf_overflow(struct intel_guc_log *log,
        return overflow;
 }
 
-unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type)
+unsigned int intel_guc_get_log_buffer_size(struct intel_guc_log *log,
+                                          enum guc_log_buffer_type type)
 {
        switch (type) {
        case GUC_DEBUG_LOG_BUFFER:
-               return DEBUG_BUFFER_SIZE;
+               return intel_guc_log_section_size_debug(log);
        case GUC_CRASH_DUMP_LOG_BUFFER:
-               return CRASH_BUFFER_SIZE;
+               return intel_guc_log_section_size_crash(log);
        case GUC_CAPTURE_LOG_BUFFER:
-               return CAPTURE_BUFFER_SIZE;
+               return intel_guc_log_section_size_capture(log);
        default:
                MISSING_CASE(type);
        }
@@ -226,7 +381,8 @@ unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type)
        return 0;
 }
 
-size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type)
+size_t intel_guc_get_log_buffer_offset(struct intel_guc_log *log,
+                                      enum guc_log_buffer_type type)
 {
        enum guc_log_buffer_type i;
        size_t offset = PAGE_SIZE;/* for the log_buffer_states */
@@ -234,7 +390,7 @@ size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type)
        for (i = GUC_DEBUG_LOG_BUFFER; i < GUC_MAX_LOG_BUFFER; ++i) {
                if (i == type)
                        break;
-               offset += intel_guc_get_log_buffer_size(i);
+               offset += intel_guc_get_log_buffer_size(log, i);
        }
 
        return offset;
@@ -285,7 +441,7 @@ static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
                 */
                memcpy(&log_buf_state_local, log_buf_state,
                       sizeof(struct guc_log_buffer_state));
-               buffer_size = intel_guc_get_log_buffer_size(type);
+               buffer_size = intel_guc_get_log_buffer_size(log, type);
                read_offset = log_buf_state_local.read_ptr;
                write_offset = log_buf_state_local.sampled_write_ptr;
                full_cnt = log_buf_state_local.buffer_full_cnt;
@@ -400,7 +556,7 @@ static int guc_log_relay_create(struct intel_guc_log *log)
          * Keep the size of sub buffers same as shared log buffer
          * but GuC log-events excludes the error-state-capture logs
          */
-       subbuf_size = log->vma->size - CAPTURE_BUFFER_SIZE;
+       subbuf_size = log->vma->size - intel_guc_log_section_size_capture(log);
 
        /*
         * Store up to 8 snapshots, which is large enough to buffer sufficient
index dc97154..0212770 100644 (file)
 
 struct intel_guc;
 
-#if defined(CONFIG_DRM_I915_DEBUG_GUC)
-#define CRASH_BUFFER_SIZE      SZ_2M
-#define DEBUG_BUFFER_SIZE      SZ_16M
-#define CAPTURE_BUFFER_SIZE    SZ_4M
-#elif defined(CONFIG_DRM_I915_DEBUG_GEM)
-#define CRASH_BUFFER_SIZE      SZ_1M
-#define DEBUG_BUFFER_SIZE      SZ_2M
-#define CAPTURE_BUFFER_SIZE    SZ_4M
-#else
-#define CRASH_BUFFER_SIZE      SZ_8K
-#define DEBUG_BUFFER_SIZE      SZ_64K
-#define CAPTURE_BUFFER_SIZE    SZ_2M
-#endif
-
 /*
  * While we're using plain log level in i915, GuC controls are much more...
  * "elaborate"? We have a couple of bits for verbosity, separate bit for actual
@@ -46,10 +32,30 @@ struct intel_guc;
 #define GUC_VERBOSITY_TO_LOG_LEVEL(x)  ((x) + 2)
 #define GUC_LOG_LEVEL_MAX GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)
 
+enum {
+       GUC_LOG_SECTIONS_CRASH,
+       GUC_LOG_SECTIONS_DEBUG,
+       GUC_LOG_SECTIONS_CAPTURE,
+       GUC_LOG_SECTIONS_LIMIT
+};
+
 struct intel_guc_log {
        u32 level;
+
+       /* Allocation settings */
+       struct {
+               s32 bytes;      /* Size in bytes */
+               s32 units;      /* GuC API units - 1MB or 4KB */
+               s32 count;      /* Number of API units */
+               u32 flag;       /* GuC API units flag */
+       } sizes[GUC_LOG_SECTIONS_LIMIT];
+       bool sizes_initialised;
+
+       /* Combined buffer allocation */
        struct i915_vma *vma;
        void *buf_addr;
+
+       /* RelayFS support */
        struct {
                bool buf_in_use;
                bool started;
@@ -58,6 +64,7 @@ struct intel_guc_log {
                struct mutex lock;
                u32 full_count;
        } relay;
+
        /* logging related stats */
        struct {
                u32 sampled_overflow;
@@ -69,8 +76,9 @@ struct intel_guc_log {
 void intel_guc_log_init_early(struct intel_guc_log *log);
 bool intel_guc_check_log_buf_overflow(struct intel_guc_log *log, enum guc_log_buffer_type type,
                                      unsigned int full_cnt);
-unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type);
-size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type);
+unsigned int intel_guc_get_log_buffer_size(struct intel_guc_log *log,
+                                          enum guc_log_buffer_type type);
+size_t intel_guc_get_log_buffer_offset(struct intel_guc_log *log, enum guc_log_buffer_type type);
 int intel_guc_log_create(struct intel_guc_log *log);
 void intel_guc_log_destroy(struct intel_guc_log *log);
 
@@ -92,4 +100,6 @@ void intel_guc_log_info(struct intel_guc_log *log, struct drm_printer *p);
 int intel_guc_log_dump(struct intel_guc_log *log, struct drm_printer *p,
                       bool dump_load_err);
 
+u32 intel_guc_log_section_size_capture(struct intel_guc_log *log);
+
 #endif
index 6fc475a..06ca5b8 100644 (file)
@@ -171,6 +171,18 @@ i915_param_named(guc_log_level, int, 0400,
        "GuC firmware logging level. Requires GuC to be loaded. "
        "(-1=auto [default], 0=disable, 1..4=enable with verbosity min..max)");
 
+i915_param_named(guc_log_size_crash, int, 0400,
+       "GuC firmware logging buffer size for crash dumps (in MB)"
+       "(-1=auto [default], NB: max = 4, other restrictions apply)");
+
+i915_param_named(guc_log_size_debug, int, 0400,
+       "GuC firmware logging buffer size for debug logs (in MB)"
+       "(-1=auto [default], NB: max = 16, other restrictions apply)");
+
+i915_param_named(guc_log_size_capture, int, 0400,
+       "GuC error capture register dump buffer size (in MB)"
+       "(-1=auto [default], NB: max = 4, other restrictions apply)");
+
 i915_param_named_unsafe(guc_firmware_path, charp, 0400,
        "GuC firmware path to use instead of the default one");
 
index 2733cb6..f684d1a 100644 (file)
@@ -61,6 +61,9 @@ struct drm_printer;
        param(int, invert_brightness, 0, 0600) \
        param(int, enable_guc, -1, 0400) \
        param(int, guc_log_level, -1, 0400) \
+       param(int, guc_log_size_crash, -1, 0400) \
+       param(int, guc_log_size_debug, -1, 0400) \
+       param(int, guc_log_size_capture, -1, 0400) \
        param(char *, guc_firmware_path, NULL, 0400) \
        param(char *, huc_firmware_path, NULL, 0400) \
        param(char *, dmc_firmware_path, NULL, 0400) \