Commit 2e7227b4 authored by Daniele Ceraolo Spurio's avatar Daniele Ceraolo Spurio Committed by Rodrigo Vivi

drm/xe/uc: Rework uC version tracking

The GSC firmware, support for which is coming soon for Xe, has both a
release version (updated on every release) and a compatibility version
(update only on interface changes). The GuC has something similar, with
a global release version and a submission version (which is also known
as the VF compatibility version). The main difference is that for the
GuC we still want to check the driver requirement against the release
version, while for the GSC we'll need to check against the compatibility
version.
Instead of special casing the GSC, this patch reworks the FW logic so
that we store both versions at the uc_fw level for all binaries and we
allow checking against either of the versions. Initially, we'll use it
to support GSC, but the logic could be re-used to allow VFs to check
against the GuC compatibility version.
Note that the GSC version has 4 numbers (major, minor, hotfix, build),
so support for that has been added as part of the rework and will be
used in follow-up patches.
Signed-off-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: John Harrison <John.C.Harrison@Intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Reviewed-by: default avatarJohn Harrison <John.C.Harrison@Intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent adce1b39
...@@ -52,15 +52,6 @@ struct xe_guc { ...@@ -52,15 +52,6 @@ struct xe_guc {
/** @seqno: suspend fences seqno */ /** @seqno: suspend fences seqno */
u32 seqno; u32 seqno;
} suspend; } suspend;
/** @version: submission version */
struct {
/** @major: major version of GuC submission */
u32 major;
/** @minor: minor version of GuC submission */
u32 minor;
/** @patch: patch version of GuC submission */
u32 patch;
} version;
#ifdef CONFIG_PROVE_LOCKING #ifdef CONFIG_PROVE_LOCKING
#define NUM_SUBMIT_WQ 256 #define NUM_SUBMIT_WQ 256
/** @submit_wq_pool: submission ordered workqueues pool */ /** @submit_wq_pool: submission ordered workqueues pool */
......
...@@ -204,9 +204,12 @@ uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw) ...@@ -204,9 +204,12 @@ uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw)
for (i = 0; i < count && p <= entries[i].platform; i++) { for (i = 0; i < count && p <= entries[i].platform; i++) {
if (p == entries[i].platform) { if (p == entries[i].platform) {
uc_fw->path = entries[i].path; uc_fw->path = entries[i].path;
uc_fw->major_ver_wanted = entries[i].major; uc_fw->versions.wanted.major = entries[i].major;
uc_fw->minor_ver_wanted = entries[i].minor; uc_fw->versions.wanted.minor = entries[i].minor;
uc_fw->full_ver_required = entries[i].full_ver_required; uc_fw->full_ver_required = entries[i].full_ver_required;
/* compatibility version checking coming soon */
uc_fw->versions.wanted_type = XE_UC_FW_VER_RELEASE;
break; break;
} }
} }
...@@ -273,32 +276,30 @@ static void uc_fw_fini(struct drm_device *drm, void *arg) ...@@ -273,32 +276,30 @@ static void uc_fw_fini(struct drm_device *drm, void *arg)
static void guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css) static void guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css)
{ {
struct xe_gt *gt = uc_fw_to_gt(uc_fw); struct xe_gt *gt = uc_fw_to_gt(uc_fw);
struct xe_guc *guc = &gt->uc.guc; struct xe_uc_fw_version *release = &uc_fw->versions.found[XE_UC_FW_VER_RELEASE];
struct xe_uc_fw_version *compatibility = &uc_fw->versions.found[XE_UC_FW_VER_COMPATIBILITY];
xe_gt_assert(gt, uc_fw->type == XE_UC_FW_TYPE_GUC); xe_gt_assert(gt, uc_fw->type == XE_UC_FW_TYPE_GUC);
xe_gt_assert(gt, uc_fw->major_ver_found >= 70); xe_gt_assert(gt, release->major >= 70);
if (uc_fw->major_ver_found > 70 || uc_fw->minor_ver_found >= 6) { if (release->major > 70 || release->minor >= 6) {
/* v70.6.0 adds CSS header support */ /* v70.6.0 adds CSS header support */
guc->submission_state.version.major = compatibility->major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
css->submission_version); css->submission_version);
guc->submission_state.version.minor = compatibility->minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
FIELD_GET(CSS_SW_VERSION_UC_MINOR,
css->submission_version); css->submission_version);
guc->submission_state.version.patch = compatibility->patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH,
FIELD_GET(CSS_SW_VERSION_UC_PATCH,
css->submission_version); css->submission_version);
} else if (uc_fw->minor_ver_found >= 3) { } else if (release->minor >= 3) {
/* v70.3.0 introduced v1.1.0 */ /* v70.3.0 introduced v1.1.0 */
guc->submission_state.version.major = 1; compatibility->major = 1;
guc->submission_state.version.minor = 1; compatibility->minor = 1;
guc->submission_state.version.patch = 0; compatibility->patch = 0;
} else { } else {
/* v70.0.0 introduced v1.0.0 */ /* v70.0.0 introduced v1.0.0 */
guc->submission_state.version.major = 1; compatibility->major = 1;
guc->submission_state.version.minor = 0; compatibility->minor = 0;
guc->submission_state.version.patch = 0; compatibility->patch = 0;
} }
uc_fw->private_data_size = css->private_data_size; uc_fw->private_data_size = css->private_data_size;
...@@ -307,30 +308,31 @@ static void guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css) ...@@ -307,30 +308,31 @@ static void guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css)
static int uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw) static int uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw)
{ {
struct xe_device *xe = uc_fw_to_xe(uc_fw); struct xe_device *xe = uc_fw_to_xe(uc_fw);
struct xe_uc_fw_version *wanted = &uc_fw->versions.wanted;
struct xe_uc_fw_version *found = &uc_fw->versions.found[uc_fw->versions.wanted_type];
/* Driver has no requirement on any version, any is good. */ /* Driver has no requirement on any version, any is good. */
if (!uc_fw->major_ver_wanted) if (!wanted->major)
return 0; return 0;
/* /*
* If full version is required, both major and minor should match. * If full version is required, both major and minor should match.
* Otherwise, at least the major version. * Otherwise, at least the major version.
*/ */
if (uc_fw->major_ver_wanted != uc_fw->major_ver_found || if (wanted->major != found->major ||
(uc_fw->full_ver_required && (uc_fw->full_ver_required && wanted->minor != found->minor)) {
uc_fw->minor_ver_wanted != uc_fw->minor_ver_found)) {
drm_notice(&xe->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n", drm_notice(&xe->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, xe_uc_fw_type_repr(uc_fw->type), uc_fw->path,
uc_fw->major_ver_found, uc_fw->minor_ver_found, found->major, found->minor,
uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted); wanted->major, wanted->minor);
goto fail; goto fail;
} }
if (uc_fw->minor_ver_wanted > uc_fw->minor_ver_found) { if (wanted->minor > found->minor) {
drm_notice(&xe->drm, "%s firmware (%u.%u) is recommended, but only (%u.%u) was found in %s\n", drm_notice(&xe->drm, "%s firmware (%u.%u) is recommended, but only (%u.%u) was found in %s\n",
xe_uc_fw_type_repr(uc_fw->type), xe_uc_fw_type_repr(uc_fw->type),
uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted, wanted->major, wanted->minor,
uc_fw->major_ver_found, uc_fw->minor_ver_found, found->major, found->minor,
uc_fw->path); uc_fw->path);
drm_info(&xe->drm, "Consider updating your linux-firmware pkg or downloading from %s\n", drm_info(&xe->drm, "Consider updating your linux-firmware pkg or downloading from %s\n",
XE_UC_FIRMWARE_URL); XE_UC_FIRMWARE_URL);
...@@ -349,6 +351,7 @@ static int uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw) ...@@ -349,6 +351,7 @@ static int uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw)
static int parse_css_header(struct xe_uc_fw *uc_fw, const void *fw_data, size_t fw_size) static int parse_css_header(struct xe_uc_fw *uc_fw, const void *fw_data, size_t fw_size)
{ {
struct xe_device *xe = uc_fw_to_xe(uc_fw); struct xe_device *xe = uc_fw_to_xe(uc_fw);
struct xe_uc_fw_version *release = &uc_fw->versions.found[XE_UC_FW_VER_RELEASE];
struct uc_css_header *css; struct uc_css_header *css;
size_t size; size_t size;
...@@ -390,12 +393,9 @@ static int parse_css_header(struct xe_uc_fw *uc_fw, const void *fw_data, size_t ...@@ -390,12 +393,9 @@ static int parse_css_header(struct xe_uc_fw *uc_fw, const void *fw_data, size_t
} }
/* Get version numbers from the CSS header */ /* Get version numbers from the CSS header */
uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, release->major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, css->sw_version);
css->sw_version); release->minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR, css->sw_version);
uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR, release->patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH, css->sw_version);
css->sw_version);
uc_fw->patch_ver_found = FIELD_GET(CSS_SW_VERSION_UC_PATCH,
css->sw_version);
if (uc_fw->type == XE_UC_FW_TYPE_GUC) if (uc_fw->type == XE_UC_FW_TYPE_GUC)
guc_read_css_info(uc_fw, css); guc_read_css_info(uc_fw, css);
...@@ -431,6 +431,7 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz ...@@ -431,6 +431,7 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz
struct xe_gt *gt = uc_fw_to_gt(uc_fw); struct xe_gt *gt = uc_fw_to_gt(uc_fw);
struct xe_device *xe = gt_to_xe(gt); struct xe_device *xe = gt_to_xe(gt);
const struct gsc_cpd_header_v2 *header = data; const struct gsc_cpd_header_v2 *header = data;
struct xe_uc_fw_version *release = &uc_fw->versions.found[XE_UC_FW_VER_RELEASE];
const struct gsc_manifest_header *manifest; const struct gsc_manifest_header *manifest;
size_t min_size = sizeof(*header); size_t min_size = sizeof(*header);
u32 offset; u32 offset;
...@@ -468,9 +469,9 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz ...@@ -468,9 +469,9 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz
manifest = data + offset; manifest = data + offset;
uc_fw->major_ver_found = manifest->fw_version.major; release->major = manifest->fw_version.major;
uc_fw->minor_ver_found = manifest->fw_version.minor; release->minor = manifest->fw_version.minor;
uc_fw->patch_ver_found = manifest->fw_version.hotfix; release->patch = manifest->fw_version.hotfix;
/* then optionally look for the css header */ /* then optionally look for the css header */
if (css_entry) { if (css_entry) {
...@@ -524,12 +525,25 @@ static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw) ...@@ -524,12 +525,25 @@ static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw)
return 0; return 0;
} }
#define print_uc_fw_version(p_, version_, prefix_, ...) \
do { \
struct xe_uc_fw_version *ver_ = (version_); \
if (ver_->build) \
drm_printf(p_, prefix_ " version %u.%u.%u.%u\n", ##__VA_ARGS__, \
ver_->major, ver_->minor, \
ver_->patch, ver_->build); \
else \
drm_printf(p_, prefix_ " version %u.%u.%u\n", ##__VA_ARGS__, \
ver_->major, ver_->minor, ver_->patch); \
} while (0)
int xe_uc_fw_init(struct xe_uc_fw *uc_fw) int xe_uc_fw_init(struct xe_uc_fw *uc_fw)
{ {
struct xe_device *xe = uc_fw_to_xe(uc_fw); struct xe_device *xe = uc_fw_to_xe(uc_fw);
struct xe_gt *gt = uc_fw_to_gt(uc_fw); struct xe_gt *gt = uc_fw_to_gt(uc_fw);
struct xe_tile *tile = gt_to_tile(gt); struct xe_tile *tile = gt_to_tile(gt);
struct device *dev = xe->drm.dev; struct device *dev = xe->drm.dev;
struct drm_printer p = drm_info_printer(dev);
const struct firmware *fw = NULL; const struct firmware *fw = NULL;
struct xe_bo *obj; struct xe_bo *obj;
int err; int err;
...@@ -567,9 +581,10 @@ int xe_uc_fw_init(struct xe_uc_fw *uc_fw) ...@@ -567,9 +581,10 @@ int xe_uc_fw_init(struct xe_uc_fw *uc_fw)
if (err) if (err)
goto fail; goto fail;
drm_info(&xe->drm, "Using %s firmware from %s version %u.%u.%u\n", print_uc_fw_version(&p,
xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, &uc_fw->versions.found[XE_UC_FW_VER_RELEASE],
uc_fw->major_ver_found, uc_fw->minor_ver_found, uc_fw->patch_ver_found); "Using %s firmware from %s",
xe_uc_fw_type_repr(uc_fw->type), uc_fw->path);
err = uc_fw_check_version_requirements(uc_fw); err = uc_fw_check_version_requirements(uc_fw);
if (err) if (err)
...@@ -686,26 +701,40 @@ int xe_uc_fw_upload(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) ...@@ -686,26 +701,40 @@ int xe_uc_fw_upload(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags)
return err; return err;
} }
static const char *version_type_repr(enum xe_uc_fw_version_types type)
{
switch (type) {
case XE_UC_FW_VER_RELEASE:
return "release";
case XE_UC_FW_VER_COMPATIBILITY:
return "compatibility";
default:
return "Unknown version type";
}
}
void xe_uc_fw_print(struct xe_uc_fw *uc_fw, struct drm_printer *p) void xe_uc_fw_print(struct xe_uc_fw *uc_fw, struct drm_printer *p)
{ {
int i;
drm_printf(p, "%s firmware: %s\n", drm_printf(p, "%s firmware: %s\n",
xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); xe_uc_fw_type_repr(uc_fw->type), uc_fw->path);
drm_printf(p, "\tstatus: %s\n", drm_printf(p, "\tstatus: %s\n",
xe_uc_fw_status_repr(uc_fw->status)); xe_uc_fw_status_repr(uc_fw->status));
drm_printf(p, "\tversion: wanted %u.%u, found %u.%u.%u\n",
uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
uc_fw->major_ver_found, uc_fw->minor_ver_found, uc_fw->patch_ver_found);
drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
if (uc_fw->type == XE_UC_FW_TYPE_GUC) { print_uc_fw_version(p, &uc_fw->versions.wanted, "\twanted %s",
struct xe_gt *gt = uc_fw_to_gt(uc_fw); version_type_repr(uc_fw->versions.wanted_type));
struct xe_guc *guc = &gt->uc.guc;
drm_printf(p, "\tSubmit version: %u.%u.%u\n", for (i = 0; i < XE_UC_FW_VER_TYPE_COUNT; i++) {
guc->submission_state.version.major, struct xe_uc_fw_version *ver = &uc_fw->versions.found[i];
guc->submission_state.version.minor,
guc->submission_state.version.patch); if (ver->major)
print_uc_fw_version(p, ver, "\tfound %s",
version_type_repr(i));
} }
if (uc_fw->ucode_size)
drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
if (uc_fw->rsa_size)
drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
} }
...@@ -59,6 +59,26 @@ enum xe_uc_fw_type { ...@@ -59,6 +59,26 @@ enum xe_uc_fw_type {
}; };
#define XE_UC_FW_NUM_TYPES 2 #define XE_UC_FW_NUM_TYPES 2
/**
* struct xe_uc_fw_version - Version for XE micro controller firmware
*/
struct xe_uc_fw_version {
/** @major: major version of the FW */
u16 major;
/** @minor: minor version of the FW */
u16 minor;
/** @patch: patch version of the FW */
u16 patch;
/** @build: build version of the FW (not always available) */
u16 build;
};
enum xe_uc_fw_version_types {
XE_UC_FW_VER_RELEASE,
XE_UC_FW_VER_COMPATIBILITY,
XE_UC_FW_VER_TYPE_COUNT
};
/** /**
* struct xe_uc_fw - XE micro controller firmware * struct xe_uc_fw - XE micro controller firmware
*/ */
...@@ -98,16 +118,15 @@ struct xe_uc_fw { ...@@ -98,16 +118,15 @@ struct xe_uc_fw {
* version required per platform. * version required per platform.
*/ */
/** @major_ver_wanted: major firmware version wanted by platform */ /** @versions: FW versions wanted and found */
u16 major_ver_wanted; struct {
/** @minor_ver_wanted: minor firmware version wanted by platform */ /** @wanted: firmware version wanted by platform */
u16 minor_ver_wanted; struct xe_uc_fw_version wanted;
/** @major_ver_found: major version found in firmware blob */ /** @wanted_type: type of firmware version wanted (release vs compatibility) */
u16 major_ver_found; enum xe_uc_fw_version_types wanted_type;
/** @minor_ver_found: major version found in firmware blob */ /** @found: fw versions found in firmware blob */
u16 minor_ver_found; struct xe_uc_fw_version found[XE_UC_FW_VER_TYPE_COUNT];
/** @patch_ver_found: patch version found in firmware blob */ } versions;
u16 patch_ver_found;
/** @rsa_size: RSA size */ /** @rsa_size: RSA size */
u32 rsa_size; u32 rsa_size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment