diff options
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/qcom/Kconfig | 18 | ||||
-rw-r--r-- | drivers/soc/qcom/glink_smem_native_xprt.c | 12 | ||||
-rw-r--r-- | drivers/soc/qcom/glink_spi_xprt.c | 15 | ||||
-rw-r--r-- | drivers/soc/qcom/glink_ssr.c | 3 | ||||
-rw-r--r-- | drivers/soc/qcom/icnss.c | 45 | ||||
-rw-r--r-- | drivers/soc/qcom/kryo-l2-accessors.c | 6 | ||||
-rw-r--r-- | drivers/soc/qcom/memshare/msm_memshare.c | 16 | ||||
-rw-r--r-- | drivers/soc/qcom/msm_smem.c | 18 | ||||
-rw-r--r-- | drivers/soc/qcom/qdsp6v2/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/qcom/qdsp6v2/cdsp-loader.c | 273 | ||||
-rw-r--r-- | drivers/soc/qcom/service-notifier.c | 4 | ||||
-rw-r--r-- | drivers/soc/qcom/wcd-dsp-glink.c | 51 |
12 files changed, 403 insertions, 59 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 281e83d90970..4a315d8f5534 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -178,6 +178,16 @@ config MSM_QMI_INTERFACE to perform QMI message marshaling and transport them over IPC Router. +config MSM_L2_IA_DEBUG + bool "Enable MSM L2 Indirect Access Debug" + depends on DEBUG_FS + default n + help + This option enables L2 indirect access debug + capability. It exposes L2 indirect access + debugfs interface to get/set data, address, + and target cpus. + config MSM_RPM_SMD bool "RPM driver using SMD protocol" help @@ -625,6 +635,14 @@ config MSM_ADSP_LOADER for the platforms that use APRv2. Say M if you want to enable this module. +config MSM_CDSP_LOADER + tristate "CDSP loader support" + help + Enable CDSP image loader. + The CDSP loader brings CDSP out of reset + during boot. + Say M if you want to enable this module. + config MSM_PERFORMANCE tristate "msm_performance driver to support perflock request" help diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 84f346385f18..f2d2aece6846 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 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,7 +51,7 @@ #define RPM_MAX_TOC_ENTRIES 20 #define RPM_FIFO_ADDR_ALIGN_BYTES 3 #define TRACER_PKT_FEATURE BIT(2) - +#define DEFERRED_CMDS_THRESHOLD 25 /** * enum command_types - definition of the types of commands sent/received * @VERSION_CMD: Version and feature set supported @@ -181,6 +181,7 @@ struct mailbox_config_info { * processing. * @deferred_cmds: List of deferred commands that need to be * processed in process context. + * @deferred_cmds_cnt: Number of deferred commands in queue. * @num_pw_states: Size of @ramp_time_us. * @ramp_time_us: Array of ramp times in microseconds where array * index position represents a power state. @@ -218,6 +219,7 @@ struct edge_info { bool in_ssr; spinlock_t rx_lock; struct list_head deferred_cmds; + uint32_t deferred_cmds_cnt; uint32_t num_pw_states; unsigned long *ramp_time_us; struct mailbox_config_info *mailbox; @@ -768,6 +770,7 @@ static bool queue_cmd(struct edge_info *einfo, void *cmd, void *data) d_cmd->param2 = _cmd->param2; d_cmd->data = data; list_add_tail(&d_cmd->list_node, &einfo->deferred_cmds); + einfo->deferred_cmds_cnt++; queue_kthread_work(&einfo->kworker, &einfo->kwork); return true; } @@ -877,10 +880,15 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) if (einfo->in_ssr) break; + if (atomic_ctx && !einfo->intentless && + einfo->deferred_cmds_cnt >= DEFERRED_CMDS_THRESHOLD) + break; + if (!atomic_ctx && !list_empty(&einfo->deferred_cmds)) { d_cmd = list_first_entry(&einfo->deferred_cmds, struct deferred_cmd, list_node); list_del(&d_cmd->list_node); + einfo->deferred_cmds_cnt--; cmd.id = d_cmd->id; cmd.param1 = d_cmd->param1; cmd.param2 = d_cmd->param2; diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c index 47c66c892736..5de6e7eac7ea 100644 --- a/drivers/soc/qcom/glink_spi_xprt.c +++ b/drivers/soc/qcom/glink_spi_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, 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 @@ -789,9 +789,9 @@ static void process_rx_cmd(struct edge_info *einfo, offset += sizeof(*intents); einfo->xprt_if.glink_core_if_ptr-> rx_cmd_remote_rx_intent_put_cookie( - &einfo->xprt_if, cmd->param1, - intents->id, intents->size, - (void *)(intents->addr)); + &einfo->xprt_if, cmd->param1, + intents->id, intents->size, + (void *)(uintptr_t)(intents->addr)); } break; @@ -821,9 +821,10 @@ static void process_rx_cmd(struct edge_info *einfo, case TRACER_PKT_CONT_CMD: rx_descp = (struct rx_desc *)(rx_data + offset); offset += sizeof(*rx_descp); - process_rx_data(einfo, cmd->id, cmd->param1, - cmd->param2, (void *)rx_descp->addr, - rx_descp->size, rx_descp->size_left); + process_rx_data(einfo, cmd->id, cmd->param1, + cmd->param2, + (void *)(uintptr_t)(rx_descp->addr), + rx_descp->size, rx_descp->size_left); break; case TX_SHORT_DATA_CMD: diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c index 4d94e6446505..5e2dbc8b1d20 100644 --- a/drivers/soc/qcom/glink_ssr.c +++ b/drivers/soc/qcom/glink_ssr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 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 @@ -339,6 +339,7 @@ void close_ch_worker(struct work_struct *work) BUG_ON(!ss_info->cb_data); kfree(ss_info->cb_data); + ss_info->cb_data = NULL; kfree(close_work); } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 44d086656a12..16ee98d8e4e0 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -146,7 +146,8 @@ enum icnss_debug_quirks { FW_REJUVENATE_ENABLE, }; -#define ICNSS_QUIRKS_DEFAULT BIT(VBATT_DISABLE) +#define ICNSS_QUIRKS_DEFAULT (BIT(VBATT_DISABLE) | \ + BIT(FW_REJUVENATE_ENABLE)) unsigned long quirks = ICNSS_QUIRKS_DEFAULT; module_param(quirks, ulong, 0600); @@ -1234,7 +1235,7 @@ out: return ret; } -static int wlfw_ini_send_sync_msg(bool enable_fw_log) +static int wlfw_ini_send_sync_msg(uint8_t fw_log_mode) { int ret; struct wlfw_ini_req_msg_v01 req; @@ -1244,14 +1245,14 @@ static int wlfw_ini_send_sync_msg(bool enable_fw_log) if (!penv || !penv->wlfw_clnt) return -ENODEV; - icnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log: %d\n", - penv->state, enable_fw_log); + icnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n", + penv->state, fw_log_mode); memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); req.enablefwlog_valid = 1; - req.enablefwlog = enable_fw_log; + req.enablefwlog = fw_log_mode; req_desc.max_msg_len = WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN; req_desc.msg_id = QMI_WLFW_INI_REQ_V01; @@ -1266,14 +1267,14 @@ static int wlfw_ini_send_sync_msg(bool enable_fw_log) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send INI req failed fw_log: %d, ret: %d\n", - enable_fw_log, ret); + icnss_pr_err("Send INI req failed fw_log_mode: %d, ret: %d\n", + fw_log_mode, ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI INI request rejected, fw_log:%d result:%d error:%d\n", - enable_fw_log, resp.resp.result, resp.resp.error); + icnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n", + fw_log_mode, resp.resp.result, resp.resp.error); ret = resp.resp.result; goto out; } @@ -1469,7 +1470,7 @@ static int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv, if (!test_bit(FW_REJUVENATE_ENABLE, &quirks)) { icnss_pr_dbg("FW rejuvenate is disabled from quirks\n"); - dynamic_feature_mask &= ~QMI_WLFW_FW_REJUVENATE_V01; + return 0; } icnss_pr_dbg("Sending dynamic feature mask request, val 0x%llx, state: 0x%lx\n", @@ -1661,10 +1662,8 @@ static int icnss_driver_event_server_arrive(void *data) if (ret < 0) goto err_setup_msa; - ret = wlfw_dynamic_feature_mask_send_sync_msg(penv, - dynamic_feature_mask); - if (ret < 0) - goto err_setup_msa; + wlfw_dynamic_feature_mask_send_sync_msg(penv, + dynamic_feature_mask); icnss_init_vph_monitor(penv); @@ -2068,7 +2067,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, icnss_pr_info("Modem went down, state: %lx\n", priv->state); - event_data = kzalloc(sizeof(*data), GFP_KERNEL); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); @@ -2143,7 +2142,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data, priv->state); - event_data = kzalloc(sizeof(*data), GFP_KERNEL); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); @@ -2519,21 +2518,19 @@ int icnss_get_soc_info(struct icnss_soc_info *info) } EXPORT_SYMBOL(icnss_get_soc_info); -int icnss_set_fw_debug_mode(bool enable_fw_log) +int icnss_set_fw_log_mode(uint8_t fw_log_mode) { int ret; - icnss_pr_dbg("%s FW debug mode", - enable_fw_log ? "Enalbing" : "Disabling"); + icnss_pr_dbg("FW log mode: %u\n", fw_log_mode); - ret = wlfw_ini_send_sync_msg(enable_fw_log); + ret = wlfw_ini_send_sync_msg(fw_log_mode); if (ret) - icnss_pr_err("Fail to send ini, ret = %d, fw_log: %d\n", ret, - enable_fw_log); - + icnss_pr_err("Fail to send ini, ret = %d, fw_log_mode: %u\n", + ret, fw_log_mode); return ret; } -EXPORT_SYMBOL(icnss_set_fw_debug_mode); +EXPORT_SYMBOL(icnss_set_fw_log_mode); int icnss_athdiag_read(struct device *dev, uint32_t offset, uint32_t mem_type, uint32_t data_len, diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c index a945f9e0ba40..1d81074d7b81 100644 --- a/drivers/soc/qcom/kryo-l2-accessors.c +++ b/drivers/soc/qcom/kryo-l2-accessors.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2017, 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 @@ -80,7 +80,7 @@ u64 get_l2_indirect_reg(u64 reg) } EXPORT_SYMBOL(get_l2_indirect_reg); -#if defined(CONFIG_DEBUG_FS) +#if defined(CONFIG_MSM_L2_IA_DEBUG) static u32 debug_addr; static int debug_target_cpu; @@ -180,4 +180,4 @@ static int l2_ia_debug_init(void) } late_initcall(l2_ia_debug_init); -#endif /* CONFIG_DEBUG_FS */ +#endif /* CONFIG_MSM_L2_IA_DEBUG */ diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index 5726c3277456..76f9ed046120 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, 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 @@ -38,6 +38,7 @@ static void mem_share_svc_recv_msg(struct work_struct *work); static DECLARE_DELAYED_WORK(work_recv_msg, mem_share_svc_recv_msg); static struct workqueue_struct *mem_share_svc_workqueue; static uint64_t bootup_request; +static bool ramdump_event; static void *memshare_ramdump_dev[MAX_CLIENTS]; static struct device *memshare_dev[MAX_CLIENTS]; @@ -337,18 +338,25 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, bootup_request++; break; + case SUBSYS_RAMDUMP_NOTIFICATION: + ramdump_event = 1; + break; + case SUBSYS_BEFORE_POWERUP: - if (_cmd) + if (_cmd) { notifdata = (struct notif_data *) _cmd; - else + } else { + ramdump_event = 0; break; + } - if (notifdata->enable_ramdump) { + if (notifdata->enable_ramdump && ramdump_event) { pr_info("memshare: %s, Ramdump collection is enabled\n", __func__); ret = mem_share_do_ramdump(); if (ret) pr_err("Ramdump collection failed\n"); + ramdump_event = 0; } break; diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index 9c4d89ac704d..d3f44ab75f67 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -1222,12 +1222,18 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d cached heap exceeds size\n", num); BUG(); } - if (hdr->host0 == SMEM_COMM_HOST && hdr->host1 == SMEM_COMM_HOST) { - comm_partition.partition_num = num; - comm_partition.offset = entry->offset; - comm_partition.size_cacheline = entry->size_cacheline; - SMEM_INFO("Common Partition %d offset:%x\n", num, - entry->offset); + if (is_comm_partition) { + if (hdr->host0 == SMEM_COMM_HOST + && hdr->host1 == SMEM_COMM_HOST) { + comm_partition.partition_num = num; + comm_partition.offset = entry->offset; + comm_partition.size_cacheline = entry->size_cacheline; + SMEM_INFO("Common Partition %d offset:%x\n", num, + entry->offset); + } else { + LOG_ERR("Smem Comm partition hosts don't match TOC\n"); + WARN_ON(1); + } return; } if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) { diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile index f3505bab1a34..8c5b0d0e81c8 100644 --- a/drivers/soc/qcom/qdsp6v2/Makefile +++ b/drivers/soc/qcom/qdsp6v2/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o obj-$(CONFIG_MSM_QDSP6_SSR) += audio_ssr.o obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.o obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += audio_notifier.o +obj-$(CONFIG_MSM_CDSP_LOADER) += cdsp-loader.o diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c new file mode 100644 index 000000000000..0b801c5cd7dd --- /dev/null +++ b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2012-2014,2017, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/sysfs.h> +#include <soc/qcom/subsystem_restart.h> + +#define BOOT_CMD 1 +#define IMAGE_UNLOAD_CMD 0 + +#define CDSP_SUBSYS_DOWN 0 +#define CDSP_SUBSYS_LOADED 1 + +static ssize_t cdsp_boot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); + +struct cdsp_loader_private { + void *pil_h; + struct kobject *boot_cdsp_obj; + struct attribute_group *attr_group; +}; + +static struct kobj_attribute cdsp_boot_attribute = + __ATTR(boot, 0220, NULL, cdsp_boot_store); + +static struct attribute *attrs[] = { + &cdsp_boot_attribute.attr, + NULL, +}; + +static u32 cdsp_state = CDSP_SUBSYS_DOWN; +static struct platform_device *cdsp_private; +static void cdsp_loader_unload(struct platform_device *pdev); + +static int cdsp_loader_do(struct platform_device *pdev) +{ + + struct cdsp_loader_private *priv = NULL; + + int rc = 0; + const char *img_name; + + if (!pdev) { + dev_err(&pdev->dev, "%s: Platform device null\n", __func__); + goto fail; + } + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, + "%s: Device tree information missing\n", __func__); + + goto fail; + } + + rc = of_property_read_string(pdev->dev.of_node, + "qcom,proc-img-to-load", + &img_name); + + if (rc) + goto fail; + + if (!strcmp(img_name, "cdsp")) { + /* cdsp_state always returns "0".*/ + if (cdsp_state == CDSP_SUBSYS_DOWN) { + priv = platform_get_drvdata(pdev); + if (!priv) { + dev_err(&pdev->dev, + " %s: Private data get failed\n", __func__); + goto fail; + } + + priv->pil_h = subsystem_get("cdsp"); + if (IS_ERR(priv->pil_h)) { + dev_err(&pdev->dev, "%s: pil get failed,\n", + __func__); + goto fail; + } + + /* Set the state of the CDSP.*/ + cdsp_state = CDSP_SUBSYS_LOADED; + } else if (cdsp_state == CDSP_SUBSYS_LOADED) { + dev_dbg(&pdev->dev, + "%s: CDSP state = %x\n", __func__, cdsp_state); + } + + dev_dbg(&pdev->dev, "%s: CDSP image is loaded\n", __func__); + return rc; + } + +fail: + dev_err(&pdev->dev, "%s: CDSP image loading failed\n", __func__); + return rc; +} + + +static ssize_t cdsp_boot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + int boot = 0, ret = 0; + + ret = sscanf(buf, "%du", &boot); + + if (ret != 1) + pr_debug("%s: invalid arguments for cdsp_loader.\n", __func__); + + if (boot == BOOT_CMD) { + pr_debug("%s: going to call cdsp_loader_do\n", __func__); + cdsp_loader_do(cdsp_private); + } else if (boot == IMAGE_UNLOAD_CMD) { + pr_debug("%s: going to call adsp_unloader\n", __func__); + cdsp_loader_unload(cdsp_private); + } + return count; +} + +static void cdsp_loader_unload(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + + if (!priv) + return; + + if (priv->pil_h) { + dev_dbg(&pdev->dev, "%s: calling subsystem put\n", __func__); + subsystem_put(priv->pil_h); + priv->pil_h = NULL; + } +} + +static int cdsp_loader_init_sysfs(struct platform_device *pdev) +{ + int ret = -EINVAL; + struct cdsp_loader_private *priv = NULL; + + cdsp_private = NULL; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + return ret; + } + + platform_set_drvdata(pdev, priv); + + priv->pil_h = NULL; + priv->boot_cdsp_obj = NULL; + priv->attr_group = devm_kzalloc(&pdev->dev, + sizeof(*(priv->attr_group)), + GFP_KERNEL); + if (!priv->attr_group) { + dev_err(&pdev->dev, "%s: malloc attr_group failed\n", + __func__); + ret = -ENOMEM; + goto error_return; + } + + priv->attr_group->attrs = attrs; + + priv->boot_cdsp_obj = kobject_create_and_add("boot_cdsp", kernel_kobj); + if (!priv->boot_cdsp_obj) { + dev_err(&pdev->dev, "%s: sysfs create and add failed\n", + __func__); + ret = -ENOMEM; + goto error_return; + } + + ret = sysfs_create_group(priv->boot_cdsp_obj, priv->attr_group); + if (ret) { + dev_err(&pdev->dev, "%s: sysfs create group failed %d\n", + __func__, ret); + goto error_return; + } + + cdsp_private = pdev; + + return 0; + +error_return: + + if (priv->boot_cdsp_obj) { + kobject_del(priv->boot_cdsp_obj); + priv->boot_cdsp_obj = NULL; + } + + return ret; +} + +static int cdsp_loader_remove(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + + if (!priv) + return 0; + + if (priv->pil_h) { + subsystem_put(priv->pil_h); + priv->pil_h = NULL; + } + + if (priv->boot_cdsp_obj) { + sysfs_remove_group(priv->boot_cdsp_obj, priv->attr_group); + kobject_del(priv->boot_cdsp_obj); + priv->boot_cdsp_obj = NULL; + } + + return 0; +} + +static int cdsp_loader_probe(struct platform_device *pdev) +{ + int ret = cdsp_loader_init_sysfs(pdev); + + if (ret != 0) { + dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__); + return ret; + } + + return 0; +} + +static const struct of_device_id cdsp_loader_dt_match[] = { + { .compatible = "qcom,cdsp-loader" }, + { } +}; +MODULE_DEVICE_TABLE(of, cdsp_loader_dt_match); + +static struct platform_driver cdsp_loader_driver = { + .driver = { + .name = "cdsp-loader", + .owner = THIS_MODULE, + .of_match_table = cdsp_loader_dt_match, + }, + .probe = cdsp_loader_probe, + .remove = cdsp_loader_remove, +}; + +static int __init cdsp_loader_init(void) +{ + return platform_driver_register(&cdsp_loader_driver); +} +module_init(cdsp_loader_init); + +static void __exit cdsp_loader_exit(void) +{ + platform_driver_unregister(&cdsp_loader_driver); +} +module_exit(cdsp_loader_exit); + +MODULE_DESCRIPTION("CDSP Loader module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index e7307c46a895..8a501d4d0615 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -215,7 +215,7 @@ static void send_ind_ack(struct work_struct *work) if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) pr_err("QMI request failed 0x%x\n", QMI_RESP_BIT_SHIFT(resp.resp.error)); - pr_debug("Indication ACKed for transid %d, service %s, instance %d!\n", + pr_info("Indication ACKed for transid %d, service %s, instance %d!\n", data->ind_msg.transaction_id, data->ind_msg.service_path, data->instance_id); } @@ -240,7 +240,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, return; } - pr_debug("Indication received from %s, state: 0x%x, trans-id: %d\n", + pr_info("Indication received from %s, state: 0x%x, trans-id: %d\n", ind_msg.service_name, ind_msg.curr_state, ind_msg.transaction_id); diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 27e66dc5d204..1ceded4db79f 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, 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 @@ -25,8 +25,10 @@ #include "sound/wcd-dsp-glink.h" #define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink" -#define WDSP_MAX_WRITE_SIZE (512 * 1024) +#define WDSP_MAX_WRITE_SIZE (256 * 1024) #define WDSP_MAX_READ_SIZE (4 * 1024) +#define WDSP_MAX_NO_OF_INTENTS (20) +#define WDSP_MAX_NO_OF_CHANNELS (10) #define MINOR_NUMBER_COUNT 1 #define WDSP_EDGE "wdsp" @@ -532,15 +534,30 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, payload = (u8 *)pkt->payload; no_of_channels = pkt->no_of_channels; + if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) { + dev_info(wpriv->dev, "%s: no_of_channels = %d are limited to %d\n", + __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS); + no_of_channels = WDSP_MAX_NO_OF_CHANNELS; + } ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *), GFP_KERNEL); if (!ch) { ret = -ENOMEM; goto done; } + wpriv->ch = ch; + wpriv->no_of_channels = no_of_channels; for (i = 0; i < no_of_channels; i++) { ch_cfg = (struct wdsp_glink_ch_cfg *)payload; + + if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) { + dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n", + __func__, ch_cfg->no_of_intents); + ret = -EINVAL; + goto err_ch_mem; + } + ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) + (sizeof(u32) * ch_cfg->no_of_intents); ch_size = sizeof(struct wdsp_glink_ch) + @@ -564,8 +581,6 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk); init_waitqueue_head(&ch[i]->ch_connect_wait); } - wpriv->ch = ch; - wpriv->no_of_channels = no_of_channels; INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk); @@ -746,15 +761,17 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, goto done; } - dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count); - - if (count > WDSP_MAX_WRITE_SIZE) { - dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_WRITE_SIZE\n", + if ((count < sizeof(struct wdsp_write_pkt)) || + (count > WDSP_MAX_WRITE_SIZE)) { + dev_err(wpriv->dev, "%s: Invalid count = %zd\n", __func__, count); - count = WDSP_MAX_WRITE_SIZE; + ret = -EINVAL; + goto done; } - tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf); + dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count); + + tx_buf_size = WDSP_MAX_WRITE_SIZE + sizeof(struct wdsp_glink_tx_buf); tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); if (!tx_buf) { ret = -ENOMEM; @@ -772,6 +789,13 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, wpkt = (struct wdsp_write_pkt *)tx_buf->buf; switch (wpkt->pkt_type) { case WDSP_REG_PKT: + if (count <= (sizeof(struct wdsp_write_pkt) + + sizeof(struct wdsp_reg_pkt))) { + dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", + __func__, count); + ret = -EINVAL; + goto free_buf; + } ret = wdsp_glink_ch_info_init(wpriv, (struct wdsp_reg_pkt *)wpkt->payload); if (IS_ERR_VALUE(ret)) @@ -794,6 +818,13 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, kfree(tx_buf); break; case WDSP_CMD_PKT: + if (count <= (sizeof(struct wdsp_write_pkt) + + sizeof(struct wdsp_cmd_pkt))) { + dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", + __func__, count); + ret = -EINVAL; + goto free_buf; + } mutex_lock(&wpriv->glink_mutex); if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) { mutex_unlock(&wpriv->glink_mutex); |