Commit dc75d037 authored by Matthew Brost's avatar Matthew Brost Committed by Rodrigo Vivi

drm/xe/guc: Add more GuC CT states

The Guc CT has more than enabled / disables states rather it has 4. The
4 states are not initialized, disabled, stopped, and enabled. Change the
code to reflect this. These states will enable proper return codes from
functions and therefore enable proper error messages.

v2:
- s/XE_GUC_CT_STATE_DROP_MESSAGES/XE_GUC_CT_STATE_STOPPED (Michal)
- Add assert for CT being initialized (Michal)
- Fix kernel for CT state enum (Michal)

v3:
- Kernel doc (Michal)
- s/reiecved/received (Michal)
- assert CT state not initialized in xe_guc_ct_init (Michal)
- add argument xe_guc_ct_set_state to clear g2h (Michal)

v4:
- Drop clear_outstanding_g2h argument (Michal)

v5:
- Move xa_destroy outside of fast lock (CI)

Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Tejas Upadhyay <tejas.upadhyay@intel.com>
Signed-off-by: default avatarMatthew Brost <matthew.brost@intel.com>
Reviewed-by: default avatarMichal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240122210156.1517444-2-matthew.brost@intel.com
parent c6878e47
...@@ -684,7 +684,7 @@ int xe_guc_mmio_send_recv(struct xe_guc *guc, const u32 *request, ...@@ -684,7 +684,7 @@ int xe_guc_mmio_send_recv(struct xe_guc *guc, const u32 *request,
BUILD_BUG_ON(VF_SW_FLAG_COUNT != MED_VF_SW_FLAG_COUNT); BUILD_BUG_ON(VF_SW_FLAG_COUNT != MED_VF_SW_FLAG_COUNT);
xe_assert(xe, !guc->ct.enabled); xe_assert(xe, !xe_guc_ct_enabled(&guc->ct));
xe_assert(xe, len); xe_assert(xe, len);
xe_assert(xe, len <= VF_SW_FLAG_COUNT); xe_assert(xe, len <= VF_SW_FLAG_COUNT);
xe_assert(xe, len <= MED_VF_SW_FLAG_COUNT); xe_assert(xe, len <= MED_VF_SW_FLAG_COUNT);
...@@ -870,7 +870,7 @@ int xe_guc_stop(struct xe_guc *guc) ...@@ -870,7 +870,7 @@ int xe_guc_stop(struct xe_guc *guc)
{ {
int ret; int ret;
xe_guc_ct_disable(&guc->ct); xe_guc_ct_stop(&guc->ct);
ret = xe_guc_submit_stop(guc); ret = xe_guc_submit_stop(guc);
if (ret) if (ret)
......
...@@ -166,6 +166,8 @@ int xe_guc_ct_init(struct xe_guc_ct *ct) ...@@ -166,6 +166,8 @@ int xe_guc_ct_init(struct xe_guc_ct *ct)
if (err) if (err)
return err; return err;
xe_assert(xe, ct->state == XE_GUC_CT_STATE_NOT_INITIALIZED);
ct->state = XE_GUC_CT_STATE_DISABLED;
return 0; return 0;
} }
...@@ -285,12 +287,35 @@ static int guc_ct_control_toggle(struct xe_guc_ct *ct, bool enable) ...@@ -285,12 +287,35 @@ static int guc_ct_control_toggle(struct xe_guc_ct *ct, bool enable)
return ret > 0 ? -EPROTO : ret; return ret > 0 ? -EPROTO : ret;
} }
static void xe_guc_ct_set_state(struct xe_guc_ct *ct,
enum xe_guc_ct_state state)
{
mutex_lock(&ct->lock); /* Serialise dequeue_one_g2h() */
spin_lock_irq(&ct->fast_lock); /* Serialise CT fast-path */
xe_gt_assert(ct_to_gt(ct), ct->g2h_outstanding == 0 ||
state == XE_GUC_CT_STATE_STOPPED);
ct->g2h_outstanding = 0;
ct->state = state;
spin_unlock_irq(&ct->fast_lock);
/*
* Lockdep doesn't like this under the fast lock and he destroy only
* needs to be serialized with the send path which ct lock provides.
*/
xa_destroy(&ct->fence_lookup);
mutex_unlock(&ct->lock);
}
int xe_guc_ct_enable(struct xe_guc_ct *ct) int xe_guc_ct_enable(struct xe_guc_ct *ct)
{ {
struct xe_device *xe = ct_to_xe(ct); struct xe_device *xe = ct_to_xe(ct);
int err; int err;
xe_assert(xe, !ct->enabled); xe_assert(xe, !xe_guc_ct_enabled(ct));
guc_ct_ctb_h2g_init(xe, &ct->ctbs.h2g, &ct->bo->vmap); guc_ct_ctb_h2g_init(xe, &ct->ctbs.h2g, &ct->bo->vmap);
guc_ct_ctb_g2h_init(xe, &ct->ctbs.g2h, &ct->bo->vmap); guc_ct_ctb_g2h_init(xe, &ct->ctbs.g2h, &ct->bo->vmap);
...@@ -307,12 +332,7 @@ int xe_guc_ct_enable(struct xe_guc_ct *ct) ...@@ -307,12 +332,7 @@ int xe_guc_ct_enable(struct xe_guc_ct *ct)
if (err) if (err)
goto err_out; goto err_out;
mutex_lock(&ct->lock); xe_guc_ct_set_state(ct, XE_GUC_CT_STATE_ENABLED);
spin_lock_irq(&ct->fast_lock);
ct->g2h_outstanding = 0;
ct->enabled = true;
spin_unlock_irq(&ct->fast_lock);
mutex_unlock(&ct->lock);
smp_mb(); smp_mb();
wake_up_all(&ct->wq); wake_up_all(&ct->wq);
...@@ -326,15 +346,26 @@ int xe_guc_ct_enable(struct xe_guc_ct *ct) ...@@ -326,15 +346,26 @@ int xe_guc_ct_enable(struct xe_guc_ct *ct)
return err; return err;
} }
/**
* xe_guc_ct_disable - Set GuC to disabled state
* @ct: the &xe_guc_ct
*
* Set GuC CT to disabled state, no outstanding g2h expected in this transition
*/
void xe_guc_ct_disable(struct xe_guc_ct *ct) void xe_guc_ct_disable(struct xe_guc_ct *ct)
{ {
mutex_lock(&ct->lock); /* Serialise dequeue_one_g2h() */ xe_guc_ct_set_state(ct, XE_GUC_CT_STATE_DISABLED);
spin_lock_irq(&ct->fast_lock); /* Serialise CT fast-path */ }
ct->enabled = false; /* Finally disable CT communication */
spin_unlock_irq(&ct->fast_lock);
mutex_unlock(&ct->lock);
xa_destroy(&ct->fence_lookup); /**
* xe_guc_ct_stop - Set GuC to stopped state
* @ct: the &xe_guc_ct
*
* Set GuC CT to stopped state and clear any outstanding g2h
*/
void xe_guc_ct_stop(struct xe_guc_ct *ct)
{
xe_guc_ct_set_state(ct, XE_GUC_CT_STATE_STOPPED);
} }
static bool h2g_has_room(struct xe_guc_ct *ct, u32 cmd_len) static bool h2g_has_room(struct xe_guc_ct *ct, u32 cmd_len)
...@@ -509,6 +540,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, ...@@ -509,6 +540,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
u16 seqno; u16 seqno;
int ret; int ret;
xe_assert(xe, ct->state != XE_GUC_CT_STATE_NOT_INITIALIZED);
xe_assert(xe, !g2h_len || !g2h_fence); xe_assert(xe, !g2h_len || !g2h_fence);
xe_assert(xe, !num_g2h || !g2h_fence); xe_assert(xe, !num_g2h || !g2h_fence);
xe_assert(xe, !g2h_len || num_g2h); xe_assert(xe, !g2h_len || num_g2h);
...@@ -520,11 +552,18 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, ...@@ -520,11 +552,18 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
goto out; goto out;
} }
if (unlikely(!ct->enabled)) { if (ct->state == XE_GUC_CT_STATE_DISABLED) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
if (ct->state == XE_GUC_CT_STATE_STOPPED) {
ret = -ECANCELED;
goto out;
}
xe_assert(xe, xe_guc_ct_enabled(ct));
if (g2h_fence) { if (g2h_fence) {
g2h_len = GUC_CTB_HXG_MSG_MAX_LEN; g2h_len = GUC_CTB_HXG_MSG_MAX_LEN;
num_g2h = 1; num_g2h = 1;
...@@ -712,7 +751,8 @@ static bool retry_failure(struct xe_guc_ct *ct, int ret) ...@@ -712,7 +751,8 @@ static bool retry_failure(struct xe_guc_ct *ct, int ret)
return false; return false;
#define ct_alive(ct) \ #define ct_alive(ct) \
(ct->enabled && !ct->ctbs.h2g.info.broken && !ct->ctbs.g2h.info.broken) (xe_guc_ct_enabled(ct) && !ct->ctbs.h2g.info.broken && \
!ct->ctbs.g2h.info.broken)
if (!wait_event_interruptible_timeout(ct->wq, ct_alive(ct), HZ * 5)) if (!wait_event_interruptible_timeout(ct->wq, ct_alive(ct), HZ * 5))
return false; return false;
#undef ct_alive #undef ct_alive
...@@ -1031,14 +1071,20 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) ...@@ -1031,14 +1071,20 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path)
u32 action; u32 action;
u32 *hxg; u32 *hxg;
xe_assert(xe, ct->state != XE_GUC_CT_STATE_NOT_INITIALIZED);
lockdep_assert_held(&ct->fast_lock); lockdep_assert_held(&ct->fast_lock);
if (!ct->enabled) if (ct->state == XE_GUC_CT_STATE_DISABLED)
return -ENODEV; return -ENODEV;
if (ct->state == XE_GUC_CT_STATE_STOPPED)
return -ECANCELED;
if (g2h->info.broken) if (g2h->info.broken)
return -EPIPE; return -EPIPE;
xe_assert(xe, xe_guc_ct_enabled(ct));
/* Calculate DW available to read */ /* Calculate DW available to read */
tail = desc_read(xe, g2h, tail); tail = desc_read(xe, g2h, tail);
avail = tail - g2h->info.head; avail = tail - g2h->info.head;
...@@ -1340,7 +1386,7 @@ struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct, ...@@ -1340,7 +1386,7 @@ struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct,
return NULL; return NULL;
} }
if (ct->enabled) { if (xe_guc_ct_enabled(ct)) {
snapshot->ct_enabled = true; snapshot->ct_enabled = true;
snapshot->g2h_outstanding = READ_ONCE(ct->g2h_outstanding); snapshot->g2h_outstanding = READ_ONCE(ct->g2h_outstanding);
guc_ctb_snapshot_capture(xe, &ct->ctbs.h2g, guc_ctb_snapshot_capture(xe, &ct->ctbs.h2g,
......
...@@ -13,6 +13,7 @@ struct drm_printer; ...@@ -13,6 +13,7 @@ struct drm_printer;
int xe_guc_ct_init(struct xe_guc_ct *ct); int xe_guc_ct_init(struct xe_guc_ct *ct);
int xe_guc_ct_enable(struct xe_guc_ct *ct); int xe_guc_ct_enable(struct xe_guc_ct *ct);
void xe_guc_ct_disable(struct xe_guc_ct *ct); void xe_guc_ct_disable(struct xe_guc_ct *ct);
void xe_guc_ct_stop(struct xe_guc_ct *ct);
void xe_guc_ct_fast_path(struct xe_guc_ct *ct); void xe_guc_ct_fast_path(struct xe_guc_ct *ct);
struct xe_guc_ct_snapshot * struct xe_guc_ct_snapshot *
...@@ -22,9 +23,14 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, ...@@ -22,9 +23,14 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot,
void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot); void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot);
void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool atomic); void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool atomic);
static inline bool xe_guc_ct_enabled(struct xe_guc_ct *ct)
{
return ct->state == XE_GUC_CT_STATE_ENABLED;
}
static inline void xe_guc_ct_irq_handler(struct xe_guc_ct *ct) static inline void xe_guc_ct_irq_handler(struct xe_guc_ct *ct)
{ {
if (!ct->enabled) if (!xe_guc_ct_enabled(ct))
return; return;
wake_up_all(&ct->wq); wake_up_all(&ct->wq);
......
...@@ -72,6 +72,20 @@ struct xe_guc_ct_snapshot { ...@@ -72,6 +72,20 @@ struct xe_guc_ct_snapshot {
struct guc_ctb_snapshot h2g; struct guc_ctb_snapshot h2g;
}; };
/**
* enum xe_guc_ct_state - CT state
* @XE_GUC_CT_STATE_NOT_INITIALIZED: CT not initialized, messages not expected in this state
* @XE_GUC_CT_STATE_DISABLED: CT disabled, messages not expected in this state
* @XE_GUC_CT_STATE_STOPPED: CT stopped, drop messages without errors
* @XE_GUC_CT_STATE_ENABLED: CT enabled, messages sent / received in this state
*/
enum xe_guc_ct_state {
XE_GUC_CT_STATE_NOT_INITIALIZED = 0,
XE_GUC_CT_STATE_DISABLED,
XE_GUC_CT_STATE_STOPPED,
XE_GUC_CT_STATE_ENABLED,
};
/** /**
* struct xe_guc_ct - GuC command transport (CT) layer * struct xe_guc_ct - GuC command transport (CT) layer
* *
...@@ -96,8 +110,8 @@ struct xe_guc_ct { ...@@ -96,8 +110,8 @@ struct xe_guc_ct {
u32 g2h_outstanding; u32 g2h_outstanding;
/** @g2h_worker: worker to process G2H messages */ /** @g2h_worker: worker to process G2H messages */
struct work_struct g2h_worker; struct work_struct g2h_worker;
/** @enabled: CT enabled */ /** @state: CT state */
bool enabled; enum xe_guc_ct_state state;
/** @fence_seqno: G2H fence seqno - 16 bits used by CT */ /** @fence_seqno: G2H fence seqno - 16 bits used by CT */
u32 fence_seqno; u32 fence_seqno;
/** @fence_lookup: G2H fence lookup */ /** @fence_lookup: G2H fence lookup */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment