summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c1
-rw-r--r--drivers/soc/qcom/glink_spi_xprt.c78
-rw-r--r--drivers/soc/qcom/icnss.c135
-rw-r--r--drivers/soc/qcom/jtagv8-etm.c13
-rw-r--r--drivers/soc/qcom/jtagv8.c7
-rw-r--r--drivers/soc/qcom/peripheral-loader.c108
-rw-r--r--drivers/soc/qcom/peripheral-loader.h28
-rw-r--r--drivers/soc/qcom/pil-msa.c10
-rw-r--r--drivers/soc/qcom/qbt1000.c101
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr.c1
-rw-r--r--drivers/soc/qcom/qdsp6v2/msm_audio_ion.c120
-rw-r--r--drivers/soc/qcom/qpnp-haptic.c14
-rw-r--r--drivers/soc/qcom/ramdump.c133
-rw-r--r--drivers/soc/qcom/scm.c95
-rw-r--r--drivers/soc/qcom/scm_qcpe.c23
-rw-r--r--drivers/soc/qcom/secure_buffer.c5
-rw-r--r--drivers/soc/qcom/socinfo.c12
-rw-r--r--drivers/soc/qcom/spcom.c62
-rw-r--r--drivers/soc/qcom/watchdog_v2.c11
19 files changed, 751 insertions, 206 deletions
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 37193bbb23b7..042108d4035b 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -2242,6 +2242,7 @@ static int parse_qos_dt_params(struct device_node *node,
einfo->ramp_time_us[i] = arr32[i];
rc = 0;
+ kfree(arr32);
return rc;
invalid_key:
diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c
index 6794c30605d7..a94c4c909a40 100644
--- a/drivers/soc/qcom/glink_spi_xprt.c
+++ b/drivers/soc/qcom/glink_spi_xprt.c
@@ -121,6 +121,8 @@ struct glink_cmpnt {
* @tx_fifo_write_reg_addr: Address of the TX FIFO Write Index Register.
* @rx_fifo_read_reg_addr: Address of the RX FIFO Read Index Register.
* @rx_fifo_write_reg_addr: Address of the RX FIFO Write Index Register.
+ * @tx_fifo_write: Internal write index for TX FIFO.
+ * @rx_fifo_read: Internal read index for RX FIFO.
* @kwork: Work to be executed when receiving data.
* @kworker: Handle to the entity processing @kwork.
* @task: Handle to the task context that runs @kworker.
@@ -158,6 +160,8 @@ struct edge_info {
unsigned int tx_fifo_write_reg_addr;
unsigned int rx_fifo_read_reg_addr;
unsigned int rx_fifo_write_reg_addr;
+ uint32_t tx_fifo_write;
+ uint32_t rx_fifo_read;
struct kthread_work kwork;
struct kthread_worker kworker;
@@ -368,6 +372,19 @@ static int glink_spi_xprt_write_avail(struct edge_info *einfo)
int write_avail;
int ret;
+ if (unlikely(!einfo->tx_fifo_start)) {
+ ret = glink_spi_xprt_reg_read(einfo,
+ einfo->tx_fifo_write_reg_addr, &einfo->tx_fifo_write);
+ if (ret < 0) {
+ pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
+ __func__, ret, einfo->xprt_cfg.edge,
+ einfo->tx_fifo_write_reg_addr);
+ return 0;
+ }
+ einfo->tx_fifo_start = einfo->tx_fifo_write;
+ }
+ write_id = einfo->tx_fifo_write;
+
ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_read_reg_addr,
&read_id);
if (ret < 0) {
@@ -377,21 +394,9 @@ static int glink_spi_xprt_write_avail(struct edge_info *einfo)
return 0;
}
- ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr,
- &write_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->tx_fifo_write_reg_addr);
- return 0;
- }
-
if (!read_id || !write_id)
return 0;
- if (unlikely(!einfo->tx_fifo_start))
- einfo->tx_fifo_start = write_id;
-
if (read_id > write_id)
write_avail = read_id - write_id;
else
@@ -421,14 +426,18 @@ static int glink_spi_xprt_read_avail(struct edge_info *einfo)
int read_avail;
int ret;
- ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr,
- &read_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->rx_fifo_read_reg_addr);
- return 0;
+ if (unlikely(!einfo->rx_fifo_start)) {
+ ret = glink_spi_xprt_reg_read(einfo,
+ einfo->rx_fifo_read_reg_addr, &einfo->rx_fifo_read);
+ if (ret < 0) {
+ pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
+ __func__, ret, einfo->xprt_cfg.edge,
+ einfo->rx_fifo_read_reg_addr);
+ return 0;
+ }
+ einfo->rx_fifo_start = einfo->rx_fifo_read;
}
+ read_id = einfo->rx_fifo_read;
ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_write_reg_addr,
&write_id);
@@ -442,9 +451,6 @@ static int glink_spi_xprt_read_avail(struct edge_info *einfo)
if (!read_id || !write_id)
return 0;
- if (unlikely(!einfo->rx_fifo_start))
- einfo->rx_fifo_start = read_id;
-
if (read_id <= write_id)
read_avail = write_id - read_id;
else
@@ -471,15 +477,7 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst,
uint32_t offset = 0;
int ret;
- ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr,
- &read_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->rx_fifo_read_reg_addr);
- return ret;
- }
-
+ read_id = einfo->rx_fifo_read;
do {
if ((read_id + size_to_read) >=
(einfo->rx_fifo_start + einfo->fifo_size))
@@ -504,6 +502,9 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst,
pr_err("%s: Error %d writing %s rx_fifo_read_reg_addr %d\n",
__func__, ret, einfo->xprt_cfg.edge,
einfo->rx_fifo_read_reg_addr);
+ else
+ einfo->rx_fifo_read = read_id;
+
return ret;
}
@@ -526,15 +527,7 @@ static int glink_spi_xprt_tx_cmd_safe(struct edge_info *einfo, void *src,
uint32_t offset = 0;
int ret;
- ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr,
- &write_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->tx_fifo_write_reg_addr);
- return ret;
- }
-
+ write_id = einfo->tx_fifo_write;
do {
if ((write_id + size_to_write) >=
(einfo->tx_fifo_start + einfo->fifo_size))
@@ -559,6 +552,9 @@ static int glink_spi_xprt_tx_cmd_safe(struct edge_info *einfo, void *src,
pr_err("%s: Error %d writing %s tx_fifo_write_reg_addr %d\n",
__func__, ret, einfo->xprt_cfg.edge,
einfo->tx_fifo_write_reg_addr);
+ else
+ einfo->tx_fifo_write = write_id;
+
return ret;
}
@@ -1236,6 +1232,8 @@ static int ssr(struct glink_transport_if *if_ptr)
einfo->tx_blocked_signal_sent = false;
einfo->tx_fifo_start = 0;
einfo->rx_fifo_start = 0;
+ einfo->tx_fifo_write = 0;
+ einfo->rx_fifo_read = 0;
einfo->fifo_size = DEFAULT_FIFO_SIZE;
einfo->xprt_if.glink_core_if_ptr->link_down(&einfo->xprt_if);
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index c74cd3b814cd..2326487302fd 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -84,35 +84,59 @@ module_param(qmi_timeout, ulong, 0600);
} while (0)
#define icnss_pr_err(_fmt, ...) do { \
- pr_err(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ printk("%s" pr_fmt(_fmt), KERN_ERR, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
#define icnss_pr_warn(_fmt, ...) do { \
- pr_warn(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("WRN: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ printk("%s" pr_fmt(_fmt), KERN_WARNING, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
#define icnss_pr_info(_fmt, ...) do { \
- pr_info(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("INF: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ printk("%s" pr_fmt(_fmt), KERN_INFO, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
+#if defined(CONFIG_DYNAMIC_DEBUG)
#define icnss_pr_dbg(_fmt, ...) do { \
- pr_debug(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_string("DBG: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ pr_debug(_fmt, ##__VA_ARGS__); \
+ icnss_ipc_log_string(pr_fmt(_fmt), ##__VA_ARGS__); \
} while (0)
#define icnss_pr_vdbg(_fmt, ...) do { \
- pr_debug(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
+ pr_debug(_fmt, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string(pr_fmt(_fmt), ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
+#define icnss_pr_dbg(_fmt, ...) do { \
+ printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define icnss_pr_vdbg(_fmt, ...) do { \
+ printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+#else
+#define icnss_pr_dbg(_fmt, ...) do { \
+ no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
} while (0)
+#define icnss_pr_vdbg(_fmt, ...) do { \
+ no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \
+ ##__VA_ARGS__); \
+ } while (0)
+#endif
+
#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do { \
if (!(_condition)) { \
@@ -128,6 +152,8 @@ bool ignore_qmi_timeout;
#define ICNSS_QMI_ASSERT() do { } while (0)
#endif
+#define QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED 0x77
+
enum icnss_debug_quirks {
HW_ALWAYS_ON,
HW_DEBUG_ENABLE,
@@ -242,7 +268,6 @@ struct icnss_msa_perm_list_t msa_perm_list[ICNSS_MSA_PERM_MAX] = {
struct icnss_event_pd_service_down_data {
bool crashed;
bool fw_rejuvenate;
- bool wdog_bite;
};
struct icnss_driver_event {
@@ -267,9 +292,9 @@ enum icnss_driver_state {
ICNSS_PD_RESTART,
ICNSS_MSA0_ASSIGNED,
ICNSS_WLFW_EXISTS,
- ICNSS_WDOG_BITE,
ICNSS_SHUTDOWN_DONE,
ICNSS_HOST_TRIGGERED_PDR,
+ ICNSS_FW_DOWN,
};
struct ce_irq_list {
@@ -480,10 +505,10 @@ static int icnss_assign_msa_perm(struct icnss_mem_region_info
phys_addr_t addr;
u32 size;
u32 i = 0;
- u32 source_vmids[ICNSS_MAX_VMIDS];
+ u32 source_vmids[ICNSS_MAX_VMIDS] = {0};
u32 source_nelems;
- u32 dest_vmids[ICNSS_MAX_VMIDS];
- u32 dest_perms[ICNSS_MAX_VMIDS];
+ u32 dest_vmids[ICNSS_MAX_VMIDS] = {0};
+ u32 dest_perms[ICNSS_MAX_VMIDS] = {0};
u32 dest_nelems;
enum icnss_msa_perm cur_perm = mem_region->perm;
struct icnss_msa_perm_list_t *new_perm_list, *old_perm_list;
@@ -711,7 +736,7 @@ static int wlfw_vbatt_send_sync_msg(struct icnss_priv *priv,
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI vbatt request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
priv->stats.vbatt_resp++;
@@ -1195,7 +1220,7 @@ static int wlfw_msa_mem_info_send_sync_msg(void)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI MSA Mem info request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
@@ -1267,7 +1292,7 @@ static int wlfw_msa_ready_send_sync_msg(void)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI MSA ready request rejected: result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.msa_ready_resp++;
@@ -1330,7 +1355,7 @@ static int wlfw_ind_register_send_sync_msg(void)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI indication register request rejected, resut:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.ind_register_resp++;
@@ -1377,7 +1402,9 @@ static int wlfw_cap_send_sync_msg(void)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI capability request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
+ if (resp.resp.error == QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED)
+ icnss_pr_err("RF card Not present");
goto out;
}
@@ -1460,7 +1487,7 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI mode request rejected, mode:%d result:%d error:%d\n",
mode, resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.mode_resp++;
@@ -1510,7 +1537,7 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI config request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.cfg_resp++;
@@ -1563,7 +1590,7 @@ static int wlfw_ini_send_sync_msg(uint8_t fw_log_mode)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
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;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.ini_resp++;
@@ -1623,7 +1650,7 @@ static int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv,
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI athdiag read request rejected, result:%d error:%d\n",
resp->resp.result, resp->resp.error);
- ret = resp->resp.result;
+ ret = -resp->resp.result;
goto out;
}
@@ -1689,7 +1716,7 @@ static int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv,
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI athdiag write request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
out:
@@ -1784,7 +1811,7 @@ static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv)
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI rejuvenate ack request rejected, result:%d error %d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
priv->stats.rejuvenate_ack_resp++;
@@ -1845,7 +1872,7 @@ static int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv,
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI dynamic feature mask request rejected, result:%d error %d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
@@ -1924,6 +1951,12 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
icnss_pr_dbg("Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len);
+ if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+ icnss_pr_dbg("FW down, ignoring 0x%x, state: 0x%lx\n",
+ msg_id, penv->state);
+ return;
+ }
+
switch (msg_id) {
case QMI_WLFW_FW_READY_IND_V01:
icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_READY_IND,
@@ -1970,6 +2003,7 @@ static int icnss_driver_event_server_arrive(void *data)
return -ENODEV;
set_bit(ICNSS_WLFW_EXISTS, &penv->state);
+ clear_bit(ICNSS_FW_DOWN, &penv->state);
penv->wlfw_clnt = qmi_handle_create(icnss_qmi_wlfw_clnt_notify, penv);
if (!penv->wlfw_clnt) {
@@ -2125,10 +2159,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
icnss_pm_relax(priv);
- if (test_bit(ICNSS_WDOG_BITE, &priv->state)) {
- icnss_call_driver_shutdown(priv);
- clear_bit(ICNSS_WDOG_BITE, &priv->state);
- }
+ icnss_call_driver_shutdown(priv);
clear_bit(ICNSS_PD_RESTART, &priv->state);
@@ -2278,8 +2309,7 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
static int icnss_fw_crashed(struct icnss_priv *priv,
struct icnss_event_pd_service_down_data *event_data)
{
- icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n",
- priv->state, event_data->wdog_bite);
+ icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state);
set_bit(ICNSS_PD_RESTART, &priv->state);
clear_bit(ICNSS_FW_READY, &priv->state);
@@ -2289,17 +2319,9 @@ static int icnss_fw_crashed(struct icnss_priv *priv,
if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
- if (event_data->wdog_bite) {
- set_bit(ICNSS_WDOG_BITE, &priv->state);
- goto out;
- }
-
- icnss_call_driver_shutdown(priv);
-
if (event_data->fw_rejuvenate)
wlfw_rejuvenate_ack_send_sync_msg(priv);
-out:
return 0;
}
@@ -2482,6 +2504,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
+ set_bit(ICNSS_FW_DOWN, &priv->state);
+
if (notif->crashed)
priv->stats.recovery.root_pd_crash++;
else
@@ -2496,9 +2520,6 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
event_data->crashed = notif->crashed;
- if (notif->crashed == CRASH_STATUS_WDOG_BITE)
- event_data->wdog_bite = true;
-
fw_down_data.crashed = !!notif->crashed;
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
@@ -2579,21 +2600,21 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
if (event_data == NULL)
return notifier_from_errno(-ENOMEM);
+ event_data->crashed = true;
+
if (state == NULL) {
- event_data->crashed = true;
priv->stats.recovery.root_pd_crash++;
goto event_post;
}
switch (*state) {
case ROOT_PD_WDOG_BITE:
- event_data->crashed = true;
- event_data->wdog_bite = true;
priv->stats.recovery.root_pd_crash++;
break;
case ROOT_PD_SHUTDOWN:
cause = ICNSS_ROOT_PD_SHUTDOWN;
priv->stats.recovery.root_pd_shutdown++;
+ event_data->crashed = false;
break;
case USER_PD_STATE_CHANGE:
if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) {
@@ -2605,7 +2626,6 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
}
break;
default:
- event_data->crashed = true;
priv->stats.recovery.root_pd_crash++;
break;
}
@@ -2613,6 +2633,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n",
*state, priv->state, icnss_pdr_cause[cause]);
event_post:
+ set_bit(ICNSS_FW_DOWN, &priv->state);
icnss_ignore_qmi_timeout(true);
clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
@@ -2621,6 +2642,8 @@ event_post:
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
done:
+ if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
+ clear_bit(ICNSS_FW_DOWN, &priv->state);
return NOTIFY_OK;
}
@@ -3808,15 +3831,15 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_WLFW_EXISTS:
seq_puts(s, "WLAN FW EXISTS");
continue;
- case ICNSS_WDOG_BITE:
- seq_puts(s, "MODEM WDOG BITE");
- continue;
case ICNSS_SHUTDOWN_DONE:
seq_puts(s, "SHUTDOWN DONE");
continue;
case ICNSS_HOST_TRIGGERED_PDR:
seq_puts(s, "HOST TRIGGERED PDR");
continue;
+ case ICNSS_FW_DOWN:
+ seq_puts(s, "FW DOWN");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/soc/qcom/jtagv8-etm.c b/drivers/soc/qcom/jtagv8-etm.c
index 2c15f7896c82..63432e6026e2 100644
--- a/drivers/soc/qcom/jtagv8-etm.c
+++ b/drivers/soc/qcom/jtagv8-etm.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
@@ -1503,6 +1503,7 @@ static int jtag_mm_etm_callback(struct notifier_block *nfb,
void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ u64 version = 0;
if (!etm[cpu])
goto out;
@@ -1524,8 +1525,8 @@ static int jtag_mm_etm_callback(struct notifier_block *nfb,
goto out;
}
if (etm_arch_supported(etm[cpu]->arch)) {
- if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) <
- TZ_DBG_ETM_VER)
+ if (!scm_get_feat_version(TZ_DBG_ETM_FEAT_ID, &version)
+ && version < TZ_DBG_ETM_VER)
etm[cpu]->save_restore_enabled = true;
else
pr_info("etm save-restore supported by TZ\n");
@@ -1615,8 +1616,10 @@ static int jtag_mm_etm_probe(struct platform_device *pdev, uint32_t cpu)
mutex_lock(&etmdata->mutex);
if (etmdata->init && !etmdata->enable) {
if (etm_arch_supported(etmdata->arch)) {
- if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) <
- TZ_DBG_ETM_VER)
+ u64 version = 0;
+
+ if (!scm_get_feat_version(TZ_DBG_ETM_FEAT_ID, &version)
+ && (version < TZ_DBG_ETM_VER))
etmdata->save_restore_enabled = true;
else
pr_info("etm save-restore supported by TZ\n");
diff --git a/drivers/soc/qcom/jtagv8.c b/drivers/soc/qcom/jtagv8.c
index 94c391eabaea..f09ccce8f9c3 100644
--- a/drivers/soc/qcom/jtagv8.c
+++ b/drivers/soc/qcom/jtagv8.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
@@ -974,7 +974,7 @@ static struct notifier_block jtag_cpu_pm_notifier = {
static int __init msm_jtag_dbg_init(void)
{
int ret;
-
+ u64 version = 0;
if (msm_jtag_fuse_apps_access_disabled())
return -EPERM;
@@ -982,7 +982,8 @@ static int __init msm_jtag_dbg_init(void)
dbg_init_arch_data();
if (dbg_arch_supported(dbg.arch)) {
- if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) {
+ if (!scm_get_feat_version(TZ_DBG_ETM_FEAT_ID, &version) &&
+ version < TZ_DBG_ETM_VER) {
dbg.save_restore_enabled = true;
} else {
pr_info("dbg save-restore supported by TZ\n");
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index ace2bc4f30b6..d77a12626330 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -56,7 +56,9 @@
#endif
#define PIL_NUM_DESC 10
+#define NUM_OF_ENCRYPTED_KEY 3
static void __iomem *pil_info_base;
+static void __iomem *pil_minidump_base;
/**
* proxy_timeout - Override for proxy vote timeouts
@@ -80,6 +82,18 @@ struct pil_mdt {
};
/**
+ * struct boot_minidump_smem_region - Representation of SMEM TOC
+ * @region_name: Name of modem segment to be dumped
+ * @region_base_address: Where segment start from
+ * @region_size: Size of segment to be dumped
+ */
+struct boot_minidump_smem_region {
+ char region_name[16];
+ u64 region_base_address;
+ u64 region_size;
+};
+
+/**
* struct pil_seg - memory map representing one segment
* @next: points to next seg mentor NULL if last segment
* @paddr: physical start address of segment
@@ -133,11 +147,67 @@ struct pil_priv {
phys_addr_t region_end;
void *region;
struct pil_image_info __iomem *info;
+ struct md_ssr_ss_info __iomem *minidump;
+ int minidump_id;
int id;
int unvoted_flag;
size_t region_size;
};
+static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
+{
+ struct boot_minidump_smem_region __iomem *region_info;
+ struct ramdump_segment *ramdump_segs, *s;
+ struct pil_priv *priv = desc->priv;
+ void __iomem *subsys_smem_base;
+ void __iomem *offset;
+ int ss_mdump_seg_cnt;
+ int ret, i;
+
+ memcpy(&offset, &priv->minidump, sizeof(priv->minidump));
+ offset = offset + sizeof(priv->minidump->md_ss_smem_regions_baseptr);
+ /* There are 3 encryption keys which also need to be dumped */
+ ss_mdump_seg_cnt = readb_relaxed(offset) +
+ NUM_OF_ENCRYPTED_KEY;
+
+ subsys_smem_base = ioremap(__raw_readl(priv->minidump),
+ ss_mdump_seg_cnt * sizeof(*region_info));
+ region_info =
+ (struct boot_minidump_smem_region __iomem *)subsys_smem_base;
+ ramdump_segs = kcalloc(ss_mdump_seg_cnt,
+ sizeof(*ramdump_segs), GFP_KERNEL);
+ if (!ramdump_segs)
+ return -ENOMEM;
+
+ if (desc->subsys_vmid > 0)
+ ret = pil_assign_mem_to_linux(desc, priv->region_start,
+ (priv->region_end - priv->region_start));
+
+ s = ramdump_segs;
+ for (i = 0; i < ss_mdump_seg_cnt; i++) {
+ memcpy(&offset, &region_info, sizeof(region_info));
+ memcpy(&s->name, &region_info, sizeof(region_info));
+ offset = offset + sizeof(region_info->region_name);
+ s->address = __raw_readl(offset);
+ offset = offset + sizeof(region_info->region_base_address);
+ s->size = __raw_readl(offset);
+ s++;
+ region_info++;
+ }
+ ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);
+ kfree(ramdump_segs);
+ if (ret)
+ pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
+ __func__, desc->name, ret);
+ writel_relaxed(0, &priv->minidump->md_ss_smem_regions_baseptr);
+ writeb_relaxed(1, &priv->minidump->md_ss_ssr_cause);
+
+ if (desc->subsys_vmid > 0)
+ ret = pil_assign_mem_to_subsys(desc, priv->region_start,
+ (priv->region_end - priv->region_start));
+ return ret;
+}
+
/**
* pil_do_ramdump() - Ramdump an image
* @desc: descriptor from pil_desc_init()
@@ -153,6 +223,9 @@ int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
int count = 0, ret;
struct ramdump_segment *ramdump_segs, *s;
+ if (priv->minidump && (__raw_readl(priv->minidump) > 0))
+ return pil_do_minidump(desc, ramdump_dev);
+
list_for_each_entry(seg, &priv->segs, list)
count++;
@@ -1014,9 +1087,10 @@ bool is_timeout_disabled(void)
int pil_desc_init(struct pil_desc *desc)
{
struct pil_priv *priv;
- int ret;
void __iomem *addr;
+ int ret, ss_imem_offset_mdump;
char buf[sizeof(priv->info->name)];
+ struct device_node *ofnode = desc->dev->of_node;
if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
"Invalid proxy voting. Ignoring\n"))
@@ -1039,6 +1113,22 @@ int pil_desc_init(struct pil_desc *desc)
strncpy(buf, desc->name, sizeof(buf));
__iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4);
}
+ if (of_property_read_u32(ofnode, "qcom,minidump-id",
+ &priv->minidump_id))
+ pr_debug("minidump-id not found for %s\n", desc->name);
+ else {
+ ss_imem_offset_mdump =
+ sizeof(struct md_ssr_ss_info) * priv->minidump_id;
+ if (pil_minidump_base) {
+ /* Add 0x4 to get start of struct md_ssr_ss_info base
+ * from struct md_ssr_toc for any subsystem,
+ * struct md_ssr_ss_info is actually the pointer
+ * of ToC in smem for any subsystem.
+ */
+ addr = pil_minidump_base + ss_imem_offset_mdump + 0x4;
+ priv->minidump = (struct md_ssr_ss_info __iomem *)addr;
+ }
+ }
ret = pil_parse_devicetree(desc);
if (ret)
@@ -1148,6 +1238,20 @@ static int __init msm_pil_init(void)
for (i = 0; i < resource_size(&res)/sizeof(u32); i++)
writel_relaxed(0, pil_info_base + (i * sizeof(u32)));
+ np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-minidump");
+ if (!np) {
+ pr_warn("pil: failed to find qcom,msm-imem-minidump node\n");
+ goto out;
+ } else {
+ pil_minidump_base = of_iomap(np, 0);
+ if (!pil_minidump_base) {
+ pr_err("unable to map pil minidump imem offset\n");
+ goto out;
+ }
+ }
+ for (i = 0; i < sizeof(struct md_ssr_toc)/sizeof(u32); i++)
+ writel_relaxed(0, pil_minidump_base + (i * sizeof(u32)));
+ writel_relaxed(1, pil_minidump_base);
out:
return register_pm_notifier(&pil_pm_notifier);
}
@@ -1158,6 +1262,8 @@ static void __exit msm_pil_exit(void)
unregister_pm_notifier(&pil_pm_notifier);
if (pil_info_base)
iounmap(pil_info_base);
+ if (pil_minidump_base)
+ iounmap(pil_minidump_base);
}
module_exit(msm_pil_exit);
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index 0cd2aeae1edd..908ab78124f7 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -74,6 +74,34 @@ struct pil_image_info {
__le32 size;
} __attribute__((__packed__));
+#define MAX_NUM_OF_SS 3
+
+/**
+ * struct md_ssr_ss_info - Info in imem about smem ToC
+ * @md_ss_smem_regions_baseptr: Start physical address of SMEM TOC
+ * @md_ss_num_of_regions: number of segments that need to be dumped
+ * @md_ss_encryption_status: status of encryption of segments
+ * @md_ss_ssr_cause: ssr cause enum
+ */
+struct md_ssr_ss_info {
+ u32 md_ss_smem_regions_baseptr;
+ u8 md_ss_num_of_regions;
+ u8 md_ss_encryption_status;
+ u8 md_ss_ssr_cause;
+ u8 reserved;
+};
+
+/**
+ * struct md_ssr_toc - Wrapper of struct md_ssr_ss_info
+ * @md_ssr_toc_init: flag to indicate to MSS SW about imem init done
+ * @md_ssr_ss: Instance of struct md_ssr_ss_info for a subsystem
+ */
+struct md_ssr_toc /* Shared IMEM ToC struct */
+{
+ u32 md_ssr_toc_init;
+ struct md_ssr_ss_info md_ssr_ss[MAX_NUM_OF_SS];
+};
+
/**
* struct pil_reset_ops - PIL operations
* @init_image: prepare an image for authentication
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 5fcb0f95733c..4bea034f0bdd 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -78,7 +78,8 @@
#define MSS_MAGIC 0XAABADEAD
/* CX_IPEAK Parameters */
#define CX_IPEAK_MSS BIT(5)
-
+/* Timeout value for MBA boot when minidump is enabled */
+#define MBA_ENCRYPTION_TIMEOUT 3000
enum scm_cmd {
PAS_MEM_SETUP_CMD = 2,
};
@@ -244,7 +245,12 @@ static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
struct device *dev = drv->desc.dev;
int ret;
u32 status;
- u64 val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
+ u64 val;
+
+ if (of_property_read_bool(dev->of_node, "qcom,minidump-id"))
+ pbl_mba_boot_timeout_ms = MBA_ENCRYPTION_TIMEOUT;
+
+ val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
/* Wait for PBL completion. */
ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index d14e82415c5a..7a62c2e36da8 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -12,6 +12,7 @@
#define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
@@ -105,10 +106,14 @@ struct qbt1000_drvdata {
*/
struct fw_ipc_cmd {
uint32_t status;
+ uint32_t numMsgs;
+ uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE];
+};
+
+struct fw_ipc_header {
uint32_t msg_type;
uint32_t msg_len;
uint32_t resp_needed;
- uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE];
};
/*
@@ -352,7 +357,14 @@ static int qbt1000_open(struct inode *inode, struct file *file)
*/
static int qbt1000_release(struct inode *inode, struct file *file)
{
- struct qbt1000_drvdata *drvdata = file->private_data;
+ struct qbt1000_drvdata *drvdata;
+
+ if (!file->private_data) {
+ pr_err("Null pointer passed in file->private_data");
+ return -EINVAL;
+ }
+
+ drvdata = file->private_data;
atomic_inc(&drvdata->available);
return 0;
@@ -374,6 +386,11 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
void __user *priv_arg = (void __user *)arg;
struct qbt1000_drvdata *drvdata;
+ if (!file->private_data) {
+ pr_err("Null pointer passed in file->private_data");
+ return -EINVAL;
+ }
+
drvdata = file->private_data;
if (IS_ERR(priv_arg)) {
@@ -789,6 +806,8 @@ static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata)
BIT_MASK(KEY_HOMEPAGE);
drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |=
BIT_MASK(KEY_CAMERA);
+ drvdata->in_dev->keybit[BIT_WORD(KEY_VOLUMEDOWN)] |=
+ BIT_MASK(KEY_VOLUMEDOWN);
drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |=
BIT_MASK(KEY_POWER);
@@ -917,11 +936,14 @@ static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id)
*/
static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
{
+ uint8_t *msg_buffer;
struct fw_ipc_cmd *rx_cmd;
- int i;
+ struct fw_ipc_header *header;
+ int i, j;
uint32_t rxipc = FP_APP_CMD_RX_IPC;
struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
int rc = 0;
+ uint32_t retry_count = 10;
pm_stay_awake(drvdata->dev);
@@ -933,18 +955,25 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
goto end;
}
- pr_debug("firmware interrupt received (irq %d)\n", irq);
-
if (!drvdata->fp_app_handle)
goto end;
- /*
- * send the TZ command to fetch the message from firmware
- * TZ will process the message if it can
- */
- rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0,
- &rxipc, sizeof(rxipc),
- (void *)&rx_cmd, sizeof(*rx_cmd));
+ while (retry_count > 0) {
+ /*
+ * send the TZ command to fetch the message from firmware
+ * TZ will process the message if it can
+ */
+ rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0,
+ &rxipc, sizeof(rxipc),
+ (void *)&rx_cmd, sizeof(*rx_cmd));
+ if (rc < 0) {
+ msleep(50); /* sleep for 50ms before retry */
+ retry_count -= 1;
+ continue;
+ } else {
+ break;
+ }
+ }
if (rc < 0) {
pr_err("failure sending tz cmd %d\n", rxipc);
@@ -956,29 +985,35 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
goto end;
}
- /*
- * given the IPC message type, search for a corresponding event for the
- * driver client. If found, add to the events FIFO
- */
- for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
- if (g_msg_to_event[i].msg_type == rx_cmd->msg_type) {
- enum qbt1000_fw_event ev = g_msg_to_event[i].fw_event;
- struct fw_event_desc fw_ev_desc;
-
- mutex_lock(&drvdata->fw_events_mutex);
- pr_debug("fw events: add %d\n", (int) ev);
- fw_ev_desc.ev = ev;
-
- if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
- pr_err("fw events: fifo full, drop event %d\n",
- (int) ev);
-
- mutex_unlock(&drvdata->fw_events_mutex);
- wake_up_interruptible(&drvdata->read_wait_queue);
- break;
+ msg_buffer = rx_cmd->msg_data;
+
+ for (j = 0; j < rx_cmd->numMsgs; j++) {
+ header = (struct fw_ipc_header *) msg_buffer;
+ /*
+ * given the IPC message type, search for a corresponding event
+ * for the driver client. If found, add to the events FIFO
+ */
+ for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
+ if (g_msg_to_event[i].msg_type == header->msg_type) {
+ enum qbt1000_fw_event ev =
+ g_msg_to_event[i].fw_event;
+ struct fw_event_desc fw_ev_desc;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ pr_debug("fw events: add %d\n", (int) ev);
+ fw_ev_desc.ev = ev;
+
+ if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
+ pr_err("fw events: fifo full, drop event %d\n",
+ (int) ev);
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ break;
+ }
}
+ msg_buffer += sizeof(*header) + header->msg_len;
}
-
+ wake_up_interruptible(&drvdata->read_wait_queue);
end:
mutex_unlock(&drvdata->mutex);
pm_relax(drvdata->dev);
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index eca992ec17e4..3791169ec0ac 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -820,6 +820,7 @@ static void dispatch_event(unsigned long code, uint16_t proc)
uint16_t clnt;
int i, j;
+ memset(&data, 0, sizeof(data));
data.opcode = RESET_EVENTS;
data.reset_event = code;
diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
index 83e3775ed533..9e61ff1ebfcc 100644
--- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
+++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -29,6 +29,7 @@
#include <linux/export.h>
#include <linux/qcom_iommu.h>
#include <asm/dma-iommu.h>
+#include <soc/qcom/secure_buffer.h>
#define MSM_AUDIO_ION_PROBED (1 << 0)
@@ -178,6 +179,123 @@ err:
}
EXPORT_SYMBOL(msm_audio_ion_alloc);
+static int msm_audio_hyp_assign(ion_phys_addr_t *paddr, size_t *pa_len,
+ u8 assign_type)
+{
+ int srcVM[1] = {VMID_HLOS};
+ int destVM[1] = {VMID_CP_ADSP_SHARED};
+ int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
+ int ret = 0;
+
+ switch (assign_type) {
+ case HLOS_TO_ADSP:
+ srcVM[0] = VMID_HLOS;
+ destVM[0] = VMID_CP_ADSP_SHARED;
+ break;
+ case ADSP_TO_HLOS:
+ srcVM[0] = VMID_CP_ADSP_SHARED;
+ destVM[0] = VMID_HLOS;
+ break;
+ default:
+ pr_err("%s: Invalid assign type = %d\n", __func__, assign_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = hyp_assign_phys(*paddr, *pa_len, srcVM, 1, destVM, destVMperm, 1);
+ if (ret)
+ pr_err("%s: hyp_assign_phys failed for type %d, rc = %d\n",
+ __func__, assign_type, ret);
+done:
+ return ret;
+}
+
+int msm_audio_ion_phys_free(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *paddr,
+ size_t *pa_len, u8 assign_type)
+{
+ int ret;
+
+ if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
+ pr_debug("%s:probe is not done, deferred\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
+ if (!client || !handle || !paddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = ion_phys(client, handle, paddr, pa_len);
+ if (ret) {
+ pr_err("%s: could not get physical address for handle, ret = %d\n",
+ __func__, ret);
+ goto err_ion_handle;
+ }
+
+ ret = msm_audio_hyp_assign(paddr, pa_len, assign_type);
+
+err_ion_handle:
+ ion_free(client, handle);
+ ion_client_destroy(client);
+
+ return ret;
+}
+
+int msm_audio_ion_phys_assign(const char *name, struct ion_client **client,
+ struct ion_handle **handle, int fd,
+ ion_phys_addr_t *paddr,
+ size_t *pa_len, u8 assign_type)
+{
+ int ret;
+
+ if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
+ pr_debug("%s:probe is not done, deferred\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
+ if (!name || !client || !handle || !paddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+
+ *client = msm_audio_ion_client_create(name);
+ if (IS_ERR_OR_NULL((void *)(*client))) {
+ pr_err("%s: ION create client failed\n", __func__);
+ return -EINVAL;
+ }
+
+ *handle = ion_import_dma_buf(*client, fd);
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
+ pr_err("%s: ion import dma buffer failed\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_destroy_client;
+ }
+
+ ret = ion_phys(*client, *handle, paddr, pa_len);
+ if (ret) {
+ pr_err("%s: could not get physical address for handle, ret = %d\n",
+ __func__, ret);
+ goto err_ion_handle;
+ }
+
+ ret = msm_audio_hyp_assign(paddr, pa_len, assign_type);
+
+ return ret;
+
+err_ion_handle:
+ ion_free(*client, *handle);
+
+err_destroy_client:
+ ion_client_destroy(*client);
+ *client = NULL;
+ *handle = NULL;
+
+ return ret;
+}
+
int msm_audio_ion_import(const char *name, struct ion_client **client,
struct ion_handle **handle, int fd,
unsigned long *ionflag, size_t bufsz,
diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c
index d86f8671705a..38cc86963181 100644
--- a/drivers/soc/qcom/qpnp-haptic.c
+++ b/drivers/soc/qcom/qpnp-haptic.c
@@ -2233,13 +2233,23 @@ static void qpnp_hap_td_enable(struct timed_output_dev *dev, int time_ms)
timed_dev);
int rc;
- if (time_ms <= 0)
+ if (time_ms < 0)
return;
+ mutex_lock(&hap->lock);
+
+ if (time_ms == 0) {
+ /* disable haptics */
+ hrtimer_cancel(&hap->hap_timer);
+ hap->state = 0;
+ schedule_work(&hap->work);
+ mutex_unlock(&hap->lock);
+ return;
+ }
+
if (time_ms < 10)
time_ms = 10;
- mutex_lock(&hap->lock);
if (is_sw_lra_auto_resonance_control(hap))
hrtimer_cancel(&hap->auto_res_err_poll_timer);
diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c
index c712ed392b0b..c8353dc8a43a 100644
--- a/drivers/soc/qcom/ramdump.c
+++ b/drivers/soc/qcom/ramdump.c
@@ -29,6 +29,8 @@
#include <linux/of.h>
#define RAMDUMP_WAIT_MSECS 120000
+#define MAX_STRTBL_SIZE 512
+#define MAX_NAME_LENGTH 16
struct ramdump_device {
char name[256];
@@ -391,12 +393,143 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments,
}
+static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr)
+{
+ return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff);
+}
+
+static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx)
+{
+ return &elf_sheader(hdr)[idx];
+}
+
+static inline char *elf_str_table(struct elfhdr *hdr)
+{
+ if (hdr->e_shstrndx == SHN_UNDEF)
+ return NULL;
+ return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset;
+}
+
+static inline unsigned int set_section_name(const char *name,
+ struct elfhdr *ehdr)
+{
+ char *strtab = elf_str_table(ehdr);
+ static int strtable_idx = 1;
+ int idx, ret = 0;
+
+ idx = strtable_idx;
+ if ((strtab == NULL) || (name == NULL))
+ return 0;
+
+ ret = idx;
+ idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH);
+ strtable_idx = idx + 1;
+
+ return ret;
+}
+
+static int _do_minidump(void *handle, struct ramdump_segment *segments,
+ int nsegments)
+{
+ int ret, i;
+ struct ramdump_device *rd_dev = (struct ramdump_device *)handle;
+ struct elfhdr *ehdr;
+ struct elf_shdr *shdr;
+ unsigned long offset, strtbl_off;
+
+ if (!rd_dev->consumer_present) {
+ pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name);
+ return -EPIPE;
+ }
+
+ rd_dev->segments = segments;
+ rd_dev->nsegments = nsegments;
+
+ rd_dev->elfcore_size = sizeof(*ehdr) +
+ (sizeof(*shdr) * (nsegments + 2)) + MAX_STRTBL_SIZE;
+ ehdr = kzalloc(rd_dev->elfcore_size, GFP_KERNEL);
+ rd_dev->elfcore_buf = (char *)ehdr;
+ if (!rd_dev->elfcore_buf)
+ return -ENOMEM;
+
+ memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+ ehdr->e_ident[EI_CLASS] = ELF_CLASS;
+ ehdr->e_ident[EI_DATA] = ELF_DATA;
+ ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr->e_ident[EI_OSABI] = ELF_OSABI;
+ ehdr->e_type = ET_CORE;
+ ehdr->e_machine = ELF_ARCH;
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_ehsize = sizeof(*ehdr);
+ ehdr->e_shoff = sizeof(*ehdr);
+ ehdr->e_shentsize = sizeof(*shdr);
+ ehdr->e_shstrndx = 1;
+
+
+ offset = rd_dev->elfcore_size;
+ shdr = (struct elf_shdr *)(ehdr + 1);
+ strtbl_off = sizeof(*ehdr) + sizeof(*shdr) * (nsegments + 2);
+ shdr++;
+ shdr->sh_type = SHT_STRTAB;
+ shdr->sh_offset = (elf_addr_t)strtbl_off;
+ shdr->sh_size = MAX_STRTBL_SIZE;
+ shdr->sh_entsize = 0;
+ shdr->sh_flags = 0;
+ shdr->sh_name = set_section_name("STR_TBL", ehdr);
+ shdr++;
+
+ for (i = 0; i < nsegments; i++, shdr++) {
+ /* Update elf header */
+ shdr->sh_type = SHT_PROGBITS;
+ shdr->sh_name = set_section_name(segments[i].name, ehdr);
+ shdr->sh_addr = (elf_addr_t)segments[i].address;
+ shdr->sh_size = segments[i].size;
+ shdr->sh_flags = SHF_WRITE;
+ shdr->sh_offset = offset;
+ shdr->sh_entsize = 0;
+ offset += shdr->sh_size;
+ }
+ ehdr->e_shnum = nsegments + 2;
+
+ rd_dev->data_ready = 1;
+ rd_dev->ramdump_status = -1;
+
+ reinit_completion(&rd_dev->ramdump_complete);
+
+ /* Tell userspace that the data is ready */
+ wake_up(&rd_dev->dump_wait_q);
+
+ /* Wait (with a timeout) to let the ramdump complete */
+ ret = wait_for_completion_timeout(&rd_dev->ramdump_complete,
+ msecs_to_jiffies(RAMDUMP_WAIT_MSECS));
+
+ if (!ret) {
+ pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
+ rd_dev->name);
+ ret = -EPIPE;
+ } else {
+ ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
+ }
+
+ rd_dev->data_ready = 0;
+ rd_dev->elfcore_size = 0;
+ kfree(rd_dev->elfcore_buf);
+ rd_dev->elfcore_buf = NULL;
+ return ret;
+}
+
int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
{
return _do_ramdump(handle, segments, nsegments, false);
}
EXPORT_SYMBOL(do_ramdump);
+int do_minidump(void *handle, struct ramdump_segment *segments, int nsegments)
+{
+ return _do_minidump(handle, segments, nsegments);
+}
+EXPORT_SYMBOL(do_minidump);
+
int
do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
{
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 31de6e5c173c..43e2e4d17648 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -397,18 +397,22 @@ static int __scm_call_armv8_64(u64 x0, u64 x1, u64 x2, u64 x3, u64 x4, u64 x5,
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
@@ -442,18 +446,22 @@ static int __scm_call_armv8_32(u32 w0, u32 w1, u32 w2, u32 w3, u32 w4, u32 w5,
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
@@ -490,18 +498,22 @@ static int __scm_call_armv8_32(u32 w0, u32 w1, u32 w2, u32 w3, u32 w4, u32 w5,
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
- __asmeq("%4", R0_STR)
- __asmeq("%5", R1_STR)
- __asmeq("%6", R2_STR)
- __asmeq("%7", R3_STR)
- __asmeq("%8", R4_STR)
- __asmeq("%9", R5_STR)
- __asmeq("%10", R6_STR)
+ __asmeq("%4", R4_STR)
+ __asmeq("%5", R5_STR)
+ __asmeq("%6", R6_STR)
+ __asmeq("%7", R0_STR)
+ __asmeq("%8", R1_STR)
+ __asmeq("%9", R2_STR)
+ __asmeq("%10", R3_STR)
+ __asmeq("%11", R4_STR)
+ __asmeq("%12", R5_STR)
+ __asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
- : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+ : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
+ "=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6));
@@ -1117,54 +1129,55 @@ int scm_is_call_available(u32 svc_id, u32 cmd_id)
ret = scm_call(SCM_SVC_INFO, IS_CALL_AVAIL_CMD, &svc_cmd,
sizeof(svc_cmd), &ret_val, sizeof(ret_val));
- if (ret)
- return ret;
+ if (!ret && ret_val)
+ return 1;
+ else
+ return 0;
- return ret_val;
}
desc.arginfo = SCM_ARGS(1);
desc.args[0] = SCM_SIP_FNID(svc_id, cmd_id);
+ desc.ret[0] = 0;
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, IS_CALL_AVAIL_CMD), &desc);
- if (ret)
- return ret;
+ if (!ret && desc.ret[0])
+ return 1;
+ else
+ return 0;
- return desc.ret[0];
}
EXPORT_SYMBOL(scm_is_call_available);
#define GET_FEAT_VERSION_CMD 3
-int scm_get_feat_version(u32 feat)
+int scm_get_feat_version(u32 feat, u64 *scm_ret)
{
struct scm_desc desc = {0};
int ret;
if (!is_scm_armv8()) {
if (scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) {
- u32 version;
- if (!scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat,
- sizeof(feat), &version, sizeof(version)))
- return version;
+ ret = scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD,
+ &feat, sizeof(feat), scm_ret, sizeof(*scm_ret));
+ return ret;
}
- return 0;
}
ret = scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD);
if (ret <= 0)
- return 0;
+ return -EAGAIN;
desc.args[0] = feat;
desc.arginfo = SCM_ARGS(1);
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, GET_FEAT_VERSION_CMD),
&desc);
- if (!ret)
- return desc.ret[0];
- return 0;
+ *scm_ret = desc.ret[0];
+
+ return ret;
}
EXPORT_SYMBOL(scm_get_feat_version);
#define RESTORE_SEC_CFG 2
-int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret)
+int scm_restore_sec_cfg(u32 device_id, u32 spare, u64 *scm_ret)
{
struct scm_desc desc = {0};
int ret;
diff --git a/drivers/soc/qcom/scm_qcpe.c b/drivers/soc/qcom/scm_qcpe.c
index 54a978157bda..1e369c73e34b 100644
--- a/drivers/soc/qcom/scm_qcpe.c
+++ b/drivers/soc/qcom/scm_qcpe.c
@@ -27,7 +27,7 @@
#define CREATE_TRACE_POINTS
#include <trace/events/scm.h>
-#include <uapi/linux/habmm.h>
+#include <linux/habmm.h>
#define SCM_ENOMEM (-5)
#define SCM_EOPNOTSUPP (-4)
@@ -218,8 +218,8 @@ static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc)
if (!opened) {
ret = habmm_socket_open(&handle, MM_QCPE_VM1, 0, 0);
- if (ret != HAB_OK) {
- pr_err("scm_call2: habmm_socket_open failed with ret = %d",
+ if (ret) {
+ pr_err("scm_call_qcpe: habmm_socket_open failed with ret = %d",
ret);
return ret;
}
@@ -235,23 +235,30 @@ static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc)
smc_params.sid = 0;
ret = habmm_socket_send(handle, &smc_params, sizeof(smc_params), 0);
- if (ret != HAB_OK)
+ if (ret)
return ret;
size_bytes = sizeof(smc_params);
+ memset(&smc_params, 0x0, sizeof(smc_params));
ret = habmm_socket_recv(handle, &smc_params, &size_bytes, 0, 0);
- if (ret != HAB_OK)
+ if (ret)
return ret;
+ if (size_bytes != sizeof(smc_params)) {
+ pr_err("scm_call_qcpe: expected size: %lu, actual=%u\n",
+ sizeof(smc_params), size_bytes);
+ return SCM_ERROR;
+ }
+
desc->ret[0] = smc_params.x1;
desc->ret[1] = smc_params.x2;
desc->ret[2] = smc_params.x3;
- pr_info("scm_call_qcpe: OUT: 0x%llx, 0x%llx, 0x%llx",
- desc->ret[0], desc->ret[1], desc->ret[2]);
+ pr_info("scm_call_qcpe: OUT: 0x%llx, 0x%llx, 0x%llx, 0x%llx",
+ smc_params.x0, desc->ret[0], desc->ret[1], desc->ret[2]);
- return 0;
+ return smc_params.x0;
}
static u32 smc(u32 cmd_addr)
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index 4307937d9f6d..e7a00cdb5b03 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -424,13 +424,14 @@ const char *msm_secure_vmid_to_string(int secure_vmid)
bool msm_secure_v2_is_supported(void)
{
- int version = scm_get_feat_version(FEATURE_ID_CP);
+ u64 version;
+ int ret = scm_get_feat_version(FEATURE_ID_CP, &version);
/*
* if the version is < 1.1.0 then dynamic buffer allocation is
* not supported
*/
- return version >= MAKE_CP_VERSION(1, 1, 0);
+ return (ret == 0) && (version >= MAKE_CP_VERSION(1, 1, 0));
}
static int __init alloc_secure_shared_memory(void)
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index b9903fe86f60..74dbd4d42272 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -566,6 +566,10 @@ static struct msm_soc_info cpu_of_id[] = {
[318] = {MSM_CPU_630, "SDM630"},
[327] = {MSM_CPU_630, "SDA630"},
+ /* 636 ID */
+ [345] = {MSM_CPU_636, "SDM636"},
+ [346] = {MSM_CPU_636, "SDA636"},
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -1289,6 +1293,14 @@ static void * __init setup_dummy_socinfo(void)
dummy_socinfo.id = 327;
strlcpy(dummy_socinfo.build_id, "sda630 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sdm636()) {
+ dummy_socinfo.id = 345;
+ strlcpy(dummy_socinfo.build_id, "sdm636 - ",
+ sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sda636()) {
+ dummy_socinfo.id = 346;
+ strlcpy(dummy_socinfo.build_id, "sda636 - ",
+ sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_apq8098()) {
dummy_socinfo.id = 319;
strlcpy(dummy_socinfo.build_id, "apq8098 - ",
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index e4afce02afc7..6c1e781d6eb9 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -196,6 +196,7 @@ struct spcom_channel {
* glink state: CONNECTED / LOCAL_DISCONNECTED, REMOTE_DISCONNECTED
*/
unsigned glink_state;
+ bool is_closing;
/* Events notification */
struct completion connect;
@@ -208,10 +209,8 @@ struct spcom_channel {
* Only one rx/tx transaction at a time (request + response).
*/
int ref_count;
- u32 pid;
- /* link UP/DOWN callback */
- void (*notify_link_state_cb)(bool up);
+ u32 pid; /* debug only to find user space application */
/* abort flags */
bool rx_abort;
@@ -483,7 +482,17 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event)
switch (event) {
case GLINK_CONNECTED:
pr_debug("GLINK_CONNECTED, ch name [%s].\n", ch->name);
+ mutex_lock(&ch->lock);
+
+ if (ch->is_closing) {
+ pr_err("Unexpected CONNECTED while closing [%s].\n",
+ ch->name);
+ mutex_unlock(&ch->lock);
+ return;
+ }
+
ch->glink_state = event;
+
/*
* if spcom_notify_state() is called within glink_open()
* then ch->glink_handle is not updated yet.
@@ -493,7 +502,16 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event)
ch->glink_handle = handle;
}
- /* prepare default rx buffer after connected */
+ /* signal before unlock mutex & before calling glink */
+ complete_all(&ch->connect);
+
+ /*
+ * Prepare default rx buffer.
+ * glink_queue_rx_intent() can be called only AFTER connected.
+ * We do it here, ASAP, to allow rx data.
+ */
+
+ pr_debug("call glink_queue_rx_intent() ch [%s].\n", ch->name);
ret = glink_queue_rx_intent(ch->glink_handle,
ch, ch->rx_buf_size);
if (ret) {
@@ -503,7 +521,9 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event)
ch->rx_buf_size);
ch->rx_buf_ready = true;
}
- complete_all(&ch->connect);
+
+ pr_debug("GLINK_CONNECTED, ch name [%s] done.\n", ch->name);
+ mutex_unlock(&ch->lock);
break;
case GLINK_LOCAL_DISCONNECTED:
/*
@@ -668,6 +688,13 @@ static int spcom_init_channel(struct spcom_channel *ch, const char *name)
ch->glink_state = GLINK_LOCAL_DISCONNECTED;
ch->actual_rx_size = 0;
ch->rx_buf_size = SPCOM_RX_BUF_SIZE;
+ ch->is_closing = false;
+ ch->glink_handle = NULL;
+ ch->ref_count = 0;
+ ch->rx_abort = false;
+ ch->tx_abort = false;
+ ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */
+ ch->pid = 0;
return 0;
}
@@ -710,6 +737,7 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
long timeleft;
const char *name;
void *handle;
+ u32 pid = current_pid();
mutex_lock(&ch->lock);
name = ch->name;
@@ -723,7 +751,7 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
}
pr_debug("ch [%s] opened by PID [%d], count [%d]\n",
- name, ch->pid, ch->ref_count);
+ name, pid, ch->ref_count);
pr_debug("Open channel [%s] timeout_msec [%d].\n", name, timeout_msec);
@@ -738,6 +766,8 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
/* init completion before calling glink_open() */
reinit_completion(&ch->connect);
+ ch->is_closing = false;
+
handle = glink_open(&cfg);
if (IS_ERR_OR_NULL(handle)) {
pr_err("glink_open failed.\n");
@@ -749,9 +779,11 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
/* init channel context after successful open */
ch->glink_handle = handle;
ch->ref_count++;
- ch->pid = current_pid();
+ ch->pid = pid;
ch->txn_id = INITIAL_TXN_ID;
+ mutex_unlock(&ch->lock);
+
pr_debug("Wait for connection on channel [%s] timeout_msec [%d].\n",
name, timeout_msec);
@@ -768,8 +800,6 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
pr_debug("Channel [%s] opened, no timeout.\n", name);
}
- mutex_unlock(&ch->lock);
-
return 0;
exit_err:
mutex_unlock(&ch->lock);
@@ -796,6 +826,8 @@ static int spcom_close(struct spcom_channel *ch)
return 0;
}
+ ch->is_closing = true;
+
ret = glink_close(ch->glink_handle);
if (ret)
pr_err("glink_close() fail, ret [%d].\n", ret);
@@ -811,6 +843,7 @@ static int spcom_close(struct spcom_channel *ch)
ch->pid = 0;
pr_debug("Channel closed [%s].\n", ch->name);
+
mutex_unlock(&ch->lock);
return 0;
@@ -1105,6 +1138,7 @@ struct spcom_client *spcom_register_client(struct spcom_client_info *info)
ch = spcom_find_channel_by_name(name);
if (!ch) {
pr_err("channel %s doesn't exist, load App first.\n", name);
+ kfree(client);
return NULL;
}
@@ -1292,6 +1326,7 @@ struct spcom_server *spcom_register_service(struct spcom_service_info *info)
ch = spcom_find_channel_by_name(name);
if (!ch) {
pr_err("channel %s doesn't exist, load App first.\n", name);
+ kfree(server);
return NULL;
}
@@ -2449,9 +2484,14 @@ static unsigned int spcom_device_poll(struct file *filp,
done = (spcom_dev->link_state == GLINK_LINK_STATE_UP);
break;
case SPCOM_POLL_CH_CONNECT:
+ /*
+ * ch is not expected to be NULL since user must call open()
+ * to get FD before it can call poll().
+ * open() will fail if no ch related to the char-device.
+ */
if (ch == NULL) {
pr_err("invalid ch pointer, file [%s].\n", name);
- return -EINVAL;
+ return POLLERR;
}
pr_debug("ch [%s] SPCOM_POLL_CH_CONNECT.\n", name);
if (wait) {
@@ -2752,7 +2792,7 @@ static int __init spcom_init(void)
{
int ret;
- pr_info("spcom driver Ver 1.0 23-Nov-2015.\n");
+ pr_info("spcom driver version 1.2 23-Aug-2017.\n");
ret = platform_driver_register(&spcom_driver);
if (ret)
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index 745a069df88a..625030f1f256 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -134,6 +134,8 @@ static int msm_watchdog_suspend(struct device *dev)
return 0;
__raw_writel(1, wdog_dd->base + WDT0_RST);
if (wdog_dd->wakeup_irq_enable) {
+ /* Make sure register write is complete before proceeding */
+ mb();
wdog_dd->last_pet = sched_clock();
return 0;
}
@@ -148,8 +150,15 @@ static int msm_watchdog_resume(struct device *dev)
{
struct msm_watchdog_data *wdog_dd =
(struct msm_watchdog_data *)dev_get_drvdata(dev);
- if (!enable || wdog_dd->wakeup_irq_enable)
+ if (!enable)
+ return 0;
+ if (wdog_dd->wakeup_irq_enable) {
+ __raw_writel(1, wdog_dd->base + WDT0_RST);
+ /* Make sure register write is complete before proceeding */
+ mb();
+ wdog_dd->last_pet = sched_clock();
return 0;
+ }
__raw_writel(1, wdog_dd->base + WDT0_EN);
__raw_writel(1, wdog_dd->base + WDT0_RST);
mb();