drm/i915/gsc: add initial support for GSC proxy

The GSC uC needs to communicate with the CSME to perform certain
operations. Since the GSC can't perform this communication directly
on platforms where it is integrated in GT, i915 needs to transfer the
messages from GSC to CSME and back.
The proxy flow is as follow:
1 - i915 submits a request to GSC asking for the message to CSME
2 - GSC replies with the proxy header + payload for CSME
3 - i915 sends the reply from GSC as-is to CSME via the mei proxy
    component
4 - CSME replies with the proxy header + payload for GSC
5 - i915 submits a request to GSC with the reply from CSME
6 - GSC replies either with a new header + payload (same as step 2,
    so we restart from there) or with an end message.

After GSC load, i915 is expected to start the first proxy message chain,
while all subsequent ones will be triggered by the GSC via interrupt.

To communicate with the CSME, we use a dedicated mei component, which
means that we need to wait for it to bind before we can initialize the
proxies. This usually happens quite fast, but given that there is a
chance that we'll have to wait a few seconds the GSC work has been moved
to a dedicated WQ to not stall other processes.

v2: fix code style, includes and variable naming (Alan)
v3: add extra check for proxy status, fix includes and comments
Signed-off-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Alan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: default avatarAlan Previn <alan.previn.teres.alexis@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230502163854.317653-4-daniele.ceraolospurio@intel.com
parent 1dd924f6
...@@ -194,6 +194,7 @@ i915-y += \ ...@@ -194,6 +194,7 @@ i915-y += \
# general-purpose microcontroller (GuC) support # general-purpose microcontroller (GuC) support
i915-y += \ i915-y += \
gt/uc/intel_gsc_fw.o \ gt/uc/intel_gsc_fw.o \
gt/uc/intel_gsc_proxy.o \
gt/uc/intel_gsc_uc.o \ gt/uc/intel_gsc_uc.o \
gt/uc/intel_gsc_uc_heci_cmd_submit.o\ gt/uc/intel_gsc_uc_heci_cmd_submit.o\
gt/uc/intel_guc.o \ gt/uc/intel_guc.o \
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define GSC_FW_STATUS_REG _MMIO(0x116C40) #define GSC_FW_STATUS_REG _MMIO(0x116C40)
#define GSC_FW_CURRENT_STATE REG_GENMASK(3, 0) #define GSC_FW_CURRENT_STATE REG_GENMASK(3, 0)
#define GSC_FW_CURRENT_STATE_RESET 0 #define GSC_FW_CURRENT_STATE_RESET 0
#define GSC_FW_PROXY_STATE_NORMAL 5
#define GSC_FW_INIT_COMPLETE_BIT REG_BIT(9) #define GSC_FW_INIT_COMPLETE_BIT REG_BIT(9)
static bool gsc_is_in_reset(struct intel_uncore *uncore) static bool gsc_is_in_reset(struct intel_uncore *uncore)
...@@ -23,6 +24,15 @@ static bool gsc_is_in_reset(struct intel_uncore *uncore) ...@@ -23,6 +24,15 @@ static bool gsc_is_in_reset(struct intel_uncore *uncore)
GSC_FW_CURRENT_STATE_RESET; GSC_FW_CURRENT_STATE_RESET;
} }
bool intel_gsc_uc_fw_proxy_init_done(struct intel_gsc_uc *gsc)
{
struct intel_uncore *uncore = gsc_uc_to_gt(gsc)->uncore;
u32 fw_status = intel_uncore_read(uncore, GSC_FW_STATUS_REG);
return REG_FIELD_GET(GSC_FW_CURRENT_STATE, fw_status) ==
GSC_FW_PROXY_STATE_NORMAL;
}
bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc) bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc)
{ {
struct intel_uncore *uncore = gsc_uc_to_gt(gsc)->uncore; struct intel_uncore *uncore = gsc_uc_to_gt(gsc)->uncore;
......
...@@ -13,5 +13,6 @@ struct intel_uncore; ...@@ -13,5 +13,6 @@ struct intel_uncore;
int intel_gsc_uc_fw_upload(struct intel_gsc_uc *gsc); int intel_gsc_uc_fw_upload(struct intel_gsc_uc *gsc);
bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc); bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc);
bool intel_gsc_uc_fw_proxy_init_done(struct intel_gsc_uc *gsc);
#endif #endif
This diff is collapsed.
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _INTEL_GSC_PROXY_H_
#define _INTEL_GSC_PROXY_H_
#include <linux/types.h>
struct intel_gsc_uc;
int intel_gsc_proxy_init(struct intel_gsc_uc *gsc);
void intel_gsc_proxy_fini(struct intel_gsc_uc *gsc);
int intel_gsc_proxy_request_handler(struct intel_gsc_uc *gsc);
#endif
...@@ -10,15 +10,39 @@ ...@@ -10,15 +10,39 @@
#include "intel_gsc_uc.h" #include "intel_gsc_uc.h"
#include "intel_gsc_fw.h" #include "intel_gsc_fw.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "intel_gsc_proxy.h"
static void gsc_work(struct work_struct *work) static void gsc_work(struct work_struct *work)
{ {
struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work); struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work);
struct intel_gt *gt = gsc_uc_to_gt(gsc); struct intel_gt *gt = gsc_uc_to_gt(gsc);
intel_wakeref_t wakeref; intel_wakeref_t wakeref;
int ret;
with_intel_runtime_pm(gt->uncore->rpm, wakeref) wakeref = intel_runtime_pm_get(gt->uncore->rpm);
intel_gsc_uc_fw_upload(gsc);
ret = intel_gsc_uc_fw_upload(gsc);
if (ret)
goto out_put;
ret = intel_gsc_proxy_request_handler(gsc);
if (ret)
goto out_put;
/*
* If there is a proxy establishment error, the GSC might still
* complete the request handling cleanly, so we need to check the
* status register to check if the proxy init was actually successful
*/
if (intel_gsc_uc_fw_proxy_init_done(gsc)) {
drm_dbg(&gt->i915->drm, "GSC Proxy initialized\n");
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_RUNNING);
} else {
drm_err(&gt->i915->drm, "GSC status reports proxy init not complete\n");
}
out_put:
intel_runtime_pm_put(gt->uncore->rpm, wakeref);
} }
static bool gsc_engine_supported(struct intel_gt *gt) static bool gsc_engine_supported(struct intel_gt *gt)
...@@ -43,6 +67,8 @@ static bool gsc_engine_supported(struct intel_gt *gt) ...@@ -43,6 +67,8 @@ static bool gsc_engine_supported(struct intel_gt *gt)
void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc) void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
{ {
struct intel_gt *gt = gsc_uc_to_gt(gsc);
intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC); intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC);
INIT_WORK(&gsc->work, gsc_work); INIT_WORK(&gsc->work, gsc_work);
...@@ -50,10 +76,16 @@ void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc) ...@@ -50,10 +76,16 @@ void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
* GT with it being not fully setup hence check device info's * GT with it being not fully setup hence check device info's
* engine mask * engine mask
*/ */
if (!gsc_engine_supported(gsc_uc_to_gt(gsc))) { if (!gsc_engine_supported(gt)) {
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED); intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
return; return;
} }
gsc->wq = alloc_ordered_workqueue("i915_gsc", 0);
if (!gsc->wq) {
gt_err(gt, "failed to allocate WQ for GSC, disabling FW\n");
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
}
} }
int intel_gsc_uc_init(struct intel_gsc_uc *gsc) int intel_gsc_uc_init(struct intel_gsc_uc *gsc)
...@@ -88,6 +120,9 @@ int intel_gsc_uc_init(struct intel_gsc_uc *gsc) ...@@ -88,6 +120,9 @@ int intel_gsc_uc_init(struct intel_gsc_uc *gsc)
gsc->ce = ce; gsc->ce = ce;
/* if we fail to init proxy we still want to load GSC for PM */
intel_gsc_proxy_init(gsc);
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE); intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE);
return 0; return 0;
...@@ -107,6 +142,12 @@ void intel_gsc_uc_fini(struct intel_gsc_uc *gsc) ...@@ -107,6 +142,12 @@ void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)
return; return;
flush_work(&gsc->work); flush_work(&gsc->work);
if (gsc->wq) {
destroy_workqueue(gsc->wq);
gsc->wq = NULL;
}
intel_gsc_proxy_fini(gsc);
if (gsc->ce) if (gsc->ce)
intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce)); intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce));
...@@ -151,5 +192,5 @@ void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc) ...@@ -151,5 +192,5 @@ void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc)
if (intel_gsc_uc_fw_init_done(gsc)) if (intel_gsc_uc_fw_init_done(gsc))
return; return;
queue_work(system_unbound_wq, &gsc->work); queue_work(gsc->wq, &gsc->work);
} }
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
struct i915_vma; struct i915_vma;
struct intel_context; struct intel_context;
struct i915_gsc_proxy_component;
struct intel_gsc_uc { struct intel_gsc_uc {
/* Generic uC firmware management */ /* Generic uC firmware management */
...@@ -19,7 +20,18 @@ struct intel_gsc_uc { ...@@ -19,7 +20,18 @@ struct intel_gsc_uc {
struct i915_vma *local; /* private memory for GSC usage */ struct i915_vma *local; /* private memory for GSC usage */
struct intel_context *ce; /* for submission to GSC FW via GSC engine */ struct intel_context *ce; /* for submission to GSC FW via GSC engine */
struct work_struct work; /* for delayed load */ /* for delayed load and proxy handling */
struct workqueue_struct *wq;
struct work_struct work;
struct {
struct i915_gsc_proxy_component *component;
bool component_added;
struct i915_vma *vma;
void *to_gsc;
void *to_csme;
struct mutex mutex; /* protects the tee channel binding */
} proxy;
}; };
void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc); void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc);
......
...@@ -14,6 +14,7 @@ struct intel_gsc_mtl_header { ...@@ -14,6 +14,7 @@ struct intel_gsc_mtl_header {
#define GSC_HECI_VALIDITY_MARKER 0xA578875A #define GSC_HECI_VALIDITY_MARKER 0xA578875A
u8 heci_client_id; u8 heci_client_id;
#define HECI_MEADDRESS_PROXY 10
#define HECI_MEADDRESS_PXP 17 #define HECI_MEADDRESS_PXP 17
#define HECI_MEADDRESS_HDCP 18 #define HECI_MEADDRESS_HDCP 18
......
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