Files
linux/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
Alan Previn 69e6dd1492 drm/i915/pxp: limit drm-errors or warning on firmware API failures
MESA driver is creating protected context on every driver handle
creation to query caps bits for app. So when running CI tests,
they are observing hundreds of drm_errors when enabling PXP
in .config but using SOC fusing or BIOS configuration that cannot
support PXP sessions.

The fixes tag referenced below was to resolve a related issue
where we wanted to silence error messages, but that case was due
to outdated IFWI (firmware) that definitely needed an upgrade and
was, at that point, considered a one-off case as opposed to today's
realization that default CI was enabling PXP in kernel config for
all testing.

So with this patch, let's strike a balance between issues that is
critical but are root-caused from HW/platform gaps (louder drm-warn
but just ONCE) vs other cases where it could also come from session
state machine (which cannot be a WARN_ONCE since it can be triggered
due to runtime operation events).

Let's use helpers for these so as more functions are added in future
features / HW (or as FW designers continue to bless upstreaming of
the error codes and meanings), we only need to update the helpers.

NOTE: Don't completely remove FW errors (via drm_debug) or else cusomer
apps that really needs to know that content protection failed won't
be aware of it.

v2: - Add fixes tag (Trvtko)
v3: - Break multi-line drm_dbg strings into separate drm_dbg (Daniele)
    - Fix couple of typecasting nits (Daniele)
v4: - Unsuccessful PXP FW cmd due to platform configuration shouldn't
      use drm_WARN_once (Tvrtko), Switched to use drm_info_once.
v5: - Added "reported-and-tested" by Eero.

Reported-and-tested-by: Eero Tamminen <eero.t.tamminen@intel.com>
Fixes: b762787bf7 ("drm/i915/pxp: Use drm_dbg if arb session failed due to fw version")
Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230323184156.4140659-1-alan.previn.teres.alexis@intel.com
2023-04-05 09:19:32 -07:00

184 lines
4.5 KiB
C

// SPDX-License-Identifier: MIT
/*
* Copyright(c) 2020, Intel Corporation. All rights reserved.
*/
#include "i915_drv.h"
#include "intel_pxp.h"
#include "intel_pxp_cmd.h"
#include "intel_pxp_session.h"
#include "intel_pxp_tee.h"
#include "intel_pxp_types.h"
#define ARB_SESSION I915_PROTECTED_CONTENT_DEFAULT_SESSION /* shorter define */
#define GEN12_KCR_SIP _MMIO(0x32260) /* KCR hwdrm session in play 0-31 */
/* PXP global terminate register for session termination */
#define PXP_GLOBAL_TERMINATE _MMIO(0x320f8)
static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id)
{
struct intel_uncore *uncore = pxp->ctrl_gt->uncore;
intel_wakeref_t wakeref;
u32 sip = 0;
/* if we're suspended the session is considered off */
with_intel_runtime_pm_if_in_use(uncore->rpm, wakeref)
sip = intel_uncore_read(uncore, GEN12_KCR_SIP);
return sip & BIT(id);
}
static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_play)
{
struct intel_uncore *uncore = pxp->ctrl_gt->uncore;
intel_wakeref_t wakeref;
u32 mask = BIT(id);
int ret;
/* if we're suspended the session is considered off */
wakeref = intel_runtime_pm_get_if_in_use(uncore->rpm);
if (!wakeref)
return in_play ? -ENODEV : 0;
ret = intel_wait_for_register(uncore,
GEN12_KCR_SIP,
mask,
in_play ? mask : 0,
100);
intel_runtime_pm_put(uncore->rpm, wakeref);
return ret;
}
static int pxp_create_arb_session(struct intel_pxp *pxp)
{
struct intel_gt *gt = pxp->ctrl_gt;
int ret;
pxp->arb_is_valid = false;
if (intel_pxp_session_is_in_play(pxp, ARB_SESSION)) {
drm_err(&gt->i915->drm, "arb session already in play at creation time\n");
return -EEXIST;
}
ret = intel_pxp_tee_cmd_create_arb_session(pxp, ARB_SESSION);
if (ret) {
drm_err(&gt->i915->drm, "tee cmd for arb session creation failed\n");
return ret;
}
ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true);
if (ret) {
drm_dbg(&gt->i915->drm, "arb session failed to go in play\n");
return ret;
}
drm_dbg(&gt->i915->drm, "PXP ARB session is alive\n");
if (!++pxp->key_instance)
++pxp->key_instance;
pxp->arb_is_valid = true;
return 0;
}
static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)
{
int ret;
struct intel_gt *gt = pxp->ctrl_gt;
/* must mark termination in progress calling this function */
GEM_WARN_ON(pxp->arb_is_valid);
/* terminate the hw sessions */
ret = intel_pxp_terminate_session(pxp, ARB_SESSION);
if (ret) {
drm_err(&gt->i915->drm, "Failed to submit session termination\n");
return ret;
}
ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false);
if (ret) {
drm_err(&gt->i915->drm, "Session state did not clear\n");
return ret;
}
intel_uncore_write(gt->uncore, PXP_GLOBAL_TERMINATE, 1);
intel_pxp_tee_end_arb_fw_session(pxp, ARB_SESSION);
return ret;
}
void intel_pxp_terminate(struct intel_pxp *pxp, bool post_invalidation_needs_restart)
{
int ret;
pxp->hw_state_invalidated = post_invalidation_needs_restart;
/*
* if we fail to submit the termination there is no point in waiting for
* it to complete. PXP will be marked as non-active until the next
* termination is issued.
*/
ret = pxp_terminate_arb_session_and_global(pxp);
if (ret)
complete_all(&pxp->termination);
}
static void pxp_terminate_complete(struct intel_pxp *pxp)
{
/* Re-create the arb session after teardown handle complete */
if (fetch_and_zero(&pxp->hw_state_invalidated))
pxp_create_arb_session(pxp);
complete_all(&pxp->termination);
}
static void pxp_session_work(struct work_struct *work)
{
struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work);
struct intel_gt *gt = pxp->ctrl_gt;
intel_wakeref_t wakeref;
u32 events = 0;
spin_lock_irq(gt->irq_lock);
events = fetch_and_zero(&pxp->session_events);
spin_unlock_irq(gt->irq_lock);
if (!events)
return;
if (events & PXP_INVAL_REQUIRED)
intel_pxp_invalidate(pxp);
/*
* If we're processing an event while suspending then don't bother,
* we're going to re-init everything on resume anyway.
*/
wakeref = intel_runtime_pm_get_if_in_use(gt->uncore->rpm);
if (!wakeref)
return;
if (events & PXP_TERMINATION_REQUEST) {
events &= ~PXP_TERMINATION_COMPLETE;
intel_pxp_terminate(pxp, true);
}
if (events & PXP_TERMINATION_COMPLETE)
pxp_terminate_complete(pxp);
intel_runtime_pm_put(gt->uncore->rpm, wakeref);
}
void intel_pxp_session_management_init(struct intel_pxp *pxp)
{
mutex_init(&pxp->arb_mutex);
INIT_WORK(&pxp->session_work, pxp_session_work);
}