summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/qcom/Kconfig18
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c12
-rw-r--r--drivers/soc/qcom/glink_spi_xprt.c15
-rw-r--r--drivers/soc/qcom/glink_ssr.c3
-rw-r--r--drivers/soc/qcom/icnss.c45
-rw-r--r--drivers/soc/qcom/kryo-l2-accessors.c6
-rw-r--r--drivers/soc/qcom/memshare/msm_memshare.c16
-rw-r--r--drivers/soc/qcom/msm_smem.c18
-rw-r--r--drivers/soc/qcom/qdsp6v2/Makefile1
-rw-r--r--drivers/soc/qcom/qdsp6v2/cdsp-loader.c273
-rw-r--r--drivers/soc/qcom/service-notifier.c4
-rw-r--r--drivers/soc/qcom/wcd-dsp-glink.c51
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);