mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-12 07:37:31 -04:00
ASOC: dsp: add spin_lock for q6asm_add_hdr
During SSR, ac could get freed after unlock the session lock during the execution of q6asm_callback. If we try to get the ac->cmd_lock after ac freed, kernel panic happens. Remove mutex_lock in reset_event to avoid kernel panic. Add spin_lock_irqsave in q6asm_add_hdr and change spin_lock to spin_lock_irqsave in q6asm_callback to add synchronize between q6asm_add_hdr and q6asm_callback to avoid kernel panic. Change-Id: I72cf959fe6a764920a13d565c72243a80ac4f236 Signed-off-by: Meng Wang <mengw@codeaurora.org>
This commit is contained in:
parent
928c67e56e
commit
d5d1092c0c
1 changed files with 53 additions and 31 deletions
84
dsp/q6asm.c
84
dsp/q6asm.c
|
|
@ -575,11 +575,12 @@ static bool q6asm_is_valid_audio_client(struct audio_client *ac)
|
|||
static void q6asm_session_free(struct audio_client *ac)
|
||||
{
|
||||
int session_id;
|
||||
unsigned long flags = 0;
|
||||
|
||||
pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
|
||||
session_id = ac->session;
|
||||
rtac_remove_popp_from_adm_devices(ac->session);
|
||||
spin_lock_bh(&(session[session_id].session_lock));
|
||||
spin_lock_irqsave(&(session[session_id].session_lock), flags);
|
||||
session[ac->session].ac = NULL;
|
||||
ac->session = 0;
|
||||
ac->perf_mode = LEGACY_PCM_MODE;
|
||||
|
|
@ -588,7 +589,7 @@ static void q6asm_session_free(struct audio_client *ac)
|
|||
ac->priv = NULL;
|
||||
kfree(ac);
|
||||
ac = NULL;
|
||||
spin_unlock_bh(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(&(session[session_id].session_lock), flags);
|
||||
}
|
||||
|
||||
static uint32_t q6asm_get_next_buf(struct audio_client *ac,
|
||||
|
|
@ -1607,6 +1608,7 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
|
|||
uint32_t i = IN;
|
||||
uint32_t *payload;
|
||||
unsigned long dsp_flags;
|
||||
unsigned long flags = 0;
|
||||
struct asm_buffer_node *buf_node = NULL;
|
||||
struct list_head *ptr, *next;
|
||||
union asm_token_struct asm_token;
|
||||
|
|
@ -1660,7 +1662,7 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
|
|||
session_id = asm_token._token.session_id;
|
||||
|
||||
if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
|
||||
spin_lock(&(session[session_id].session_lock));
|
||||
spin_lock_irqsave(&(session[session_id].session_lock), flags);
|
||||
|
||||
ac = q6asm_get_audio_client(session_id);
|
||||
dir = q6asm_get_flag_from_token(&asm_token, ASM_DIRECTION_OFFSET);
|
||||
|
|
@ -1670,7 +1672,8 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
|
|||
__func__, session_id);
|
||||
if ((session_id > 0 &&
|
||||
session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1723,7 +1726,8 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
|
|||
}
|
||||
if ((session_id > 0 &&
|
||||
session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1759,7 +1763,8 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
|
|||
ac->cb(data->opcode, data->token,
|
||||
data->payload, ac->priv);
|
||||
if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1827,7 +1832,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
uint8_t buf_index;
|
||||
struct msm_adsp_event_data *pp_event_package = NULL;
|
||||
uint32_t payload_size = 0;
|
||||
|
||||
unsigned long flags = 0;
|
||||
int session_id;
|
||||
|
||||
if (ac == NULL) {
|
||||
|
|
@ -1845,12 +1850,13 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
session_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_lock(&(session[session_id].session_lock));
|
||||
spin_lock_irqsave(&(session[session_id].session_lock), flags);
|
||||
|
||||
if (!q6asm_is_valid_audio_client(ac)) {
|
||||
pr_err("%s: audio client pointer is invalid, ac = %pK\n",
|
||||
__func__, ac);
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1863,9 +1869,6 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
}
|
||||
|
||||
if (data->opcode == RESET_EVENTS) {
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
mutex_lock(&ac->cmd_lock);
|
||||
spin_lock(&(session[session_id].session_lock));
|
||||
atomic_set(&ac->reset, 1);
|
||||
if (ac->apr == NULL) {
|
||||
ac->apr = ac->apr2;
|
||||
|
|
@ -1886,8 +1889,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
wake_up(&ac->time_wait);
|
||||
wake_up(&ac->cmd_wait);
|
||||
wake_up(&ac->mem_wait);
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
mutex_unlock(&ac->cmd_lock);
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1901,7 +1904,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
(data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
|
||||
if (payload == NULL) {
|
||||
pr_err("%s: payload is null\n", __func__);
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
|
||||
|
|
@ -1928,7 +1932,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
ret = q6asm_is_valid_session(data, priv);
|
||||
if (ret != 0) {
|
||||
pr_err("%s: session invalid %d\n", __func__, ret);
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return ret;
|
||||
}
|
||||
case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2:
|
||||
|
|
@ -1971,8 +1976,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
payload[1]);
|
||||
wake_up(&ac->cmd_wait);
|
||||
}
|
||||
spin_unlock(
|
||||
&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock),
|
||||
flags);
|
||||
return 0;
|
||||
}
|
||||
if ((is_adsp_reg_event(payload[0]) >= 0) ||
|
||||
|
|
@ -2004,8 +2010,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
atomic_set(&ac->mem_state, payload[1]);
|
||||
wake_up(&ac->mem_wait);
|
||||
}
|
||||
spin_unlock(
|
||||
&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock),
|
||||
flags);
|
||||
return 0;
|
||||
}
|
||||
if (atomic_read(&ac->mem_state) && wakeup_flag) {
|
||||
|
|
@ -2054,7 +2061,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2069,8 +2077,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
if (port->buf == NULL) {
|
||||
pr_err("%s: Unexpected Write Done\n",
|
||||
__func__);
|
||||
spin_unlock(
|
||||
&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock),
|
||||
flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_lock_irqsave(&port->dsp_lock, dsp_flags);
|
||||
|
|
@ -2085,8 +2094,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
__func__, payload[0], payload[1]);
|
||||
spin_unlock_irqrestore(&port->dsp_lock,
|
||||
dsp_flags);
|
||||
spin_unlock(
|
||||
&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock),
|
||||
flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
port->buf[buf_index].used = 1;
|
||||
|
|
@ -2157,8 +2167,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
if (ac->io_mode & SYNC_IO_MODE) {
|
||||
if (port->buf == NULL) {
|
||||
pr_err("%s: Unexpected Write Done\n", __func__);
|
||||
spin_unlock(
|
||||
&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock),
|
||||
flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_lock_irqsave(&port->dsp_lock, dsp_flags);
|
||||
|
|
@ -2234,7 +2245,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
__func__, payload[0], payload[1]);
|
||||
i = is_adsp_raise_event(data->opcode);
|
||||
if (i < 0) {
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2253,7 +2265,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
+ sizeof(struct msm_adsp_event_data),
|
||||
GFP_ATOMIC);
|
||||
if (!pp_event_package) {
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -2264,7 +2277,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
ac->cb(data->opcode, data->token,
|
||||
(void *)pp_event_package, ac->priv);
|
||||
kfree(pp_event_package);
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
|
||||
pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
|
||||
|
|
@ -2290,7 +2304,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
|
|||
if (ac->cb)
|
||||
ac->cb(data->opcode, data->token,
|
||||
data->payload, ac->priv);
|
||||
spin_unlock(&(session[session_id].session_lock));
|
||||
spin_unlock_irqrestore(
|
||||
&(session[session_id].session_lock), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2506,11 +2521,16 @@ int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
|
|||
static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
|
||||
uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
|
||||
dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
|
||||
__func__, pkt_size, cmd_flg, ac->session, stream_id);
|
||||
mutex_lock(&ac->cmd_lock);
|
||||
spin_lock_irqsave(&(session[ac->session].session_lock), flags);
|
||||
if (ac->apr == NULL) {
|
||||
pr_err("%s: AC APR handle NULL", __func__);
|
||||
spin_unlock_irqrestore(
|
||||
&(session[ac->session].session_lock), flags);
|
||||
mutex_unlock(&ac->cmd_lock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2533,6 +2553,8 @@ static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
|
|||
WAIT_CMD);
|
||||
|
||||
hdr->pkt_size = pkt_size;
|
||||
spin_unlock_irqrestore(
|
||||
&(session[ac->session].session_lock), flags);
|
||||
mutex_unlock(&ac->cmd_lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue