Reviewed-by: Alan Previn <alan.previn.teres.alexis@xxxxxxxxx> On Tue, 2022-04-26 at 17:26 -0700, Daniele Ceraolo Spurio wrote: > HuC loading via GSC is performed via a PXP command sent through the mei > modules, so we need both MEI_GSC and MEI_PXP to be available. Given that > the GSC will do both the transfer and the authentication, the legacy HuC > loading paths can be safely skipped. > Also note that the GSC-loaded HuC survives GT reset. > > Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@xxxxxxxxx> > --- > drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h | 1 + > drivers/gpu/drm/i915/gt/uc/intel_huc.c | 76 +++++++++++++++++++--- > drivers/gpu/drm/i915/gt/uc/intel_huc.h | 6 ++ > drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c | 5 +- > drivers/gpu/drm/i915/gt/uc/intel_uc.c | 11 +++- > 5 files changed, 88 insertions(+), 11 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h > index 66027a42cda9e..2516705b9f365 100644 > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_reg.h > @@ -96,6 +96,7 @@ > > #define GUC_SHIM_CONTROL2 _MMIO(0xc068) > #define GUC_IS_PRIVILEGED (1<<29) > +#define GSC_LOADS_HUC (1<<30) > > #define GUC_SEND_INTERRUPT _MMIO(0xc4c8) > #define GUC_SEND_TRIGGER (1<<0) > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c > index 773020e69589a..76a7df7f136fc 100644 > --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c > +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c > @@ -6,6 +6,7 @@ > #include <linux/types.h> > > #include "gt/intel_gt.h" > +#include "intel_guc_reg.h" > #include "intel_huc.h" > #include "i915_drv.h" > > @@ -17,11 +18,15 @@ > * capabilities by adding HuC specific commands to batch buffers. > * > * The kernel driver is only responsible for loading the HuC firmware and > - * triggering its security authentication, which is performed by the GuC. For > - * The GuC to correctly perform the authentication, the HuC binary must be > - * loaded before the GuC one. Loading the HuC is optional; however, not using > - * the HuC might negatively impact power usage and/or performance of media > - * workloads, depending on the use-cases. > + * triggering its security authentication, which is performed by the GuC on > + * older platforms and by the GSC on newer ones. For the GuC to correctly > + * perform the authentication, the HuC binary must be loaded before the GuC one. > + * Loading the HuC is optional; however, not using the HuC might negatively > + * impact power usage and/or performance of media workloads, depending on the > + * use-cases. > + * HuC must be reloaded on events that cause the WOPCM to lose its contents > + * (S3/S4, FLR); GuC-authenticated HuC must also be reloaded on GuC/GT reset, > + * while GSC-managed HuC will survive that. > * > * See https://github.com/intel/media-driver for the latest details on HuC > * functionality. > @@ -54,11 +59,51 @@ void intel_huc_init_early(struct intel_huc *huc) > } > } > > +#define HUC_LOAD_MODE_STRING(x) (x ? "GSC" : "legacy") > +static int check_huc_loading_mode(struct intel_huc *huc) > +{ > + struct intel_gt *gt = huc_to_gt(huc); > + bool fw_needs_gsc = intel_huc_is_loaded_by_gsc(huc); > + bool hw_uses_gsc = false; > + > + /* > + * The fuse for HuC load via GSC is only valid on platforms that have > + * GuC deprivilege. > + */ > + if (HAS_GUC_DEPRIVILEGE(gt->i915)) > + hw_uses_gsc = intel_uncore_read(gt->uncore, GUC_SHIM_CONTROL2) & > + GSC_LOADS_HUC; > + > + if (fw_needs_gsc != hw_uses_gsc) { > + drm_err(>->i915->drm, > + "mismatch between HuC FW (%s) and HW (%s) load modes\n", > + HUC_LOAD_MODE_STRING(fw_needs_gsc), > + HUC_LOAD_MODE_STRING(hw_uses_gsc)); > + return -ENOEXEC; > + } > + > + /* make sure we can access the GSC via the mei driver if we need it */ > + if (!(IS_ENABLED(CONFIG_INTEL_MEI_PXP) && IS_ENABLED(CONFIG_INTEL_MEI_GSC)) && > + fw_needs_gsc) { > + drm_info(>->i915->drm, > + "Can't load HuC due to missing MEI modules\n"); > + return -EIO; > + } > + > + drm_dbg(>->i915->drm, "GSC loads huc=%s\n", str_yes_no(fw_needs_gsc)); > + > + return 0; > +} > + > int intel_huc_init(struct intel_huc *huc) > { > struct drm_i915_private *i915 = huc_to_gt(huc)->i915; > int err; > > + err = check_huc_loading_mode(huc); > + if (err) > + goto out; > + > err = intel_uc_fw_init(&huc->fw); > if (err) > goto out; > @@ -108,17 +153,20 @@ int intel_huc_auth(struct intel_huc *huc) > struct intel_guc *guc = >->uc.guc; > int ret; > > - GEM_BUG_ON(huc_is_authenticated(huc)); > - > if (!intel_uc_fw_is_loaded(&huc->fw)) > return -ENOEXEC; > > + /* GSC will do the auth */ > + if (intel_huc_is_loaded_by_gsc(huc)) > + return -ENODEV; > + > ret = i915_inject_probe_error(gt->i915, -ENXIO); > if (ret) > goto fail; > > - ret = intel_guc_auth_huc(guc, > - intel_guc_ggtt_offset(guc, huc->fw.rsa_data)); > + GEM_BUG_ON(huc_is_authenticated(huc)); > + > + ret = intel_guc_auth_huc(guc, intel_guc_ggtt_offset(guc, huc->fw.rsa_data)); > if (ret) { > DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret); > goto fail; > @@ -178,6 +226,16 @@ int intel_huc_check_status(struct intel_huc *huc) > return huc_is_authenticated(huc); > } > > +void intel_huc_update_auth_status(struct intel_huc *huc) > +{ > + if (!intel_uc_fw_is_loadable(&huc->fw)) > + return; > + > + if (huc_is_authenticated(huc)) > + intel_uc_fw_change_status(&huc->fw, > + INTEL_UC_FIRMWARE_RUNNING); > +} > + > /** > * intel_huc_load_status - dump information about HuC load status > * @huc: the HuC > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h > index 77d813840d76c..d7e25b6e879eb 100644 > --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h > +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h > @@ -27,6 +27,7 @@ int intel_huc_init(struct intel_huc *huc); > void intel_huc_fini(struct intel_huc *huc); > int intel_huc_auth(struct intel_huc *huc); > int intel_huc_check_status(struct intel_huc *huc); > +void intel_huc_update_auth_status(struct intel_huc *huc); > > static inline int intel_huc_sanitize(struct intel_huc *huc) > { > @@ -50,6 +51,11 @@ static inline bool intel_huc_is_used(struct intel_huc *huc) > return intel_uc_fw_is_available(&huc->fw); > } > > +static inline bool intel_huc_is_loaded_by_gsc(const struct intel_huc *huc) > +{ > + return huc->fw.loaded_via_gsc; > +} > + > void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p); > > #endif > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c > index e5ef509c70e89..9d6ab1e016395 100644 > --- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c > +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c > @@ -8,7 +8,7 @@ > #include "i915_drv.h" > > /** > - * intel_huc_fw_upload() - load HuC uCode to device > + * intel_huc_fw_upload() - load HuC uCode to device via DMA transfer > * @huc: intel_huc structure > * > * Called from intel_uc_init_hw() during driver load, resume from sleep and > @@ -21,6 +21,9 @@ > */ > int intel_huc_fw_upload(struct intel_huc *huc) > { > + if (intel_huc_is_loaded_by_gsc(huc)) > + return -ENODEV; > + > /* HW doesn't look at destination address for HuC, so set it to 0 */ > return intel_uc_fw_upload(&huc->fw, 0, HUC_UKERNEL); > } > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c > index 8c9ef690ac9d8..0dce94f896a8c 100644 > --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c > +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c > @@ -509,7 +509,16 @@ static int __uc_init_hw(struct intel_uc *uc) > if (ret) > goto err_log_capture; > > - intel_huc_auth(huc); > + /* > + * GSC-loaded HuC is authenticated by the GSC, so we don't need to > + * trigger the auth here. However, given that the HuC loaded this way > + * survive GT reset, we still need to update our SW bookkeeping to make > + * sure it reflects the correct HW status. > + */ > + if (intel_huc_is_loaded_by_gsc(huc)) > + intel_huc_update_auth_status(huc); > + else > + intel_huc_auth(huc); > > if (intel_uc_uses_guc_submission(uc)) > intel_guc_submission_enable(guc);