From: Avaneesh Kumar Dwivedi Date: Tue, 21 Jun 2016 13:38:10 +0000 (+0530) Subject: soc: qcom: Make service locator call asynchronous X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=077bf167f0d11b42bcc0a6f2a38d1073abc0ef85;p=sagit-ice-cold%2Fkernel_xiaomi_msm8998.git 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 --- diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index e4d235957981..2bc425a437b2 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -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,50 +329,86 @@ 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; } + + pqcd = kmalloc(sizeof(struct pd_qmi_client_data), GFP_KERNEL); + if (!pqcd) { + rc = -ENOMEM; + pr_err("Allocation failed\n"); + goto err; + } + 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) + 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: - return rc; + kfree(data); + kfree(pdqw); } -EXPORT_SYMBOL(get_service_location); int find_subsys(const char *pd_path, char *subsys) { @@ -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); diff --git a/include/soc/qcom/service-locator.h b/include/soc/qcom/service-locator.h index be1a2b431dd9..6bf8ac0be15f 100644 --- a/include/soc/qcom/service-locator.h +++ b/include/soc/qcom/service-locator.h @@ -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)