Loading drivers/soc/qcom/service-locator.c +159 −56 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -288,7 +294,6 @@ out: static int init_service_locator(void) { static bool service_inited; int rc = 0; mutex_lock(&service_init_mutex); Loading Loading @@ -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) { Loading @@ -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, 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; 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); return count; } 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); } static int servloc_open(struct inode *inode, struct file *file) { return single_open(file, (void *)show_servloc, inode->i_private); return count; } 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); include/soc/qcom/service-locator.h +15 −8 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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 Loading @@ -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 Loading
drivers/soc/qcom/service-locator.c +159 −56 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -288,7 +294,6 @@ out: static int init_service_locator(void) { static bool service_inited; int rc = 0; mutex_lock(&service_init_mutex); Loading Loading @@ -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) { Loading @@ -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, 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; 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); return count; } 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); } static int servloc_open(struct inode *inode, struct file *file) { return single_open(file, (void *)show_servloc, inode->i_private); return count; } 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);
include/soc/qcom/service-locator.h +15 −8 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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 Loading @@ -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