From 97f90ea914913fa6c2c0ba6e27667a3604dbf732 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Tue, 28 Apr 2020 09:16:55 +0530 Subject: ASoC: dsp: Synchronise adm and rtac commands Race condition observed while processing the set_pp_params command responses sent back to back by adsp for commands sent from adm and rtac. Handle this by synchronising the get/set pp_params command in both the drivers. Change-Id: Id89d98217dc5cad3703e5d545ddee21cb145c874 Signed-off-by: Soumya Managoli --- dsp/q6adm.c | 107 ++++++++++++++++++++++++++++++++++--------------- dsp/rtac.c | 30 ++------------ include/dsp/q6adm-v2.h | 2 + 3 files changed, 81 insertions(+), 58 deletions(-) diff --git a/dsp/q6adm.c b/dsp/q6adm.c index 51ca185b..708cc0fd 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -95,6 +95,7 @@ struct adm_ctl { struct param_outband outband_memmap; struct source_tracking_data sourceTrackingData; + struct mutex adm_apr_lock; int set_custom_topology; int ec_ref_rx; int num_ec_ref_rx_chans; @@ -869,6 +870,58 @@ exit: } EXPORT_SYMBOL(adm_set_custom_chmix_cfg); +/* + * adm_apr_send_pkt : returns 0 on success, negative otherwise. + */ +int adm_apr_send_pkt(void *data, wait_queue_head_t *wait, + int port_idx, int copp_idx) +{ + int ret = 0; + atomic_t *copp_stat = NULL; + wait = &this_adm.copp.wait[port_idx][copp_idx]; + + if (!wait) + return -EINVAL; + + mutex_lock(&this_adm.adm_apr_lock); + pr_debug("%s: port idx %d copp idx %d\n", __func__, + port_idx, copp_idx); + copp_stat = &this_adm.copp.stat[port_idx][copp_idx]; + atomic_set(copp_stat, -1); + + if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) { + pr_err("%s: port[0x%x] coppid[0x%x] is not active, ERROR\n", + __func__, port_idx, copp_idx); + mutex_unlock(&this_adm.adm_apr_lock); + return -EINVAL; + } + + ret = apr_send_pkt(this_adm.apr, data); + if (ret > 0) { + ret = wait_event_timeout(*wait, + atomic_read(copp_stat) >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (atomic_read(copp_stat) > 0) { + pr_err("%s: DSP returned error[%s]\n", __func__, + adsp_err_get_err_str(atomic_read(copp_stat))); + ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat)); + } else if (!ret) { + pr_err_ratelimited("%s: request timedout\n", + __func__); + ret = -ETIMEDOUT; + } else { + ret = 0; + } + } else if (ret == 0) { + pr_err("%s: packet not transmitted\n", __func__); + /* apr_send_pkt can return 0 when nothing is transmitted */ + ret = -EINVAL; + } + + mutex_unlock(&this_adm.adm_apr_lock); + return ret; +} + /* * With pre-packed data, only the opcode differes from V5 and V6. * Use q6common_pack_pp_params to pack the data correctly. @@ -880,7 +933,6 @@ int adm_set_pp_params(int port_id, int copp_idx, struct adm_cmd_set_pp_params *adm_set_params = NULL; int size = 0; int port_idx = 0; - atomic_t *copp_stat = NULL; int ret = 0; port_id = afe_convert_virtual_to_portid(port_id); @@ -938,32 +990,9 @@ int adm_set_pp_params(int port_id, int copp_idx, ret = -EINVAL; goto done; } - - copp_stat = &this_adm.copp.stat[port_idx][copp_idx]; - atomic_set(copp_stat, -1); - ret = apr_send_pkt(this_adm.apr, (uint32_t *) adm_set_params); - if (ret < 0) { - pr_err("%s: Set params APR send failed port = 0x%x ret %d\n", - __func__, port_id, ret); - goto done; - } - ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], - atomic_read(copp_stat) >= 0, - msecs_to_jiffies(TIMEOUT_MS)); - if (!ret) { - pr_err("%s: Set params timed out port = 0x%x\n", __func__, - port_id); - ret = -ETIMEDOUT; - goto done; - } - if (atomic_read(copp_stat) > 0) { - pr_err("%s: DSP returned error[%s]\n", __func__, - adsp_err_get_err_str(atomic_read(copp_stat))); - ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat)); - goto done; - } - - ret = 0; + ret = adm_apr_send_pkt((uint32_t *) adm_set_params, + &this_adm.copp.wait[port_idx][copp_idx], + port_idx, copp_idx); done: kfree(adm_set_params); return ret; @@ -1601,8 +1630,15 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) this_adm.sourceTrackingData. apr_cmd_status = payload[1]; else if (rtac_make_adm_callback(payload, - data->payload_size)) - break; + data->payload_size)) { + pr_debug("%s: rtac cmd response\n", + __func__); + } + atomic_set(&this_adm.copp.stat[port_idx] + [copp_idx], payload[1]); + wake_up( + &this_adm.copp.wait[port_idx][copp_idx]); + break; /* * if soft volume is called and already * interrupted break out of the sequence here @@ -1611,8 +1647,8 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) case ADM_CMD_DEVICE_CLOSE_V5: case ADM_CMD_DEVICE_OPEN_V6: case ADM_CMD_DEVICE_OPEN_V8: - pr_debug("%s: Basic callback received, wake up.\n", - __func__); + pr_debug("%s: Basic callback received for 0x%x, wake up.\n", + __func__, payload[0]); atomic_set(&this_adm.copp.stat[port_idx] [copp_idx], payload[1]); wake_up( @@ -1745,8 +1781,13 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) this_adm.sourceTrackingData.apr_cmd_status = payload[0]; else if (rtac_make_adm_callback(payload, - data->payload_size)) + data->payload_size)) { + pr_debug("%s: rtac cmd response\n", __func__); + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], + payload[0]); + wake_up(&this_adm.copp.wait[port_idx][copp_idx]); break; + } idx = ADM_GET_PARAMETER_LENGTH * copp_idx; if (payload[0] == 0 && data->payload_size > 0) { @@ -5504,6 +5545,7 @@ int __init adm_init(void) this_adm.ffecns_port_id = -1; init_waitqueue_head(&this_adm.matrix_map_wait); init_waitqueue_head(&this_adm.adm_wait); + mutex_init(&this_adm.adm_apr_lock); for (i = 0; i < AFE_MAX_PORTS; i++) { for (j = 0; j < MAX_COPPS_PER_PORT; j++) { @@ -5528,6 +5570,7 @@ int __init adm_init(void) void adm_exit(void) { + mutex_destroy(&this_adm.adm_apr_lock); if (this_adm.apr) adm_reset_data(); adm_delete_cal_data(); diff --git a/dsp/rtac.c b/dsp/rtac.c index c77b5f09..ed298e9c 100644 --- a/dsp/rtac.c +++ b/dsp/rtac.c @@ -728,7 +728,6 @@ bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size) atomic_set(&rtac_common.apr_err_code, payload[1]); atomic_set(&rtac_adm_apr_data.cmd_state, 0); - wake_up(&rtac_adm_apr_data.cmd_wait); return true; } @@ -880,33 +879,12 @@ int send_adm_apr(void *buf, u32 opcode) pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n", __func__, opcode, &rtac_cal[ADM_RTAC_CAL].cal_data.paddr); + mutex_unlock(&rtac_adm_apr_mutex); - result = apr_send_pkt(rtac_adm_apr_data.apr_handle, - (uint32_t *)rtac_adm_buffer); - if (result < 0) { - pr_err("%s: Set params failed copp = %d\n", __func__, copp_id); - goto err; - } - /* Wait for the callback */ - result = wait_event_timeout(rtac_adm_apr_data.cmd_wait, - (atomic_read(&rtac_adm_apr_data.cmd_state) == 0), - msecs_to_jiffies(TIMEOUT_MS)); - if (!result) { - pr_err("%s: Set params timed out copp = %d\n", __func__, - copp_id); - goto err; - } - if (atomic_read(&rtac_common.apr_err_code)) { - pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n", - __func__, adsp_err_get_err_str(atomic_read( - &rtac_common.apr_err_code)), - opcode); - result = adsp_err_get_lnx_err_code( - atomic_read( - &rtac_common.apr_err_code)); - goto err; - } + result = adm_apr_send_pkt((uint32_t *)rtac_adm_buffer, + NULL, port_idx, copp_idx); + mutex_lock(&rtac_adm_apr_mutex); if (opcode == ADM_CMD_GET_PP_PARAMS_V5) { bytes_returned = ((u32 *)rtac_cal[ADM_RTAC_CAL].cal_data. kvaddr)[2] + 3 * sizeof(u32); diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h index 644855d0..20b2450b 100644 --- a/include/dsp/q6adm-v2.h +++ b/include/dsp/q6adm-v2.h @@ -229,4 +229,6 @@ void msm_dts_srs_acquire_lock(void); void msm_dts_srs_release_lock(void); void adm_set_native_mode(int mode); int adm_set_ffecns_freeze_event(bool ffecns_freeze_event); +int adm_apr_send_pkt(void *data, wait_queue_head_t *wait, + int port_idx, int copp_idx); #endif /* __Q6_ADM_V2_H__ */ -- cgit v1.2.3 From cc71e4908e5d5a60892793d54a4b0be61d458421 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Wed, 14 Oct 2020 20:52:09 +0530 Subject: asoc: bolero: Add core_vote before gfmux access GFMUX access happen during RX macro usecase. Update rx macro to do core_vote before clock request. Change-Id: I1afd38ae13066dcfbda307308afce7c4291142d9 Signed-off-by: Laxminath Kasam --- asoc/codecs/bolero/rx-macro.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index 07dd8ada..7b3cad04 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -350,6 +350,7 @@ struct rx_macro_bcl_pmic_params { u8 ppid; }; +static int rx_macro_core_vote(void *handle, bool enable); static int rx_macro_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai); @@ -1230,6 +1231,7 @@ static int rx_macro_mclk_enable(struct rx_macro_priv *rx_priv, if (rx_priv->rx_mclk_users == 0) { if (rx_priv->is_native_on) rx_priv->clk_id = RX_CORE_CLK; + rx_macro_core_vote(rx_priv, true); ret = bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, rx_priv->clk_id, @@ -1283,6 +1285,7 @@ static int rx_macro_mclk_enable(struct rx_macro_priv *rx_priv, 0x01, 0x00); bolero_clk_rsc_fs_gen_request(rx_priv->dev, false); + rx_macro_core_vote(rx_priv, true); bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, rx_priv->clk_id, @@ -1396,18 +1399,21 @@ static int rx_macro_event_handler(struct snd_soc_component *component, } break; case BOLERO_MACRO_EVT_PRE_SSR_UP: + rx_macro_core_vote(rx_priv, true); /* enable&disable RX_CORE_CLK to reset GFMUX reg */ ret = bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, RX_CORE_CLK, true); - if (ret < 0) + if (ret < 0) { dev_err_ratelimited(rx_priv->dev, "%s, failed to enable clk, ret:%d\n", __func__, ret); - else + } else { + rx_macro_core_vote(rx_priv, true); bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, RX_CORE_CLK, false); + } break; case BOLERO_MACRO_EVT_SSR_UP: trace_printk("%s, enter SSR up\n", __func__); -- cgit v1.2.3 From 0a0c718a77ba6da31de9bf5d6726635f2a924b3d Mon Sep 17 00:00:00 2001 From: "Vangala, Amarnath" Date: Thu, 3 Dec 2020 14:14:56 +0530 Subject: asoc: codecs: add child devices after completing initialization In bolero-cdc and tx, va, wsa and rx macros, move schedule_work call to add the child devices to the point later to where the parent initialization gets completed. Change-Id: Iaa07329a25020dde21d9249c3848bb7fcf7d816a Signed-off-by: Vangala, Amarnath --- asoc/codecs/bolero/bolero-cdc.c | 2 +- asoc/codecs/bolero/rx-macro.c | 2 +- asoc/codecs/bolero/tx-macro.c | 4 ++-- asoc/codecs/bolero/va-macro.c | 4 ++-- asoc/codecs/bolero/wsa-macro.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index 53c70fab..e80a8239 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -1379,7 +1379,6 @@ static int bolero_probe(struct platform_device *pdev) mutex_init(&priv->vote_lock); INIT_WORK(&priv->bolero_add_child_devices_work, bolero_add_child_devices); - schedule_work(&priv->bolero_add_child_devices_work); /* Register LPASS core hw vote */ lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote"); @@ -1403,6 +1402,7 @@ static int bolero_probe(struct platform_device *pdev) } priv->lpass_audio_hw_vote = lpass_audio_hw_vote; + schedule_work(&priv->bolero_add_child_devices_work); return 0; } diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index 07dd8ada..f619c51a 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -4165,12 +4165,12 @@ static int rx_macro_probe(struct platform_device *pdev) "%s: register macro failed\n", __func__); goto err_reg_macro; } - schedule_work(&rx_priv->rx_macro_add_child_devices_work); pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); + schedule_work(&rx_priv->rx_macro_add_child_devices_work); return 0; diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index de04e1e9..a9afea49 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -3280,13 +3280,13 @@ static int tx_macro_probe(struct platform_device *pdev) "%s: register macro failed\n", __func__); goto err_reg_macro; } - if (is_used_tx_swr_gpio) - schedule_work(&tx_priv->tx_macro_add_child_devices_work); pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); + if (is_used_tx_swr_gpio) + schedule_work(&tx_priv->tx_macro_add_child_devices_work); return 0; err_reg_macro: diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index 2e369952..20117e7f 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -3143,13 +3143,13 @@ static int va_macro_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: register macro failed\n", __func__); goto reg_macro_fail; } - if (is_used_va_swr_gpio) - schedule_work(&va_priv->va_macro_add_child_devices_work); pm_runtime_set_autosuspend_delay(&pdev->dev, VA_AUTO_SUSPEND_DELAY); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); + if (is_used_va_swr_gpio) + schedule_work(&va_priv->va_macro_add_child_devices_work); return ret; reg_macro_fail: diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index 5ace96db..e867141f 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -3237,12 +3237,12 @@ static int wsa_macro_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: register macro failed\n", __func__); goto reg_macro_fail; } - schedule_work(&wsa_priv->wsa_macro_add_child_devices_work); pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); + schedule_work(&wsa_priv->wsa_macro_add_child_devices_work); return ret; reg_macro_fail: -- cgit v1.2.3 From 34df55a3bd442a10cb6839bb729bfb08dc0e8c93 Mon Sep 17 00:00:00 2001 From: Kunlei Zhang Date: Wed, 24 Feb 2021 11:25:41 +0800 Subject: dsp: update size check for get VI param function In afe_get_cal_sp_th_vi_param functions, data size should check with size of cal_type_header. The check is not present which might lead to out of bounds access. Update condition to ensure data_size is greater than or equal to size of cal_type_header. Change-Id: Ib2904f53243f4fb858131511812fd90de32b4656 Signed-off-by: Kunlei Zhang --- dsp/q6afe.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 88124df9..7f594f29 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -10160,6 +10160,7 @@ static int afe_get_cal_sp_th_vi_param(int32_t cal_type, size_t data_size, if (cal_data == NULL || data_size > sizeof(*cal_data) || + data_size < sizeof(cal_data->cal_hdr) || this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL) return 0; @@ -10188,7 +10189,8 @@ static int afe_get_cal_spv4_ex_vi_ftm_param(int32_t cal_type, size_t data_size, pr_debug("%s: cal_type = %d\n", __func__, cal_type); if (this_afe.cal_data[AFE_FB_SPKR_PROT_V4_EX_VI_CAL] == NULL || cal_data == NULL || - data_size != sizeof(*cal_data)) + data_size > sizeof(*cal_data) || + data_size < sizeof(cal_data->cal_hdr)) goto done; mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_V4_EX_VI_CAL]->lock); @@ -10255,7 +10257,8 @@ static int afe_get_cal_sp_ex_vi_ftm_param(int32_t cal_type, size_t data_size, pr_debug("%s: cal_type = %d\n", __func__, cal_type); if (this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL] == NULL || cal_data == NULL || - data_size != sizeof(*cal_data)) + data_size > sizeof(*cal_data) || + data_size < sizeof(cal_data->cal_hdr)) goto done; mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock); -- cgit v1.2.3 From e4c6762dbd22f4290839ce63165dccfbdaf4e9bc Mon Sep 17 00:00:00 2001 From: Shashi Kant Maurya Date: Tue, 23 Feb 2021 17:30:16 +0530 Subject: dsp: adm: add to check output/input channel To avoid out of bound value of output/input channel add the check. Change-Id: I25b7616d6fc08c2d0bb530dfb1457471dc25861c Signed-off-by: Shashi Kant Maurya Signed-off-by: Lakshman Chaluvaraju --- asoc/msm-pcm-routing-v2.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index 7aafe2b9..99e93c39 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -1729,6 +1729,11 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, for (i = 0; i < ADM_MAX_CHANNELS && channel_input[fe_id][i] > 0; ++i) { be_id = channel_input[fe_id][i] - 1; + if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) { + pr_err("%s: Received out of bounds be_id %d\n", + __func__, be_id); + return -EINVAL; + } channel_mixer[fe_id].input_channels[i] = msm_bedais[be_id].channel; @@ -3470,10 +3475,10 @@ static int msm_pcm_get_out_chs(struct snd_kcontrol *kcontrol, static int msm_pcm_put_out_chs(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - u16 fe_id = 0; - + u16 fe_id = 0, out_ch = 0; fe_id = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; + out_ch = ucontrol->value.integer.value[0]; if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { pr_err("%s: invalid FE %d\n", __func__, fe_id); return -EINVAL; @@ -3482,6 +3487,12 @@ static int msm_pcm_put_out_chs(struct snd_kcontrol *kcontrol, pr_debug("%s: fe_id is %d, output channels = %d\n", __func__, fe_id, (unsigned int)(ucontrol->value.integer.value[0])); + if (out_ch < 0 || + out_ch > ADM_MAX_CHANNELS) { + pr_err("%s: invalid output channel %d\n", __func__, + out_ch); + return -EINVAL; + } channel_mixer[fe_id].output_channel = (unsigned int)(ucontrol->value.integer.value[0]); -- cgit v1.2.3 From d0adc6a072415e18524238c02685a29a59363577 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Wed, 24 Feb 2021 19:33:53 +0530 Subject: ASoC: dsp: Synchronise adm commands Race condition observed while processing the get/set_pp_params and adm_close command. Synchronise adm open, close and get/set_pp_params by sending the apr cmd pkt using the same lock. Change-Id: I9a1ebcedc91f78f3940846688f8569ec9088e1e7 Signed-off-by: Soumya Managoli --- dsp/q6adm.c | 120 +++++++++++++++---------------------------------- dsp/rtac.c | 4 +- include/dsp/q6adm-v2.h | 4 +- 3 files changed, 40 insertions(+), 88 deletions(-) diff --git a/dsp/q6adm.c b/dsp/q6adm.c index 708cc0fd..e63547d8 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -874,10 +874,11 @@ EXPORT_SYMBOL(adm_set_custom_chmix_cfg); * adm_apr_send_pkt : returns 0 on success, negative otherwise. */ int adm_apr_send_pkt(void *data, wait_queue_head_t *wait, - int port_idx, int copp_idx) + int port_idx, int copp_idx, int opcode) { int ret = 0; atomic_t *copp_stat = NULL; + int32_t time_out = msecs_to_jiffies(TIMEOUT_MS); wait = &this_adm.copp.wait[port_idx][copp_idx]; if (!wait) @@ -889,18 +890,30 @@ int adm_apr_send_pkt(void *data, wait_queue_head_t *wait, copp_stat = &this_adm.copp.stat[port_idx][copp_idx]; atomic_set(copp_stat, -1); - if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) { - pr_err("%s: port[0x%x] coppid[0x%x] is not active, ERROR\n", - __func__, port_idx, copp_idx); - mutex_unlock(&this_adm.adm_apr_lock); - return -EINVAL; + if (opcode != ADM_CMD_DEVICE_OPEN_V8 && + opcode != ADM_CMD_DEVICE_OPEN_V6 && + opcode != ADM_CMD_DEVICE_OPEN_V5 && + opcode != ADM_CMD_DEVICE_CLOSE_V5) { + if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) + == 0) { + pr_err("%s: port[0x%x] copp[0x%x] inactive\n", + __func__, port_idx, copp_idx); + mutex_unlock(&this_adm.adm_apr_lock); + return -EINVAL; + } + } + + if (opcode == ADM_CMD_DEVICE_OPEN_V8 || + opcode == ADM_CMD_DEVICE_OPEN_V6 || + opcode == ADM_CMD_DEVICE_OPEN_V5) { + time_out = msecs_to_jiffies(2 * TIMEOUT_MS); } ret = apr_send_pkt(this_adm.apr, data); if (ret > 0) { ret = wait_event_timeout(*wait, atomic_read(copp_stat) >= 0, - msecs_to_jiffies(TIMEOUT_MS)); + time_out); if (atomic_read(copp_stat) > 0) { pr_err("%s: DSP returned error[%s]\n", __func__, adsp_err_get_err_str(atomic_read(copp_stat))); @@ -992,7 +1005,7 @@ int adm_set_pp_params(int port_id, int copp_idx, } ret = adm_apr_send_pkt((uint32_t *) adm_set_params, &this_adm.copp.wait[port_idx][copp_idx], - port_idx, copp_idx); + port_idx, copp_idx, adm_set_params->apr_hdr.opcode); done: kfree(adm_set_params); return ret; @@ -1045,7 +1058,6 @@ int adm_get_pp_params(int port_id, int copp_idx, uint32_t client_id, int returned_param_size_in_bytes = 0; int port_idx = 0; int idx = 0; - atomic_t *copp_stat = NULL; int ret = 0; if (param_hdr == NULL) { @@ -1093,33 +1105,9 @@ int adm_get_pp_params(int port_id, int copp_idx, uint32_t client_id, else adm_get_params.apr_hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5; - copp_stat = &this_adm.copp.stat[port_idx][copp_idx]; - atomic_set(copp_stat, -1); - - ret = apr_send_pkt(this_adm.apr, (uint32_t *) &adm_get_params); - if (ret < 0) { - pr_err("%s: Get params APR send failed port = 0x%x ret %d\n", - __func__, port_id, ret); - ret = -EINVAL; - goto done; - } - ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], - atomic_read(copp_stat) >= 0, - msecs_to_jiffies(TIMEOUT_MS)); - if (!ret) { - pr_err("%s: Get params timed out port = 0x%x\n", __func__, - port_id); - ret = -ETIMEDOUT; - goto done; - } - if (atomic_read(copp_stat) > 0) { - pr_err("%s: DSP returned error[%s]\n", __func__, - adsp_err_get_err_str(atomic_read(copp_stat))); - ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat)); - goto done; - } - - ret = 0; + ret = adm_apr_send_pkt((uint32_t *) &adm_get_params, + &this_adm.copp.wait[port_idx][copp_idx], + port_idx, copp_idx, adm_get_params.apr_hdr.opcode); /* Copy data to caller if sent in band */ if (!returned_param_data) { @@ -1147,7 +1135,6 @@ int adm_get_pp_params(int port_id, int copp_idx, uint32_t client_id, memcpy(returned_param_data, &adm_get_parameters[idx + 1], returned_param_size_in_bytes); -done: return ret; } EXPORT_SYMBOL(adm_get_pp_params); @@ -3328,8 +3315,9 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, ep2_payload_size); } - ret = apr_send_pkt(this_adm.apr, - (uint32_t *)adm_params); + ret = adm_apr_send_pkt((uint32_t *) adm_params, + &this_adm.copp.wait[port_idx][copp_idx], + port_idx, copp_idx, open_v8.hdr.opcode); if (ret < 0) { pr_err("%s: port_id: 0x%x for[0x%x] failed %d for open_v8\n", __func__, tmp_port, port_id, ret); @@ -3415,11 +3403,13 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, if (ret) return ret; - ret = apr_send_pkt(this_adm.apr, - (uint32_t *)&open_v6); + ret = adm_apr_send_pkt((uint32_t *) &open_v6, + &this_adm.copp.wait[port_idx][copp_idx], + port_idx, copp_idx, open_v6.hdr.opcode); } else { - ret = apr_send_pkt(this_adm.apr, - (uint32_t *)&open); + ret = adm_apr_send_pkt((uint32_t *) &open, + &this_adm.copp.wait[port_idx][copp_idx], + port_idx, copp_idx, open.hdr.opcode); } if (ret < 0) { pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n", @@ -3427,26 +3417,6 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, return -EINVAL; } } - - /* Wait for the callback with copp id */ - ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]) >= 0, - msecs_to_jiffies(2 * TIMEOUT_MS)); - if (!ret) { - pr_err("%s: ADM open timedout for port_id: 0x%x for [0x%x]\n", - __func__, tmp_port, port_id); - return -EINVAL; - } else if (atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]) > 0) { - pr_err("%s: DSP returned error[%s]\n", - __func__, adsp_err_get_err_str( - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]))); - return adsp_err_get_lnx_err_code( - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx])); - } } atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]); @@ -3951,31 +3921,13 @@ int adm_close(int port_id, int perf_mode, int copp_idx) clear_bit(ADM_STATUS_CALIBRATION_REQUIRED, (void *)&this_adm.copp.adm_status[port_idx][copp_idx]); - - ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close); + ret = adm_apr_send_pkt((uint32_t *) &close, + &this_adm.copp.wait[port_idx][copp_idx], + port_idx, copp_idx, close.opcode); if (ret < 0) { pr_err("%s: ADM close failed %d\n", __func__, ret); return -EINVAL; } - - ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]) >= 0, - msecs_to_jiffies(TIMEOUT_MS)); - if (!ret) { - pr_err("%s: ADM cmd Route timedout for port 0x%x\n", - __func__, port_id); - return -EINVAL; - } else if (atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]) > 0) { - pr_err("%s: DSP returned error[%s]\n", - __func__, adsp_err_get_err_str( - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]))); - return adsp_err_get_lnx_err_code( - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx])); - } } if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) { diff --git a/dsp/rtac.c b/dsp/rtac.c index ed298e9c..4ae16f06 100644 --- a/dsp/rtac.c +++ b/dsp/rtac.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include @@ -882,7 +882,7 @@ int send_adm_apr(void *buf, u32 opcode) mutex_unlock(&rtac_adm_apr_mutex); result = adm_apr_send_pkt((uint32_t *)rtac_adm_buffer, - NULL, port_idx, copp_idx); + NULL, port_idx, copp_idx, adm_params.opcode); mutex_lock(&rtac_adm_apr_mutex); if (opcode == ADM_CMD_GET_PP_PARAMS_V5) { diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h index 20b2450b..84fc1e01 100644 --- a/include/dsp/q6adm-v2.h +++ b/include/dsp/q6adm-v2.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #ifndef __Q6_ADM_V2_H__ #define __Q6_ADM_V2_H__ @@ -230,5 +230,5 @@ void msm_dts_srs_release_lock(void); void adm_set_native_mode(int mode); int adm_set_ffecns_freeze_event(bool ffecns_freeze_event); int adm_apr_send_pkt(void *data, wait_queue_head_t *wait, - int port_idx, int copp_idx); + int port_idx, int copp_idx, int opcode); #endif /* __Q6_ADM_V2_H__ */ -- cgit v1.2.3 From 258d29334a915d45b7ad6b1820cc5a0be5b375b0 Mon Sep 17 00:00:00 2001 From: "Vangala, Amarnath" Date: Tue, 27 Oct 2020 23:53:04 +0530 Subject: asoc: codecs: fix race condition of core vote and reg access Auto suspend timer for core vote is triggering before read write complete. Move the auto suspend of core vote to post read write operation. Change-Id: Ib0f6b026fe0e7fd3fbe052691db492915e436a78 Signed-off-by: Vangala, Amarnath --- asoc/codecs/bolero/rx-macro.c | 17 ++++++++++------ asoc/codecs/bolero/tx-macro.c | 13 +++++++----- asoc/codecs/bolero/va-macro.c | 13 +++++++----- asoc/codecs/bolero/wsa-macro.c | 13 +++++++----- soc/swr-mstr-ctrl.c | 45 +++++++++++++++++++++++++++++++++++------- 5 files changed, 73 insertions(+), 28 deletions(-) diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index 9167088f..9934a865 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -1236,6 +1236,7 @@ static int rx_macro_mclk_enable(struct rx_macro_priv *rx_priv, rx_priv->default_clk_id, rx_priv->clk_id, true); + rx_macro_core_vote(rx_priv, false); if (ret < 0) { dev_err(rx_priv->dev, "%s: rx request clock enable failed\n", @@ -1290,6 +1291,7 @@ static int rx_macro_mclk_enable(struct rx_macro_priv *rx_priv, rx_priv->default_clk_id, rx_priv->clk_id, false); + rx_macro_core_vote(rx_priv, false); rx_priv->clk_id = rx_priv->default_clk_id; } } @@ -1409,11 +1411,11 @@ static int rx_macro_event_handler(struct snd_soc_component *component, "%s, failed to enable clk, ret:%d\n", __func__, ret); } else { - rx_macro_core_vote(rx_priv, true); bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, RX_CORE_CLK, false); } + rx_macro_core_vote(rx_priv, false); break; case BOLERO_MACRO_EVT_SSR_UP: trace_printk("%s, enter SSR up\n", __func__); @@ -3678,22 +3680,25 @@ static const struct snd_soc_dapm_route rx_audio_map[] = { static int rx_macro_core_vote(void *handle, bool enable) { + int rc = 0; struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle; if (rx_priv == NULL) { pr_err("%s: rx priv data is NULL\n", __func__); return -EINVAL; } + if (enable) { pm_runtime_get_sync(rx_priv->dev); + if (bolero_check_core_votes(rx_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { pm_runtime_put_autosuspend(rx_priv->dev); pm_runtime_mark_last_busy(rx_priv->dev); } - - if (bolero_check_core_votes(rx_priv->dev)) - return 0; - else - return -EINVAL; + return rc; } static int rx_swrm_clock(void *handle, bool enable) diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index a9afea49..7f0e758b 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -2678,22 +2678,25 @@ static int tx_macro_clk_switch(struct snd_soc_component *component, int clk_src) static int tx_macro_core_vote(void *handle, bool enable) { + int rc = 0; struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle; if (tx_priv == NULL) { pr_err("%s: tx priv data is NULL\n", __func__); return -EINVAL; } + if (enable) { pm_runtime_get_sync(tx_priv->dev); + if (bolero_check_core_votes(tx_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { pm_runtime_put_autosuspend(tx_priv->dev); pm_runtime_mark_last_busy(tx_priv->dev); } - - if (bolero_check_core_votes(tx_priv->dev)) - return 0; - else - return -EINVAL; + return rc; } static int tx_macro_swrm_clock(void *handle, bool enable) diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index 20117e7f..93fc0fc9 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -671,22 +671,25 @@ done: static int va_macro_core_vote(void *handle, bool enable) { + int rc = 0; struct va_macro_priv *va_priv = (struct va_macro_priv *) handle; if (va_priv == NULL) { pr_err("%s: va priv data is NULL\n", __func__); return -EINVAL; } + if (enable) { pm_runtime_get_sync(va_priv->dev); + if (bolero_check_core_votes(va_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { pm_runtime_put_autosuspend(va_priv->dev); pm_runtime_mark_last_busy(va_priv->dev); } - - if (bolero_check_core_votes(va_priv->dev)) - return 0; - else - return -EINVAL; + return rc; } static int va_macro_swrm_clock(void *handle, bool enable) diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index e867141f..4e06d12b 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -2828,22 +2828,25 @@ static void wsa_macro_init_reg(struct snd_soc_component *component) static int wsa_macro_core_vote(void *handle, bool enable) { + int rc = 0; struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle; if (wsa_priv == NULL) { pr_err("%s: wsa priv data is NULL\n", __func__); return -EINVAL; } + if (enable) { pm_runtime_get_sync(wsa_priv->dev); + if (bolero_check_core_votes(wsa_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { pm_runtime_put_autosuspend(wsa_priv->dev); pm_runtime_mark_last_busy(wsa_priv->dev); } - - if (bolero_check_core_votes(wsa_priv->dev)) - return 0; - else - return -EINVAL; + return rc; } static int wsa_swrm_clock(void *handle, bool enable) diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 385e59fa..4cdb3f50 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -457,7 +457,7 @@ static int swrm_get_ssp_period(struct swr_mstr_ctrl *swrm, return ((swrm->bus_clk * 2) / ((row * col) * frame_sync)); } -static int swrm_core_vote_request(struct swr_mstr_ctrl *swrm) +static int swrm_core_vote_request(struct swr_mstr_ctrl *swrm, bool enable) { int ret = 0; @@ -470,7 +470,7 @@ static int swrm_core_vote_request(struct swr_mstr_ctrl *swrm) goto exit; } if (swrm->core_vote) { - ret = swrm->core_vote(swrm->handle, true); + ret = swrm->core_vote(swrm->handle, enable); if (ret) dev_err_ratelimited(swrm->dev, "%s: core vote request failed\n", __func__); @@ -501,8 +501,10 @@ static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable) dev_err_ratelimited(swrm->dev, "%s: core vote request failed\n", __func__); + swrm->core_vote(swrm->handle, false); goto exit; } + ret = swrm->core_vote(swrm->handle, false); } } swrm->clk_ref_count++; @@ -538,6 +540,7 @@ static int swrm_ahb_write(struct swr_mstr_ctrl *swrm, { u32 temp = (u32)(*value); int ret = 0; + int vote_ret = 0; mutex_lock(&swrm->devlock); if (!swrm->dev_up) @@ -551,13 +554,20 @@ static int swrm_ahb_write(struct swr_mstr_ctrl *swrm, __func__); goto err; } - } else if (swrm_core_vote_request(swrm)) { - goto err; + } else { + vote_ret = swrm_core_vote_request(swrm, true); + if (vote_ret == -ENOTSYNC) + goto err_vote; + else if (vote_ret) + goto err; } iowrite32(temp, swrm->swrm_dig_base + reg); if (is_swr_clk_needed(swrm)) swrm_clk_request(swrm, FALSE); +err_vote: + if (!is_swr_clk_needed(swrm)) + swrm_core_vote_request(swrm, false); err: mutex_unlock(&swrm->devlock); return ret; @@ -568,6 +578,7 @@ static int swrm_ahb_read(struct swr_mstr_ctrl *swrm, { u32 temp = 0; int ret = 0; + int vote_ret = 0; mutex_lock(&swrm->devlock); if (!swrm->dev_up) @@ -580,14 +591,21 @@ static int swrm_ahb_read(struct swr_mstr_ctrl *swrm, __func__); goto err; } - } else if (swrm_core_vote_request(swrm)) { - goto err; + } else { + vote_ret = swrm_core_vote_request(swrm, true); + if (vote_ret == -ENOTSYNC) + goto err_vote; + else if (vote_ret) + goto err; } temp = ioread32(swrm->swrm_dig_base + reg); *value = temp; if (is_swr_clk_needed(swrm)) swrm_clk_request(swrm, FALSE); +err_vote: + if (!is_swr_clk_needed(swrm)) + swrm_core_vote_request(swrm, false); err: mutex_unlock(&swrm->devlock); return ret; @@ -2577,6 +2595,7 @@ static int swrm_probe(struct platform_device *pdev) int ret = 0; struct clk *lpass_core_hw_vote = NULL; struct clk *lpass_core_audio = NULL; + u32 swrm_hw_ver = 0; /* Allocate soundwire master driver structure */ swrm = devm_kzalloc(&pdev->dev, sizeof(struct swr_mstr_ctrl), @@ -2603,6 +2622,14 @@ static int swrm_probe(struct platform_device *pdev) ret = -EINVAL; goto err_pdata_fail; } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,swr-master-version", + &swrm->version); + if (ret) { + dev_dbg(&pdev->dev, "%s: swrm version not defined, use default\n", + __func__); + swrm->version = SWRM_VERSION_1_6; + } ret = of_property_read_u32(pdev->dev.of_node, "qcom,swr_master_id", &swrm->master_id); if (ret) { @@ -2850,7 +2877,11 @@ static int swrm_probe(struct platform_device *pdev) swr_master_add_boarddevices(&swrm->master); mutex_lock(&swrm->mlock); swrm_clk_request(swrm, true); - swrm->version = swr_master_read(swrm, SWRM_COMP_HW_VERSION); + swrm_hw_ver = swr_master_read(swrm, SWRM_COMP_HW_VERSION); + if (swrm->version != swrm_hw_ver) + dev_info(&pdev->dev, + "%s: version specified in dtsi: 0x%x not match with HW read version 0x%x\n", + __func__, swrm->version, swrm_hw_ver); ret = swrm_master_init(swrm); if (ret < 0) { dev_err(&pdev->dev, -- cgit v1.2.3