drm/i915/mtl/huc: auth HuC via GSC
authorDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Wed, 31 May 2023 23:54:13 +0000 (16:54 -0700)
committerDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Mon, 5 Jun 2023 16:53:51 +0000 (09:53 -0700)
The full authentication via the GSC requires an heci packet submission
to the GSC FW via the GSC CS. The GSC has new PXP command for this
(literally called NEW_HUC_AUTH).
The intel_huc_auth function is also updated to handle both authentication
types.

v2: check that the GuC auth for clear media has completed before
    proceding with the full auth

v3: use a define for the object size (Alan)

Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Alan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: Alan Previn <alan.previn.teres.alexis@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230531235415.1467475-6-daniele.ceraolospurio@intel.com
drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c
drivers/gpu/drm/i915/gt/uc/intel_huc.c
drivers/gpu/drm/i915/gt/uc/intel_huc.h
drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
drivers/gpu/drm/i915/gt/uc/intel_uc.c
drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h
drivers/gpu/drm/i915/pxp/intel_pxp_huc.c

index b26f493..c659cc0 100644 (file)
@@ -29,13 +29,32 @@ static void gsc_work(struct work_struct *work)
 
        if (actions & GSC_ACTION_FW_LOAD) {
                ret = intel_gsc_uc_fw_upload(gsc);
-               if (ret == -EEXIST) /* skip proxy if not a new load */
-                       actions &= ~GSC_ACTION_FW_LOAD;
-               else if (ret)
+               if (!ret)
+                       /* setup proxy on a new load */
+                       actions |= GSC_ACTION_SW_PROXY;
+               else if (ret != -EEXIST)
                        goto out_put;
+
+               /*
+                * The HuC auth can be done both before or after the proxy init;
+                * if done after, a proxy request will be issued and must be
+                * serviced before the authentication can complete.
+                * Since this worker also handles proxy requests, we can't
+                * perform an action that requires the proxy from within it and
+                * then stall waiting for it, because we'd be blocking the
+                * service path. Therefore, it is easier for us to load HuC
+                * first and do proxy later. The GSC will ack the HuC auth and
+                * then send the HuC proxy request as part of the proxy init
+                * flow.
+                * Note that we can only do the GSC auth if the GuC auth was
+                * successful.
+                */
+               if (intel_uc_uses_huc(&gt->uc) &&
+                   intel_huc_is_authenticated(&gt->uc.huc, INTEL_HUC_AUTH_BY_GUC))
+                       intel_huc_auth(&gt->uc.huc, INTEL_HUC_AUTH_BY_GSC);
        }
 
-       if (actions & (GSC_ACTION_FW_LOAD | GSC_ACTION_SW_PROXY)) {
+       if (actions & GSC_ACTION_SW_PROXY) {
                if (!intel_gsc_uc_fw_init_done(gsc)) {
                        gt_err(gt, "Proxy request received with GSC not loaded!\n");
                        goto out_put;
index 579c0f5..0ad0903 100644 (file)
@@ -99,7 +99,7 @@ void intel_gsc_uc_heci_cmd_emit_mtl_header(struct intel_gsc_mtl_header *header,
                                           u64 host_session_id)
 {
        host_session_id &= ~HOST_SESSION_MASK;
-       if (heci_client_id == HECI_MEADDRESS_PXP)
+       if (host_session_id && heci_client_id == HECI_MEADDRESS_PXP)
                host_session_id |= HOST_SESSION_PXP_SINGLE;
 
        header->validity_marker = GSC_HECI_VALIDITY_MARKER;
index 4c8592a..e0afd8f 100644 (file)
@@ -11,6 +11,7 @@
 #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>
@@ -371,20 +372,36 @@ static int check_huc_loading_mode(struct intel_huc *huc)
 
 int intel_huc_init(struct intel_huc *huc)
 {
+       struct intel_gt *gt = huc_to_gt(huc);
        int err;
 
        err = check_huc_loading_mode(huc);
        if (err)
                goto out;
 
+       if (HAS_ENGINE(gt, GSC0)) {
+               struct i915_vma *vma;
+
+               vma = intel_guc_allocate_vma(&gt->uc.guc, PXP43_HUC_AUTH_INOUT_SIZE * 2);
+               if (IS_ERR(vma)) {
+                       huc_info(huc, "Failed to allocate heci pkt\n");
+                       goto out;
+               }
+
+               huc->heci_pkt = vma;
+       }
+
        err = intel_uc_fw_init(&huc->fw);
        if (err)
-               goto out;
+               goto out_pkt;
 
        intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOADABLE);
 
        return 0;
 
+out_pkt:
+       if (huc->heci_pkt)
+               i915_vma_unpin_and_release(&huc->heci_pkt, 0);
 out:
        intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_INIT_FAIL);
        huc_info(huc, "initialization failed %pe\n", ERR_PTR(err));
@@ -399,6 +416,9 @@ void intel_huc_fini(struct intel_huc *huc)
         */
        delayed_huc_load_fini(huc);
 
+       if (huc->heci_pkt)
+               i915_vma_unpin_and_release(&huc->heci_pkt, 0);
+
        if (intel_uc_fw_is_loadable(&huc->fw))
                intel_uc_fw_fini(&huc->fw);
 }
@@ -454,6 +474,7 @@ int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
 /**
  * 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().
  *
@@ -461,7 +482,7 @@ int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
  * 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)
+int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type type)
 {
        struct intel_gt *gt = huc_to_gt(huc);
        struct intel_guc *guc = &gt->uc.guc;
@@ -470,31 +491,41 @@ int intel_huc_auth(struct intel_huc *huc)
        if (!intel_uc_fw_is_loaded(&huc->fw))
                return -ENOEXEC;
 
-       /* GSC will do the auth */
+       /* GSC will do the auth with the load */
        if (intel_huc_is_loaded_by_gsc(huc))
                return -ENODEV;
 
+       if (intel_huc_is_authenticated(huc, type))
+               return -EEXIST;
+
        ret = i915_inject_probe_error(gt->i915, -ENXIO);
        if (ret)
                goto fail;
 
-       GEM_BUG_ON(intel_uc_fw_is_running(&huc->fw));
-
-       ret = intel_guc_auth_huc(guc, intel_guc_ggtt_offset(guc, huc->fw.rsa_data));
-       if (ret) {
-               huc_err(huc, "authentication by GuC failed %pe\n", ERR_PTR(ret));
-               goto fail;
+       switch (type) {
+       case INTEL_HUC_AUTH_BY_GUC:
+               ret = intel_guc_auth_huc(guc, intel_guc_ggtt_offset(guc, huc->fw.rsa_data));
+               break;
+       case INTEL_HUC_AUTH_BY_GSC:
+               ret = intel_huc_fw_auth_via_gsccs(huc);
+               break;
+       default:
+               MISSING_CASE(type);
+               ret = -EINVAL;
        }
+       if (ret)
+               goto fail;
 
        /* Check authentication status, it should be done by now */
-       ret = intel_huc_wait_for_auth_complete(huc, INTEL_HUC_AUTH_BY_GUC);
+       ret = intel_huc_wait_for_auth_complete(huc, type);
        if (ret)
                goto fail;
 
        return 0;
 
 fail:
-       huc_probe_error(huc, "authentication failed %pe\n", ERR_PTR(ret));
+       huc_probe_error(huc, "%s authentication failed %pe\n",
+                       auth_mode_string(huc, type), ERR_PTR(ret));
        return ret;
 }
 
index 3f6aa7c..ba5cb08 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/hrtimer.h>
 
 struct bus_type;
+struct i915_vma;
 
 enum intel_huc_delayed_load_status {
        INTEL_HUC_WAITING_ON_GSC = 0,
@@ -46,6 +47,9 @@ struct intel_huc {
                enum intel_huc_delayed_load_status status;
        } delayed_load;
 
+       /* for load via GSCCS */
+       struct i915_vma *heci_pkt;
+
        bool loaded_via_gsc;
 };
 
@@ -54,7 +58,7 @@ void intel_huc_init_early(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);
-int intel_huc_auth(struct intel_huc *huc);
+int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type type);
 int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
                                     enum intel_huc_authentication_type type);
 bool intel_huc_is_authenticated(struct intel_huc *huc,
index ac2ae5f..e608152 100644 (file)
 #include "gt/intel_gsc.h"
 #include "gt/intel_gt.h"
 #include "intel_gsc_binary_headers.h"
+#include "intel_gsc_uc_heci_cmd_submit.h"
 #include "intel_huc.h"
 #include "intel_huc_fw.h"
 #include "intel_huc_print.h"
 #include "i915_drv.h"
 #include "pxp/intel_pxp_huc.h"
+#include "pxp/intel_pxp_cmd_interface_43.h"
+
+struct mtl_huc_auth_msg_in {
+       struct intel_gsc_mtl_header header;
+       struct pxp43_new_huc_auth_in huc_in;
+} __packed;
+
+struct mtl_huc_auth_msg_out {
+       struct intel_gsc_mtl_header header;
+       struct pxp43_huc_auth_out huc_out;
+} __packed;
+
+int intel_huc_fw_auth_via_gsccs(struct intel_huc *huc)
+{
+       struct intel_gt *gt = huc_to_gt(huc);
+       struct drm_i915_private *i915 = gt->i915;
+       struct drm_i915_gem_object *obj;
+       struct mtl_huc_auth_msg_in *msg_in;
+       struct mtl_huc_auth_msg_out *msg_out;
+       void *pkt_vaddr;
+       u64 pkt_offset;
+       int retry = 5;
+       int err = 0;
+
+       if (!huc->heci_pkt)
+               return -ENODEV;
+
+       obj = huc->heci_pkt->obj;
+       pkt_offset = i915_ggtt_offset(huc->heci_pkt);
+
+       pkt_vaddr = i915_gem_object_pin_map_unlocked(obj,
+                                                    i915_coherent_map_type(i915, obj, true));
+       if (IS_ERR(pkt_vaddr))
+               return PTR_ERR(pkt_vaddr);
+
+       msg_in = pkt_vaddr;
+       msg_out = pkt_vaddr + PXP43_HUC_AUTH_INOUT_SIZE;
+
+       intel_gsc_uc_heci_cmd_emit_mtl_header(&msg_in->header,
+                                             HECI_MEADDRESS_PXP,
+                                             sizeof(*msg_in), 0);
+
+       msg_in->huc_in.header.api_version = PXP_APIVER(4, 3);
+       msg_in->huc_in.header.command_id = PXP43_CMDID_NEW_HUC_AUTH;
+       msg_in->huc_in.header.status = 0;
+       msg_in->huc_in.header.buffer_len = sizeof(msg_in->huc_in) -
+                                          sizeof(msg_in->huc_in.header);
+       msg_in->huc_in.huc_base_address = huc->fw.vma_res.start;
+       msg_in->huc_in.huc_size = huc->fw.obj->base.size;
+
+       do {
+               err = intel_gsc_uc_heci_cmd_submit_packet(&gt->uc.gsc,
+                                                         pkt_offset, sizeof(*msg_in),
+                                                         pkt_offset + PXP43_HUC_AUTH_INOUT_SIZE,
+                                                         PXP43_HUC_AUTH_INOUT_SIZE);
+               if (err) {
+                       huc_err(huc, "failed to submit GSC request to auth: %d\n", err);
+                       goto out_unpin;
+               }
+
+               if (msg_out->header.flags & GSC_OUTFLAG_MSG_PENDING) {
+                       msg_in->header.gsc_message_handle = msg_out->header.gsc_message_handle;
+                       err = -EBUSY;
+                       msleep(50);
+               }
+       } while (--retry && err == -EBUSY);
+
+       if (err)
+               goto out_unpin;
+
+       if (msg_out->header.message_size != sizeof(*msg_out)) {
+               huc_err(huc, "invalid GSC reply length %u [expected %zu]\n",
+                       msg_out->header.message_size, sizeof(*msg_out));
+               err = -EPROTO;
+               goto out_unpin;
+       }
+
+       /*
+        * The GSC will return PXP_STATUS_OP_NOT_PERMITTED if the HuC is already
+        * loaded. If the same error is ever returned with HuC not loaded we'll
+        * still catch it when we check the authentication bit later.
+        */
+       if (msg_out->huc_out.header.status != PXP_STATUS_SUCCESS &&
+           msg_out->huc_out.header.status != PXP_STATUS_OP_NOT_PERMITTED) {
+               huc_err(huc, "auth failed with GSC error = 0x%x\n",
+                       msg_out->huc_out.header.status);
+               err = -EIO;
+               goto out_unpin;
+       }
+
+out_unpin:
+       i915_gem_object_unpin_map(obj);
+       return err;
+}
 
 static void get_version_from_gsc_manifest(struct intel_uc_fw_ver *ver, const void *data)
 {
index 0999ffe..307ab45 100644 (file)
@@ -12,6 +12,7 @@ struct intel_uc_fw;
 #include <linux/types.h>
 
 int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc);
+int intel_huc_fw_auth_via_gsccs(struct intel_huc *huc);
 int intel_huc_fw_upload(struct intel_huc *huc);
 int intel_huc_fw_get_binary_info(struct intel_uc_fw *huc_fw, const void *data, size_t size);
 #endif
index 1e7f5cc..18250fb 100644 (file)
@@ -538,7 +538,7 @@ static int __uc_init_hw(struct intel_uc *uc)
        if (intel_huc_is_loaded_by_gsc(huc))
                intel_huc_update_auth_status(huc);
        else
-               intel_huc_auth(huc);
+               intel_huc_auth(huc, INTEL_HUC_AUTH_BY_GUC);
 
        if (intel_uc_uses_guc_submission(uc)) {
                ret = intel_guc_submission_enable(guc);
index 0977771..0165d38 100644 (file)
 
 /* PXP-Cmd-Op definitions */
 #define PXP43_CMDID_START_HUC_AUTH 0x0000003A
+#define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */
 #define PXP43_CMDID_INIT_SESSION 0x00000036
 
 /* PXP-Packet sizes for MTL's GSCCS-HECI instruction */
 #define PXP43_MAX_HECI_INOUT_SIZE (SZ_32K)
 
-/* PXP-Input-Packet: HUC-Authentication */
+/* PXP-Packet size for MTL's NEW_HUC_AUTH instruction */
+#define PXP43_HUC_AUTH_INOUT_SIZE (SZ_4K)
+
+/* PXP-Input-Packet: HUC Load and Authentication */
 struct pxp43_start_huc_auth_in {
        struct pxp_cmd_header header;
        __le64 huc_base_address;
 } __packed;
 
-/* PXP-Output-Packet: HUC-Authentication */
-struct pxp43_start_huc_auth_out {
+/* PXP-Input-Packet: HUC Auth-only */
+struct pxp43_new_huc_auth_in {
+       struct pxp_cmd_header header;
+       u64 huc_base_address;
+       u32 huc_size;
+} __packed;
+
+/* PXP-Output-Packet: HUC Load and Authentication or Auth-only */
+struct pxp43_huc_auth_out {
        struct pxp_cmd_header header;
 } __packed;
 
index 23431c3..5eedce9 100644 (file)
@@ -19,7 +19,7 @@ int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp)
        struct intel_gt *gt;
        struct intel_huc *huc;
        struct pxp43_start_huc_auth_in huc_in = {0};
-       struct pxp43_start_huc_auth_out huc_out = {0};
+       struct pxp43_huc_auth_out huc_out = {0};
        dma_addr_t huc_phys_addr;
        u8 client_id = 0;
        u8 fence_id = 0;