soc: qcom: Make service locator call asynchronous
Make get_service_location() asynchronous, which was a blocking call before. This also means every client will have it's own thread and doesn't need to create thread on their end. CRs-Fixed: 1045353 Change-Id: Ibcccf56d41779b808d1835f62969e3c9365939e8 Signed-off-by: Avaneesh Kumar Dwivedi <akdwived@codeaurora.org>
This commit is contained in:
parent
3f4a2a724e
commit
077bf167f0
2 changed files with 178 additions and 68 deletions
|
@ -48,6 +48,7 @@ module_param_named(enable, locator_status, uint, S_IRUGO | S_IWUSR);
|
||||||
static void service_locator_svc_arrive(struct work_struct *work);
|
static void service_locator_svc_arrive(struct work_struct *work);
|
||||||
static void service_locator_svc_exit(struct work_struct *work);
|
static void service_locator_svc_exit(struct work_struct *work);
|
||||||
static void service_locator_recv_msg(struct work_struct *work);
|
static void service_locator_recv_msg(struct work_struct *work);
|
||||||
|
static void pd_locator_work(struct work_struct *work);
|
||||||
|
|
||||||
struct workqueue_struct *servloc_wq;
|
struct workqueue_struct *servloc_wq;
|
||||||
|
|
||||||
|
@ -61,6 +62,11 @@ struct pd_qmi_data {
|
||||||
struct qmi_handle *clnt_handle;
|
struct qmi_handle *clnt_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct pd_qmi_work {
|
||||||
|
struct work_struct pd_loc_work;
|
||||||
|
struct pd_qmi_client_data *pdc;
|
||||||
|
struct notifier_block *notifier;
|
||||||
|
};
|
||||||
DEFINE_MUTEX(service_init_mutex);
|
DEFINE_MUTEX(service_init_mutex);
|
||||||
struct pd_qmi_data service_locator;
|
struct pd_qmi_data service_locator;
|
||||||
|
|
||||||
|
@ -288,7 +294,6 @@ out:
|
||||||
|
|
||||||
static int init_service_locator(void)
|
static int init_service_locator(void)
|
||||||
{
|
{
|
||||||
static bool service_inited;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
mutex_lock(&service_init_mutex);
|
mutex_lock(&service_init_mutex);
|
||||||
|
@ -324,51 +329,87 @@ static int init_service_locator(void)
|
||||||
goto inited;
|
goto inited;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = wait_for_completion_timeout(&service_locator.service_available,
|
wait_for_completion(&service_locator.service_available);
|
||||||
msecs_to_jiffies(QMI_SERVREG_LOC_SERVER_INITIAL_TIMEOUT));
|
|
||||||
if (!rc) {
|
|
||||||
rc = -ENODEV;
|
|
||||||
mutex_unlock(&service_init_mutex);
|
|
||||||
pr_err("Process domain service locator response timeout!\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
service_inited = true;
|
service_inited = true;
|
||||||
mutex_unlock(&service_init_mutex);
|
mutex_unlock(&service_init_mutex);
|
||||||
pr_info("Service locator initialized\n");
|
pr_info("Service locator initialized\n");
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
|
||||||
qmi_svc_event_notifier_unregister(SERVREG_LOC_SERVICE_ID_V01,
|
|
||||||
SERVREG_LOC_SERVICE_VERS_V01, SERVREG_LOC_SERVICE_INSTANCE_ID,
|
|
||||||
&service_locator.notifier);
|
|
||||||
destroy_workqueue(servloc_wq);
|
|
||||||
inited:
|
inited:
|
||||||
mutex_unlock(&service_init_mutex);
|
mutex_unlock(&service_init_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_service_location(struct pd_qmi_client_data *data)
|
int get_service_location(char *client_name, char *service_name,
|
||||||
|
struct notifier_block *locator_nb)
|
||||||
{
|
{
|
||||||
|
struct pd_qmi_client_data *pqcd;
|
||||||
|
struct pd_qmi_work *pqw;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (!data || !data->client_name || !data->service_name) {
|
if (!locator_nb || !client_name || !service_name) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_err("Invalid input!\n");
|
pr_err("Invalid input!\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
rc = init_service_locator();
|
|
||||||
if (rc) {
|
pqcd = kmalloc(sizeof(struct pd_qmi_client_data), GFP_KERNEL);
|
||||||
pr_err("Unable to connect to service locator!, rc = %d\n", rc);
|
if (!pqcd) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
pr_err("Allocation failed\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
rc = service_locator_send_msg(data);
|
strlcpy(pqcd->client_name, client_name, ARRAY_SIZE(pqcd->client_name));
|
||||||
if (rc)
|
strlcpy(pqcd->service_name, service_name,
|
||||||
pr_err("Failed to get process domains for %s for client %s\n",
|
ARRAY_SIZE(pqcd->service_name));
|
||||||
data->service_name, data->client_name);
|
|
||||||
|
pqw = kmalloc(sizeof(struct pd_qmi_work), GFP_KERNEL);
|
||||||
|
if (!pqw) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
pr_err("Allocation failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pqw->notifier = locator_nb;
|
||||||
|
pqw->pdc = pqcd;
|
||||||
|
|
||||||
|
INIT_WORK(&pqw->pd_loc_work, pd_locator_work);
|
||||||
|
schedule_work(&pqw->pd_loc_work);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_service_location);
|
EXPORT_SYMBOL(get_service_location);
|
||||||
|
|
||||||
|
static void pd_locator_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct pd_qmi_client_data *data;
|
||||||
|
struct pd_qmi_work *pdqw = container_of(work, struct pd_qmi_work,
|
||||||
|
pd_loc_work);
|
||||||
|
|
||||||
|
data = pdqw->pdc;
|
||||||
|
rc = init_service_locator();
|
||||||
|
if (rc) {
|
||||||
|
pr_err("Unable to connect to service locator!, rc = %d\n", rc);
|
||||||
|
pdqw->notifier->notifier_call(pdqw->notifier,
|
||||||
|
LOCATOR_DOWN, NULL);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = service_locator_send_msg(data);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("Failed to get process domains for %s for client %s\n",
|
||||||
|
data->service_name, data->client_name);
|
||||||
|
pdqw->notifier->notifier_call(pdqw->notifier,
|
||||||
|
LOCATOR_DOWN, NULL);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pdqw->notifier->notifier_call(pdqw->notifier, LOCATOR_UP, data);
|
||||||
|
|
||||||
|
err:
|
||||||
|
kfree(data);
|
||||||
|
kfree(pdqw);
|
||||||
|
}
|
||||||
|
|
||||||
int find_subsys(const char *pd_path, char *subsys)
|
int find_subsys(const char *pd_path, char *subsys)
|
||||||
{
|
{
|
||||||
char *start, *end;
|
char *start, *end;
|
||||||
|
@ -391,75 +432,137 @@ EXPORT_SYMBOL(find_subsys);
|
||||||
|
|
||||||
static struct pd_qmi_client_data test_data;
|
static struct pd_qmi_client_data test_data;
|
||||||
|
|
||||||
static ssize_t show_servloc(struct seq_file *f, void *unused)
|
static int servloc_test_pdr_cb(struct notifier_block *this,
|
||||||
|
unsigned long opcode, void *ptr)
|
||||||
{
|
{
|
||||||
int rc = 0, i = 0;
|
int i, rc = 0;
|
||||||
char subsys[QMI_SERVREG_LOC_NAME_LENGTH_V01];
|
char subsys[QMI_SERVREG_LOC_NAME_LENGTH_V01];
|
||||||
|
struct pd_qmi_client_data *return_data;
|
||||||
|
|
||||||
rc = get_service_location(&test_data);
|
return_data = (struct pd_qmi_client_data *)ptr;
|
||||||
if (rc) {
|
|
||||||
seq_printf(f, "Failed to get process domain!, rc = %d\n", rc);
|
if (opcode) {
|
||||||
|
pr_err("%s: Failed to get process domain!, opcode = %lu\n",
|
||||||
|
__func__, opcode);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
seq_printf(f, "Service Name: %s\tTotal Domains: %d\n",
|
pr_err("Service Name: %s\tTotal Domains: %d\n",
|
||||||
test_data.service_name, test_data.total_domains);
|
return_data->service_name, return_data->total_domains);
|
||||||
for (i = 0; i < test_data.total_domains; i++) {
|
|
||||||
seq_printf(f, "Instance ID: %d\t ",
|
for (i = 0; i < return_data->total_domains; i++) {
|
||||||
test_data.domain_list[i].instance_id);
|
pr_err("Instance ID: %d\t ",
|
||||||
seq_printf(f, "Domain Name: %s\n",
|
return_data->domain_list[i].instance_id);
|
||||||
test_data.domain_list[i].name);
|
pr_err("Domain Name: %s\n",
|
||||||
rc = find_subsys(test_data.domain_list[i].name, subsys);
|
return_data->domain_list[i].name);
|
||||||
|
rc = find_subsys(return_data->domain_list[i].name,
|
||||||
|
subsys);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
seq_printf(f, "No valid subsys found for %s!\n",
|
pr_err("No valid subsys found for %s!\n",
|
||||||
test_data.domain_list[i].name);
|
return_data->domain_list[i].name);
|
||||||
else
|
else
|
||||||
seq_printf(f, "Subsys: %s\n", subsys);
|
pr_err("Subsys: %s\n", subsys);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t store_servloc(struct file *fp, const char __user *buf,
|
static struct notifier_block pdr_service_nb = {
|
||||||
size_t count, loff_t *unused)
|
.notifier_call = servloc_test_pdr_cb,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t servloc_read(struct file *filp, char __user *ubuf,
|
||||||
|
size_t cnt, loff_t *ppos)
|
||||||
{
|
{
|
||||||
|
int rc = 0;
|
||||||
|
char *node_name = filp->private_data;
|
||||||
|
|
||||||
|
if (!strcmp(node_name, "test_servloc_get"))
|
||||||
|
rc = get_service_location(test_data.client_name,
|
||||||
|
test_data.service_name, &pdr_service_nb);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t servloc_write(struct file *fp, const char __user *buf,
|
||||||
|
size_t count, loff_t *unused)
|
||||||
|
{
|
||||||
|
char *node_name = fp->private_data;
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
snprintf(test_data.service_name, sizeof(test_data.service_name),
|
if (!strcmp(node_name, "service_name")) {
|
||||||
|
snprintf(test_data.service_name, sizeof(test_data.service_name),
|
||||||
"%.*s", (int) min((size_t)count - 1,
|
"%.*s", (int) min((size_t)count - 1,
|
||||||
(sizeof(test_data.service_name) - 1)), buf);
|
(sizeof(test_data.service_name) - 1)), buf);
|
||||||
|
} else {
|
||||||
|
snprintf(test_data.client_name, sizeof(test_data.client_name),
|
||||||
|
"%.*s", (int) min((size_t)count - 1,
|
||||||
|
(sizeof(test_data.client_name) - 1)), buf);
|
||||||
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int servloc_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
return single_open(file, (void *)show_servloc, inode->i_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations servloc_fops = {
|
static const struct file_operations servloc_fops = {
|
||||||
.open = servloc_open,
|
.open = simple_open,
|
||||||
.read = seq_read,
|
.read = servloc_read,
|
||||||
.write = store_servloc,
|
.write = servloc_write,
|
||||||
.llseek = seq_lseek,
|
|
||||||
.release = seq_release,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dentry *servloc_base_dir;
|
||||||
static struct dentry *test_servloc_file;
|
static struct dentry *test_servloc_file;
|
||||||
|
|
||||||
|
static int __init servloc_debugfs_init(void)
|
||||||
|
{
|
||||||
|
servloc_base_dir = debugfs_create_dir("test_servloc", NULL);
|
||||||
|
return !servloc_base_dir ? -ENOMEM : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void servloc_debugfs_exit(void)
|
||||||
|
{
|
||||||
|
debugfs_remove_recursive(servloc_base_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int servloc_debugfs_add(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!servloc_base_dir)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
test_servloc_file = debugfs_create_file("client_name",
|
||||||
|
S_IRUGO | S_IWUSR, servloc_base_dir,
|
||||||
|
"client_name", &servloc_fops);
|
||||||
|
rc = !test_servloc_file ? -ENOMEM : 0;
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
test_servloc_file = debugfs_create_file("service_name",
|
||||||
|
S_IRUGO | S_IWUSR, servloc_base_dir,
|
||||||
|
"service_name", &servloc_fops);
|
||||||
|
rc = !test_servloc_file ? -ENOMEM : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
test_servloc_file = debugfs_create_file("test_servloc_get",
|
||||||
|
S_IRUGO | S_IWUSR, servloc_base_dir,
|
||||||
|
"test_servloc_get", &servloc_fops);
|
||||||
|
rc = !test_servloc_file ? -ENOMEM : 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init service_locator_init(void)
|
static int __init service_locator_init(void)
|
||||||
{
|
{
|
||||||
pr_debug("service_locator_status = %d\n", locator_status);
|
pr_debug("service_locator_status = %d\n", locator_status);
|
||||||
test_servloc_file = debugfs_create_file("test_servloc",
|
if (servloc_debugfs_init())
|
||||||
S_IRUGO | S_IWUSR, NULL, NULL,
|
pr_err("Could not create test_servloc base directory!");
|
||||||
&servloc_fops);
|
if (servloc_debugfs_add())
|
||||||
if (!test_servloc_file)
|
pr_err("Could not create test_servloc node entries!");
|
||||||
pr_err("Could not create test_servloc debugfs entry!");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit service_locator_exit(void)
|
static void __exit service_locator_exit(void)
|
||||||
{
|
{
|
||||||
debugfs_remove(test_servloc_file);
|
servloc_debugfs_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(service_locator_init);
|
module_init(service_locator_init);
|
||||||
module_exit(service_locator_exit);
|
module_exit(service_locator_exit);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 and
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -51,16 +51,22 @@ struct pd_qmi_client_data {
|
||||||
struct servreg_loc_entry_v01 *domain_list;
|
struct servreg_loc_entry_v01 *domain_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum service_locator_state {
|
||||||
|
LOCATOR_DOWN = 0x0F,
|
||||||
|
LOCATOR_UP = 0x1F,
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_MSM_SERVICE_LOCATOR)
|
#if defined(CONFIG_MSM_SERVICE_LOCATOR)
|
||||||
/*
|
/*
|
||||||
* Use this api to request information regarding the process domains on which
|
* Use this api to request information regarding the process domains on
|
||||||
* a particular service runs. The client name and the service name inside the
|
* which a particular service runs. The client name, the service name
|
||||||
* pd_qmi_client_data structure need to be filled in by the client calling the
|
* and notifier block pointer need to be provided by client calling the api.
|
||||||
* api. The total domains, db revision and the domain list will be filled in
|
* The total domains, db revision and the domain list will be filled in
|
||||||
* by the service locator.
|
* by the service locator.
|
||||||
* Returns 0 on success; otherwise a value < 0 if no valid subsystem is found.
|
* Returns 0 on success; otherwise a value < 0 if no valid subsystem is found.
|
||||||
*/
|
*/
|
||||||
int get_service_location(struct pd_qmi_client_data *data);
|
int get_service_location(char *client_name, char *service_name,
|
||||||
|
struct notifier_block *locator_nb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use this api to request information regarding the subsystem the process
|
* Use this api to request information regarding the subsystem the process
|
||||||
|
@ -73,9 +79,10 @@ int find_subsys(const char *pd_path, char *subsys);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int get_service_location(struct pd_qmi_client_data *data)
|
static inline int get_service_location(char *client_name,
|
||||||
|
char *service_name, struct notifier_block *locator_nb);
|
||||||
{
|
{
|
||||||
return 0;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int find_subsys(const char *pd_path, const char *subsys)
|
static inline int find_subsys(const char *pd_path, const char *subsys)
|
||||||
|
|
Loading…
Add table
Reference in a new issue