guc->submission_state.enabled = false;
}
-static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q, u32 xa_count)
+static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q,
+ int count)
{
int i;
- lockdep_assert_held(&guc->submission_state.lock);
+ mutex_lock(&guc->submission_state.lock);
- for (i = 0; i < xa_count; ++i)
- xa_erase(&guc->submission_state.exec_queue_lookup, q->guc->id + i);
+ for (i = 0; i < count; ++i)
+ xa_erase(&guc->submission_state.exec_queue_lookup,
+ q->guc->id + i);
xe_guc_id_mgr_release_locked(&guc->submission_state.idm,
q->guc->id, q->width);
if (xa_empty(&guc->submission_state.exec_queue_lookup))
wake_up(&guc->submission_state.fini_wq);
+
+ mutex_unlock(&guc->submission_state.lock);
}
static int alloc_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
{
- int ret;
- int i;
-
- /*
- * Must use GFP_NOWAIT as this lock is in the dma fence signalling path,
- * worse case user gets -ENOMEM on engine create and has to try again.
- *
- * FIXME: Have caller pre-alloc or post-alloc /w GFP_KERNEL to prevent
- * failure.
- */
- lockdep_assert_held(&guc->submission_state.lock);
+ int ret, i;
+ mutex_lock(&guc->submission_state.lock);
ret = xe_guc_id_mgr_reserve_locked(&guc->submission_state.idm,
q->width);
+ mutex_unlock(&guc->submission_state.lock);
if (ret < 0)
return ret;
q->guc->id = ret;
+ /* Reserve empty slots. */
for (i = 0; i < q->width; ++i) {
- ret = xa_err(xa_store(&guc->submission_state.exec_queue_lookup,
- q->guc->id + i, q, GFP_NOWAIT));
+ ret = xa_insert(&guc->submission_state.exec_queue_lookup,
+ q->guc->id + i, NULL, GFP_KERNEL);
if (ret)
goto err_release;
}
return ret;
}
+static void publish_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
+{
+ int i;
+
+ lockdep_assert_held(&guc->submission_state.lock);
+
+ for (i = 0; i < q->width; ++i) {
+ void *old;
+
+ old = xa_store(&guc->submission_state.exec_queue_lookup,
+ q->guc->id + i, q, GFP_NOWAIT);
+ XE_WARN_ON(old || xa_is_err(old));
+ }
+}
+
static void release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
{
- mutex_lock(&guc->submission_state.lock);
__release_guc_id(guc, q, q->width);
- mutex_unlock(&guc->submission_state.lock);
}
struct exec_queue_policy {
timeout = (q->vm && xe_vm_in_lr_mode(q->vm)) ? MAX_SCHEDULE_TIMEOUT :
msecs_to_jiffies(q->sched_props.job_timeout_ms);
+ err = alloc_guc_id(guc, q);
+ if (err)
+ goto err_free;
+
+ xe_exec_queue_assign_name(q, q->guc->id);
+
/*
* Use primary queue's submit_wq for all secondary queues of a
* multi queue group. This serialization avoids any locking around
timeout, guc_to_gt(guc)->ordered_wq, NULL,
q->name, gt_to_xe(q->gt)->drm.dev);
if (err)
- goto err_free;
+ goto err_release_id;
sched = &ge->sched;
err = xe_sched_entity_init(&ge->entity, sched);
if (err)
goto err_sched;
- mutex_lock(&guc->submission_state.lock);
-
- err = alloc_guc_id(guc, q);
- if (err)
- goto err_entity;
-
q->entity = &ge->entity;
+ mutex_lock(&guc->submission_state.lock);
if (xe_guc_read_stopped(guc) || vf_recovery(guc))
xe_sched_stop(sched);
-
+ publish_guc_id(guc, q);
mutex_unlock(&guc->submission_state.lock);
- xe_exec_queue_assign_name(q, q->guc->id);
-
/*
* Maintain secondary queues of the multi queue group in a list
* for handling dependencies across the queues in the group.
return 0;
-err_entity:
- mutex_unlock(&guc->submission_state.lock);
- xe_sched_entity_fini(&ge->entity);
err_sched:
xe_sched_fini(&ge->sched);
+err_release_id:
+ release_guc_id(guc, q);
err_free:
kfree(ge);