Skip to content

Commit

Permalink
drm/i915/guc: Use GuC submission API version number
Browse files Browse the repository at this point in the history
The GuC firmware includes an extra version number to specify the
submission API level. So use that rather than the main firmware
version number for submission related checks.

Also, while it is guaranteed that GuC version number components are
only 8-bits in size, other firmwares do not have that restriction. So
stop making assumptions about them generically fitting in a u16
individually, or in a u32 as a combined 8.8.8.

Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221129232031.3401386-4-John.C.Harrison@Intel.com
  • Loading branch information
John Harrison authored and John Harrison committed Nov 30, 2022
1 parent 92fcd24 commit 9bbba06
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 26 deletions.
11 changes: 11 additions & 0 deletions drivers/gpu/drm/i915/gt/uc/intel_guc.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ struct intel_guc {
bool submission_selected;
/** @submission_initialized: tracks whether GuC submission has been initialised */
bool submission_initialized;
/** @submission_version: Submission API version of the currently loaded firmware */
struct intel_uc_fw_ver submission_version;

/**
* @rc_supported: tracks whether we support GuC rc on the current platform
*/
Expand Down Expand Up @@ -268,6 +271,14 @@ struct intel_guc {
#endif
};

/*
* GuC version number components are only 8-bit, so converting to a 32bit 8.8.8
* integer works.
*/
#define MAKE_GUC_VER(maj, min, pat) (((maj) << 16) | ((min) << 8) | (pat))
#define MAKE_GUC_VER_STRUCT(ver) MAKE_GUC_VER((ver).major, (ver).minor, (ver).patch)
#define GUC_SUBMIT_VER(guc) MAKE_GUC_VER_STRUCT((guc)->submission_version)

static inline struct intel_guc *log_to_guc(struct intel_guc_log *log)
{
return container_of(log, struct intel_guc, log);
Expand Down
15 changes: 9 additions & 6 deletions drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
if (guc->submission_initialized)
return 0;

if (GET_UC_VER(guc) < MAKE_UC_VER(70, 0, 0)) {
if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 0, 0)) {
ret = guc_lrc_desc_pool_create_v69(guc);
if (ret)
return ret;
Expand Down Expand Up @@ -2329,7 +2329,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 (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0))
if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0))
ret = register_context_v70(guc, ce, loop);
else
ret = register_context_v69(guc, ce, loop);
Expand All @@ -2341,7 +2341,7 @@ static int register_context(struct intel_context *ce, bool loop)
set_context_registered(ce);
spin_unlock_irqrestore(&ce->guc_state.lock, flags);

if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0))
if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0))
guc_context_policy_init_v70(ce, loop);
}

Expand Down Expand Up @@ -2955,7 +2955,7 @@ static void __guc_context_set_preemption_timeout(struct intel_guc *guc,
u16 guc_id,
u32 preemption_timeout)
{
if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0)) {
if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0)) {
struct context_policy policy;

__guc_context_policy_start_klv(&policy, guc_id);
Expand Down Expand Up @@ -3282,7 +3282,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 (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0)) {
if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0)) {
struct context_policy policy;

__guc_context_policy_start_klv(&policy, ce->guc_id.id);
Expand Down Expand Up @@ -4365,7 +4365,7 @@ static int guc_init_global_schedule_policy(struct intel_guc *guc)
intel_wakeref_t wakeref;
int ret = 0;

if (GET_UC_VER(guc) < MAKE_UC_VER(70, 3, 0))
if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 1, 0))
return 0;

__guc_scheduling_policy_start_klv(&policy);
Expand Down Expand Up @@ -4904,6 +4904,9 @@ void intel_guc_submission_print_info(struct intel_guc *guc,
if (!sched_engine)
return;

drm_printf(p, "GuC Submission API Version: %d.%d.%d\n",
guc->submission_version.major, guc->submission_version.minor,
guc->submission_version.patch);
drm_printf(p, "GuC Number Outstanding Submission G2H: %u\n",
atomic_read(&guc->outstanding_submission_g2h));
drm_printf(p, "GuC tasklet count: %u\n",
Expand Down
124 changes: 112 additions & 12 deletions drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,62 @@ static int check_gsc_manifest(const struct firmware *fw,
return 0;
}

static void uc_unpack_css_version(struct intel_uc_fw_ver *ver, u32 css_value)
{
/* Get version numbers from the CSS header */
ver->major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, css_value);
ver->minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR, css_value);
ver->patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH, css_value);
}

static void guc_read_css_info(struct intel_uc_fw *uc_fw, struct uc_css_header *css)
{
struct intel_guc *guc = container_of(uc_fw, struct intel_guc, fw);

/*
* The GuC firmware includes an extra version number to specify the
* submission API level. This allows submission code to work with
* multiple GuC versions without having to know the absolute firmware
* version number (there are likely to be multiple firmware releases
* which all support the same submission API level).
*
* Note that the spec for the CSS header defines this version number
* as 'vf_version' as it was originally intended for virtualisation.
* However, it is applicable to native submission as well.
*
* Unfortunately, due to an oversight, this version number was only
* exposed in the CSS header from v70.6.0.
*/
if (uc_fw->file_selected.ver.major >= 70) {
if (uc_fw->file_selected.ver.minor >= 6) {
/* v70.6.0 adds CSS header support */
uc_unpack_css_version(&guc->submission_version, css->vf_version);
} else if (uc_fw->file_selected.ver.minor >= 3) {
/* v70.3.0 introduced v1.1.0 */
guc->submission_version.major = 1;
guc->submission_version.minor = 1;
guc->submission_version.patch = 0;
} else {
/* v70.0.0 introduced v1.0.0 */
guc->submission_version.major = 1;
guc->submission_version.minor = 0;
guc->submission_version.patch = 0;
}
} else if (uc_fw->file_selected.ver.major >= 69) {
/* v69.0.0 introduced v0.10.0 */
guc->submission_version.major = 0;
guc->submission_version.minor = 10;
guc->submission_version.patch = 0;
} else {
/* Prior versions were v0.1.0 */
guc->submission_version.major = 0;
guc->submission_version.minor = 1;
guc->submission_version.patch = 0;
}

uc_fw->private_data_size = css->private_data_size;
}

static int check_ccs_header(struct intel_gt *gt,
const struct firmware *fw,
struct intel_uc_fw *uc_fw)
Expand Down Expand Up @@ -532,20 +588,50 @@ static int check_ccs_header(struct intel_gt *gt,
return -E2BIG;
}

/* Get version numbers from the CSS header */
uc_fw->file_selected.ver.major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
css->sw_version);
uc_fw->file_selected.ver.minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
css->sw_version);
uc_fw->file_selected.ver.patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH,
css->sw_version);
uc_unpack_css_version(&uc_fw->file_selected.ver, css->sw_version);

if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
uc_fw->private_data_size = css->private_data_size;
guc_read_css_info(uc_fw, css);

return 0;
}

static bool is_ver_8bit(struct intel_uc_fw_ver *ver)
{
return ver->major < 0xFF && ver->minor < 0xFF && ver->patch < 0xFF;
}

static bool guc_check_version_range(struct intel_uc_fw *uc_fw)
{
struct intel_guc *guc = container_of(uc_fw, struct intel_guc, fw);

/*
* GuC version number components are defined as being 8-bits.
* The submission code relies on this to optimise version comparison
* tests. So enforce the restriction here.
*/

if (!is_ver_8bit(&uc_fw->file_selected.ver)) {
drm_warn(&__uc_fw_to_gt(uc_fw)->i915->drm, "%s firmware: invalid file version: 0x%02X:%02X:%02X\n",
intel_uc_fw_type_repr(uc_fw->type),
uc_fw->file_selected.ver.major,
uc_fw->file_selected.ver.minor,
uc_fw->file_selected.ver.patch);
return false;
}

if (!is_ver_8bit(&guc->submission_version)) {
drm_warn(&__uc_fw_to_gt(uc_fw)->i915->drm, "%s firmware: invalid submit version: 0x%02X:%02X:%02X\n",
intel_uc_fw_type_repr(uc_fw->type),
guc->submission_version.major,
guc->submission_version.minor,
guc->submission_version.patch);
return false;
}

return true;
}

/**
* intel_uc_fw_fetch - fetch uC firmware
* @uc_fw: uC firmware
Expand Down Expand Up @@ -622,6 +708,9 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
if (err)
goto fail;

if (uc_fw->type == INTEL_UC_FW_TYPE_GUC && !guc_check_version_range(uc_fw))
goto fail;

if (uc_fw->file_wanted.ver.major) {
/* Check the file's major version was as it claimed */
if (uc_fw->file_selected.ver.major != uc_fw->file_wanted.ver.major) {
Expand Down Expand Up @@ -1055,7 +1144,7 @@ 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;
bool got_wanted;

drm_printf(p, "%s firmware: %s\n",
intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path);
Expand All @@ -1064,9 +1153,20 @@ void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
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));
ver_sel = MAKE_UC_VER_STRUCT(uc_fw->file_selected.ver);
ver_want = MAKE_UC_VER_STRUCT(uc_fw->file_wanted.ver);
if (ver_sel < ver_want)

if (uc_fw->file_selected.ver.major < uc_fw->file_wanted.ver.major)
got_wanted = false;
else if ((uc_fw->file_selected.ver.major == uc_fw->file_wanted.ver.major) &&
(uc_fw->file_selected.ver.minor < uc_fw->file_wanted.ver.minor))
got_wanted = false;
else if ((uc_fw->file_selected.ver.major == uc_fw->file_wanted.ver.major) &&
(uc_fw->file_selected.ver.minor == uc_fw->file_wanted.ver.minor) &&
(uc_fw->file_selected.ver.patch < uc_fw->file_wanted.ver.patch))
got_wanted = false;
else
got_wanted = true;

if (!got_wanted)
drm_printf(p, "\tversion: wanted %u.%u.%u, found %u.%u.%u\n",
uc_fw->file_wanted.ver.major,
uc_fw->file_wanted.ver.minor,
Expand Down
10 changes: 3 additions & 7 deletions drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ enum intel_uc_fw_type {
#define INTEL_UC_FW_NUM_TYPES 2

struct intel_uc_fw_ver {
u16 major;
u16 minor;
u16 patch;
u32 major;
u32 minor;
u32 patch;
};

/*
Expand Down Expand Up @@ -114,10 +114,6 @@ struct intel_uc_fw {
bool loaded_via_gsc;
};

#define MAKE_UC_VER(maj, min, pat) ((pat) | ((min) << 8) | ((maj) << 16))
#define MAKE_UC_VER_STRUCT(ver) MAKE_UC_VER((ver).major, (ver).minor, (ver).patch)
#define GET_UC_VER(uc) (MAKE_UC_VER_STRUCT((uc)->fw.file_selected.ver))

/*
* When we load the uC binaries, we pin them in a reserved section at the top of
* the GGTT, which is ~18 MBs. On multi-GT systems where the GTs share the GGTT,
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ struct uc_css_header {
#define CSS_SW_VERSION_UC_MAJOR (0xFF << 16)
#define CSS_SW_VERSION_UC_MINOR (0xFF << 8)
#define CSS_SW_VERSION_UC_PATCH (0xFF << 0)
u32 reserved0[13];
u32 vf_version;
u32 reserved0[12];
union {
u32 private_data_size; /* only applies to GuC */
u32 reserved1;
Expand Down

0 comments on commit 9bbba06

Please sign in to comment.