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_exit(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;
|
||||
|
||||
|
@ -61,6 +62,11 @@ struct pd_qmi_data {
|
|||
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);
|
||||
struct pd_qmi_data service_locator;
|
||||
|
||||
|
@ -288,7 +294,6 @@ out:
|
|||
|
||||
static int init_service_locator(void)
|
||||
{
|
||||
static bool service_inited;
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&service_init_mutex);
|
||||
|
@ -324,51 +329,87 @@ static int init_service_locator(void)
|
|||
goto inited;
|
||||
}
|
||||
|
||||
rc = wait_for_completion_timeout(&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;
|
||||
}
|
||||
wait_for_completion(&service_locator.service_available);
|
||||
service_inited = true;
|
||||
mutex_unlock(&service_init_mutex);
|
||||
pr_info("Service locator initialized\n");
|
||||
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:
|
||||
mutex_unlock(&service_init_mutex);
|
||||
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;
|
||||
|
||||
if (!data || !data->client_name || !data->service_name) {
|
||||
if (!locator_nb || !client_name || !service_name) {
|
||||
rc = -EINVAL;
|
||||
pr_err("Invalid input!\n");
|
||||
goto err;
|
||||
}
|
||||
rc = init_service_locator();
|
||||
if (rc) {
|
||||
pr_err("Unable to connect to service locator!, rc = %d\n", rc);
|
||||
|
||||
pqcd = kmalloc(sizeof(struct pd_qmi_client_data), GFP_KERNEL);
|
||||
if (!pqcd) {
|
||||
rc = -ENOMEM;
|
||||
pr_err("Allocation failed\n");
|
||||
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);
|
||||
strlcpy(pqcd->client_name, client_name, ARRAY_SIZE(pqcd->client_name));
|
||||
strlcpy(pqcd->service_name, service_name,
|
||||
ARRAY_SIZE(pqcd->service_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:
|
||||
return rc;
|
||||
}
|
||||
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)
|
||||
{
|
||||
char *start, *end;
|
||||
|
@ -391,75 +432,137 @@ EXPORT_SYMBOL(find_subsys);
|
|||
|
||||
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];
|
||||
struct pd_qmi_client_data *return_data;
|
||||
|
||||
rc = get_service_location(&test_data);
|
||||
if (rc) {
|
||||
seq_printf(f, "Failed to get process domain!, rc = %d\n", rc);
|
||||
return_data = (struct pd_qmi_client_data *)ptr;
|
||||
|
||||
if (opcode) {
|
||||
pr_err("%s: Failed to get process domain!, opcode = %lu\n",
|
||||
__func__, opcode);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
seq_printf(f, "Service Name: %s\tTotal Domains: %d\n",
|
||||
test_data.service_name, test_data.total_domains);
|
||||
for (i = 0; i < test_data.total_domains; i++) {
|
||||
seq_printf(f, "Instance ID: %d\t ",
|
||||
test_data.domain_list[i].instance_id);
|
||||
seq_printf(f, "Domain Name: %s\n",
|
||||
test_data.domain_list[i].name);
|
||||
rc = find_subsys(test_data.domain_list[i].name, subsys);
|
||||
pr_err("Service Name: %s\tTotal Domains: %d\n",
|
||||
return_data->service_name, return_data->total_domains);
|
||||
|
||||
for (i = 0; i < return_data->total_domains; i++) {
|
||||
pr_err("Instance ID: %d\t ",
|
||||
return_data->domain_list[i].instance_id);
|
||||
pr_err("Domain Name: %s\n",
|
||||
return_data->domain_list[i].name);
|
||||
rc = find_subsys(return_data->domain_list[i].name,
|
||||
subsys);
|
||||
if (rc < 0)
|
||||
seq_printf(f, "No valid subsys found for %s!\n",
|
||||
test_data.domain_list[i].name);
|
||||
pr_err("No valid subsys found for %s!\n",
|
||||
return_data->domain_list[i].name);
|
||||
else
|
||||
seq_printf(f, "Subsys: %s\n", subsys);
|
||||
}
|
||||
pr_err("Subsys: %s\n", subsys);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_servloc(struct file *fp, const char __user *buf,
|
||||
size_t count, loff_t *unused)
|
||||
static struct notifier_block pdr_service_nb = {
|
||||
.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)
|
||||
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,
|
||||
(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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.open = servloc_open,
|
||||
.read = seq_read,
|
||||
.write = store_servloc,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
.open = simple_open,
|
||||
.read = servloc_read,
|
||||
.write = servloc_write,
|
||||
};
|
||||
|
||||
static struct dentry *servloc_base_dir;
|
||||
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)
|
||||
{
|
||||
pr_debug("service_locator_status = %d\n", locator_status);
|
||||
test_servloc_file = debugfs_create_file("test_servloc",
|
||||
S_IRUGO | S_IWUSR, NULL, NULL,
|
||||
&servloc_fops);
|
||||
if (!test_servloc_file)
|
||||
pr_err("Could not create test_servloc debugfs entry!");
|
||||
if (servloc_debugfs_init())
|
||||
pr_err("Could not create test_servloc base directory!");
|
||||
if (servloc_debugfs_add())
|
||||
pr_err("Could not create test_servloc node entries!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit service_locator_exit(void)
|
||||
{
|
||||
debugfs_remove(test_servloc_file);
|
||||
servloc_debugfs_exit();
|
||||
}
|
||||
|
||||
module_init(service_locator_init);
|
||||
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
|
||||
* 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;
|
||||
};
|
||||
|
||||
enum service_locator_state {
|
||||
LOCATOR_DOWN = 0x0F,
|
||||
LOCATOR_UP = 0x1F,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MSM_SERVICE_LOCATOR)
|
||||
/*
|
||||
* Use this api to request information regarding the process domains on which
|
||||
* a particular service runs. The client name and the service name inside the
|
||||
* pd_qmi_client_data structure need to be filled in by the client calling the
|
||||
* api. The total domains, db revision and the domain list will be filled in
|
||||
* Use this api to request information regarding the process domains on
|
||||
* which a particular service runs. The client name, the service name
|
||||
* and notifier block pointer need to be provided by client calling the api.
|
||||
* The total domains, db revision and the domain list will be filled in
|
||||
* by the service locator.
|
||||
* 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
|
||||
|
@ -73,9 +79,10 @@ int find_subsys(const char *pd_path, char *subsys);
|
|||
|
||||
#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)
|
||||
|
|
Loading…
Add table
Reference in a new issue