// SPDX-License-Identifier: MIT /* * Copyright © 2016-2019 Intel Corporation */ #include <linux/types.h> #include "gt/intel_gt.h" #include "gt/intel_rps.h" #include "intel_guc_reg.h" #include "intel_huc.h" #include "intel_huc_print.h" #include "i915_drv.h" #include "i915_reg.h" #include "pxp/intel_pxp_cmd_interface_43.h" #include <linux/device/bus.h> #include <linux/mei_aux.h> /** * DOC: HuC * * The HuC is a dedicated microcontroller for usage in media HEVC (High * Efficiency Video Coding) operations. Userspace can directly use the firmware * 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. This is done differently depending * on the platform: * * - older platforms (from Gen9 to most Gen12s): the load is performed via DMA * and the authentication via GuC * - DG2: load and authentication are both performed via GSC. * - MTL and newer platforms: the load is performed via DMA (same as with * not-DG2 older platforms), while the authentication is done in 2-steps, * a first auth for clear-media workloads via GuC and a second one for all * workloads via GSC. * * On platforms where the GuC does the authentication, to correctly do so 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); on older platforms the HuC must also be reloaded on GuC/GT * reset, while on newer ones it will survive that. * * See https://github.com/intel/media-driver for the latest details on HuC * functionality. */ /** * DOC: HuC Memory Management * * Similarly to the GuC, the HuC can't do any memory allocations on its own, * with the difference being that the allocations for HuC usage are handled by * the userspace driver instead of the kernel one. The HuC accesses the memory * via the PPGTT belonging to the context loaded on the VCS executing the * HuC-specific commands. */ /* * MEI-GSC load is an async process. The probing of the exposed aux device * (see intel_gsc.c) usually happens a few seconds after i915 probe, depending * on when the kernel schedules it. Unless something goes terribly wrong, we're * guaranteed for this to happen during boot, so the big timeout is a safety net * that we never expect to need. * MEI-PXP + HuC load usually takes ~300ms, but if the GSC needs to be resumed * and/or reset, this can take longer. Note that the kernel might schedule * other work between the i915 init/resume and the MEI one, which can add to * the delay. */ #define GSC_INIT_TIMEOUT_MS … #define PXP_INIT_TIMEOUT_MS … static int sw_fence_dummy_notify(struct i915_sw_fence *sf, enum i915_sw_fence_notify state) { … } static void __delayed_huc_load_complete(struct intel_huc *huc) { … } static void delayed_huc_load_complete(struct intel_huc *huc) { … } static void __gsc_init_error(struct intel_huc *huc) { … } static void gsc_init_error(struct intel_huc *huc) { … } static void gsc_init_done(struct intel_huc *huc) { … } static enum hrtimer_restart huc_delayed_load_timer_callback(struct hrtimer *hrtimer) { … } static void huc_delayed_load_start(struct intel_huc *huc) { … } static int gsc_notifier(struct notifier_block *nb, unsigned long action, void *data) { … } void intel_huc_register_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus) { … } void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus) { … } static void delayed_huc_load_init(struct intel_huc *huc) { … } static void delayed_huc_load_fini(struct intel_huc *huc) { … } int intel_huc_sanitize(struct intel_huc *huc) { … } static bool vcs_supported(struct intel_gt *gt) { … } void intel_huc_init_early(struct intel_huc *huc) { … } #define HUC_LOAD_MODE_STRING(x) … static int check_huc_loading_mode(struct intel_huc *huc) { … } int intel_huc_init(struct intel_huc *huc) { … } void intel_huc_fini(struct intel_huc *huc) { … } void intel_huc_suspend(struct intel_huc *huc) { … } static const char *auth_mode_string(struct intel_huc *huc, enum intel_huc_authentication_type type) { … } /* * Use a longer timeout for debug builds so that problems can be detected * and analysed. But a shorter timeout for releases so that user's don't * wait forever to find out there is a problem. Note that the only reason * an end user should hit the timeout is in case of extreme thermal throttling. * And a system that is that hot during boot is probably dead anyway! */ #if defined(CONFIG_DRM_I915_DEBUG_GEM) #define HUC_LOAD_RETRY_LIMIT … #else #define HUC_LOAD_RETRY_LIMIT … #endif int intel_huc_wait_for_auth_complete(struct intel_huc *huc, enum intel_huc_authentication_type type) { … } /** * intel_huc_auth() - Authenticate HuC uCode * @huc: intel_huc structure * @type: authentication type (via GuC or via GSC) * * Called after HuC and GuC firmware loading during intel_uc_init_hw(). * * This function invokes the GuC action to authenticate the HuC firmware, * passing the offset of the RSA signature to intel_guc_auth_huc(). It then * waits for up to 50ms for firmware verification ACK. */ int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type type) { … } bool intel_huc_is_authenticated(struct intel_huc *huc, enum intel_huc_authentication_type type) { … } static bool huc_is_fully_authenticated(struct intel_huc *huc) { … } /** * intel_huc_check_status() - check HuC status * @huc: intel_huc structure * * This function reads status register to verify if HuC * firmware was successfully loaded. * * The return values match what is expected for the I915_PARAM_HUC_STATUS * getparam. */ int intel_huc_check_status(struct intel_huc *huc) { … } static bool huc_has_delayed_load(struct intel_huc *huc) { … } void intel_huc_update_auth_status(struct intel_huc *huc) { … } /** * intel_huc_load_status - dump information about HuC load status * @huc: the HuC * @p: the &drm_printer * * Pretty printer for HuC load status. */ void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p) { … }