diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 120fcdc5950a..f68815f3cf1a 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -933,9 +934,15 @@ static struct kgsl_process_private *kgsl_process_private_new( /* Search in the process list */ list_for_each_entry(private, &kgsl_driver.process_list, list) { if (private->pid == cur_pid) { - if (!kgsl_process_private_get(private)) { - private = ERR_PTR(-EINVAL); - } + if (!kgsl_process_private_get(private)) + /* + * This will happen only if refcount is zero + * i.e. destroy is triggered but didn't complete + * yet. Return -EEXIST to indicate caller that + * destroy is pending to allow caller to take + * appropriate action. + */ + private = ERR_PTR(-EEXIST); /* * We need to hold only one reference to the PID for * each process struct to avoid overflowing the @@ -1043,8 +1050,7 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv, kgsl_process_private_put(private); } - -static struct kgsl_process_private *kgsl_process_private_open( +static struct kgsl_process_private *_process_private_open( struct kgsl_device *device) { struct kgsl_process_private *private; @@ -1062,6 +1068,27 @@ done: return private; } +static struct kgsl_process_private *kgsl_process_private_open( + struct kgsl_device *device) +{ + struct kgsl_process_private *private; + int i; + + private = _process_private_open(device); + + /* + * If we get error and error is -EEXIST that means previous process + * private destroy is triggered but didn't complete. Retry creating + * process private after sometime to allow previous destroy to complete. + */ + for (i = 0; (PTR_ERR_OR_ZERO(private) == -EEXIST) && (i < 5); i++) { + usleep_range(10, 100); + private = _process_private_open(device); + } + + return private; +} + int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count) { struct kgsl_process_private *p;