diff --git a/drivers/gpu/msm/Kconfig b/drivers/gpu/msm/Kconfig index f6664a9a55ce..7231c36fbd37 100644 --- a/drivers/gpu/msm/Kconfig +++ b/drivers/gpu/msm/Kconfig @@ -61,3 +61,11 @@ config QCOM_KGSL_IDLE_TIMEOUT long the GPU will go into slumber. A higher value will mean that the GPU is powered ON for a longer duration which will have power costs. + +config QCOM_KGSL_CONTEXT_DEBUG + bool "Log kgsl context information for all processes" + depends on QCOM_KGSL + help + When enabled, total number of KGSL contexts, number of attached and + detached contexts are dumped into kernel log for all the processes. + This gives insight about the number of contexts held by each process. diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 5d65fa78c38c..fbe5308fcdcf 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -718,7 +718,7 @@ static void setup_fault_process(struct kgsl_device *device, if (kgsl_mmu_is_perprocess(&device->mmu)) { struct kgsl_process_private *tmp; - spin_lock(&kgsl_driver.proclist_lock); + read_lock(&kgsl_driver.proclist_lock); list_for_each_entry(tmp, &kgsl_driver.process_list, list) { u64 pt_ttbr0; @@ -729,7 +729,7 @@ static void setup_fault_process(struct kgsl_device *device, break; } } - spin_unlock(&kgsl_driver.proclist_lock); + read_unlock(&kgsl_driver.proclist_lock); } done: snapshot->process = process; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 418ad5d7e46a..74da3a44b7fd 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -500,6 +500,52 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) entry->priv = NULL; } +#ifdef CONFIG_QCOM_KGSL_CONTEXT_DEBUG +static void kgsl_context_debug_info(struct kgsl_device *device) +{ + struct kgsl_context *context; + struct kgsl_process_private *p; + int next; + /* + * Keep an interval between consecutive logging to avoid + * flooding the kernel log + */ + static DEFINE_RATELIMIT_STATE(_rs, 10 * HZ, 1); + + if (!__ratelimit(&_rs)) + return; + + dev_info(device->dev, "KGSL active contexts:\n"); + dev_info(device->dev, "pid process total attached detached\n"); + + read_lock(&kgsl_driver.proclist_lock); + read_lock(&device->context_lock); + + list_for_each_entry(p, &kgsl_driver.process_list, list) { + int total_contexts = 0, num_detached = 0; + + idr_for_each_entry(&device->context_idr, context, next) { + if (context->proc_priv == p) { + total_contexts++; + if (kgsl_context_detached(context)) + num_detached++; + } + } + + dev_info(device->dev, "%-8u %-15.15s %-8d %-10d %-10d\n", + pid_nr(p->pid), p->comm, total_contexts, + total_contexts - num_detached, num_detached); + } + + read_unlock(&device->context_lock); + read_unlock(&kgsl_driver.proclist_lock); +} +#else +static void kgsl_context_debug_info(struct kgsl_device *device) +{ +} +#endif + /** * kgsl_context_dump() - dump information about a draw context * @device: KGSL device that owns the context @@ -572,6 +618,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, "Per process context limit reached for pid %u\n", pid_nr(dev_priv->process_priv->pid)); spin_unlock(&proc_priv->ctxt_count_lock); + kgsl_context_debug_info(device); return -ENOSPC; } @@ -591,10 +638,12 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, } if (id < 0) { - if (id == -ENOSPC) + if (id == -ENOSPC) { dev_warn(device->dev, "cannot have more than %zu contexts due to memstore limitation\n", KGSL_MEMSTORE_MAX); + kgsl_context_debug_info(device); + } atomic_dec(&proc_priv->ctxt_count); return id; } @@ -818,7 +867,7 @@ struct kgsl_process_private *kgsl_process_private_find(pid_t pid) { struct kgsl_process_private *p, *private = NULL; - spin_lock(&kgsl_driver.proclist_lock); + read_lock(&kgsl_driver.proclist_lock); list_for_each_entry(p, &kgsl_driver.process_list, list) { if (pid_nr(p->pid) == pid) { if (kgsl_process_private_get(p)) @@ -826,7 +875,7 @@ struct kgsl_process_private *kgsl_process_private_find(pid_t pid) break; } } - spin_unlock(&kgsl_driver.proclist_lock); + read_unlock(&kgsl_driver.proclist_lock); return private; } @@ -936,9 +985,9 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv, kgsl_mmu_detach_pagetable(private->pagetable); /* Remove the process struct from the master list */ - spin_lock(&kgsl_driver.proclist_lock); + write_lock(&kgsl_driver.proclist_lock); list_del(&private->list); - spin_unlock(&kgsl_driver.proclist_lock); + write_unlock(&kgsl_driver.proclist_lock); /* * Unlock the mutex before releasing the memory and the debugfs @@ -974,9 +1023,9 @@ static struct kgsl_process_private *kgsl_process_private_open( kgsl_process_init_sysfs(device, private); kgsl_process_init_debugfs(private); - spin_lock(&kgsl_driver.proclist_lock); + write_lock(&kgsl_driver.proclist_lock); list_add(&private->list, &kgsl_driver.process_list); - spin_unlock(&kgsl_driver.proclist_lock); + write_unlock(&kgsl_driver.proclist_lock); } done: @@ -4057,7 +4106,7 @@ static const struct file_operations kgsl_fops = { struct kgsl_driver kgsl_driver = { .process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex), - .proclist_lock = __SPIN_LOCK_UNLOCKED(kgsl_driver.proclist_lock), + .proclist_lock = __RW_LOCK_UNLOCKED(kgsl_driver.proclist_lock), .ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock), .devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock), /* diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 6c088450ec83..143ef72f89b5 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -125,7 +125,7 @@ struct kgsl_driver { struct list_head pagetable_list; spinlock_t ptlock; struct mutex process_mutex; - spinlock_t proclist_lock; + rwlock_t proclist_lock; struct mutex devlock; struct { atomic_long_t vmalloc; diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 05d05025427b..847682c555af 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -538,7 +538,7 @@ static struct kgsl_process_private *kgsl_iommu_get_process(u64 ptbase) struct kgsl_process_private *p; struct kgsl_iommu_pt *iommu_pt; - spin_lock(&kgsl_driver.proclist_lock); + read_lock(&kgsl_driver.proclist_lock); list_for_each_entry(p, &kgsl_driver.process_list, list) { iommu_pt = p->pagetable->priv; @@ -546,12 +546,12 @@ static struct kgsl_process_private *kgsl_iommu_get_process(u64 ptbase) if (!kgsl_process_private_get(p)) p = NULL; - spin_unlock(&kgsl_driver.proclist_lock); + read_unlock(&kgsl_driver.proclist_lock); return p; } } - spin_unlock(&kgsl_driver.proclist_lock); + read_unlock(&kgsl_driver.proclist_lock); return NULL; }