summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2018-01-11 04:14:55 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2018-01-11 04:14:55 -0800
commite64256fca08b086bc31339b8d044700ea90f86bf (patch)
tree38bc8388d4a78743a7dd413475a4aaa7d0b8ad0a
parenteb26d9d0c0580f20037e1402674b4991a986b9b1 (diff)
parent13661b77b8242d390e7bf60c7f8a3253f07a1856 (diff)
Merge "ASoC: msm: qdsp6v2: add spin lock to protect ac"
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c152
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 */