From 8833b6fd82c41cb1dd8c1f8a97e77b9f462c4edc Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Thu, 3 Sep 2020 21:05:00 -0600 Subject: [PATCH] msm: kgsl: Update internal timestamp when preemption is toggled Say preemption is enabled and a context is bound to ringbuffer-1. It's internal timestamp say is 0x4000. Now if we disable preemption, all the contexts are bound to ringbuffer-0. Now, say the context is going away. The context destroy path will check timestamp 0x4000 which is from the stale ringbuffer, against ringbuffer-0, and its very likely that ringbuffer-0's timestamp is less than 0x4000 which will cause a false context-detach fault. Fix this by updating the context's internal timestamp to the last retired timestamp on the new ringbuffer. Also, toggle preemption only if ringbuffers are completely drained. Change-Id: I674978593b11df3998765017c270c3f0dde6c0a5 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_sysfs.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index c9bd4c7f1cbf..be8ef6db3d74 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -144,16 +144,38 @@ static void change_preemption(struct adreno_device *adreno_dev, void *priv) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_context *context; struct adreno_context *drawctxt; - int id; + struct adreno_ringbuffer *rb; + int id, i, ret; + + /* Make sure all ringbuffers are finished */ + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + ret = adreno_ringbuffer_waittimestamp(rb, rb->timestamp, + 2 * 1000); + if (ret) { + dev_err(device->dev, + "Cannot disable preemption because couldn't idle ringbuffer[%d] ret: %d\n", + rb->id, ret); + return; + } + } change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); - adreno_dev->cur_rb = &(adreno_dev->ringbuffers[0]); + adreno_dev->cur_rb = &adreno_dev->ringbuffers[0]; + adreno_dev->next_rb = NULL; + adreno_dev->prev_rb = NULL; /* Update the ringbuffer for each draw context */ write_lock(&device->context_lock); idr_for_each_entry(&device->context_idr, context, id) { drawctxt = ADRENO_CONTEXT(context); drawctxt->rb = adreno_ctx_get_rb(adreno_dev, drawctxt); + + /* + * Make sure context destroy checks against the correct + * ringbuffer's timestamp. + */ + adreno_rb_readtimestamp(adreno_dev, drawctxt->rb, + KGSL_TIMESTAMP_RETIRED, &drawctxt->internal_timestamp); } write_unlock(&device->context_lock); }