tzcom: Implement abort and cleanup of driver
Add a new IOCTL call to the driver to properly abort all threads blocked on wait queues. Updated release call for proper cleanup. CRs-fixed: 303637, 304152 Signed-off-by: Sachin Shah <sachins@codeaurora.org>
This commit is contained in:
committed by
Bryan Huntsman
parent
e0b11453c1
commit
d7e02d4d60
@@ -88,6 +88,9 @@ struct tzcom_data_t {
|
|||||||
wait_queue_head_t cont_cmd_wq;
|
wait_queue_head_t cont_cmd_wq;
|
||||||
int cont_cmd_flag;
|
int cont_cmd_flag;
|
||||||
u32 handled_cmd_svc_instance_id;
|
u32 handled_cmd_svc_instance_id;
|
||||||
|
int abort;
|
||||||
|
wait_queue_head_t abort_wq;
|
||||||
|
atomic_t ioctl_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tzcom_scm_call(const void *cmd_buf, size_t cmd_len,
|
static int tzcom_scm_call(const void *cmd_buf, size_t cmd_len,
|
||||||
@@ -233,6 +236,13 @@ static int tzcom_unregister_service(struct tzcom_data_t *data,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __tzcom_is_cont_cmd(struct tzcom_data_t *data)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = (data->cont_cmd_flag != 0);
|
||||||
|
return ret || data->abort;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* +---------+ +-----+ +-----------------+
|
* +---------+ +-----+ +-----------------+
|
||||||
* | TZCOM | | SCM | | TZCOM_SCHEDULER |
|
* | TZCOM | | SCM | | TZCOM_SCHEDULER |
|
||||||
@@ -409,10 +419,15 @@ static int tzcom_send_cmd(struct tzcom_data_t *data, void __user *argp)
|
|||||||
PDEBUG("waking up next_cmd_wq and "
|
PDEBUG("waking up next_cmd_wq and "
|
||||||
"waiting for cont_cmd_wq");
|
"waiting for cont_cmd_wq");
|
||||||
if (wait_event_interruptible(data->cont_cmd_wq,
|
if (wait_event_interruptible(data->cont_cmd_wq,
|
||||||
data->cont_cmd_flag != 0)) {
|
__tzcom_is_cont_cmd(data))) {
|
||||||
PWARN("Interrupted: exiting send_cmd loop");
|
PWARN("Interrupted: exiting send_cmd loop");
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->abort) {
|
||||||
|
PERR("Aborting driver");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
data->cont_cmd_flag = 0;
|
data->cont_cmd_flag = 0;
|
||||||
cmd.cmd_type = TZ_SCHED_CMD_PENDING;
|
cmd.cmd_type = TZ_SCHED_CMD_PENDING;
|
||||||
mutex_lock(&sb_in_lock);
|
mutex_lock(&sb_in_lock);
|
||||||
@@ -515,6 +530,14 @@ static int __tzcom_copy_cmd(struct tzcom_data_t *data,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __tzcom_is_next_cmd(struct tzcom_data_t *data,
|
||||||
|
struct tzcom_registered_svc_list *svc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = (svc->next_cmd_flag != 0);
|
||||||
|
return ret || data->abort;
|
||||||
|
}
|
||||||
|
|
||||||
static int tzcom_read_next_cmd(struct tzcom_data_t *data, void __user *argp)
|
static int tzcom_read_next_cmd(struct tzcom_data_t *data, void __user *argp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -543,11 +566,16 @@ static int tzcom_read_next_cmd(struct tzcom_data_t *data, void __user *argp)
|
|||||||
while (1) {
|
while (1) {
|
||||||
PDEBUG("Before wait_event next_cmd.");
|
PDEBUG("Before wait_event next_cmd.");
|
||||||
if (wait_event_interruptible(this_svc->next_cmd_wq,
|
if (wait_event_interruptible(this_svc->next_cmd_wq,
|
||||||
this_svc->next_cmd_flag != 0)) {
|
__tzcom_is_next_cmd(data, this_svc))) {
|
||||||
PWARN("Interrupted: exiting wait_next_cmd loop");
|
PWARN("Interrupted: exiting wait_next_cmd loop");
|
||||||
/* woken up for different reason */
|
/* woken up for different reason */
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->abort) {
|
||||||
|
PERR("Aborting driver");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
PDEBUG("After wait_event next_cmd.");
|
PDEBUG("After wait_event next_cmd.");
|
||||||
this_svc->next_cmd_flag = 0;
|
this_svc->next_cmd_flag = 0;
|
||||||
|
|
||||||
@@ -604,6 +632,41 @@ static int tzcom_cont_cmd(struct tzcom_data_t *data, void __user *argp)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tzcom_abort(struct tzcom_data_t *data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
struct tzcom_registered_svc_list *lsvc, *nsvc;
|
||||||
|
if (data->abort) {
|
||||||
|
PERR("Already aborting");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->abort = 1;
|
||||||
|
|
||||||
|
PDEBUG("Waking up cont_cmd_wq");
|
||||||
|
wake_up_all(&data->cont_cmd_wq);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&data->registered_svc_list_lock, flags);
|
||||||
|
PDEBUG("Before waking up service wait queues");
|
||||||
|
list_for_each_entry_safe(lsvc, nsvc,
|
||||||
|
&data->registered_svc_list_head, list) {
|
||||||
|
wake_up_all(&lsvc->next_cmd_wq);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&data->registered_svc_list_lock, flags);
|
||||||
|
|
||||||
|
PDEBUG("ioctl_count before loop: %d", atomic_read(&data->ioctl_count));
|
||||||
|
while (atomic_read(&data->ioctl_count) > 0) {
|
||||||
|
if (wait_event_interruptible(data->abort_wq,
|
||||||
|
atomic_read(&data->ioctl_count) <= 0)) {
|
||||||
|
PERR("Interrupted from abort");
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static long tzcom_ioctl(struct file *file, unsigned cmd,
|
static long tzcom_ioctl(struct file *file, unsigned cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
@@ -611,17 +674,28 @@ static long tzcom_ioctl(struct file *file, unsigned cmd,
|
|||||||
struct tzcom_data_t *tzcom_data = file->private_data;
|
struct tzcom_data_t *tzcom_data = file->private_data;
|
||||||
void __user *argp = (void __user *) arg;
|
void __user *argp = (void __user *) arg;
|
||||||
PDEBUG("enter tzcom_ioctl()");
|
PDEBUG("enter tzcom_ioctl()");
|
||||||
|
if (tzcom_data->abort) {
|
||||||
|
PERR("Aborting tzcom driver");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case TZCOM_IOCTL_REGISTER_SERVICE_REQ: {
|
case TZCOM_IOCTL_REGISTER_SERVICE_REQ: {
|
||||||
PDEBUG("ioctl register_service_req()");
|
PDEBUG("ioctl register_service_req()");
|
||||||
|
atomic_inc(&tzcom_data->ioctl_count);
|
||||||
ret = tzcom_register_service(tzcom_data, argp);
|
ret = tzcom_register_service(tzcom_data, argp);
|
||||||
|
atomic_dec(&tzcom_data->ioctl_count);
|
||||||
|
wake_up_interruptible(&tzcom_data->abort_wq);
|
||||||
if (ret)
|
if (ret)
|
||||||
PERR("failed tzcom_register_service: %d", ret);
|
PERR("failed tzcom_register_service: %d", ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TZCOM_IOCTL_UNREGISTER_SERVICE_REQ: {
|
case TZCOM_IOCTL_UNREGISTER_SERVICE_REQ: {
|
||||||
PDEBUG("ioctl unregister_service_req()");
|
PDEBUG("ioctl unregister_service_req()");
|
||||||
|
atomic_inc(&tzcom_data->ioctl_count);
|
||||||
ret = tzcom_unregister_service(tzcom_data, argp);
|
ret = tzcom_unregister_service(tzcom_data, argp);
|
||||||
|
atomic_dec(&tzcom_data->ioctl_count);
|
||||||
|
wake_up_interruptible(&tzcom_data->abort_wq);
|
||||||
if (ret)
|
if (ret)
|
||||||
PERR("failed tzcom_unregister_service: %d", ret);
|
PERR("failed tzcom_unregister_service: %d", ret);
|
||||||
break;
|
break;
|
||||||
@@ -630,7 +704,10 @@ static long tzcom_ioctl(struct file *file, unsigned cmd,
|
|||||||
PDEBUG("ioctl send_cmd_req()");
|
PDEBUG("ioctl send_cmd_req()");
|
||||||
/* Only one client allowed here at a time */
|
/* Only one client allowed here at a time */
|
||||||
mutex_lock(&send_cmd_lock);
|
mutex_lock(&send_cmd_lock);
|
||||||
|
atomic_inc(&tzcom_data->ioctl_count);
|
||||||
ret = tzcom_send_cmd(tzcom_data, argp);
|
ret = tzcom_send_cmd(tzcom_data, argp);
|
||||||
|
atomic_dec(&tzcom_data->ioctl_count);
|
||||||
|
wake_up_interruptible(&tzcom_data->abort_wq);
|
||||||
mutex_unlock(&send_cmd_lock);
|
mutex_unlock(&send_cmd_lock);
|
||||||
if (ret)
|
if (ret)
|
||||||
PERR("failed tzcom_send_cmd: %d", ret);
|
PERR("failed tzcom_send_cmd: %d", ret);
|
||||||
@@ -638,18 +715,31 @@ static long tzcom_ioctl(struct file *file, unsigned cmd,
|
|||||||
}
|
}
|
||||||
case TZCOM_IOCTL_READ_NEXT_CMD_REQ: {
|
case TZCOM_IOCTL_READ_NEXT_CMD_REQ: {
|
||||||
PDEBUG("ioctl read_next_cmd_req()");
|
PDEBUG("ioctl read_next_cmd_req()");
|
||||||
|
atomic_inc(&tzcom_data->ioctl_count);
|
||||||
ret = tzcom_read_next_cmd(tzcom_data, argp);
|
ret = tzcom_read_next_cmd(tzcom_data, argp);
|
||||||
|
atomic_dec(&tzcom_data->ioctl_count);
|
||||||
|
wake_up_interruptible(&tzcom_data->abort_wq);
|
||||||
if (ret)
|
if (ret)
|
||||||
PERR("failed tzcom_read_next: %d", ret);
|
PERR("failed tzcom_read_next: %d", ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TZCOM_IOCTL_CONTINUE_CMD_REQ: {
|
case TZCOM_IOCTL_CONTINUE_CMD_REQ: {
|
||||||
PDEBUG("ioctl continue_cmd_req()");
|
PDEBUG("ioctl continue_cmd_req()");
|
||||||
|
atomic_inc(&tzcom_data->ioctl_count);
|
||||||
ret = tzcom_cont_cmd(tzcom_data, argp);
|
ret = tzcom_cont_cmd(tzcom_data, argp);
|
||||||
|
atomic_dec(&tzcom_data->ioctl_count);
|
||||||
|
wake_up_interruptible(&tzcom_data->abort_wq);
|
||||||
if (ret)
|
if (ret)
|
||||||
PERR("failed tzcom_cont_cmd: %d", ret);
|
PERR("failed tzcom_cont_cmd: %d", ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TZCOM_IOCTL_ABORT_REQ: {
|
||||||
|
PDEBUG("ioctl abort_req()");
|
||||||
|
ret = tzcom_abort(tzcom_data);
|
||||||
|
if (ret)
|
||||||
|
PERR("failed tzcom_abort: %d", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -754,6 +844,9 @@ static int tzcom_open(struct inode *inode, struct file *file)
|
|||||||
init_waitqueue_head(&tzcom_data->cont_cmd_wq);
|
init_waitqueue_head(&tzcom_data->cont_cmd_wq);
|
||||||
tzcom_data->cont_cmd_flag = 0;
|
tzcom_data->cont_cmd_flag = 0;
|
||||||
tzcom_data->handled_cmd_svc_instance_id = 0;
|
tzcom_data->handled_cmd_svc_instance_id = 0;
|
||||||
|
tzcom_data->abort = 0;
|
||||||
|
init_waitqueue_head(&tzcom_data->abort_wq);
|
||||||
|
atomic_set(&tzcom_data->ioctl_count, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,23 +855,35 @@ static int tzcom_release(struct inode *inode, struct file *file)
|
|||||||
struct tzcom_data_t *tzcom_data = file->private_data;
|
struct tzcom_data_t *tzcom_data = file->private_data;
|
||||||
struct tzcom_callback_list *lcb, *ncb;
|
struct tzcom_callback_list *lcb, *ncb;
|
||||||
struct tzcom_registered_svc_list *lsvc, *nsvc;
|
struct tzcom_registered_svc_list *lsvc, *nsvc;
|
||||||
|
unsigned long flags;
|
||||||
PDEBUG("In here");
|
PDEBUG("In here");
|
||||||
|
|
||||||
wake_up_all(&tzcom_data->cont_cmd_wq);
|
if (!tzcom_data->abort) {
|
||||||
|
PDEBUG("Calling abort");
|
||||||
|
tzcom_abort(tzcom_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDEBUG("Before removing callback list");
|
||||||
|
mutex_lock(&tzcom_data->callback_list_lock);
|
||||||
list_for_each_entry_safe(lcb, ncb,
|
list_for_each_entry_safe(lcb, ncb,
|
||||||
&tzcom_data->callback_list_head, list) {
|
&tzcom_data->callback_list_head, list) {
|
||||||
list_del(&lcb->list);
|
list_del(&lcb->list);
|
||||||
kfree(lcb);
|
kfree(lcb);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&tzcom_data->callback_list_lock);
|
||||||
|
PDEBUG("After removing callback list");
|
||||||
|
|
||||||
|
PDEBUG("Before removing svc list");
|
||||||
|
spin_lock_irqsave(&tzcom_data->registered_svc_list_lock, flags);
|
||||||
list_for_each_entry_safe(lsvc, nsvc,
|
list_for_each_entry_safe(lsvc, nsvc,
|
||||||
&tzcom_data->registered_svc_list_head, list) {
|
&tzcom_data->registered_svc_list_head, list) {
|
||||||
wake_up_all(&lsvc->next_cmd_wq);
|
|
||||||
list_del(&lsvc->list);
|
list_del(&lsvc->list);
|
||||||
kfree(lsvc);
|
kfree(lsvc);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&tzcom_data->registered_svc_list_lock, flags);
|
||||||
|
PDEBUG("After removing svc list");
|
||||||
|
|
||||||
|
PDEBUG("Freeing tzcom data");
|
||||||
kfree(tzcom_data);
|
kfree(tzcom_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,4 +98,6 @@ struct tzcom_cont_cmd_op_req {
|
|||||||
#define TZCOM_IOCTL_CONTINUE_CMD_REQ \
|
#define TZCOM_IOCTL_CONTINUE_CMD_REQ \
|
||||||
_IOWR(TZCOM_IOC_MAGIC, 5, struct tzcom_cont_cmd_op_req)
|
_IOWR(TZCOM_IOC_MAGIC, 5, struct tzcom_cont_cmd_op_req)
|
||||||
|
|
||||||
|
#define TZCOM_IOCTL_ABORT_REQ _IO(TZCOM_IOC_MAGIC, 6)
|
||||||
|
|
||||||
#endif /* __TZCOM_H_ */
|
#endif /* __TZCOM_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user