diff options
| -rw-r--r-- | sound/soc/msm/qdsp6v2/q6asm.c | 152 |
1 files changed, 120 insertions, 32 deletions
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 5f0a61fb9081..201234a25bd9 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -93,8 +93,13 @@ struct asm_mmap { }; static struct asm_mmap this_mmap; + +struct audio_session { + struct audio_client *ac; + spinlock_t session_lock; +}; /* session id: 0 reserved */ -static struct audio_client *session[ASM_ACTIVE_STREAMS_ALLOWED + 1]; +static struct audio_session session[ASM_ACTIVE_STREAMS_ALLOWED + 1]; struct asm_buffer_node { struct list_head list; @@ -546,8 +551,8 @@ static int q6asm_session_alloc(struct audio_client *ac) { int n; for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) { - if (!session[n]) { - session[n] = ac; + if (!(session[n].ac)) { + session[n].ac = ac; return n; } } @@ -555,24 +560,39 @@ static int q6asm_session_alloc(struct audio_client *ac) return -ENOMEM; } -static bool q6asm_is_valid_audio_client(struct audio_client *ac) +static int q6asm_get_session_id_from_audio_client(struct audio_client *ac) { int n; for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) { - if (session[n] == ac) - return 1; + if (session[n].ac == ac) + return n; } return 0; } +static bool q6asm_is_valid_audio_client(struct audio_client *ac) +{ + return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0; +} + static void q6asm_session_free(struct audio_client *ac) { + int session_id; + unsigned long flags; + pr_debug("%s: sessionid[%d]\n", __func__, ac->session); + session_id = ac->session; rtac_remove_popp_from_adm_devices(ac->session); - session[ac->session] = 0; + spin_lock_irqsave(&(session[session_id].session_lock), flags); + session[ac->session].ac = NULL; ac->session = 0; ac->perf_mode = LEGACY_PCM_MODE; ac->fptr_cache_ops = NULL; + ac->cb = NULL; + ac->priv = NULL; + kfree(ac); + ac = NULL; + spin_unlock_irqrestore(&(session[session_id].session_lock), flags); return; } @@ -1084,8 +1104,6 @@ void q6asm_audio_client_free(struct audio_client *ac) pr_debug("%s: APR De-Register\n", __func__); /*done:*/ - kfree(ac); - ac = NULL; mutex_unlock(&session_lock); return; @@ -1220,6 +1238,7 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) if (n <= 0) { pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n); mutex_unlock(&session_lock); + kfree(ac); goto fail_session; } ac->session = n; @@ -1296,7 +1315,6 @@ fail_apr2: fail_apr1: q6asm_session_free(ac); fail_session: - kfree(ac); return NULL; } @@ -1311,11 +1329,11 @@ struct audio_client *q6asm_get_audio_client(int session_id) goto err; } - if (!session[session_id]) { + if (!(session[session_id].ac)) { pr_err("%s: session not active: %d\n", __func__, session_id); goto err; } - return session[session_id]; + return session[session_id].ac; err: return NULL; } @@ -1519,6 +1537,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; struct asm_buffer_node *buf_node = NULL; struct list_head *ptr, *next; union asm_token_struct asm_token; @@ -1526,6 +1545,8 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) struct audio_client *ac = NULL; struct audio_port_data *port; + int session_id; + if (!data) { pr_err("%s: Invalid CB\n", __func__); return 0; @@ -1566,13 +1587,23 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) rtac_clear_mapping(ASM_RTAC_CAL); return 0; } + asm_token.token = data->token; - ac = q6asm_get_audio_client(asm_token._token.session_id); + session_id = asm_token._token.session_id; + + if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED)) + 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); if (!ac) { pr_debug("%s: session[%d] already freed\n", - __func__, asm_token._token.session_id); + __func__, session_id); + if ((session_id > 0 && + session_id <= ASM_ACTIVE_STREAMS_ALLOWED)) + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1623,6 +1654,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + if ((session_id > 0 && + session_id <= ASM_ACTIVE_STREAMS_ALLOWED)) + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1657,6 +1692,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); + if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED)) + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); + return 0; } @@ -1724,6 +1763,8 @@ 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; + int session_id; if (ac == NULL) { pr_err("%s: ac NULL\n", __func__); @@ -1733,15 +1774,21 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_err("%s: data NULL\n", __func__); return -EINVAL; } - if (!q6asm_is_valid_audio_client(ac)) { - pr_err("%s: audio client pointer is invalid, ac = %pK\n", - __func__, ac); + + session_id = q6asm_get_session_id_from_audio_client(ac); + if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) { + pr_err("%s: Session ID is invalid, session = %d\n", __func__, + session_id); return -EINVAL; } - if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { - pr_err("%s: Session ID is invalid, session = %d\n", __func__, - ac->session); + 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_irqrestore( + &(session[session_id].session_lock), flags); return -EINVAL; } @@ -1754,7 +1801,6 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } if (data->opcode == RESET_EVENTS) { - mutex_lock(&ac->cmd_lock); atomic_set(&ac->reset, 1); if (ac->apr == NULL) { ac->apr = ac->apr2; @@ -1775,7 +1821,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); - mutex_unlock(&ac->cmd_lock); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1789,6 +1836,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_irqrestore( + &(session[session_id].session_lock), flags); return -EINVAL; } dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", @@ -1815,6 +1864,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_irqrestore( + &(session[session_id].session_lock), flags); return ret; } case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2: @@ -1857,6 +1908,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) payload[1]); wake_up(&ac->cmd_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if ((is_adsp_reg_event(payload[0]) >= 0) || @@ -1888,6 +1942,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_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->mem_state) && wakeup_flag) { @@ -1935,6 +1992,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1948,6 +2008,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_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -1962,6 +2025,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_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } port->buf[buf_index].used = 1; @@ -2032,6 +2098,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_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -2106,8 +2175,11 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]", __func__, payload[0], payload[1]); i = is_adsp_raise_event(data->opcode); - if (i < 0) + if (i < 0) { + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; + } /* repack payload for asm_stream_pp_event * package is composed of event type + size + actual payload @@ -2116,8 +2188,11 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pp_event_package = kzalloc(payload_size + sizeof(struct msm_adsp_event_data), GFP_ATOMIC); - if (!pp_event_package) + if (!pp_event_package) { + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return -ENOMEM; + } pp_event_package->event_type = i; pp_event_package->payload_len = payload_size; @@ -2126,6 +2201,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_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", @@ -2151,7 +2228,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_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -2327,11 +2405,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; + 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; } @@ -2354,6 +2437,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); return; } @@ -8875,7 +8960,7 @@ int q6asm_get_apr_service_id(int session_id) return -EINVAL; } - return ((struct apr_svc *)session[session_id]->apr)->id; + return ((struct apr_svc *)(session[session_id].ac)->apr)->id; } int q6asm_get_asm_topology(int session_id) @@ -8886,12 +8971,12 @@ int q6asm_get_asm_topology(int session_id) pr_err("%s: invalid session_id = %d\n", __func__, session_id); goto done; } - if (session[session_id] == NULL) { + if (session[session_id].ac == NULL) { pr_err("%s: session not created for session id = %d\n", __func__, session_id); goto done; } - topology = session[session_id]->topology; + topology = (session[session_id].ac)->topology; done: return topology; } @@ -8904,12 +8989,12 @@ int q6asm_get_asm_app_type(int session_id) pr_err("%s: invalid session_id = %d\n", __func__, session_id); goto done; } - if (session[session_id] == NULL) { + if (session[session_id].ac == NULL) { pr_err("%s: session not created for session id = %d\n", __func__, session_id); goto done; } - app_type = session[session_id]->app_type; + app_type = (session[session_id].ac)->app_type; done: return app_type; } @@ -9211,7 +9296,10 @@ static int __init q6asm_init(void) int lcnt, ret; pr_debug("%s:\n", __func__); - memset(session, 0, sizeof(session)); + memset(session, 0, sizeof(struct audio_session) * + (ASM_ACTIVE_STREAMS_ALLOWED + 1)); + for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++) + spin_lock_init(&(session[lcnt].session_lock)); set_custom_topology = 1; /*setup common client used for cal mem map */ |
