disp: msm: sde: add support for hwfence profiling

This change adds hwfence input and output fence profiling
registers and debugfs to enable them.
To enable input hw fences timestamps:
echo 0x1 > /d/dri/0/debug/hw_fence_status
To enable output hw fences timestamps:
echo 0x2 > /d/dri/0/debug/hw_fence_status
To enable both, input and output hw fences timestamps:
echo 0x3 > /d/dri/0/debug/hw_fence_status.

Change-Id: I269a38f3843a01ec8c0816890e50bb7d847a4ed9
Signed-off-by: Christina Oliveira <quic_coliveir@quicinc.com>
This commit is contained in:
Christina Oliveira
2022-05-18 09:38:40 -07:00
parent d2d060cf80
commit 21ca2acab9
11 changed files with 252 additions and 23 deletions

View File

@@ -3801,22 +3801,23 @@ static bool _sde_crtc_wait_for_fences(struct drm_crtc *crtc)
int num_hw_fences = 0;
struct sde_hw_ctl *hw_ctl;
bool input_hw_fences_enable;
struct sde_kms *sde_kms = _sde_crtc_get_kms(crtc);
int ret;
SDE_DEBUG("\n");
if (!crtc || !crtc->state) {
if (!crtc || !crtc->state || !sde_kms) {
SDE_ERROR("invalid crtc/state %pK\n", crtc);
return false;
}
hw_ctl = _sde_crtc_get_hw_ctl(crtc);
SDE_ATRACE_BEGIN("plane_wait_input_fence");
/* update ctl hw to wait for ipcc input signal before fetch */
if (test_bit(HW_FENCE_IN_FENCES_ENABLE, sde_crtc->hwfence_features_mask) &&
!sde_fence_update_input_hw_fence_signal(hw_ctl))
!sde_fence_update_input_hw_fence_signal(hw_ctl, sde_kms->debugfs_hw_fence,
sde_kms->hw_mdp))
ipcc_input_signal_wait = true;
/* avoid hw-fences in first frame after timing engine enable */
@@ -4626,7 +4627,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
* condition between txq update and the hw signal during ctl-done for partial updates
*/
if (test_bit(HW_FENCE_OUT_FENCES_ENABLE, sde_crtc->hwfence_features_mask) && !is_vid)
sde_fence_update_hw_fences_txq(sde_crtc->output_fence, false, 0);
sde_fence_update_hw_fences_txq(sde_crtc->output_fence, false, 0,
sde_kms->debugfs_hw_fence);
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc != crtc)

View File

@@ -3433,6 +3433,35 @@ static enum sde_wb sde_encoder_get_wb(struct sde_mdss_cfg *catalog,
return WB_MAX;
}
void sde_encoder_hw_fence_status(struct sde_kms *sde_kms,
struct drm_crtc *crtc, struct sde_hw_ctl *hw_ctl)
{
u64 start_timestamp, end_timestamp;
if (!sde_kms || !hw_ctl || !sde_kms->hw_mdp) {
SDE_ERROR("invalid inputs\n");
return;
}
if ((sde_kms->debugfs_hw_fence & SDE_INPUT_HW_FENCE_TIMESTAMP)
&& sde_kms->hw_mdp->ops.hw_fence_input_status) {
sde_kms->hw_mdp->ops.hw_fence_input_status(sde_kms->hw_mdp,
&start_timestamp, &end_timestamp);
trace_sde_hw_fence_status(crtc->base.id, "input",
start_timestamp, end_timestamp);
}
if ((sde_kms->debugfs_hw_fence & SDE_OUTPUT_HW_FENCE_TIMESTAMP)
&& hw_ctl->ops.hw_fence_output_status) {
hw_ctl->ops.hw_fence_output_status(hw_ctl,
&start_timestamp, &end_timestamp);
trace_sde_hw_fence_status(crtc->base.id, "output",
start_timestamp, end_timestamp);
}
}
void sde_encoder_perf_uidle_status(struct sde_kms *sde_kms,
struct drm_crtc *crtc)
{
@@ -3492,7 +3521,7 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc,
unsigned long lock_flags;
ktime_t ts = 0;
if (!drm_enc || !phy_enc)
if (!drm_enc || !phy_enc || !phy_enc->sde_kms)
return;
SDE_ATRACE_BEGIN("encoder_vblank_callback");
@@ -3502,8 +3531,7 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc,
* calculate accurate vsync timestamp when available
* set current time otherwise
*/
if (phy_enc->sde_kms && test_bit(SDE_FEATURE_HW_VSYNC_TS,
phy_enc->sde_kms->catalog->features))
if (test_bit(SDE_FEATURE_HW_VSYNC_TS, phy_enc->sde_kms->catalog->features))
ts = sde_encoder_calc_last_vsync_timestamp(drm_enc);
if (!ts)
ts = ktime_get();
@@ -3515,10 +3543,12 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc,
sde_enc->crtc_vblank_cb(sde_enc->crtc_vblank_cb_data, ts);
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
if (phy_enc->sde_kms &&
phy_enc->sde_kms->catalog->uidle_cfg.debugfs_perf)
if (phy_enc->sde_kms->catalog->uidle_cfg.debugfs_perf)
sde_encoder_perf_uidle_status(phy_enc->sde_kms, sde_enc->crtc);
if (phy_enc->sde_kms->debugfs_hw_fence)
sde_encoder_hw_fence_status(phy_enc->sde_kms, sde_enc->crtc, phy_enc->hw_ctl);
SDE_ATRACE_END("encoder_vblank_callback");
}
@@ -3706,7 +3736,8 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc)
* phys: Pointer to physical encoder structure
*
*/
static inline void _sde_encoder_update_retire_txq(struct sde_encoder_phys *phys)
static inline void _sde_encoder_update_retire_txq(struct sde_encoder_phys *phys,
struct sde_kms *sde_kms)
{
struct sde_connector *c_conn;
int line_count;
@@ -3720,7 +3751,8 @@ static inline void _sde_encoder_update_retire_txq(struct sde_encoder_phys *phys)
line_count = sde_connector_get_property(phys->connector->state,
CONNECTOR_PROP_EARLY_FENCE_LINE);
if (c_conn->hwfence_wb_retire_fences_enable)
sde_fence_update_hw_fences_txq(c_conn->retire_fence, false, line_count);
sde_fence_update_hw_fences_txq(c_conn->retire_fence, false, line_count,
sde_kms->debugfs_hw_fence);
}
/**
@@ -3933,16 +3965,23 @@ void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc)
void sde_encoder_helper_update_out_fence_txq(struct sde_encoder_virt *sde_enc, bool is_vid)
{
struct sde_crtc *sde_crtc;
struct sde_kms *sde_kms = NULL;
if (!sde_enc || !sde_enc->crtc) {
SDE_ERROR("invalid encoder %d\n", !sde_enc);
return;
}
sde_kms = sde_encoder_get_kms(&sde_enc->base);
if (!sde_kms) {
SDE_ERROR("invalid kms\n");
return;
}
sde_crtc = to_sde_crtc(sde_enc->crtc);
SDE_EVT32(DRMID(sde_enc->crtc), is_vid);
sde_fence_update_hw_fences_txq(sde_crtc->output_fence, is_vid, 0);
sde_fence_update_hw_fences_txq(sde_crtc->output_fence, is_vid, 0, sde_kms ?
sde_kms->debugfs_hw_fence : 0);
}
/**
@@ -4594,6 +4633,7 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool config_changed)
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
struct sde_kms *sde_kms;
unsigned int i;
if (!drm_enc) {
@@ -4619,8 +4659,9 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool config_changed)
}
/* update txq for any output retire hw-fence (wb-path) */
sde_kms = sde_encoder_get_kms(&sde_enc->base);
if (sde_enc->cur_master)
_sde_encoder_update_retire_txq(sde_enc->cur_master);
_sde_encoder_update_retire_txq(sde_enc->cur_master, sde_kms);
/* All phys encs are ready to go, trigger the kickoff */
_sde_encoder_kickoff_phys(sde_enc, config_changed);

View File

@@ -251,7 +251,7 @@ int sde_fence_register_hw_fences_wait(struct sde_hw_ctl *hw_ctl, struct dma_fenc
return ret;
}
static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count)
static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count, u32 debugfs_hw_fence)
{
struct sde_hw_fence_data *data;
u32 ipcc_out_signal;
@@ -279,6 +279,10 @@ static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count)
SDE_DEBUG("out-fence ctl_id:%d out_signal:%d hw_fence_client:%s\n",
ctl_id, ipcc_out_signal, _get_client_id_name(data->hw_fence_client_id));
if ((debugfs_hw_fence & SDE_OUTPUT_HW_FENCE_TIMESTAMP) &&
hw_ctl->ops.hw_fence_output_timestamp_ctrl)
hw_ctl->ops.hw_fence_output_timestamp_ctrl(hw_ctl, true, false);
/* update client/signal output fence */
hw_ctl->ops.hw_fence_update_output_fence(hw_ctl, data->ipcc_out_client, ipcc_out_signal);
SDE_EVT32_VERBOSE(ctl_id, ipcc_out_signal);
@@ -293,7 +297,8 @@ static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count)
return 0;
}
static int _sde_fence_arm_output_hw_fence(struct sde_fence_context *ctx, u32 line_count)
static int _sde_fence_arm_output_hw_fence(struct sde_fence_context *ctx, u32 line_count,
u32 debugfs_hw_fence)
{
struct sde_hw_ctl *hw_ctl = NULL;
struct sde_fence *fc, *next;
@@ -330,13 +335,14 @@ static int _sde_fence_arm_output_hw_fence(struct sde_fence_context *ctx, u32 lin
/* arm dpu to trigger output hw-fence ipcc signal upon completion */
if (hw_ctl)
_arm_output_hw_fence(hw_ctl, line_count);
_arm_output_hw_fence(hw_ctl, line_count, debugfs_hw_fence);
return 0;
}
/* update output hw_fences txq */
int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count)
int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count,
u32 debugfs_hw_fence)
{
int ret = 0;
struct sde_hw_fence_data *data;
@@ -409,7 +415,7 @@ exit:
/* arm dpu to trigger output hw-fence ipcc signal upon completion in vid-mode */
if ((txq_updated && hw_ctl) || line_count)
_sde_fence_arm_output_hw_fence(ctx, line_count);
_sde_fence_arm_output_hw_fence(ctx, line_count, debugfs_hw_fence);
return ret;
}
@@ -462,7 +468,8 @@ static int _reset_hw_fence_timeline(struct sde_hw_ctl *hw_ctl, u32 flags)
return ret;
}
int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl)
int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl, u32 debugfs_hw_fence,
struct sde_hw_mdp *hw_mdp)
{
struct sde_hw_fence_data *data;
u32 ipcc_signal_id;
@@ -470,7 +477,7 @@ int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl)
int ctl_id;
/* we must support sw_override as well, so check both functions */
if (!hw_ctl || !hw_ctl->ops.hw_fence_update_input_fence ||
if (!hw_mdp || !hw_ctl || !hw_ctl->ops.hw_fence_update_input_fence ||
!hw_ctl->ops.hw_fence_trigger_sw_override) {
SDE_ERROR("missing ctl/override/update fence %d\n", !hw_ctl);
return -EINVAL;
@@ -479,6 +486,10 @@ int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl)
ctl_id = hw_ctl->idx - CTL_0;
data = &hw_ctl->hwfence_data;
if ((debugfs_hw_fence & SDE_INPUT_HW_FENCE_TIMESTAMP)
&& hw_mdp->ops.hw_fence_input_timestamp_ctrl)
hw_mdp->ops.hw_fence_input_timestamp_ctrl(hw_mdp, true, false);
ipcc_signal_id = data->ipcc_in_signal;
ipcc_client_id = data->ipcc_in_client;

View File

@@ -19,6 +19,9 @@
#define HW_FENCE_TRIGGER_SEL_CTRL_DONE 0x0
#define HW_FENCE_TRIGGER_SEL_PROG_LINE_COUNT 0x1
#define SDE_INPUT_HW_FENCE_TIMESTAMP BIT(0)
#define SDE_OUTPUT_HW_FENCE_TIMESTAMP BIT(1)
#define SDE_FENCE_NAME_SIZE 24
#define MAX_SDE_HFENCE_OUT_SIGNAL_PING_PONG 2
@@ -179,17 +182,21 @@ int sde_fence_register_hw_fences_wait(struct sde_hw_ctl *hw_ctl, struct dma_fenc
*
* Returns: Zero on success, otherwise returns an error code.
*/
int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count);
int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count,
u32 debugfs_hw_fence);
/**
* sde_fence_update_input_hw_fence_signal - updates input-fence ipcc signal in dpu and enables
* hw-fences for the ctl.
*
* @ctl: hw ctl to update the input-fence and enable hw-fences
* @debugfs_hw_fence: hw-fence timestamp debugfs value
* @hw_mdp: pointer to hw_mdp to get timestamp registers
*
* Returns: Zero on success, otherwise returns an error code.
*/
int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *ctl);
int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *ctl, u32 debugfs_hw_fence,
struct sde_hw_mdp *hw_mdp);
/**
* sde_fence_deinit - deinit fence container

View File

@@ -61,6 +61,11 @@
#define CTL_OUTPUT_FENCE_ID 0x260
#define CTL_HW_FENCE_STATUS 0x278
#define CTL_OUTPUT_FENCE_SW_OVERRIDE 0x27C
#define CTL_TIMESTAMP_CTRL 0x264
#define CTL_OUTPUT_FENCE_START_TIMESTAMP0 0x268
#define CTL_OUTPUT_FENCE_START_TIMESTAMP1 0x26C
#define CTL_OUTPUT_FENCE_END_TIMESTAMP0 0x270
#define CTL_OUTPUT_FENCE_END_TIMESTAMP1 0x274
#define CTL_MIXER_BORDER_OUT BIT(24)
#define CTL_FLUSH_MASK_ROT BIT(27)
@@ -377,6 +382,46 @@ static inline void sde_hw_ctl_trigger_output_fence_override(struct sde_hw_ctl *c
SDE_REG_WRITE(&ctx->hw, CTL_OUTPUT_FENCE_SW_OVERRIDE, 0x1);
}
static inline void sde_hw_ctl_fence_timestamp_ctrl(struct sde_hw_ctl *ctx, bool enable, bool clear)
{
u32 val;
val = SDE_REG_READ(&ctx->hw, CTL_TIMESTAMP_CTRL);
if (enable)
val |= BIT(0);
else
val &= ~BIT(0);
if (clear)
val |= BIT(1);
else
val &= ~BIT(1);
SDE_REG_WRITE(&ctx->hw, CTL_TIMESTAMP_CTRL, val);
wmb(); /* make sure the ctrl is written */
}
static inline int sde_hw_ctl_output_fence_timestamps(struct sde_hw_ctl *ctx,
u64 *val_start, u64 *val_end)
{
u32 start_l, start_h, end_l, end_h;
if (!ctx || IS_ERR_OR_NULL(val_start) || IS_ERR_OR_NULL(val_end))
return -EINVAL;
start_l = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_START_TIMESTAMP0);
start_h = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_START_TIMESTAMP1);
*val_start = (u64)start_h << 32 | start_l;
end_l = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_END_TIMESTAMP0);
end_h = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_END_TIMESTAMP1);
*val_end = (u64)end_h << 32 | end_l;
/* clear timestamps */
sde_hw_ctl_fence_timestamp_ctrl(ctx, false, true);
return 0;
}
static inline int sde_hw_ctl_trigger_start(struct sde_hw_ctl *ctx)
{
if (!ctx)
@@ -1433,6 +1478,8 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
ops->hw_fence_trigger_sw_override = sde_hw_ctl_trigger_sw_override;
ops->get_hw_fence_status = sde_hw_ctl_get_hw_fence_status;
ops->trigger_output_fence_override = sde_hw_ctl_trigger_output_fence_override;
ops->hw_fence_output_status = sde_hw_ctl_output_fence_timestamps;
ops->hw_fence_output_timestamp_ctrl = sde_hw_ctl_fence_timestamp_ctrl;
}
if (cap & BIT(SDE_CTL_UIDLE))

View File

@@ -189,6 +189,23 @@ struct sde_hw_ctl_ops {
*/
void (*hw_fence_trigger_sw_override)(struct sde_hw_ctl *ctx);
/**
* enable or clear hw fence output fence timestamps
* @ctx : ctl path ctx pointer
* @enable : indicates if timestamps should be enabled
* @clear : indicates if timestamps should be cleared
*/
void (*hw_fence_output_timestamp_ctrl)(struct sde_hw_ctl *ctx, bool enable, bool clear);
/**
* get hw fence output fence timestamps and clear them
* @ctx : ctl path ctx pointer
* @val_start : pointer to start timestamp value
* @val_end : pointer to end timestamp value
* @Return: error code
*/
int (*hw_fence_output_status)(struct sde_hw_ctl *ctx, u64 *val_start, u64 *val_end);
/**
* configure output hw fence trigger
* @ctx : ctl path ctx pointer

View File

@@ -593,6 +593,60 @@ static u32 sde_hw_get_autorefresh_status(struct sde_hw_mdp *mdp, u32 intf_idx)
return autorefresh_status;
}
static void sde_hw_hw_fence_timestamp_ctrl(struct sde_hw_mdp *mdp, bool enable, bool clear)
{
struct sde_hw_blk_reg_map c;
u32 val;
if (!mdp) {
SDE_ERROR("invalid mdp, won't enable hw-fence timestamping\n");
return;
}
/* start from the base-address of the mdss */
c = mdp->hw;
c.blk_off = 0x0;
val = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_ID_TIMESTAMP_CTRL);
if (enable)
val |= BIT(0);
else
val &= ~BIT(0);
if (clear)
val |= BIT(1);
else
val &= ~BIT(1);
SDE_REG_WRITE(&c, MDP_CTL_HW_FENCE_ID_TIMESTAMP_CTRL, val);
}
static void sde_hw_input_hw_fence_status(struct sde_hw_mdp *mdp, u64 *s_val, u64 *e_val)
{
u32 start_h, start_l, end_h, end_l;
struct sde_hw_blk_reg_map c;
if (!mdp || IS_ERR_OR_NULL(s_val) || IS_ERR_OR_NULL(e_val)) {
SDE_ERROR("invalid mdp\n");
return;
}
/* start from the base-address of the mdss */
c = mdp->hw;
c.blk_off = 0x0;
start_l = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_START_TIMESTAMP0);
start_h = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_START_TIMESTAMP1);
*s_val = (u64)start_h << 32 | start_l;
end_l = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_END_TIMESTAMP0);
end_h = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_END_TIMESTAMP1);
*e_val = (u64)end_h << 32 | end_l;
/* clear the timestamps */
sde_hw_hw_fence_timestamp_ctrl(mdp, false, true);
wmb(); /* make sure the timestamps are cleared */
}
static void sde_hw_setup_hw_fences_config(struct sde_hw_mdp *mdp, u32 protocol_id,
unsigned long ipcc_base_addr)
{
@@ -711,8 +765,11 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, unsigned long cap, u32 hw
ops->set_hdr_plus_metadata = sde_hw_set_hdr_plus_metadata;
ops->get_autorefresh_status = sde_hw_get_autorefresh_status;
if (hw_fence_rev)
if (hw_fence_rev) {
ops->setup_hw_fences = sde_hw_setup_hw_fences_config;
ops->hw_fence_input_timestamp_ctrl = sde_hw_hw_fence_timestamp_ctrl;
ops->hw_fence_input_status = sde_hw_input_hw_fence_status;
}
}
static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,

View File

@@ -215,6 +215,21 @@ struct sde_hw_mdp_ops {
void (*setup_hw_fences)(struct sde_hw_mdp *mdp, u32 protocol_id,
unsigned long ipcc_base_addr);
/**
* hw_fence_input_status - get hw_fence input fence timestamps and clear them
* @mdp: mdp top context driver
* @s_val: pointer to start timestamp value to populate
* @e_val: pointer to end timestamp value to populate
*/
void (*hw_fence_input_status)(struct sde_hw_mdp *mdp, u64 *s_val, u64 *e_val);
/**
* hw_fence_input_timestamp_ctrl - enable or clear input fence timestamps
* @mdp: mdp top context driver
* @enable: indicates if timestamps should be enabled
* @enable: indicates if timestamps should be cleared
*/
void (*hw_fence_input_timestamp_ctrl)(struct sde_hw_mdp *mdp, bool enable, bool clear);
};
struct sde_hw_mdp {

View File

@@ -172,6 +172,8 @@ static int _sde_debugfs_init(struct sde_kms *sde_kms)
debugfs_create_u32("pm_suspend_clk_dump", 0600, debugfs_root,
(u32 *)&sde_kms->pm_suspend_clk_dump);
debugfs_create_u32("hw_fence_status", 0600, debugfs_root,
(u32 *)&sde_kms->debugfs_hw_fence);
return 0;
}

View File

@@ -318,6 +318,7 @@ struct sde_kms {
struct sde_vm *vm;
unsigned long ipcc_base_addr;
u32 debugfs_hw_fence;
};
struct vsync_info {

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
*/
@@ -420,6 +421,34 @@ TRACE_EVENT(sde_perf_uidle_status,
)
);
TRACE_EVENT(sde_hw_fence_status,
TP_PROTO(u32 crtc,
char *fence,
u32 hw_fence_start_timestamp,
u32 hw_fence_end_timestamp),
TP_ARGS(crtc,
fence,
hw_fence_start_timestamp,
hw_fence_end_timestamp),
TP_STRUCT__entry(
__field(u32, crtc)
__field(char *, fence)
__field(u32, hw_fence_start_timestamp)
__field(u32, hw_fence_end_timestamp)),
TP_fast_assign(
__entry->crtc = crtc;
__entry->fence = fence;
__entry->hw_fence_start_timestamp = hw_fence_start_timestamp;
__entry->hw_fence_end_timestamp = hw_fence_end_timestamp;),
TP_printk(
"crtc:%d %s hw-fence start timestamp:%llu end timestamp:%llu",
__entry->crtc,
__entry->fence,
__entry->hw_fence_start_timestamp,
__entry->hw_fence_end_timestamp
)
);
#define sde_atrace trace_tracing_mark_write
#define SDE_ATRACE_END(name) sde_atrace('E', current, name, 0)