Contributors: 13
| Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
| Vinay Belgaumkar |
231 |
51.68% |
7 |
22.58% |
| Matthew Brost |
141 |
31.54% |
2 |
6.45% |
| Michal Wajdeczko |
13 |
2.91% |
6 |
19.35% |
| Matt Roper |
12 |
2.68% |
2 |
6.45% |
| Rodrigo Vivi |
10 |
2.24% |
3 |
9.68% |
| Himal Prasad Ghimiray |
8 |
1.79% |
3 |
9.68% |
| Michał Winiarski |
8 |
1.79% |
1 |
3.23% |
| Brian Welty |
8 |
1.79% |
1 |
3.23% |
| Matthew Auld |
8 |
1.79% |
2 |
6.45% |
| Ashutosh Dixit |
3 |
0.67% |
1 |
3.23% |
| Daniele Ceraolo Spurio |
2 |
0.45% |
1 |
3.23% |
| Riana Tauro |
2 |
0.45% |
1 |
3.23% |
| Lucas De Marchi |
1 |
0.22% |
1 |
3.23% |
| Total |
447 |
|
31 |
|
// SPDX-License-Identifier: MIT
/*
* Copyright © 2026 Intel Corporation
*/
#include <drm/drm_print.h>
#include "abi/guc_actions_slpc_abi.h"
#include "xe_device.h"
#include "xe_force_wake.h"
#include "xe_gt.h"
#include "xe_gt_idle.h"
#include "xe_gt_printk.h"
#include "xe_guc.h"
#include "xe_guc_ct.h"
#include "xe_guc_pc.h"
#include "xe_guc_rc.h"
#include "xe_pm.h"
/**
* DOC: GuC RC (Render C-states)
*
* GuC handles the GT transition to deeper C-states in conjunction with Pcode.
* GuC RC can be enabled independently of the frequency component in SLPC,
* which is also controlled by GuC.
*
* This file will contain all H2G related logic for handling Render C-states.
* There are some calls to xe_gt_idle, where we enable host C6 when GuC RC is
* skipped. GuC RC is mostly independent of xe_guc_pc with the exception of
* functions that override the mode for which we have to rely on the SLPC H2G
* calls.
*/
static int guc_action_setup_gucrc(struct xe_guc *guc, u32 control)
{
u32 action[] = {
GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC,
control,
};
int ret;
ret = xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0);
if (ret && !(xe_device_wedged(guc_to_xe(guc)) && ret == -ECANCELED))
xe_gt_err(guc_to_gt(guc),
"GuC RC setup %s(%u) failed (%pe)\n",
control == GUCRC_HOST_CONTROL ? "HOST_CONTROL" :
control == GUCRC_FIRMWARE_CONTROL ? "FIRMWARE_CONTROL" :
"UNKNOWN", control, ERR_PTR(ret));
return ret;
}
/**
* xe_guc_rc_disable() - Disable GuC RC
* @guc: Xe GuC instance
*
* Disables GuC RC by taking control of RC6 back from GuC.
*/
void xe_guc_rc_disable(struct xe_guc *guc)
{
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
if (!xe->info.skip_guc_pc && xe->info.platform != XE_PVC)
if (guc_action_setup_gucrc(guc, GUCRC_HOST_CONTROL))
return;
xe_gt_WARN_ON(gt, xe_gt_idle_disable_c6(gt));
}
static void xe_guc_rc_fini_hw(void *arg)
{
struct xe_guc *guc = arg;
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
if (xe_device_wedged(xe))
return;
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT);
xe_guc_rc_disable(guc);
}
/**
* xe_guc_rc_init() - Init GuC RC
* @guc: Xe GuC instance
*
* Add callback action for GuC RC
*
* Return: 0 on success, negative error code on error.
*/
int xe_guc_rc_init(struct xe_guc *guc)
{
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
xe_gt_assert(gt, xe_device_uc_enabled(xe));
return devm_add_action_or_reset(xe->drm.dev, xe_guc_rc_fini_hw, guc);
}
/**
* xe_guc_rc_enable() - Enable GuC RC feature if applicable
* @guc: Xe GuC instance
*
* Enables GuC RC feature.
*
* Return: 0 on success, negative error code on error.
*/
int xe_guc_rc_enable(struct xe_guc *guc)
{
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
xe_gt_assert(gt, xe_device_uc_enabled(xe));
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT);
if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT))
return -ETIMEDOUT;
if (xe->info.platform == XE_PVC) {
xe_guc_rc_disable(guc);
return 0;
}
if (xe->info.skip_guc_pc) {
xe_gt_idle_enable_c6(gt);
return 0;
}
return guc_action_setup_gucrc(guc, GUCRC_FIRMWARE_CONTROL);
}