summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/gt/uc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/gt/uc')
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.c55
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c81
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_log.c175
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_log.h42
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c86
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c17
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc.c8
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c462
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h39
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h8
-rw-r--r--drivers/gpu/drm/i915/gt/uc/selftest_guc.c3
11 files changed, 615 insertions, 361 deletions
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
index ab4aacc516aa..24451d000a6a 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
@@ -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;
}
@@ -396,8 +365,6 @@ void intel_guc_dump_time_info(struct intel_guc *guc, struct drm_printer *p)
u32 stamp = 0;
u64 ktime;
- intel_device_info_print_runtime(RUNTIME_INFO(gt->i915), p);
-
with_intel_runtime_pm(&gt->i915->runtime_pm, wakeref)
stamp = intel_uncore_read(gt->uncore, GUCPMTIMESTAMP);
ktime = ktime_get_boottime_ns();
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index b54b7883320b..8f1165146013 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -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;
@@ -1381,33 +1383,22 @@ guc_capture_reg_to_str(const struct intel_guc *guc, u32 owner, u32 type,
return NULL;
}
-#ifdef CONFIG_DRM_I915_DEBUG_GUC
-#define __out(a, ...) \
- do { \
- drm_warn((&(a)->i915->drm), __VA_ARGS__); \
- i915_error_printf((a), __VA_ARGS__); \
- } while (0)
-#else
-#define __out(a, ...) \
- i915_error_printf(a, __VA_ARGS__)
-#endif
-
#define GCAP_PRINT_INTEL_ENG_INFO(ebuf, eng) \
do { \
- __out(ebuf, " i915-Eng-Name: %s command stream\n", \
- (eng)->name); \
- __out(ebuf, " i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
- __out(ebuf, " i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
- __out(ebuf, " i915-Eng-LogicalMask: 0x%08x\n", \
- (eng)->logical_mask); \
+ i915_error_printf(ebuf, " i915-Eng-Name: %s command stream\n", \
+ (eng)->name); \
+ i915_error_printf(ebuf, " i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
+ i915_error_printf(ebuf, " i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
+ i915_error_printf(ebuf, " i915-Eng-LogicalMask: 0x%08x\n", \
+ (eng)->logical_mask); \
} while (0)
#define GCAP_PRINT_GUC_INST_INFO(ebuf, node) \
do { \
- __out(ebuf, " GuC-Engine-Inst-Id: 0x%08x\n", \
- (node)->eng_inst); \
- __out(ebuf, " GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
- __out(ebuf, " LRCA: 0x%08x\n", (node)->lrca); \
+ i915_error_printf(ebuf, " GuC-Engine-Inst-Id: 0x%08x\n", \
+ (node)->eng_inst); \
+ i915_error_printf(ebuf, " GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
+ i915_error_printf(ebuf, " LRCA: 0x%08x\n", (node)->lrca); \
} while (0)
int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
@@ -1439,57 +1430,57 @@ int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
guc = &ee->engine->gt->uc.guc;
- __out(ebuf, "global --- GuC Error Capture on %s command stream:\n",
- ee->engine->name);
+ i915_error_printf(ebuf, "global --- GuC Error Capture on %s command stream:\n",
+ ee->engine->name);
node = ee->guc_capture_node;
if (!node) {
- __out(ebuf, " No matching ee-node\n");
+ i915_error_printf(ebuf, " No matching ee-node\n");
return 0;
}
- __out(ebuf, "Coverage: %s\n", grptype[node->is_partial]);
+ i915_error_printf(ebuf, "Coverage: %s\n", grptype[node->is_partial]);
for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
- __out(ebuf, " RegListType: %s\n",
- datatype[i % GUC_CAPTURE_LIST_TYPE_MAX]);
- __out(ebuf, " Owner-Id: %d\n", node->reginfo[i].vfid);
+ i915_error_printf(ebuf, " RegListType: %s\n",
+ datatype[i % GUC_CAPTURE_LIST_TYPE_MAX]);
+ i915_error_printf(ebuf, " Owner-Id: %d\n", node->reginfo[i].vfid);
switch (i) {
case GUC_CAPTURE_LIST_TYPE_GLOBAL:
default:
break;
case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
- __out(ebuf, " GuC-Eng-Class: %d\n", node->eng_class);
- __out(ebuf, " i915-Eng-Class: %d\n",
- guc_class_to_engine_class(node->eng_class));
+ i915_error_printf(ebuf, " GuC-Eng-Class: %d\n", node->eng_class);
+ i915_error_printf(ebuf, " i915-Eng-Class: %d\n",
+ guc_class_to_engine_class(node->eng_class));
break;
case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
eng = intel_guc_lookup_engine(guc, node->eng_class, node->eng_inst);
if (eng)
GCAP_PRINT_INTEL_ENG_INFO(ebuf, eng);
else
- __out(ebuf, " i915-Eng-Lookup Fail!\n");
+ i915_error_printf(ebuf, " i915-Eng-Lookup Fail!\n");
GCAP_PRINT_GUC_INST_INFO(ebuf, node);
break;
}
numregs = node->reginfo[i].num_regs;
- __out(ebuf, " NumRegs: %d\n", numregs);
+ i915_error_printf(ebuf, " NumRegs: %d\n", numregs);
j = 0;
while (numregs--) {
regs = node->reginfo[i].regs;
str = guc_capture_reg_to_str(guc, GUC_CAPTURE_LIST_INDEX_PF, i,
node->eng_class, 0, regs[j].offset, &is_ext);
if (!str)
- __out(ebuf, " REG-0x%08x", regs[j].offset);
+ i915_error_printf(ebuf, " REG-0x%08x", regs[j].offset);
else
- __out(ebuf, " %s", str);
+ i915_error_printf(ebuf, " %s", str);
if (is_ext)
- __out(ebuf, "[%ld][%ld]",
- FIELD_GET(GUC_REGSET_STEERING_GROUP, regs[j].flags),
- FIELD_GET(GUC_REGSET_STEERING_INSTANCE, regs[j].flags));
- __out(ebuf, ": 0x%08x\n", regs[j].value);
+ i915_error_printf(ebuf, "[%ld][%ld]",
+ FIELD_GET(GUC_REGSET_STEERING_GROUP, regs[j].flags),
+ FIELD_GET(GUC_REGSET_STEERING_INSTANCE, regs[j].flags));
+ i915_error_printf(ebuf, ": 0x%08x\n", regs[j].value);
++j;
}
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
index 4722d4b18ed1..b071973ac41c 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
@@ -13,8 +13,157 @@
#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] = {
+ GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE / SZ_1M,
+ GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE / SZ_1M,
+ GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE / SZ_1M,
+ };
+ 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 &&
+ 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 +187,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 +317,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 +363,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 +380,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 +389,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 +440,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 +555,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
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
index dc9715411d62..02127703be80 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
@@ -15,20 +15,6 @@
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
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
index e1fa1f32f29e..fdd895f73f9f 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
@@ -137,17 +137,6 @@ static int guc_action_slpc_set_param(struct intel_guc *guc, u8 id, u32 value)
return ret > 0 ? -EPROTO : ret;
}
-static int guc_action_slpc_unset_param(struct intel_guc *guc, u8 id)
-{
- u32 request[] = {
- GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,
- SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1),
- id,
- };
-
- return intel_guc_send(guc, request, ARRAY_SIZE(request));
-}
-
static bool slpc_is_running(struct intel_guc_slpc *slpc)
{
return slpc_get_state(slpc) == SLPC_GLOBAL_STATE_RUNNING;
@@ -201,16 +190,6 @@ static int slpc_set_param(struct intel_guc_slpc *slpc, u8 id, u32 value)
return ret;
}
-static int slpc_unset_param(struct intel_guc_slpc *slpc,
- u8 id)
-{
- struct intel_guc *guc = slpc_to_guc(slpc);
-
- GEM_BUG_ON(id >= SLPC_MAX_PARAM);
-
- return guc_action_slpc_unset_param(guc, id);
-}
-
static int slpc_force_min_freq(struct intel_guc_slpc *slpc, u32 freq)
{
struct drm_i915_private *i915 = slpc_to_i915(slpc);
@@ -488,23 +467,33 @@ int intel_guc_slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 val)
/* Need a lock now since waitboost can be modifying min as well */
mutex_lock(&slpc->lock);
-
- with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
-
- ret = slpc_set_param(slpc,
- SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,
- val);
-
- /* Return standardized err code for sysfs calls */
- if (ret)
- ret = -EIO;
+ wakeref = intel_runtime_pm_get(&i915->runtime_pm);
+
+ /* Ignore efficient freq if lower min freq is requested */
+ ret = slpc_set_param(slpc,
+ SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY,
+ val < slpc->rp1_freq);
+ if (ret) {
+ i915_probe_error(i915, "Failed to toggle efficient freq (%pe)\n",
+ ERR_PTR(ret));
+ goto out;
}
+ ret = slpc_set_param(slpc,
+ SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,
+ val);
+
if (!ret)
slpc->min_freq_softlimit = val;
+out:
+ intel_runtime_pm_put(&i915->runtime_pm, wakeref);
mutex_unlock(&slpc->lock);
+ /* Return standardized err code for sysfs calls */
+ if (ret)
+ ret = -EIO;
+
return ret;
}
@@ -587,7 +576,9 @@ static int slpc_set_softlimits(struct intel_guc_slpc *slpc)
return ret;
if (!slpc->min_freq_softlimit) {
- slpc->min_freq_softlimit = slpc->min_freq;
+ ret = intel_guc_slpc_get_min_freq(slpc, &slpc->min_freq_softlimit);
+ if (unlikely(ret))
+ return ret;
slpc_to_gt(slpc)->defaults.min_freq = slpc->min_freq_softlimit;
} else if (slpc->min_freq_softlimit != slpc->min_freq) {
return intel_guc_slpc_set_min_freq(slpc,
@@ -597,29 +588,6 @@ static int slpc_set_softlimits(struct intel_guc_slpc *slpc)
return 0;
}
-static int slpc_ignore_eff_freq(struct intel_guc_slpc *slpc, bool ignore)
-{
- int ret = 0;
-
- if (ignore) {
- ret = slpc_set_param(slpc,
- SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY,
- ignore);
- if (!ret)
- return slpc_set_param(slpc,
- SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,
- slpc->min_freq);
- } else {
- ret = slpc_unset_param(slpc,
- SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY);
- if (!ret)
- return slpc_unset_param(slpc,
- SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ);
- }
-
- return ret;
-}
-
static int slpc_use_fused_rp0(struct intel_guc_slpc *slpc)
{
/* Force SLPC to used platform rp0 */
@@ -679,14 +647,6 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
slpc_get_rp_values(slpc);
- /* Ignore efficient freq and set min to platform min */
- ret = slpc_ignore_eff_freq(slpc, true);
- if (unlikely(ret)) {
- i915_probe_error(i915, "Failed to set SLPC min to RPn (%pe)\n",
- ERR_PTR(ret));
- return ret;
- }
-
/* Set SLPC max limit to RP0 */
ret = slpc_use_fused_rp0(slpc);
if (unlikely(ret)) {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index 0d17da77e787..64c4e83153f4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -1868,7 +1868,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
if (guc->submission_initialized)
return 0;
- if (guc->fw.major_ver_found < 70) {
+ if (GET_UC_VER(guc) < MAKE_UC_VER(70, 0, 0)) {
ret = guc_lrc_desc_pool_create_v69(guc);
if (ret)
return ret;
@@ -2303,7 +2303,7 @@ static int register_context(struct intel_context *ce, bool loop)
GEM_BUG_ON(intel_context_is_child(ce));
trace_intel_context_register(ce);
- if (guc->fw.major_ver_found >= 70)
+ if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0))
ret = register_context_v70(guc, ce, loop);
else
ret = register_context_v69(guc, ce, loop);
@@ -2315,7 +2315,7 @@ static int register_context(struct intel_context *ce, bool loop)
set_context_registered(ce);
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
- if (guc->fw.major_ver_found >= 70)
+ if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0))
guc_context_policy_init_v70(ce, loop);
}
@@ -2921,7 +2921,7 @@ static void __guc_context_set_preemption_timeout(struct intel_guc *guc,
u16 guc_id,
u32 preemption_timeout)
{
- if (guc->fw.major_ver_found >= 70) {
+ if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0)) {
struct context_policy policy;
__guc_context_policy_start_klv(&policy, guc_id);
@@ -3186,7 +3186,7 @@ static int guc_context_alloc(struct intel_context *ce)
static void __guc_context_set_prio(struct intel_guc *guc,
struct intel_context *ce)
{
- if (guc->fw.major_ver_found >= 70) {
+ if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0)) {
struct context_policy policy;
__guc_context_policy_start_klv(&policy, ce->guc_id.id);
@@ -4003,6 +4003,13 @@ static inline void guc_init_lrc_mapping(struct intel_guc *guc)
xa_destroy(&guc->context_lookup);
/*
+ * A reset might have occurred while we had a pending stalled request,
+ * so make sure we clean that up.
+ */
+ guc->stalled_request = NULL;
+ guc->submission_stall_reason = STALL_NONE;
+
+ /*
* Some contexts might have been pinned before we enabled GuC
* submission, so we need to add them to the GuC bookeeping.
* Also, after a reset the of the GuC we want to make sure that the
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
index f2e7c82985ef..abf4e142596d 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
@@ -435,9 +435,11 @@ static void print_fw_ver(struct intel_uc *uc, struct intel_uc_fw *fw)
{
struct drm_i915_private *i915 = uc_to_gt(uc)->i915;
- drm_info(&i915->drm, "%s firmware %s version %u.%u\n",
- intel_uc_fw_type_repr(fw->type), fw->path,
- fw->major_ver_found, fw->minor_ver_found);
+ drm_info(&i915->drm, "%s firmware %s version %u.%u.%u\n",
+ intel_uc_fw_type_repr(fw->type), fw->file_selected.path,
+ fw->file_selected.major_ver,
+ fw->file_selected.minor_ver,
+ fw->file_selected.patch_ver);
}
static int __uc_init_hw(struct intel_uc *uc)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index 58547292efa0..af425916cdf6 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -41,7 +41,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
"%s firmware -> %s\n",
intel_uc_fw_type_repr(uc_fw->type),
status == INTEL_UC_FIRMWARE_SELECTED ?
- uc_fw->path : intel_uc_fw_status_repr(status));
+ uc_fw->file_selected.path : intel_uc_fw_status_repr(status));
}
#endif
@@ -51,84 +51,149 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
*
* Note that RKL and ADL-S have the same GuC/HuC device ID's and use the same
* firmware as TGL.
+ *
+ * Version numbers:
+ * Originally, the driver required an exact match major/minor/patch furmware
+ * file and only supported that one version for any given platform. However,
+ * the new direction from upstream is to be backwards compatible with all
+ * prior releases and to be as flexible as possible as to what firmware is
+ * loaded.
+ *
+ * For GuC, the major version number signifies a backwards breaking API change.
+ * So, new format GuC firmware files are labelled by their major version only.
+ * For HuC, there is no KMD interaction, hence no version matching requirement.
+ * So, new format HuC firmware files have no version number at all.
+ *
+ * All of which means that the table below must keep all old format files with
+ * full three point version number. But newer files have reduced requirements.
+ * Having said that, the driver still needs to track the minor version number
+ * for GuC at least. As it is useful to report to the user that they are not
+ * running with a recent enough version for all KMD supported features,
+ * security fixes, etc. to be enabled.
*/
-#define INTEL_GUC_FIRMWARE_DEFS(fw_def, guc_def) \
- fw_def(DG2, 0, guc_def(dg2, 70, 4, 1)) \
- fw_def(ALDERLAKE_P, 0, guc_def(adlp, 70, 1, 1)) \
- fw_def(ALDERLAKE_S, 0, guc_def(tgl, 70, 1, 1)) \
- fw_def(DG1, 0, guc_def(dg1, 70, 1, 1)) \
- fw_def(ROCKETLAKE, 0, guc_def(tgl, 70, 1, 1)) \
- fw_def(TIGERLAKE, 0, guc_def(tgl, 70, 1, 1)) \
- fw_def(JASPERLAKE, 0, guc_def(ehl, 70, 1, 1)) \
- fw_def(ELKHARTLAKE, 0, guc_def(ehl, 70, 1, 1)) \
- fw_def(ICELAKE, 0, guc_def(icl, 70, 1, 1)) \
- fw_def(COMETLAKE, 5, guc_def(cml, 70, 1, 1)) \
- fw_def(COMETLAKE, 0, guc_def(kbl, 70, 1, 1)) \
- fw_def(COFFEELAKE, 0, guc_def(kbl, 70, 1, 1)) \
- fw_def(GEMINILAKE, 0, guc_def(glk, 70, 1, 1)) \
- fw_def(KABYLAKE, 0, guc_def(kbl, 70, 1, 1)) \
- fw_def(BROXTON, 0, guc_def(bxt, 70, 1, 1)) \
- fw_def(SKYLAKE, 0, guc_def(skl, 70, 1, 1))
-
-#define INTEL_GUC_FIRMWARE_DEFS_FALLBACK(fw_def, guc_def) \
- fw_def(ALDERLAKE_P, 0, guc_def(adlp, 69, 0, 3)) \
- fw_def(ALDERLAKE_S, 0, guc_def(tgl, 69, 0, 3))
-
-#define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_def) \
- fw_def(ALDERLAKE_P, 0, huc_def(tgl, 7, 9, 3)) \
- fw_def(ALDERLAKE_S, 0, huc_def(tgl, 7, 9, 3)) \
- fw_def(DG1, 0, huc_def(dg1, 7, 9, 3)) \
- fw_def(ROCKETLAKE, 0, huc_def(tgl, 7, 9, 3)) \
- fw_def(TIGERLAKE, 0, huc_def(tgl, 7, 9, 3)) \
- fw_def(JASPERLAKE, 0, huc_def(ehl, 9, 0, 0)) \
- fw_def(ELKHARTLAKE, 0, huc_def(ehl, 9, 0, 0)) \
- fw_def(ICELAKE, 0, huc_def(icl, 9, 0, 0)) \
- fw_def(COMETLAKE, 5, huc_def(cml, 4, 0, 0)) \
- fw_def(COMETLAKE, 0, huc_def(kbl, 4, 0, 0)) \
- fw_def(COFFEELAKE, 0, huc_def(kbl, 4, 0, 0)) \
- fw_def(GEMINILAKE, 0, huc_def(glk, 4, 0, 0)) \
- fw_def(KABYLAKE, 0, huc_def(kbl, 4, 0, 0)) \
- fw_def(BROXTON, 0, huc_def(bxt, 2, 0, 0)) \
- fw_def(SKYLAKE, 0, huc_def(skl, 2, 0, 0))
-
-#define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_) \
+#define INTEL_GUC_FIRMWARE_DEFS(fw_def, guc_maj, guc_mmp) \
+ fw_def(DG2, 0, guc_mmp(dg2, 70, 4, 1)) \
+ fw_def(ALDERLAKE_P, 0, guc_mmp(adlp, 70, 1, 1)) \
+ fw_def(ALDERLAKE_P, 0, guc_mmp(adlp, 69, 0, 3)) \
+ fw_def(ALDERLAKE_S, 0, guc_mmp(tgl, 70, 1, 1)) \
+ fw_def(ALDERLAKE_S, 0, guc_mmp(tgl, 69, 0, 3)) \
+ fw_def(DG1, 0, guc_mmp(dg1, 70, 1, 1)) \
+ fw_def(ROCKETLAKE, 0, guc_mmp(tgl, 70, 1, 1)) \
+ fw_def(TIGERLAKE, 0, guc_mmp(tgl, 70, 1, 1)) \
+ fw_def(JASPERLAKE, 0, guc_mmp(ehl, 70, 1, 1)) \
+ fw_def(ELKHARTLAKE, 0, guc_mmp(ehl, 70, 1, 1)) \
+ fw_def(ICELAKE, 0, guc_mmp(icl, 70, 1, 1)) \
+ fw_def(COMETLAKE, 5, guc_mmp(cml, 70, 1, 1)) \
+ fw_def(COMETLAKE, 0, guc_mmp(kbl, 70, 1, 1)) \
+ fw_def(COFFEELAKE, 0, guc_mmp(kbl, 70, 1, 1)) \
+ fw_def(GEMINILAKE, 0, guc_mmp(glk, 70, 1, 1)) \
+ fw_def(KABYLAKE, 0, guc_mmp(kbl, 70, 1, 1)) \
+ fw_def(BROXTON, 0, guc_mmp(bxt, 70, 1, 1)) \
+ fw_def(SKYLAKE, 0, guc_mmp(skl, 70, 1, 1))
+
+#define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_raw, huc_mmp) \
+ fw_def(ALDERLAKE_P, 0, huc_mmp(tgl, 7, 9, 3)) \
+ fw_def(ALDERLAKE_S, 0, huc_mmp(tgl, 7, 9, 3)) \
+ fw_def(DG1, 0, huc_mmp(dg1, 7, 9, 3)) \
+ fw_def(ROCKETLAKE, 0, huc_mmp(tgl, 7, 9, 3)) \
+ fw_def(TIGERLAKE, 0, huc_mmp(tgl, 7, 9, 3)) \
+ fw_def(JASPERLAKE, 0, huc_mmp(ehl, 9, 0, 0)) \
+ fw_def(ELKHARTLAKE, 0, huc_mmp(ehl, 9, 0, 0)) \
+ fw_def(ICELAKE, 0, huc_mmp(icl, 9, 0, 0)) \
+ fw_def(COMETLAKE, 5, huc_mmp(cml, 4, 0, 0)) \
+ fw_def(COMETLAKE, 0, huc_mmp(kbl, 4, 0, 0)) \
+ fw_def(COFFEELAKE, 0, huc_mmp(kbl, 4, 0, 0)) \
+ fw_def(GEMINILAKE, 0, huc_mmp(glk, 4, 0, 0)) \
+ fw_def(KABYLAKE, 0, huc_mmp(kbl, 4, 0, 0)) \
+ fw_def(BROXTON, 0, huc_mmp(bxt, 2, 0, 0)) \
+ fw_def(SKYLAKE, 0, huc_mmp(skl, 2, 0, 0))
+
+/*
+ * Set of macros for producing a list of filenames from the above table.
+ */
+#define __MAKE_UC_FW_PATH_BLANK(prefix_, name_) \
+ "i915/" \
+ __stringify(prefix_) name_ ".bin"
+
+#define __MAKE_UC_FW_PATH_MAJOR(prefix_, name_, major_) \
+ "i915/" \
+ __stringify(prefix_) name_ \
+ __stringify(major_) ".bin"
+
+#define __MAKE_UC_FW_PATH_MMP(prefix_, name_, major_, minor_, patch_) \
"i915/" \
__stringify(prefix_) name_ \
__stringify(major_) "." \
__stringify(minor_) "." \
__stringify(patch_) ".bin"
-#define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
- __MAKE_UC_FW_PATH(prefix_, "_guc_", major_, minor_, patch_)
+/* Minor for internal driver use, not part of file name */
+#define MAKE_GUC_FW_PATH_MAJOR(prefix_, major_, minor_) \
+ __MAKE_UC_FW_PATH_MAJOR(prefix_, "_guc_", major_)
-#define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
- __MAKE_UC_FW_PATH(prefix_, "_huc_", major_, minor_, bld_num_)
+#define MAKE_GUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \
+ __MAKE_UC_FW_PATH_MMP(prefix_, "_guc_", major_, minor_, patch_)
-/* All blobs need to be declared via MODULE_FIRMWARE() */
+#define MAKE_HUC_FW_PATH_BLANK(prefix_) \
+ __MAKE_UC_FW_PATH_BLANK(prefix_, "_huc")
+
+#define MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \
+ __MAKE_UC_FW_PATH_MMP(prefix_, "_huc_", major_, minor_, patch_)
+
+/*
+ * All blobs need to be declared via MODULE_FIRMWARE().
+ * This first expansion of the table macros is solely to provide
+ * that declaration.
+ */
#define INTEL_UC_MODULE_FW(platform_, revid_, uc_) \
MODULE_FIRMWARE(uc_);
-INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH)
-INTEL_GUC_FIRMWARE_DEFS_FALLBACK(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH)
-INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH)
+INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH_MAJOR, MAKE_GUC_FW_PATH_MMP)
+INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH_BLANK, MAKE_HUC_FW_PATH_MMP)
-/* The below structs and macros are used to iterate across the list of blobs */
+/*
+ * The next expansion of the table macros (in __uc_fw_auto_select below) provides
+ * actual data structures with both the filename and the version information.
+ * These structure arrays are then iterated over to the list of suitable files
+ * for the current platform and to then attempt to load those files, in the order
+ * listed, until one is successfully found.
+ */
struct __packed uc_fw_blob {
+ const char *path;
+ bool legacy;
u8 major;
u8 minor;
- const char *path;
+ u8 patch;
};
-#define UC_FW_BLOB(major_, minor_, path_) \
- { .major = major_, .minor = minor_, .path = path_ }
+#define UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \
+ .major = major_, \
+ .minor = minor_, \
+ .patch = patch_, \
+ .path = path_,
+
+#define UC_FW_BLOB_NEW(major_, minor_, patch_, path_) \
+ { UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \
+ .legacy = false }
+
+#define UC_FW_BLOB_OLD(major_, minor_, patch_, path_) \
+ { UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \
+ .legacy = true }
-#define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \
- UC_FW_BLOB(major_, minor_, \
- MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_))
+#define GUC_FW_BLOB(prefix_, major_, minor_) \
+ UC_FW_BLOB_NEW(major_, minor_, 0, \
+ MAKE_GUC_FW_PATH_MAJOR(prefix_, major_, minor_))
-#define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \
- UC_FW_BLOB(major_, minor_, \
- MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_))
+#define GUC_FW_BLOB_MMP(prefix_, major_, minor_, patch_) \
+ UC_FW_BLOB_OLD(major_, minor_, patch_, \
+ MAKE_GUC_FW_PATH_MMP(prefix_, major_, minor_, patch_))
+
+#define HUC_FW_BLOB(prefix_) \
+ UC_FW_BLOB_NEW(0, 0, 0, MAKE_HUC_FW_PATH_BLANK(prefix_))
+
+#define HUC_FW_BLOB_MMP(prefix_, major_, minor_, patch_) \
+ UC_FW_BLOB_OLD(major_, minor_, patch_, \
+ MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_))
struct __packed uc_fw_platform_requirement {
enum intel_platform p;
@@ -152,18 +217,16 @@ static void
__uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
{
static const struct uc_fw_platform_requirement blobs_guc[] = {
- INTEL_GUC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB)
- };
- static const struct uc_fw_platform_requirement blobs_guc_fallback[] = {
- INTEL_GUC_FIRMWARE_DEFS_FALLBACK(MAKE_FW_LIST, GUC_FW_BLOB)
+ INTEL_GUC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, GUC_FW_BLOB_MMP)
};
static const struct uc_fw_platform_requirement blobs_huc[] = {
- INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB)
+ INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB, HUC_FW_BLOB_MMP)
};
static const struct fw_blobs_by_type blobs_all[INTEL_UC_FW_NUM_TYPES] = {
[INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) },
[INTEL_UC_FW_TYPE_HUC] = { blobs_huc, ARRAY_SIZE(blobs_huc) },
};
+ static bool verified;
const struct uc_fw_platform_requirement *fw_blobs;
enum intel_platform p = INTEL_INFO(i915)->platform;
u32 fw_count;
@@ -184,49 +247,94 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
fw_count = blobs_all[uc_fw->type].count;
for (i = 0; i < fw_count && p <= fw_blobs[i].p; i++) {
- if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
- const struct uc_fw_blob *blob = &fw_blobs[i].blob;
- uc_fw->path = blob->path;
- uc_fw->wanted_path = blob->path;
- uc_fw->major_ver_wanted = blob->major;
- uc_fw->minor_ver_wanted = blob->minor;
- break;
- }
- }
+ const struct uc_fw_blob *blob = &fw_blobs[i].blob;
- if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) {
- const struct uc_fw_platform_requirement *blobs = blobs_guc_fallback;
- u32 count = ARRAY_SIZE(blobs_guc_fallback);
+ if (p != fw_blobs[i].p)
+ continue;
- for (i = 0; i < count && p <= blobs[i].p; i++) {
- if (p == blobs[i].p && rev >= blobs[i].rev) {
- const struct uc_fw_blob *blob = &blobs[i].blob;
+ if (rev < fw_blobs[i].rev)
+ continue;
- uc_fw->fallback.path = blob->path;
- uc_fw->fallback.major_ver = blob->major;
- uc_fw->fallback.minor_ver = blob->minor;
- break;
- }
+ if (uc_fw->file_selected.path) {
+ if (uc_fw->file_selected.path == blob->path)
+ uc_fw->file_selected.path = NULL;
+
+ continue;
}
+
+ uc_fw->file_selected.path = blob->path;
+ uc_fw->file_wanted.path = blob->path;
+ uc_fw->file_wanted.major_ver = blob->major;
+ uc_fw->file_wanted.minor_ver = blob->minor;
+ break;
}
/* make sure the list is ordered as expected */
- if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
+ if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST) && !verified) {
+ verified = true;
+
for (i = 1; i < fw_count; i++) {
+ /* Next platform is good: */
if (fw_blobs[i].p < fw_blobs[i - 1].p)
continue;
+ /* Next platform revision is good: */
if (fw_blobs[i].p == fw_blobs[i - 1].p &&
fw_blobs[i].rev < fw_blobs[i - 1].rev)
continue;
- drm_err(&i915->drm, "Invalid FW blob order: %s r%u comes before %s r%u\n",
- intel_platform_name(fw_blobs[i - 1].p),
- fw_blobs[i - 1].rev,
- intel_platform_name(fw_blobs[i].p),
- fw_blobs[i].rev);
+ /* Platform/revision must be in order: */
+ if (fw_blobs[i].p != fw_blobs[i - 1].p ||
+ fw_blobs[i].rev != fw_blobs[i - 1].rev)
+ goto bad;
+
+ /* Next major version is good: */
+ if (fw_blobs[i].blob.major < fw_blobs[i - 1].blob.major)
+ continue;
+
+ /* New must be before legacy: */
+ if (!fw_blobs[i].blob.legacy && fw_blobs[i - 1].blob.legacy)
+ goto bad;
+
+ /* New to legacy also means 0.0 to X.Y (HuC), or X.0 to X.Y (GuC) */
+ if (fw_blobs[i].blob.legacy && !fw_blobs[i - 1].blob.legacy) {
+ if (!fw_blobs[i - 1].blob.major)
+ continue;
+
+ if (fw_blobs[i].blob.major == fw_blobs[i - 1].blob.major)
+ continue;
+ }
+
+ /* Major versions must be in order: */
+ if (fw_blobs[i].blob.major != fw_blobs[i - 1].blob.major)
+ goto bad;
+
+ /* Next minor version is good: */
+ if (fw_blobs[i].blob.minor < fw_blobs[i - 1].blob.minor)
+ continue;
+
+ /* Minor versions must be in order: */
+ if (fw_blobs[i].blob.minor != fw_blobs[i - 1].blob.minor)
+ goto bad;
+
+ /* Patch versions must be in order: */
+ if (fw_blobs[i].blob.patch <= fw_blobs[i - 1].blob.patch)
+ continue;
- uc_fw->path = NULL;
+bad:
+ drm_err(&i915->drm, "\x1B[35;1mInvalid FW blob order: %s r%u %s%d.%d.%d comes before %s r%u %s%d.%d.%d\n",
+ intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev,
+ fw_blobs[i - 1].blob.legacy ? "L" : "v",
+ fw_blobs[i - 1].blob.major,
+ fw_blobs[i - 1].blob.minor,
+ fw_blobs[i - 1].blob.patch,
+ intel_platform_name(fw_blobs[i].p), fw_blobs[i].rev,
+ fw_blobs[i].blob.legacy ? "L" : "v",
+ fw_blobs[i].blob.major,
+ fw_blobs[i].blob.minor,
+ fw_blobs[i].blob.patch);
+
+ uc_fw->file_selected.path = NULL;
}
}
}
@@ -259,7 +367,7 @@ static void __uc_fw_user_override(struct drm_i915_private *i915, struct intel_uc
}
if (unlikely(path)) {
- uc_fw->path = path;
+ uc_fw->file_selected.path = path;
uc_fw->user_overridden = true;
}
}
@@ -283,7 +391,7 @@ void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
*/
BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED);
GEM_BUG_ON(uc_fw->status);
- GEM_BUG_ON(uc_fw->path);
+ GEM_BUG_ON(uc_fw->file_selected.path);
uc_fw->type = type;
@@ -292,7 +400,7 @@ void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
__uc_fw_user_override(i915, uc_fw);
}
- intel_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ?
+ intel_uc_fw_change_status(uc_fw, uc_fw->file_selected.path ? *uc_fw->file_selected.path ?
INTEL_UC_FIRMWARE_SELECTED :
INTEL_UC_FIRMWARE_DISABLED :
INTEL_UC_FIRMWARE_NOT_SUPPORTED);
@@ -305,32 +413,32 @@ static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e)
if (i915_inject_probe_error(i915, e)) {
/* non-existing blob */
- uc_fw->path = "<invalid>";
+ uc_fw->file_selected.path = "<invalid>";
uc_fw->user_overridden = user;
} else if (i915_inject_probe_error(i915, e)) {
/* require next major version */
- uc_fw->major_ver_wanted += 1;
- uc_fw->minor_ver_wanted = 0;
+ uc_fw->file_wanted.major_ver += 1;
+ uc_fw->file_wanted.minor_ver = 0;
uc_fw->user_overridden = user;
} else if (i915_inject_probe_error(i915, e)) {
/* require next minor version */
- uc_fw->minor_ver_wanted += 1;
+ uc_fw->file_wanted.minor_ver += 1;
uc_fw->user_overridden = user;
- } else if (uc_fw->major_ver_wanted &&
+ } else if (uc_fw->file_wanted.major_ver &&
i915_inject_probe_error(i915, e)) {
/* require prev major version */
- uc_fw->major_ver_wanted -= 1;
- uc_fw->minor_ver_wanted = 0;
+ uc_fw->file_wanted.major_ver -= 1;
+ uc_fw->file_wanted.minor_ver = 0;
uc_fw->user_overridden = user;
- } else if (uc_fw->minor_ver_wanted &&
+ } else if (uc_fw->file_wanted.minor_ver &&
i915_inject_probe_error(i915, e)) {
/* require prev minor version - hey, this should work! */
- uc_fw->minor_ver_wanted -= 1;
+ uc_fw->file_wanted.minor_ver -= 1;
uc_fw->user_overridden = user;
} else if (user && i915_inject_probe_error(i915, e)) {
/* officially unsupported platform */
- uc_fw->major_ver_wanted = 0;
- uc_fw->minor_ver_wanted = 0;
+ uc_fw->file_wanted.major_ver = 0;
+ uc_fw->file_wanted.minor_ver = 0;
uc_fw->user_overridden = true;
}
}
@@ -339,10 +447,12 @@ static int check_gsc_manifest(const struct firmware *fw,
struct intel_uc_fw *uc_fw)
{
u32 *dw = (u32 *)fw->data;
- u32 version = dw[HUC_GSC_VERSION_DW];
+ u32 version_hi = dw[HUC_GSC_VERSION_HI_DW];
+ u32 version_lo = dw[HUC_GSC_VERSION_LO_DW];
- uc_fw->major_ver_found = FIELD_GET(HUC_GSC_MAJOR_VER_MASK, version);
- uc_fw->minor_ver_found = FIELD_GET(HUC_GSC_MINOR_VER_MASK, version);
+ uc_fw->file_selected.major_ver = FIELD_GET(HUC_GSC_MAJOR_VER_HI_MASK, version_hi);
+ uc_fw->file_selected.minor_ver = FIELD_GET(HUC_GSC_MINOR_VER_HI_MASK, version_hi);
+ uc_fw->file_selected.patch_ver = FIELD_GET(HUC_GSC_PATCH_VER_LO_MASK, version_lo);
return 0;
}
@@ -357,7 +467,7 @@ static int check_ccs_header(struct drm_i915_private *i915,
/* Check the size of the blob before examining buffer contents */
if (unlikely(fw->size < sizeof(struct uc_css_header))) {
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
fw->size, sizeof(struct uc_css_header));
return -ENODATA;
}
@@ -370,7 +480,7 @@ static int check_ccs_header(struct drm_i915_private *i915,
if (unlikely(size != sizeof(struct uc_css_header))) {
drm_warn(&i915->drm,
"%s firmware %s: unexpected header size: %zu != %zu\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
fw->size, sizeof(struct uc_css_header));
return -EPROTO;
}
@@ -385,7 +495,7 @@ static int check_ccs_header(struct drm_i915_private *i915,
size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
if (unlikely(fw->size < size)) {
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
fw->size, size);
return -ENOEXEC;
}
@@ -394,16 +504,18 @@ static int check_ccs_header(struct drm_i915_private *i915,
size = __intel_uc_fw_get_upload_size(uc_fw);
if (unlikely(size >= i915->wopcm.size)) {
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
size, (size_t)i915->wopcm.size);
return -E2BIG;
}
/* Get version numbers from the CSS header */
- uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
- css->sw_version);
- uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
- css->sw_version);
+ uc_fw->file_selected.major_ver = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
+ css->sw_version);
+ uc_fw->file_selected.minor_ver = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
+ css->sw_version);
+ uc_fw->file_selected.patch_ver = FIELD_GET(CSS_SW_VERSION_UC_PATCH,
+ css->sw_version);
if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
uc_fw->private_data_size = css->private_data_size;
@@ -422,9 +534,11 @@ static int check_ccs_header(struct drm_i915_private *i915,
int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
{
struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
+ struct intel_uc_fw_file file_ideal;
struct device *dev = i915->drm.dev;
struct drm_i915_gem_object *obj;
const struct firmware *fw = NULL;
+ bool old_ver = false;
int err;
GEM_BUG_ON(!i915->wopcm.size);
@@ -437,27 +551,33 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
__force_fw_fetch_failures(uc_fw, -EINVAL);
__force_fw_fetch_failures(uc_fw, -ESTALE);
- err = firmware_request_nowarn(&fw, uc_fw->path, dev);
- if (err && !intel_uc_fw_is_overridden(uc_fw) && uc_fw->fallback.path) {
- err = firmware_request_nowarn(&fw, uc_fw->fallback.path, dev);
- if (!err) {
- drm_notice(&i915->drm,
- "%s firmware %s is recommended, but only %s was found\n",
- intel_uc_fw_type_repr(uc_fw->type),
- uc_fw->wanted_path,
- uc_fw->fallback.path);
- drm_info(&i915->drm,
- "Consider updating your linux-firmware pkg or downloading from %s\n",
- INTEL_UC_FIRMWARE_URL);
-
- uc_fw->path = uc_fw->fallback.path;
- uc_fw->major_ver_wanted = uc_fw->fallback.major_ver;
- uc_fw->minor_ver_wanted = uc_fw->fallback.minor_ver;
+ err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
+ memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal));
+ if (!err || intel_uc_fw_is_overridden(uc_fw))
+ goto done;
+
+ while (err == -ENOENT) {
+ __uc_fw_auto_select(i915, uc_fw);
+ if (!uc_fw->file_selected.path) {
+ /*
+ * No more options! But set the path back to something
+ * valid just in case it gets dereferenced.
+ */
+ uc_fw->file_selected.path = file_ideal.path;
+
+ /* Also, preserve the version that was really wanted */
+ memcpy(&uc_fw->file_wanted, &file_ideal, sizeof(uc_fw->file_wanted));
+ break;
}
+
+ err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
}
+
if (err)
goto fail;
+ old_ver = true;
+done:
if (uc_fw->loaded_via_gsc)
err = check_gsc_manifest(fw, uc_fw);
else
@@ -465,18 +585,39 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
if (err)
goto fail;
- if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
- uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
- drm_notice(&i915->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
- uc_fw->major_ver_found, uc_fw->minor_ver_found,
- uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
- if (!intel_uc_fw_is_overridden(uc_fw)) {
- err = -ENOEXEC;
- goto fail;
+ if (uc_fw->file_wanted.major_ver) {
+ /* Check the file's major version was as it claimed */
+ if (uc_fw->file_selected.major_ver != uc_fw->file_wanted.major_ver) {
+ drm_notice(&i915->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
+ uc_fw->file_selected.major_ver, uc_fw->file_selected.minor_ver,
+ uc_fw->file_wanted.major_ver, uc_fw->file_wanted.minor_ver);
+ if (!intel_uc_fw_is_overridden(uc_fw)) {
+ err = -ENOEXEC;
+ goto fail;
+ }
+ } else {
+ if (uc_fw->file_selected.minor_ver < uc_fw->file_wanted.minor_ver)
+ old_ver = true;
}
}
+ if (old_ver) {
+ /* Preserve the version that was really wanted */
+ memcpy(&uc_fw->file_wanted, &file_ideal, sizeof(uc_fw->file_wanted));
+
+ drm_notice(&i915->drm,
+ "%s firmware %s (%d.%d) is recommended, but only %s (%d.%d) was found\n",
+ intel_uc_fw_type_repr(uc_fw->type),
+ uc_fw->file_wanted.path,
+ uc_fw->file_wanted.major_ver, uc_fw->file_wanted.minor_ver,
+ uc_fw->file_selected.path,
+ uc_fw->file_selected.major_ver, uc_fw->file_selected.minor_ver);
+ drm_info(&i915->drm,
+ "Consider updating your linux-firmware pkg or downloading from %s\n",
+ INTEL_UC_FIRMWARE_URL);
+ }
+
if (HAS_LMEM(i915)) {
obj = i915_gem_object_create_lmem_from_data(i915, fw->data, fw->size);
if (!IS_ERR(obj))
@@ -503,7 +644,7 @@ fail:
INTEL_UC_FIRMWARE_ERROR);
i915_probe_error(i915, "%s firmware %s: fetch failed with error %d\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path, err);
drm_info(&i915->drm, "%s firmware(s) can be downloaded from %s\n",
intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
@@ -645,7 +786,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
fail:
i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
err);
intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
return err;
@@ -863,19 +1004,34 @@ size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
*/
void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
{
+ u32 ver_sel, ver_want;
+
drm_printf(p, "%s firmware: %s\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->wanted_path);
- if (uc_fw->fallback.path) {
- drm_printf(p, "%s firmware fallback: %s\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->fallback.path);
- drm_printf(p, "fallback selected: %s\n",
- str_yes_no(uc_fw->path == uc_fw->fallback.path));
- }
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path);
+ if (uc_fw->file_selected.path != uc_fw->file_wanted.path)
+ drm_printf(p, "%s firmware wanted: %s\n",
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_wanted.path);
drm_printf(p, "\tstatus: %s\n",
intel_uc_fw_status_repr(uc_fw->status));
- drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
- uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
- uc_fw->major_ver_found, uc_fw->minor_ver_found);
+ ver_sel = MAKE_UC_VER(uc_fw->file_selected.major_ver,
+ uc_fw->file_selected.minor_ver,
+ uc_fw->file_selected.patch_ver);
+ ver_want = MAKE_UC_VER(uc_fw->file_wanted.major_ver,
+ uc_fw->file_wanted.minor_ver,
+ uc_fw->file_wanted.patch_ver);
+ if (ver_sel < ver_want)
+ drm_printf(p, "\tversion: wanted %u.%u.%u, found %u.%u.%u\n",
+ uc_fw->file_wanted.major_ver,
+ uc_fw->file_wanted.minor_ver,
+ uc_fw->file_wanted.patch_ver,
+ uc_fw->file_selected.major_ver,
+ uc_fw->file_selected.minor_ver,
+ uc_fw->file_selected.patch_ver);
+ else
+ drm_printf(p, "\tversion: found %u.%u.%u\n",
+ uc_fw->file_selected.major_ver,
+ uc_fw->file_selected.minor_ver,
+ uc_fw->file_selected.patch_ver);
drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
index 7aa2644400b9..cb586f7df270 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
@@ -65,6 +65,18 @@ enum intel_uc_fw_type {
#define INTEL_UC_FW_NUM_TYPES 2
/*
+ * The firmware build process will generate a version header file with major and
+ * minor version defined. The versions are built into CSS header of firmware.
+ * i915 kernel driver set the minimal firmware version required per platform.
+ */
+struct intel_uc_fw_file {
+ const char *path;
+ u16 major_ver;
+ u16 minor_ver;
+ u16 patch_ver;
+};
+
+/*
* This structure encapsulates all the data needed during the process
* of fetching, caching, and loading the firmware image into the uC.
*/
@@ -74,11 +86,12 @@ struct intel_uc_fw {
const enum intel_uc_fw_status status;
enum intel_uc_fw_status __status; /* no accidental overwrites */
};
- const char *wanted_path;
- const char *path;
+ struct intel_uc_fw_file file_wanted;
+ struct intel_uc_fw_file file_selected;
bool user_overridden;
size_t size;
struct drm_i915_gem_object *obj;
+
/**
* @dummy: A vma used in binding the uc fw to ggtt. We can't define this
* vma on the stack as it can lead to a stack overflow, so we define it
@@ -89,30 +102,18 @@ struct intel_uc_fw {
struct i915_vma_resource dummy;
struct i915_vma *rsa_data;
- /*
- * The firmware build process will generate a version header file with major and
- * minor version defined. The versions are built into CSS header of firmware.
- * i915 kernel driver set the minimal firmware version required per platform.
- */
- u16 major_ver_wanted;
- u16 minor_ver_wanted;
- u16 major_ver_found;
- u16 minor_ver_found;
-
- struct {
- const char *path;
- u16 major_ver;
- u16 minor_ver;
- } fallback;
-
u32 rsa_size;
u32 ucode_size;
-
u32 private_data_size;
bool loaded_via_gsc;
};
+#define MAKE_UC_VER(maj, min, pat) ((pat) | ((min) << 8) | ((maj) << 16))
+#define GET_UC_VER(uc) (MAKE_UC_VER((uc)->fw.file_selected.major_ver, \
+ (uc)->fw.file_selected.minor_ver, \
+ (uc)->fw.file_selected.patch_ver))
+
#ifdef CONFIG_DRM_I915_DEBUG_GUC
void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
enum intel_uc_fw_status status);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
index b05e0e35b734..7a411178bdbf 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
@@ -83,8 +83,10 @@ struct uc_css_header {
} __packed;
static_assert(sizeof(struct uc_css_header) == 128);
-#define HUC_GSC_VERSION_DW 44
-#define HUC_GSC_MAJOR_VER_MASK (0xFF << 0)
-#define HUC_GSC_MINOR_VER_MASK (0xFF << 16)
+#define HUC_GSC_VERSION_HI_DW 44
+#define HUC_GSC_MAJOR_VER_HI_MASK (0xFF << 0)
+#define HUC_GSC_MINOR_VER_HI_MASK (0xFF << 16)
+#define HUC_GSC_VERSION_LO_DW 45
+#define HUC_GSC_PATCH_VER_LO_MASK (0xFF << 0)
#endif /* _INTEL_UC_FW_ABI_H */
diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc.c
index 20e0c39259fb..e28518fe8b90 100644
--- a/drivers/gpu/drm/i915/gt/uc/selftest_guc.c
+++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc.c
@@ -54,6 +54,9 @@ static int intel_guc_scrub_ctbs(void *arg)
struct intel_engine_cs *engine;
struct intel_context *ce;
+ if (!intel_has_gpu_reset(gt))
+ return 0;
+
wakeref = intel_runtime_pm_get(gt->uncore->rpm);
engine = intel_selftest_find_any_engine(gt);