summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinay Kalia <vinaykalia@google.com>2022-06-28 22:55:38 +0000
committerVinay Kalia <vinaykalia@google.com>2022-06-30 19:18:41 +0000
commit9a4469b98e3697f9f8adb531db708e4d673bdc70 (patch)
treea036cc45ef013d158dbe8ff48fb4a064a7f46465
parent1a4c201bca53689c4b10e1b73e4d1c72ffa01df2 (diff)
downloadgchips-9a4469b98e3697f9f8adb531db708e4d673bdc70.tar.gz
bigocean: Ensure that bigocean instance is not destroyed while work is pending
Destroying the instance while hardware is active can lead to faults like SysMMU page faults. bug: 236515139 Signed-off-by: Vinay Kalia <vinaykalia@google.com> Change-Id: I20e037204db4a7a09bdcfbb512f8cddc96800768
-rw-r--r--bigo.c36
-rw-r--r--bigo_prioq.c17
-rw-r--r--bigo_prioq.h2
3 files changed, 44 insertions, 11 deletions
diff --git a/bigo.c b/bigo.c
index 24722ac..f3046a9 100644
--- a/bigo.c
+++ b/bigo.c
@@ -187,17 +187,15 @@ err:
static void bigo_close(struct kref *ref)
{
struct bigo_inst *inst = container_of(ref, struct bigo_inst, refcount);
- struct bigo_core *core = inst->core;
- if (!inst || !core) {
- pr_err("No instance or core\n");
- return;
+ if (inst && inst->core) {
+ clear_job_from_prioq(inst->core, inst);
+ bigo_unmap_all(inst);
+ kfree(inst->job.regs);
+ kfree(inst);
+ bigo_update_qos(inst->core);
+ pr_info("closed instance\n");
}
- bigo_unmap_all(inst);
- kfree(inst->job.regs);
- kfree(inst);
- bigo_update_qos(core);
- pr_info("closed instance\n");
}
static int bigo_release(struct inode *inode, struct file *file)
@@ -342,6 +340,8 @@ static long bigo_unlocked_ioctl(struct file *file, unsigned int cmd,
struct bigo_ioc_mapping mapping;
struct bigo_ioc_frmsize frmsize;
struct bigo_cache_info cinfo;
+ struct bigo_inst *curr_inst;
+ bool found = false;
int rc = 0;
if (_IOC_TYPE(cmd) != BIGO_IOC_MAGIC) {
@@ -356,6 +356,21 @@ static long bigo_unlocked_ioctl(struct file *file, unsigned int cmd,
pr_err("No instance or core\n");
return -EINVAL;
}
+ mutex_lock(&core->lock);
+ list_for_each_entry(curr_inst, &core->instances, list) {
+ if (curr_inst == inst) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ mutex_unlock(&core->lock);
+ pr_err("this instance is invalid");
+ return -EINVAL;
+ }
+ kref_get(&inst->refcount);
+ mutex_unlock(&core->lock);
switch (cmd) {
case BIGO_IOCX_PROCESS:
{
@@ -378,6 +393,7 @@ static long bigo_unlocked_ioctl(struct file *file, unsigned int cmd,
msecs_to_jiffies(JOB_COMPLETE_TIMEOUT_MS * 16));
if (!ret) {
pr_err("timed out waiting for HW: %d\n", rc);
+ clear_job_from_prioq(core, inst);
rc = -ETIMEDOUT;
} else {
rc = (ret > 0) ? 0 : ret;
@@ -452,6 +468,7 @@ static long bigo_unlocked_ioctl(struct file *file, unsigned int cmd,
break;
}
+ kref_put(&inst->refcount, bigo_close);
return rc;
}
@@ -589,7 +606,6 @@ static int bigo_worker_thread(void *data)
done:
job->status = rc;
complete(&inst->job_comp);
- kref_put(&inst->refcount, bigo_close);
}
return 0;
}
diff --git a/bigo_prioq.c b/bigo_prioq.c
index 19da48a..c6e36ef 100644
--- a/bigo_prioq.c
+++ b/bigo_prioq.c
@@ -24,7 +24,6 @@ int enqueue_prioq(struct bigo_core *core, struct bigo_inst *inst)
set_bit(inst->priority, &core->prioq.bitmap);
mutex_unlock(&core->prioq.lock);
- kref_get(&inst->refcount);
wake_up(&core->worker);
return 0;
}
@@ -63,5 +62,21 @@ exit:
return *job != NULL;
}
+void clear_job_from_prioq(struct bigo_core *core, struct bigo_inst *inst)
+{
+ int i;
+ struct bigo_job *curr, *next;
+ struct bigo_inst *curr_inst;
+ mutex_lock(&core->prioq.lock);
+ for (i = 0; i < BO_MAX_PRIO; i++) {
+ list_for_each_entry_safe(curr, next, &core->prioq.queue[i], list) {
+ curr_inst = container_of(curr, struct bigo_inst, job);
+ if (inst == curr_inst)
+ list_del(&curr->list);
+ }
+ }
+ mutex_unlock(&core->prioq.lock);
+}
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ruofei Ma <ruofeim@google.com>");
diff --git a/bigo_prioq.h b/bigo_prioq.h
index 0a49290..77cb337 100644
--- a/bigo_prioq.h
+++ b/bigo_prioq.h
@@ -14,4 +14,6 @@ bool dequeue_prioq(struct bigo_core *core, struct bigo_job **job,
bool *should_stop);
int enqueue_prioq(struct bigo_core *core, struct bigo_inst *inst);
+void clear_job_from_prioq(struct bigo_core *core, struct bigo_inst *inst);
+
#endif //_BIGO_PRIOQ_H_