Let's simply convert all the current callers towards direct xe_pm_runtime access and remove this extra layer of indirection. No functional change is expected with this patch since xe_mem_access_get was already using the xe_pm_runtime_get_noresume at this point. v2: Convert all the current callers instead of a big refactor at once. v3: - Rebased - Squashed the GSC/HDCP - Added a new case: sriov_pf_policy - Improved commit message to highlight that there's no functional change in this patch. Reviewed-by: Matthew Auld <matthew.auld@intel.com> #v2 Cc: Suraj Kandpal <suraj.kandpal@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240418143049.43231-1-rodrigo.vivi@intel.com
418 lines
11 KiB
C
418 lines
11 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2023-2024 Intel Corporation
|
|
*/
|
|
|
|
#include "abi/guc_actions_sriov_abi.h"
|
|
|
|
#include "xe_bo.h"
|
|
#include "xe_gt.h"
|
|
#include "xe_gt_sriov_pf_helpers.h"
|
|
#include "xe_gt_sriov_pf_policy.h"
|
|
#include "xe_gt_sriov_printk.h"
|
|
#include "xe_guc_ct.h"
|
|
#include "xe_guc_klv_helpers.h"
|
|
#include "xe_pm.h"
|
|
|
|
/*
|
|
* Return: number of KLVs that were successfully parsed and saved,
|
|
* negative error code on failure.
|
|
*/
|
|
static int guc_action_update_vgt_policy(struct xe_guc *guc, u64 addr, u32 size)
|
|
{
|
|
u32 request[] = {
|
|
GUC_ACTION_PF2GUC_UPDATE_VGT_POLICY,
|
|
lower_32_bits(addr),
|
|
upper_32_bits(addr),
|
|
size,
|
|
};
|
|
|
|
return xe_guc_ct_send_block(&guc->ct, request, ARRAY_SIZE(request));
|
|
}
|
|
|
|
/*
|
|
* Return: number of KLVs that were successfully parsed and saved,
|
|
* negative error code on failure.
|
|
*/
|
|
static int pf_send_policy_klvs(struct xe_gt *gt, const u32 *klvs, u32 num_dwords)
|
|
{
|
|
const u32 bytes = num_dwords * sizeof(u32);
|
|
struct xe_tile *tile = gt_to_tile(gt);
|
|
struct xe_device *xe = tile_to_xe(tile);
|
|
struct xe_guc *guc = >->uc.guc;
|
|
struct xe_bo *bo;
|
|
int ret;
|
|
|
|
bo = xe_bo_create_pin_map(xe, tile, NULL,
|
|
ALIGN(bytes, PAGE_SIZE),
|
|
ttm_bo_type_kernel,
|
|
XE_BO_FLAG_VRAM_IF_DGFX(tile) |
|
|
XE_BO_FLAG_GGTT);
|
|
if (IS_ERR(bo))
|
|
return PTR_ERR(bo);
|
|
|
|
xe_map_memcpy_to(xe, &bo->vmap, 0, klvs, bytes);
|
|
|
|
ret = guc_action_update_vgt_policy(guc, xe_bo_ggtt_addr(bo), num_dwords);
|
|
|
|
xe_bo_unpin_map_no_vm(bo);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Return: 0 on success, -ENOKEY if some KLVs were not updated, -EPROTO if reply was malformed,
|
|
* negative error code on failure.
|
|
*/
|
|
static int pf_push_policy_klvs(struct xe_gt *gt, u32 num_klvs,
|
|
const u32 *klvs, u32 num_dwords)
|
|
{
|
|
int ret;
|
|
|
|
xe_gt_assert(gt, num_klvs == xe_guc_klv_count(klvs, num_dwords));
|
|
|
|
ret = pf_send_policy_klvs(gt, klvs, num_dwords);
|
|
|
|
if (ret != num_klvs) {
|
|
int err = ret < 0 ? ret : ret < num_klvs ? -ENOKEY : -EPROTO;
|
|
struct drm_printer p = xe_gt_info_printer(gt);
|
|
|
|
xe_gt_sriov_notice(gt, "Failed to push %u policy KLV%s (%pe)\n",
|
|
num_klvs, str_plural(num_klvs), ERR_PTR(err));
|
|
xe_guc_klv_print(klvs, num_dwords, &p);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pf_push_policy_u32(struct xe_gt *gt, u16 key, u32 value)
|
|
{
|
|
u32 klv[] = {
|
|
PREP_GUC_KLV(key, 1),
|
|
value,
|
|
};
|
|
|
|
return pf_push_policy_klvs(gt, 1, klv, ARRAY_SIZE(klv));
|
|
}
|
|
|
|
static int pf_update_policy_bool(struct xe_gt *gt, u16 key, bool *policy, bool value)
|
|
{
|
|
int err;
|
|
|
|
err = pf_push_policy_u32(gt, key, value);
|
|
if (unlikely(err)) {
|
|
xe_gt_sriov_notice(gt, "Failed to update policy %#x '%s' to '%s' (%pe)\n",
|
|
key, xe_guc_klv_key_to_string(key),
|
|
str_enabled_disabled(value), ERR_PTR(err));
|
|
return err;
|
|
}
|
|
|
|
xe_gt_sriov_dbg(gt, "policy key %#x '%s' updated to '%s'\n",
|
|
key, xe_guc_klv_key_to_string(key),
|
|
str_enabled_disabled(value));
|
|
|
|
*policy = value;
|
|
return 0;
|
|
}
|
|
|
|
static int pf_update_policy_u32(struct xe_gt *gt, u16 key, u32 *policy, u32 value)
|
|
{
|
|
int err;
|
|
|
|
err = pf_push_policy_u32(gt, key, value);
|
|
if (unlikely(err)) {
|
|
xe_gt_sriov_notice(gt, "Failed to update policy %#x '%s' to '%s' (%pe)\n",
|
|
key, xe_guc_klv_key_to_string(key),
|
|
str_enabled_disabled(value), ERR_PTR(err));
|
|
return err;
|
|
}
|
|
|
|
xe_gt_sriov_dbg(gt, "policy key %#x '%s' updated to %u\n",
|
|
key, xe_guc_klv_key_to_string(key), value);
|
|
|
|
*policy = value;
|
|
return 0;
|
|
}
|
|
|
|
static int pf_provision_sched_if_idle(struct xe_gt *gt, bool enable)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return pf_update_policy_bool(gt, GUC_KLV_VGT_POLICY_SCHED_IF_IDLE_KEY,
|
|
>->sriov.pf.policy.guc.sched_if_idle,
|
|
enable);
|
|
}
|
|
|
|
static int pf_reprovision_sched_if_idle(struct xe_gt *gt)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return pf_provision_sched_if_idle(gt, gt->sriov.pf.policy.guc.sched_if_idle);
|
|
}
|
|
|
|
static void pf_sanitize_sched_if_idle(struct xe_gt *gt)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
gt->sriov.pf.policy.guc.sched_if_idle = false;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_set_sched_if_idle - Control the 'sched_if_idle' policy.
|
|
* @gt: the &xe_gt where to apply the policy
|
|
* @enable: the value of the 'sched_if_idle' policy
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_gt_sriov_pf_policy_set_sched_if_idle(struct xe_gt *gt, bool enable)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
err = pf_provision_sched_if_idle(gt, enable);
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_get_sched_if_idle - Retrieve value of 'sched_if_idle' policy.
|
|
* @gt: the &xe_gt where to read the policy from
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: value of 'sched_if_idle' policy.
|
|
*/
|
|
bool xe_gt_sriov_pf_policy_get_sched_if_idle(struct xe_gt *gt)
|
|
{
|
|
bool enable;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
enable = gt->sriov.pf.policy.guc.sched_if_idle;
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return enable;
|
|
}
|
|
|
|
static int pf_provision_reset_engine(struct xe_gt *gt, bool enable)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return pf_update_policy_bool(gt, GUC_KLV_VGT_POLICY_RESET_AFTER_VF_SWITCH_KEY,
|
|
>->sriov.pf.policy.guc.reset_engine, enable);
|
|
}
|
|
|
|
static int pf_reprovision_reset_engine(struct xe_gt *gt)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return pf_provision_reset_engine(gt, gt->sriov.pf.policy.guc.reset_engine);
|
|
}
|
|
|
|
static void pf_sanitize_reset_engine(struct xe_gt *gt)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
gt->sriov.pf.policy.guc.reset_engine = false;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_set_reset_engine - Control the 'reset_engine' policy.
|
|
* @gt: the &xe_gt where to apply the policy
|
|
* @enable: the value of the 'reset_engine' policy
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_gt_sriov_pf_policy_set_reset_engine(struct xe_gt *gt, bool enable)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
err = pf_provision_reset_engine(gt, enable);
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_get_reset_engine - Retrieve value of 'reset_engine' policy.
|
|
* @gt: the &xe_gt where to read the policy from
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: value of 'reset_engine' policy.
|
|
*/
|
|
bool xe_gt_sriov_pf_policy_get_reset_engine(struct xe_gt *gt)
|
|
{
|
|
bool enable;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
enable = gt->sriov.pf.policy.guc.reset_engine;
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return enable;
|
|
}
|
|
|
|
static int pf_provision_sample_period(struct xe_gt *gt, u32 value)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return pf_update_policy_u32(gt, GUC_KLV_VGT_POLICY_ADVERSE_SAMPLE_PERIOD_KEY,
|
|
>->sriov.pf.policy.guc.sample_period, value);
|
|
}
|
|
|
|
static int pf_reprovision_sample_period(struct xe_gt *gt)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return pf_provision_sample_period(gt, gt->sriov.pf.policy.guc.sample_period);
|
|
}
|
|
|
|
static void pf_sanitize_sample_period(struct xe_gt *gt)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
gt->sriov.pf.policy.guc.sample_period = 0;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_set_sample_period - Control the 'sample_period' policy.
|
|
* @gt: the &xe_gt where to apply the policy
|
|
* @value: the value of the 'sample_period' policy
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_gt_sriov_pf_policy_set_sample_period(struct xe_gt *gt, u32 value)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
err = pf_provision_sample_period(gt, value);
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_get_sample_period - Retrieve value of 'sample_period' policy.
|
|
* @gt: the &xe_gt where to read the policy from
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: value of 'sample_period' policy.
|
|
*/
|
|
u32 xe_gt_sriov_pf_policy_get_sample_period(struct xe_gt *gt)
|
|
{
|
|
u32 value;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
value = gt->sriov.pf.policy.guc.sample_period;
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return value;
|
|
}
|
|
|
|
static void pf_sanitize_guc_policies(struct xe_gt *gt)
|
|
{
|
|
pf_sanitize_sched_if_idle(gt);
|
|
pf_sanitize_reset_engine(gt);
|
|
pf_sanitize_sample_period(gt);
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_sanitize - Reset policy settings.
|
|
* @gt: the &xe_gt
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
void xe_gt_sriov_pf_policy_sanitize(struct xe_gt *gt)
|
|
{
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
pf_sanitize_guc_policies(gt);
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_reprovision - Reprovision (and optionally reset) policy settings.
|
|
* @gt: the &xe_gt
|
|
* @reset: if true will reprovision using default values instead of latest
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_gt_sriov_pf_policy_reprovision(struct xe_gt *gt, bool reset)
|
|
{
|
|
int err = 0;
|
|
|
|
xe_pm_runtime_get_noresume(gt_to_xe(gt));
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
if (reset)
|
|
pf_sanitize_guc_policies(gt);
|
|
err |= pf_reprovision_sched_if_idle(gt);
|
|
err |= pf_reprovision_reset_engine(gt);
|
|
err |= pf_reprovision_sample_period(gt);
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
xe_pm_runtime_put(gt_to_xe(gt));
|
|
|
|
return err ? -ENXIO : 0;
|
|
}
|
|
|
|
static void print_guc_policies(struct drm_printer *p, struct xe_gt_sriov_guc_policies *policy)
|
|
{
|
|
drm_printf(p, "%s:\t%s\n",
|
|
xe_guc_klv_key_to_string(GUC_KLV_VGT_POLICY_SCHED_IF_IDLE_KEY),
|
|
str_enabled_disabled(policy->sched_if_idle));
|
|
drm_printf(p, "%s:\t%s\n",
|
|
xe_guc_klv_key_to_string(GUC_KLV_VGT_POLICY_RESET_AFTER_VF_SWITCH_KEY),
|
|
str_enabled_disabled(policy->reset_engine));
|
|
drm_printf(p, "%s:\t%u %s\n",
|
|
xe_guc_klv_key_to_string(GUC_KLV_VGT_POLICY_ADVERSE_SAMPLE_PERIOD_KEY),
|
|
policy->sample_period, policy->sample_period ? "ms" : "(disabled)");
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_policy_print - Dump actual policy values.
|
|
* @gt: the &xe_gt where to read the policy from
|
|
* @p: the &drm_printer
|
|
*
|
|
* This function can only be called on PF.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_gt_sriov_pf_policy_print(struct xe_gt *gt, struct drm_printer *p)
|
|
{
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
|
|
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
|
print_guc_policies(p, >->sriov.pf.policy.guc);
|
|
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
|
|
|
return 0;
|
|
}
|