drm/xe/multi_queue: Capture queue run times for active queues

If a queue is currently active on the CS, query the QUEUE TIMESTAMP
register to get an up to date value of the runtime. To do so, ensure
that the primary queue is active and then check if the secondary queue
is executing on the CS.

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Reviewed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Link: https://patch.msgid.link/20260507162016.3888309-21-umesh.nerlige.ramappa@intel.com
This commit is contained in:
Umesh Nerlige Ramappa 2026-05-07 09:20:25 -07:00
parent e3a9c46fc3
commit bccf190ea7
2 changed files with 101 additions and 23 deletions

View File

@ -170,6 +170,10 @@
#define GFX_DISABLE_LEGACY_MODE REG_BIT(3)
#define RING_CSMQDEBUG(base) XE_REG((base) + 0x2b0)
#define CURRENT_ACTIVE_QUEUE_ID_MASK REG_GENMASK(7, 0)
#define RING_QUEUE_TIMESTAMP(base) XE_REG((base) + 0x4c0)
#define RING_QUEUE_TIMESTAMP_UDW(base) XE_REG((base) + 0x4c0 + 4)
#define RING_TIMESTAMP(base) XE_REG((base) + 0x358)

View File

@ -21,6 +21,7 @@
#include "xe_configfs.h"
#include "xe_device.h"
#include "xe_drm_client.h"
#include "xe_exec_queue.h"
#include "xe_exec_queue_types.h"
#include "xe_gt.h"
#include "xe_gt_clock.h"
@ -2652,22 +2653,69 @@ static int get_ctx_timestamp(struct xe_lrc *lrc, u32 engine_id, u64 *reg_ctx_ts)
return 0;
}
static u64 get_queue_timestamp(struct xe_hw_engine *hwe)
{
return xe_mmio_read64_2x32(&hwe->gt->mmio,
RING_QUEUE_TIMESTAMP(hwe->mmio_base));
}
static u32 get_multi_queue_active_queue_id(struct xe_hw_engine *hwe)
{
u32 val = xe_mmio_read32(&hwe->gt->mmio,
RING_CSMQDEBUG(hwe->mmio_base));
return REG_FIELD_GET(CURRENT_ACTIVE_QUEUE_ID_MASK, val);
}
static bool context_active(struct xe_lrc *lrc)
{
return xe_lrc_ctx_timestamp(lrc) == CONTEXT_ACTIVE;
}
/**
* xe_lrc_timestamp() - Current ctx timestamp
* @lrc: Pointer to the lrc.
*
* Return latest ctx timestamp. With support for active contexts, the
* calculation may be slightly racy, so follow a read-again logic to ensure that
* the context is still active before returning the right timestamp.
*
* Returns: New ctx timestamp value
*/
u64 xe_lrc_timestamp(struct xe_lrc *lrc)
static u64 xe_lrc_multi_queue_timestamp(struct xe_lrc *lrc)
{
struct xe_device *xe = lrc_to_xe(lrc);
struct xe_lrc *primary_lrc = lrc->multi_queue.primary_lrc;
struct xe_hw_engine *hwe;
u64 reg_queue_ts = lrc->queue_timestamp;
if (IS_SRIOV_VF(xe))
return xe_lrc_queue_timestamp(lrc);
xe_assert(xe, primary_lrc);
/* WA BB populates CONTEXT_ACTIVE cookie for primary context only */
if (!context_active(primary_lrc))
return xe_lrc_queue_timestamp(lrc);
/* WA BB populates engine id in PPHWSP of primary context only */
hwe = engine_id_to_hwe(primary_lrc->gt, xe_lrc_engine_id(primary_lrc));
if (!hwe)
return xe_lrc_queue_timestamp(lrc);
if (get_multi_queue_active_queue_id(hwe) != lrc->multi_queue.pos)
return xe_lrc_queue_timestamp(lrc);
/* queue is active, so store the queue timestamp register */
reg_queue_ts = get_queue_timestamp(hwe);
/* double check queue and primary queue are both still active */
if (get_multi_queue_active_queue_id(hwe) != lrc->multi_queue.pos ||
!context_active(primary_lrc))
return xe_lrc_queue_timestamp(lrc);
return reg_queue_ts;
}
static u64 xe_lrc_update_multi_queue_timestamp(struct xe_lrc *lrc, u64 *old_ts)
{
*old_ts = lrc->queue_timestamp;
lrc->queue_timestamp = xe_lrc_multi_queue_timestamp(lrc);
return lrc->queue_timestamp;
}
static u64 xe_lrc_context_timestamp(struct xe_lrc *lrc)
{
u64 reg_ts, new_ts = lrc->ctx_timestamp;
@ -2689,26 +2737,52 @@ u64 xe_lrc_timestamp(struct xe_lrc *lrc)
return new_ts;
}
/**
* xe_lrc_update_timestamp() - Update ctx timestamp
* @lrc: Pointer to the lrc.
* @old_ts: Old timestamp value
*
* Populate @old_ts current saved ctx timestamp, read new ctx timestamp and
* update saved value.
*
* Returns: New ctx timestamp value
*/
u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts)
static u64 xe_lrc_update_context_timestamp(struct xe_lrc *lrc, u64 *old_ts)
{
*old_ts = lrc->ctx_timestamp;
lrc->ctx_timestamp = xe_lrc_timestamp(lrc);
lrc->ctx_timestamp = xe_lrc_context_timestamp(lrc);
trace_xe_lrc_update_timestamp(lrc, *old_ts);
return lrc->ctx_timestamp;
}
/**
* xe_lrc_timestamp() - Current lrc timestamp
* @lrc: Pointer to the lrc.
*
* Return latest lrc timestamp. With support for active contexts/queues, the
* calculation may be slightly racy, so follow a read-again logic to ensure that
* the context/queue is still active before returning the right timestamp.
*
* Returns: New lrc timestamp value
*/
u64 xe_lrc_timestamp(struct xe_lrc *lrc)
{
if (xe_lrc_is_multi_queue(lrc))
return xe_lrc_multi_queue_timestamp(lrc);
else
return xe_lrc_context_timestamp(lrc);
}
/**
* xe_lrc_update_timestamp() - Update lrc timestamp
* @lrc: Pointer to the lrc.
* @old_ts: Old timestamp value
*
* Populate @old_ts with current saved lrc timestamp, read new lrc timestamp and
* update saved value.
*
* Returns: New lrc timestamp value
*/
u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts)
{
if (xe_lrc_is_multi_queue(lrc))
return xe_lrc_update_multi_queue_timestamp(lrc, old_ts);
else
return xe_lrc_update_context_timestamp(lrc, old_ts);
}
/**
* xe_lrc_ring_is_idle() - LRC is idle
* @lrc: Pointer to the lrc.