static int submit_lock_objects(struct etnaviv_gem_submit *submit, struct ww_acquire_ctx *ticket) { int contended, slow_locked = -1, i, ret = 0; retry: for (i = 0; i < submit->nr_bos; i++) { struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; if (slow_locked == i) slow_locked = -1; contended = i; if (!(submit->bos[i].flags & BO_LOCKED)) { ret = ww_mutex_lock_interruptible(&etnaviv_obj->resv->lock, ticket); if (ret == -EALREADY) DRM_ERROR("BO at index %u already on submit list\n", i); if (ret) goto fail; submit->bos[i].flags |= BO_LOCKED; } } ww_acquire_done(ticket); return 0; fail: for (; i >= 0; i--) submit_unlock_object(submit, i); if (slow_locked > 0) submit_unlock_object(submit, slow_locked); if (ret == -EDEADLK) { struct etnaviv_gem_object *etnaviv_obj; etnaviv_obj = submit->bos[contended].obj; /* we lost out in a seqno race, lock and retry.. */ ret = ww_mutex_lock_slow_interruptible(&etnaviv_obj->resv->lock, ticket); if (!ret) { submit->bos[contended].flags |= BO_LOCKED; slow_locked = contended; goto retry; } } return ret; }
int drm_lock_reservations(struct reservation_object **resvs, unsigned int num_resvs, struct ww_acquire_ctx *ctx) { unsigned int r; struct reservation_object *slow_res = NULL; ww_acquire_init(ctx, &reservation_ww_class); retry: for (r = 0; r < num_resvs; r++) { int ret; /* skip the resv we locked with slow lock */ if (resvs[r] == slow_res) { slow_res = NULL; continue; } ret = ww_mutex_lock(&resvs[r]->lock, ctx); if (ret < 0) { unsigned int slow_r = r; /* * undo all the locks we already done, * in reverse order */ while (r > 0) { r--; ww_mutex_unlock(&resvs[r]->lock); } if (slow_res) ww_mutex_unlock(&slow_res->lock); if (ret == -EDEADLK) { slow_res = resvs[slow_r]; ww_mutex_lock_slow(&slow_res->lock, ctx); goto retry; } ww_acquire_fini(ctx); return ret; } } ww_acquire_done(ctx); return 0; }