msm: kgsl: Log context information on ENOSPC

There can be maximum of 200 contexts per process and 800
contexts in total. Whenever the limit is exhausted, an
-ENOSPC error is returned. With this change, more information
is logged: total number of contexts, number of attached and
detached contexts for all processes.

Change-Id: If714b5375f1d4ce0551fcb8d156ef5129dbafa6c
Signed-off-by: Kamal Agrawal <kamaagra@codeaurora.org>
This commit is contained in:
Kamal Agrawal 2020-12-08 21:19:26 +05:30
commit d9b8457ddd
5 changed files with 71 additions and 14 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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),
/*

View file

@ -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;

View file

@ -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;
}