|
|
|
|
@ -162,7 +162,8 @@ guc_create_parallel(struct intel_engine_cs **engines,
|
|
|
|
|
#define SCHED_STATE_ENABLED BIT(4)
|
|
|
|
|
#define SCHED_STATE_PENDING_ENABLE BIT(5)
|
|
|
|
|
#define SCHED_STATE_REGISTERED BIT(6)
|
|
|
|
|
#define SCHED_STATE_BLOCKED_SHIFT 7
|
|
|
|
|
#define SCHED_STATE_POLICY_REQUIRED BIT(7)
|
|
|
|
|
#define SCHED_STATE_BLOCKED_SHIFT 8
|
|
|
|
|
#define SCHED_STATE_BLOCKED BIT(SCHED_STATE_BLOCKED_SHIFT)
|
|
|
|
|
#define SCHED_STATE_BLOCKED_MASK (0xfff << SCHED_STATE_BLOCKED_SHIFT)
|
|
|
|
|
|
|
|
|
|
@ -301,6 +302,23 @@ static inline void clr_context_registered(struct intel_context *ce)
|
|
|
|
|
ce->guc_state.sched_state &= ~SCHED_STATE_REGISTERED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool context_policy_required(struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
return ce->guc_state.sched_state & SCHED_STATE_POLICY_REQUIRED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void set_context_policy_required(struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
lockdep_assert_held(&ce->guc_state.lock);
|
|
|
|
|
ce->guc_state.sched_state |= SCHED_STATE_POLICY_REQUIRED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void clr_context_policy_required(struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
lockdep_assert_held(&ce->guc_state.lock);
|
|
|
|
|
ce->guc_state.sched_state &= ~SCHED_STATE_POLICY_REQUIRED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline u32 context_blocked(struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
return (ce->guc_state.sched_state & SCHED_STATE_BLOCKED_MASK) >>
|
|
|
|
|
@ -396,12 +414,12 @@ struct sync_semaphore {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct parent_scratch {
|
|
|
|
|
struct guc_process_desc pdesc;
|
|
|
|
|
struct guc_sched_wq_desc wq_desc;
|
|
|
|
|
|
|
|
|
|
struct sync_semaphore go;
|
|
|
|
|
struct sync_semaphore join[MAX_ENGINE_INSTANCE + 1];
|
|
|
|
|
|
|
|
|
|
u8 unused[WQ_OFFSET - sizeof(struct guc_process_desc) -
|
|
|
|
|
u8 unused[WQ_OFFSET - sizeof(struct guc_sched_wq_desc) -
|
|
|
|
|
sizeof(struct sync_semaphore) * (MAX_ENGINE_INSTANCE + 2)];
|
|
|
|
|
|
|
|
|
|
u32 wq[WQ_SIZE / sizeof(u32)];
|
|
|
|
|
@ -438,15 +456,15 @@ __get_parent_scratch(struct intel_context *ce)
|
|
|
|
|
LRC_STATE_OFFSET) / sizeof(u32)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct guc_process_desc *
|
|
|
|
|
__get_process_desc(struct intel_context *ce)
|
|
|
|
|
static struct guc_sched_wq_desc *
|
|
|
|
|
__get_wq_desc(struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
struct parent_scratch *ps = __get_parent_scratch(ce);
|
|
|
|
|
|
|
|
|
|
return &ps->pdesc;
|
|
|
|
|
return &ps->wq_desc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 *get_wq_pointer(struct guc_process_desc *desc,
|
|
|
|
|
static u32 *get_wq_pointer(struct guc_sched_wq_desc *wq_desc,
|
|
|
|
|
struct intel_context *ce,
|
|
|
|
|
u32 wqi_size)
|
|
|
|
|
{
|
|
|
|
|
@ -458,7 +476,7 @@ static u32 *get_wq_pointer(struct guc_process_desc *desc,
|
|
|
|
|
#define AVAILABLE_SPACE \
|
|
|
|
|
CIRC_SPACE(ce->parallel.guc.wqi_tail, ce->parallel.guc.wqi_head, WQ_SIZE)
|
|
|
|
|
if (wqi_size > AVAILABLE_SPACE) {
|
|
|
|
|
ce->parallel.guc.wqi_head = READ_ONCE(desc->head);
|
|
|
|
|
ce->parallel.guc.wqi_head = READ_ONCE(wq_desc->head);
|
|
|
|
|
|
|
|
|
|
if (wqi_size > AVAILABLE_SPACE)
|
|
|
|
|
return NULL;
|
|
|
|
|
@ -468,15 +486,6 @@ static u32 *get_wq_pointer(struct guc_process_desc *desc,
|
|
|
|
|
return &__get_parent_scratch(ce)->wq[ce->parallel.guc.wqi_tail / sizeof(u32)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct guc_lrc_desc *__get_lrc_desc(struct intel_guc *guc, u32 index)
|
|
|
|
|
{
|
|
|
|
|
struct guc_lrc_desc *base = guc->lrc_desc_pool_vaddr;
|
|
|
|
|
|
|
|
|
|
GEM_BUG_ON(index >= GUC_MAX_CONTEXT_ID);
|
|
|
|
|
|
|
|
|
|
return &base[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline struct intel_context *__get_context(struct intel_guc *guc, u32 id)
|
|
|
|
|
{
|
|
|
|
|
struct intel_context *ce = xa_load(&guc->context_lookup, id);
|
|
|
|
|
@ -486,39 +495,11 @@ static inline struct intel_context *__get_context(struct intel_guc *guc, u32 id)
|
|
|
|
|
return ce;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int guc_lrc_desc_pool_create(struct intel_guc *guc)
|
|
|
|
|
{
|
|
|
|
|
u32 size;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
size = PAGE_ALIGN(sizeof(struct guc_lrc_desc) *
|
|
|
|
|
GUC_MAX_CONTEXT_ID);
|
|
|
|
|
ret = intel_guc_allocate_and_map_vma(guc, size, &guc->lrc_desc_pool,
|
|
|
|
|
(void **)&guc->lrc_desc_pool_vaddr);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void guc_lrc_desc_pool_destroy(struct intel_guc *guc)
|
|
|
|
|
{
|
|
|
|
|
guc->lrc_desc_pool_vaddr = NULL;
|
|
|
|
|
i915_vma_unpin_and_release(&guc->lrc_desc_pool, I915_VMA_RELEASE_MAP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool guc_submission_initialized(struct intel_guc *guc)
|
|
|
|
|
{
|
|
|
|
|
return guc->submission_initialized;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void _reset_lrc_desc(struct intel_guc *guc, u32 id)
|
|
|
|
|
{
|
|
|
|
|
struct guc_lrc_desc *desc = __get_lrc_desc(guc, id);
|
|
|
|
|
|
|
|
|
|
memset(desc, 0, sizeof(*desc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool ctx_id_mapped(struct intel_guc *guc, u32 id)
|
|
|
|
|
{
|
|
|
|
|
return __get_context(guc, id);
|
|
|
|
|
@ -545,8 +526,6 @@ static inline void clr_ctx_id_mapping(struct intel_guc *guc, u32 id)
|
|
|
|
|
if (unlikely(!guc_submission_initialized(guc)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_reset_lrc_desc(guc, id);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* xarray API doesn't have xa_erase_irqsave wrapper, so calling
|
|
|
|
|
* the lower level functions directly.
|
|
|
|
|
@ -632,6 +611,7 @@ int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout)
|
|
|
|
|
true, timeout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int guc_context_policy_init(struct intel_context *ce, bool loop);
|
|
|
|
|
static int try_context_registration(struct intel_context *ce, bool loop);
|
|
|
|
|
|
|
|
|
|
static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
|
|
|
|
|
@ -658,6 +638,12 @@ static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
|
|
|
|
|
GEM_BUG_ON(!atomic_read(&ce->guc_id.ref));
|
|
|
|
|
GEM_BUG_ON(context_guc_id_invalid(ce));
|
|
|
|
|
|
|
|
|
|
if (context_policy_required(ce)) {
|
|
|
|
|
err = guc_context_policy_init(ce, false);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spin_lock(&ce->guc_state.lock);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@ -751,7 +737,7 @@ static u32 wq_space_until_wrap(struct intel_context *ce)
|
|
|
|
|
return (WQ_SIZE - ce->parallel.guc.wqi_tail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void write_wqi(struct guc_process_desc *desc,
|
|
|
|
|
static void write_wqi(struct guc_sched_wq_desc *wq_desc,
|
|
|
|
|
struct intel_context *ce,
|
|
|
|
|
u32 wqi_size)
|
|
|
|
|
{
|
|
|
|
|
@ -764,13 +750,13 @@ static void write_wqi(struct guc_process_desc *desc,
|
|
|
|
|
|
|
|
|
|
ce->parallel.guc.wqi_tail = (ce->parallel.guc.wqi_tail + wqi_size) &
|
|
|
|
|
(WQ_SIZE - 1);
|
|
|
|
|
WRITE_ONCE(desc->tail, ce->parallel.guc.wqi_tail);
|
|
|
|
|
WRITE_ONCE(wq_desc->tail, ce->parallel.guc.wqi_tail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int guc_wq_noop_append(struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
struct guc_process_desc *desc = __get_process_desc(ce);
|
|
|
|
|
u32 *wqi = get_wq_pointer(desc, ce, wq_space_until_wrap(ce));
|
|
|
|
|
struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
|
|
|
|
|
u32 *wqi = get_wq_pointer(wq_desc, ce, wq_space_until_wrap(ce));
|
|
|
|
|
u32 len_dw = wq_space_until_wrap(ce) / sizeof(u32) - 1;
|
|
|
|
|
|
|
|
|
|
if (!wqi)
|
|
|
|
|
@ -789,7 +775,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
|
|
|
|
|
{
|
|
|
|
|
struct intel_context *ce = request_to_scheduling_context(rq);
|
|
|
|
|
struct intel_context *child;
|
|
|
|
|
struct guc_process_desc *desc = __get_process_desc(ce);
|
|
|
|
|
struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
|
|
|
|
|
unsigned int wqi_size = (ce->parallel.number_children + 4) *
|
|
|
|
|
sizeof(u32);
|
|
|
|
|
u32 *wqi;
|
|
|
|
|
@ -809,7 +795,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wqi = get_wq_pointer(desc, ce, wqi_size);
|
|
|
|
|
wqi = get_wq_pointer(wq_desc, ce, wqi_size);
|
|
|
|
|
if (!wqi)
|
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
|
|
@ -824,7 +810,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
|
|
|
|
|
for_each_child(ce, child)
|
|
|
|
|
*wqi++ = child->ring->tail / sizeof(u64);
|
|
|
|
|
|
|
|
|
|
write_wqi(desc, ce, wqi_size);
|
|
|
|
|
write_wqi(wq_desc, ce, wqi_size);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -1812,20 +1798,10 @@ static void reset_fail_worker_func(struct work_struct *w);
|
|
|
|
|
int intel_guc_submission_init(struct intel_guc *guc)
|
|
|
|
|
{
|
|
|
|
|
struct intel_gt *gt = guc_to_gt(guc);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (guc->submission_initialized)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ret = guc_lrc_desc_pool_create(guc);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
/*
|
|
|
|
|
* Keep static analysers happy, let them know that we allocated the
|
|
|
|
|
* vma after testing that it didn't exist earlier.
|
|
|
|
|
*/
|
|
|
|
|
GEM_BUG_ON(!guc->lrc_desc_pool);
|
|
|
|
|
|
|
|
|
|
guc->submission_state.guc_ids_bitmap =
|
|
|
|
|
bitmap_zalloc(NUMBER_MULTI_LRC_GUC_ID(guc), GFP_KERNEL);
|
|
|
|
|
if (!guc->submission_state.guc_ids_bitmap)
|
|
|
|
|
@ -1844,7 +1820,6 @@ void intel_guc_submission_fini(struct intel_guc *guc)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
guc_flush_destroyed_contexts(guc);
|
|
|
|
|
guc_lrc_desc_pool_destroy(guc);
|
|
|
|
|
i915_sched_engine_put(guc->sched_engine);
|
|
|
|
|
bitmap_free(guc->submission_state.guc_ids_bitmap);
|
|
|
|
|
guc->submission_initialized = false;
|
|
|
|
|
@ -2104,69 +2079,96 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce)
|
|
|
|
|
|
|
|
|
|
static int __guc_action_register_multi_lrc(struct intel_guc *guc,
|
|
|
|
|
struct intel_context *ce,
|
|
|
|
|
u32 guc_id,
|
|
|
|
|
u32 offset,
|
|
|
|
|
struct guc_ctxt_registration_info *info,
|
|
|
|
|
bool loop)
|
|
|
|
|
{
|
|
|
|
|
struct intel_context *child;
|
|
|
|
|
u32 action[4 + MAX_ENGINE_INSTANCE];
|
|
|
|
|
u32 action[13 + (MAX_ENGINE_INSTANCE * 2)];
|
|
|
|
|
int len = 0;
|
|
|
|
|
u32 next_id;
|
|
|
|
|
|
|
|
|
|
GEM_BUG_ON(ce->parallel.number_children > MAX_ENGINE_INSTANCE);
|
|
|
|
|
|
|
|
|
|
action[len++] = INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC;
|
|
|
|
|
action[len++] = guc_id;
|
|
|
|
|
action[len++] = info->flags;
|
|
|
|
|
action[len++] = info->context_idx;
|
|
|
|
|
action[len++] = info->engine_class;
|
|
|
|
|
action[len++] = info->engine_submit_mask;
|
|
|
|
|
action[len++] = info->wq_desc_lo;
|
|
|
|
|
action[len++] = info->wq_desc_hi;
|
|
|
|
|
action[len++] = info->wq_base_lo;
|
|
|
|
|
action[len++] = info->wq_base_hi;
|
|
|
|
|
action[len++] = info->wq_size;
|
|
|
|
|
action[len++] = ce->parallel.number_children + 1;
|
|
|
|
|
action[len++] = offset;
|
|
|
|
|
action[len++] = info->hwlrca_lo;
|
|
|
|
|
action[len++] = info->hwlrca_hi;
|
|
|
|
|
|
|
|
|
|
next_id = info->context_idx + 1;
|
|
|
|
|
for_each_child(ce, child) {
|
|
|
|
|
offset += sizeof(struct guc_lrc_desc);
|
|
|
|
|
action[len++] = offset;
|
|
|
|
|
GEM_BUG_ON(next_id++ != child->guc_id.id);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* NB: GuC interface supports 64 bit LRCA even though i915/HW
|
|
|
|
|
* only supports 32 bit currently.
|
|
|
|
|
*/
|
|
|
|
|
action[len++] = lower_32_bits(child->lrc.lrca);
|
|
|
|
|
action[len++] = upper_32_bits(child->lrc.lrca);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GEM_BUG_ON(len > ARRAY_SIZE(action));
|
|
|
|
|
|
|
|
|
|
return guc_submission_send_busy_loop(guc, action, len, 0, loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __guc_action_register_context(struct intel_guc *guc,
|
|
|
|
|
u32 guc_id,
|
|
|
|
|
u32 offset,
|
|
|
|
|
struct guc_ctxt_registration_info *info,
|
|
|
|
|
bool loop)
|
|
|
|
|
{
|
|
|
|
|
u32 action[] = {
|
|
|
|
|
INTEL_GUC_ACTION_REGISTER_CONTEXT,
|
|
|
|
|
guc_id,
|
|
|
|
|
offset,
|
|
|
|
|
info->flags,
|
|
|
|
|
info->context_idx,
|
|
|
|
|
info->engine_class,
|
|
|
|
|
info->engine_submit_mask,
|
|
|
|
|
info->wq_desc_lo,
|
|
|
|
|
info->wq_desc_hi,
|
|
|
|
|
info->wq_base_lo,
|
|
|
|
|
info->wq_base_hi,
|
|
|
|
|
info->wq_size,
|
|
|
|
|
info->hwlrca_lo,
|
|
|
|
|
info->hwlrca_hi,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action),
|
|
|
|
|
0, loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void prepare_context_registration_info(struct intel_context *ce);
|
|
|
|
|
static void prepare_context_registration_info(struct intel_context *ce,
|
|
|
|
|
struct guc_ctxt_registration_info *info);
|
|
|
|
|
|
|
|
|
|
static int register_context(struct intel_context *ce, bool loop)
|
|
|
|
|
{
|
|
|
|
|
struct guc_ctxt_registration_info info;
|
|
|
|
|
struct intel_guc *guc = ce_to_guc(ce);
|
|
|
|
|
u32 offset = intel_guc_ggtt_offset(guc, guc->lrc_desc_pool) +
|
|
|
|
|
ce->guc_id.id * sizeof(struct guc_lrc_desc);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
GEM_BUG_ON(intel_context_is_child(ce));
|
|
|
|
|
trace_intel_context_register(ce);
|
|
|
|
|
|
|
|
|
|
prepare_context_registration_info(ce);
|
|
|
|
|
prepare_context_registration_info(ce, &info);
|
|
|
|
|
|
|
|
|
|
if (intel_context_is_parent(ce))
|
|
|
|
|
ret = __guc_action_register_multi_lrc(guc, ce, ce->guc_id.id,
|
|
|
|
|
offset, loop);
|
|
|
|
|
ret = __guc_action_register_multi_lrc(guc, ce, &info, loop);
|
|
|
|
|
else
|
|
|
|
|
ret = __guc_action_register_context(guc, ce->guc_id.id, offset,
|
|
|
|
|
loop);
|
|
|
|
|
ret = __guc_action_register_context(guc, &info, loop);
|
|
|
|
|
if (likely(!ret)) {
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ce->guc_state.lock, flags);
|
|
|
|
|
set_context_registered(ce);
|
|
|
|
|
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
|
|
|
|
|
|
|
|
|
|
guc_context_policy_init(ce, loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
@ -2216,26 +2218,118 @@ static inline u32 get_children_join_value(struct intel_context *ce,
|
|
|
|
|
return __get_parent_scratch(ce)->join[child_index].semaphore;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void guc_context_policy_init(struct intel_engine_cs *engine,
|
|
|
|
|
struct guc_lrc_desc *desc)
|
|
|
|
|
struct context_policy {
|
|
|
|
|
u32 count;
|
|
|
|
|
struct guc_update_context_policy h2g;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static u32 __guc_context_policy_action_size(struct context_policy *policy)
|
|
|
|
|
{
|
|
|
|
|
desc->policy_flags = 0;
|
|
|
|
|
size_t bytes = sizeof(policy->h2g.header) +
|
|
|
|
|
(sizeof(policy->h2g.klv[0]) * policy->count);
|
|
|
|
|
|
|
|
|
|
if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION)
|
|
|
|
|
desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE;
|
|
|
|
|
|
|
|
|
|
/* NB: For both of these, zero means disabled. */
|
|
|
|
|
desc->execution_quantum = engine->props.timeslice_duration_ms * 1000;
|
|
|
|
|
desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000;
|
|
|
|
|
return bytes / sizeof(u32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void prepare_context_registration_info(struct intel_context *ce)
|
|
|
|
|
static void __guc_context_policy_start_klv(struct context_policy *policy, u16 guc_id)
|
|
|
|
|
{
|
|
|
|
|
policy->h2g.header.action = INTEL_GUC_ACTION_HOST2GUC_UPDATE_CONTEXT_POLICIES;
|
|
|
|
|
policy->h2g.header.ctx_id = guc_id;
|
|
|
|
|
policy->count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MAKE_CONTEXT_POLICY_ADD(func, id) \
|
|
|
|
|
static void __guc_context_policy_add_##func(struct context_policy *policy, u32 data) \
|
|
|
|
|
{ \
|
|
|
|
|
GEM_BUG_ON(policy->count >= GUC_CONTEXT_POLICIES_KLV_NUM_IDS); \
|
|
|
|
|
policy->h2g.klv[policy->count].kl = \
|
|
|
|
|
FIELD_PREP(GUC_KLV_0_KEY, GUC_CONTEXT_POLICIES_KLV_ID_##id) | \
|
|
|
|
|
FIELD_PREP(GUC_KLV_0_LEN, 1); \
|
|
|
|
|
policy->h2g.klv[policy->count].value = data; \
|
|
|
|
|
policy->count++; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MAKE_CONTEXT_POLICY_ADD(execution_quantum, EXECUTION_QUANTUM)
|
|
|
|
|
MAKE_CONTEXT_POLICY_ADD(preemption_timeout, PREEMPTION_TIMEOUT)
|
|
|
|
|
MAKE_CONTEXT_POLICY_ADD(priority, SCHEDULING_PRIORITY)
|
|
|
|
|
MAKE_CONTEXT_POLICY_ADD(preempt_to_idle, PREEMPT_TO_IDLE_ON_QUANTUM_EXPIRY)
|
|
|
|
|
|
|
|
|
|
#undef MAKE_CONTEXT_POLICY_ADD
|
|
|
|
|
|
|
|
|
|
static int __guc_context_set_context_policies(struct intel_guc *guc,
|
|
|
|
|
struct context_policy *policy,
|
|
|
|
|
bool loop)
|
|
|
|
|
{
|
|
|
|
|
return guc_submission_send_busy_loop(guc, (u32 *)&policy->h2g,
|
|
|
|
|
__guc_context_policy_action_size(policy),
|
|
|
|
|
0, loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int guc_context_policy_init(struct intel_context *ce, bool loop)
|
|
|
|
|
{
|
|
|
|
|
struct intel_engine_cs *engine = ce->engine;
|
|
|
|
|
struct intel_guc *guc = &engine->gt->uc.guc;
|
|
|
|
|
struct context_policy policy;
|
|
|
|
|
u32 execution_quantum;
|
|
|
|
|
u32 preemption_timeout;
|
|
|
|
|
bool missing = false;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* NB: For both of these, zero means disabled. */
|
|
|
|
|
execution_quantum = engine->props.timeslice_duration_ms * 1000;
|
|
|
|
|
preemption_timeout = engine->props.preempt_timeout_ms * 1000;
|
|
|
|
|
|
|
|
|
|
__guc_context_policy_start_klv(&policy, ce->guc_id.id);
|
|
|
|
|
|
|
|
|
|
__guc_context_policy_add_priority(&policy, ce->guc_state.prio);
|
|
|
|
|
__guc_context_policy_add_execution_quantum(&policy, execution_quantum);
|
|
|
|
|
__guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
|
|
|
|
|
|
|
|
|
|
if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION)
|
|
|
|
|
__guc_context_policy_add_preempt_to_idle(&policy, 1);
|
|
|
|
|
|
|
|
|
|
ret = __guc_context_set_context_policies(guc, &policy, loop);
|
|
|
|
|
missing = ret != 0;
|
|
|
|
|
|
|
|
|
|
if (!missing && intel_context_is_parent(ce)) {
|
|
|
|
|
struct intel_context *child;
|
|
|
|
|
|
|
|
|
|
for_each_child(ce, child) {
|
|
|
|
|
__guc_context_policy_start_klv(&policy, child->guc_id.id);
|
|
|
|
|
|
|
|
|
|
if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION)
|
|
|
|
|
__guc_context_policy_add_preempt_to_idle(&policy, 1);
|
|
|
|
|
|
|
|
|
|
child->guc_state.prio = ce->guc_state.prio;
|
|
|
|
|
__guc_context_policy_add_priority(&policy, ce->guc_state.prio);
|
|
|
|
|
__guc_context_policy_add_execution_quantum(&policy, execution_quantum);
|
|
|
|
|
__guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
|
|
|
|
|
|
|
|
|
|
ret = __guc_context_set_context_policies(guc, &policy, loop);
|
|
|
|
|
if (ret) {
|
|
|
|
|
missing = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ce->guc_state.lock, flags);
|
|
|
|
|
if (missing)
|
|
|
|
|
set_context_policy_required(ce);
|
|
|
|
|
else
|
|
|
|
|
clr_context_policy_required(ce);
|
|
|
|
|
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void prepare_context_registration_info(struct intel_context *ce,
|
|
|
|
|
struct guc_ctxt_registration_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct intel_engine_cs *engine = ce->engine;
|
|
|
|
|
struct intel_guc *guc = &engine->gt->uc.guc;
|
|
|
|
|
u32 ctx_id = ce->guc_id.id;
|
|
|
|
|
struct guc_lrc_desc *desc;
|
|
|
|
|
struct intel_context *child;
|
|
|
|
|
|
|
|
|
|
GEM_BUG_ON(!engine->mask);
|
|
|
|
|
|
|
|
|
|
@ -2246,47 +2340,42 @@ static void prepare_context_registration_info(struct intel_context *ce)
|
|
|
|
|
GEM_BUG_ON(i915_gem_object_is_lmem(guc->ct.vma->obj) !=
|
|
|
|
|
i915_gem_object_is_lmem(ce->ring->vma->obj));
|
|
|
|
|
|
|
|
|
|
desc = __get_lrc_desc(guc, ctx_id);
|
|
|
|
|
desc->engine_class = engine_class_to_guc_class(engine->class);
|
|
|
|
|
desc->engine_submit_mask = engine->logical_mask;
|
|
|
|
|
desc->hw_context_desc = ce->lrc.lrca;
|
|
|
|
|
desc->priority = ce->guc_state.prio;
|
|
|
|
|
desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
|
|
|
|
|
guc_context_policy_init(engine, desc);
|
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
|
info->context_idx = ctx_id;
|
|
|
|
|
info->engine_class = engine_class_to_guc_class(engine->class);
|
|
|
|
|
info->engine_submit_mask = engine->logical_mask;
|
|
|
|
|
/*
|
|
|
|
|
* NB: GuC interface supports 64 bit LRCA even though i915/HW
|
|
|
|
|
* only supports 32 bit currently.
|
|
|
|
|
*/
|
|
|
|
|
info->hwlrca_lo = lower_32_bits(ce->lrc.lrca);
|
|
|
|
|
info->hwlrca_hi = upper_32_bits(ce->lrc.lrca);
|
|
|
|
|
info->flags = CONTEXT_REGISTRATION_FLAG_KMD;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If context is a parent, we need to register a process descriptor
|
|
|
|
|
* describing a work queue and register all child contexts.
|
|
|
|
|
*/
|
|
|
|
|
if (intel_context_is_parent(ce)) {
|
|
|
|
|
struct guc_process_desc *pdesc;
|
|
|
|
|
struct guc_sched_wq_desc *wq_desc;
|
|
|
|
|
u64 wq_desc_offset, wq_base_offset;
|
|
|
|
|
|
|
|
|
|
ce->parallel.guc.wqi_tail = 0;
|
|
|
|
|
ce->parallel.guc.wqi_head = 0;
|
|
|
|
|
|
|
|
|
|
desc->process_desc = i915_ggtt_offset(ce->state) +
|
|
|
|
|
__get_parent_scratch_offset(ce);
|
|
|
|
|
desc->wq_addr = i915_ggtt_offset(ce->state) +
|
|
|
|
|
__get_wq_offset(ce);
|
|
|
|
|
desc->wq_size = WQ_SIZE;
|
|
|
|
|
wq_desc_offset = i915_ggtt_offset(ce->state) +
|
|
|
|
|
__get_parent_scratch_offset(ce);
|
|
|
|
|
wq_base_offset = i915_ggtt_offset(ce->state) +
|
|
|
|
|
__get_wq_offset(ce);
|
|
|
|
|
info->wq_desc_lo = lower_32_bits(wq_desc_offset);
|
|
|
|
|
info->wq_desc_hi = upper_32_bits(wq_desc_offset);
|
|
|
|
|
info->wq_base_lo = lower_32_bits(wq_base_offset);
|
|
|
|
|
info->wq_base_hi = upper_32_bits(wq_base_offset);
|
|
|
|
|
info->wq_size = WQ_SIZE;
|
|
|
|
|
|
|
|
|
|
pdesc = __get_process_desc(ce);
|
|
|
|
|
memset(pdesc, 0, sizeof(*(pdesc)));
|
|
|
|
|
pdesc->stage_id = ce->guc_id.id;
|
|
|
|
|
pdesc->wq_base_addr = desc->wq_addr;
|
|
|
|
|
pdesc->wq_size_bytes = desc->wq_size;
|
|
|
|
|
pdesc->wq_status = WQ_STATUS_ACTIVE;
|
|
|
|
|
|
|
|
|
|
for_each_child(ce, child) {
|
|
|
|
|
desc = __get_lrc_desc(guc, child->guc_id.id);
|
|
|
|
|
|
|
|
|
|
desc->engine_class =
|
|
|
|
|
engine_class_to_guc_class(engine->class);
|
|
|
|
|
desc->hw_context_desc = child->lrc.lrca;
|
|
|
|
|
desc->priority = ce->guc_state.prio;
|
|
|
|
|
desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
|
|
|
|
|
guc_context_policy_init(engine, desc);
|
|
|
|
|
}
|
|
|
|
|
wq_desc = __get_wq_desc(ce);
|
|
|
|
|
memset(wq_desc, 0, sizeof(*wq_desc));
|
|
|
|
|
wq_desc->wq_status = WQ_STATUS_ACTIVE;
|
|
|
|
|
|
|
|
|
|
clear_children_join_go_memory(ce);
|
|
|
|
|
}
|
|
|
|
|
@ -2602,13 +2691,11 @@ static void __guc_context_set_preemption_timeout(struct intel_guc *guc,
|
|
|
|
|
u16 guc_id,
|
|
|
|
|
u32 preemption_timeout)
|
|
|
|
|
{
|
|
|
|
|
u32 action[] = {
|
|
|
|
|
INTEL_GUC_ACTION_SET_CONTEXT_PREEMPTION_TIMEOUT,
|
|
|
|
|
guc_id,
|
|
|
|
|
preemption_timeout
|
|
|
|
|
};
|
|
|
|
|
struct context_policy policy;
|
|
|
|
|
|
|
|
|
|
intel_guc_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true);
|
|
|
|
|
__guc_context_policy_start_klv(&policy, guc_id);
|
|
|
|
|
__guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
|
|
|
|
|
__guc_context_set_context_policies(guc, &policy, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void guc_context_ban(struct intel_context *ce, struct i915_request *rq)
|
|
|
|
|
@ -2853,16 +2940,20 @@ static int guc_context_alloc(struct intel_context *ce)
|
|
|
|
|
return lrc_alloc(ce, ce->engine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __guc_context_set_prio(struct intel_guc *guc,
|
|
|
|
|
struct intel_context *ce)
|
|
|
|
|
{
|
|
|
|
|
struct context_policy policy;
|
|
|
|
|
|
|
|
|
|
__guc_context_policy_start_klv(&policy, ce->guc_id.id);
|
|
|
|
|
__guc_context_policy_add_priority(&policy, ce->guc_state.prio);
|
|
|
|
|
__guc_context_set_context_policies(guc, &policy, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void guc_context_set_prio(struct intel_guc *guc,
|
|
|
|
|
struct intel_context *ce,
|
|
|
|
|
u8 prio)
|
|
|
|
|
{
|
|
|
|
|
u32 action[] = {
|
|
|
|
|
INTEL_GUC_ACTION_SET_CONTEXT_PRIORITY,
|
|
|
|
|
ce->guc_id.id,
|
|
|
|
|
prio,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
GEM_BUG_ON(prio < GUC_CLIENT_PRIORITY_KMD_HIGH ||
|
|
|
|
|
prio > GUC_CLIENT_PRIORITY_NORMAL);
|
|
|
|
|
lockdep_assert_held(&ce->guc_state.lock);
|
|
|
|
|
@ -2873,9 +2964,9 @@ static void guc_context_set_prio(struct intel_guc *guc,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true);
|
|
|
|
|
|
|
|
|
|
ce->guc_state.prio = prio;
|
|
|
|
|
__guc_context_set_prio(guc, ce);
|
|
|
|
|
|
|
|
|
|
trace_intel_context_set_prio(ce);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4360,17 +4451,17 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc,
|
|
|
|
|
guc_log_context_priority(p, ce);
|
|
|
|
|
|
|
|
|
|
if (intel_context_is_parent(ce)) {
|
|
|
|
|
struct guc_process_desc *desc = __get_process_desc(ce);
|
|
|
|
|
struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
|
|
|
|
|
struct intel_context *child;
|
|
|
|
|
|
|
|
|
|
drm_printf(p, "\t\tNumber children: %u\n",
|
|
|
|
|
ce->parallel.number_children);
|
|
|
|
|
drm_printf(p, "\t\tWQI Head: %u\n",
|
|
|
|
|
READ_ONCE(desc->head));
|
|
|
|
|
READ_ONCE(wq_desc->head));
|
|
|
|
|
drm_printf(p, "\t\tWQI Tail: %u\n",
|
|
|
|
|
READ_ONCE(desc->tail));
|
|
|
|
|
READ_ONCE(wq_desc->tail));
|
|
|
|
|
drm_printf(p, "\t\tWQI Status: %u\n\n",
|
|
|
|
|
READ_ONCE(desc->wq_status));
|
|
|
|
|
READ_ONCE(wq_desc->wq_status));
|
|
|
|
|
|
|
|
|
|
if (ce->engine->emit_bb_start ==
|
|
|
|
|
emit_bb_start_parent_no_preempt_mid_batch) {
|
|
|
|
|
|