[alsa-devel] [RESEND PATCH v3] ASoC: Intel: Skylake: large_config_get overhaul
Cezary Rojewski
cezary.rojewski at intel.com
Wed Aug 7 22:51:12 CEST 2019
On 2019-08-07 22:00, Pierre-Louis Bossart wrote:
> I find this patch quite convoluted, so I ordered my comments to make
> them linear.
Sure thing, thanks for feedback!
>> LARGE_CONFIG_GET is among the most crucial IPCs. Host is expected to
>> send single request first to obtain total payload size from received
>> header's data_off_size. From then on, it loops for each frame exceeding
>> inbox size until entire payload is read. If entire payload is contained
>> within the very first frame, no looping is performed.
>
> so there's got to be a test that defines if looping is required or not
> but see [1] below.
>
Precisely! That is also why reply handling was needed (already applied
by Mark). Without "data_off_size" field retrieved from reply's header
(extension), you're in the dark when it comes to payload size.
>>
>> LARGE_CONFIG_GET is a flexible IPC, it not only receives payload but may
>> carry one with them to provide list of params DSP module should return
>> info for. This behavior is usually reserved for vendors and IPC handler
>> should not touch that content. To achieve that, simply pass provided
>> payload and bytes to sst_ipc_tx_message_wait as a part of request.
>
> [2] And this has nothing to do with the loops, does it?
If I'm to dive into details so be it. _get_ operates in 3 modes:
1) single request : single reply (requests fits into single frame)
1 config param to retrieve
fw status/ fw error code will point directly what's going on
(after all there is just one param here..)
param_id < 0xFF
data_off_size has single meaning here: payload size
2) large request, spanning over several frames : as many replies as
required (dsp reply.header.extension.final_block == 1)
1 config param to retrieve
fw status/ fw error code will point directly what's going on
(after all there is just one param here..)
param_id < 0xFF
data_off_size switches context here:
reply.header.extension.data_off_size for the very first reply carries
TOTAL payload size. From then on, it marks buffer offset size - host
makes use of this offset and injects data into right pos within his own
buffer.
3) vendor request : single reply (request MUST fit into single frame)
X config params to retrieve, each represented by TLV
fw status/ fw error code provides generic outcome only
(on failure error-payload is returned. Can be parsed to get idx of TLV,
from specified TLV array, which caused the failure to occur)
param_id == 0xFF
data_off_size has single meaning here: payload size
Error-payload is by no means restricted to 3rd case-only, it's just
optional and may not be provided by DSP depending on particular request.
>
>> In current state, LARGE_CONFIG_GET message handler does nothing of that,
>> in consequence making it dysfunctional. Overhaul said handler allowing
>> rightful king of IPCs to return back on his throne - kingdom he shares
>> with his twin brother: LARGE_CONFIG_SET.
>
> [3] what is dysfunctional? the unnecessary loops or handling data in the
> IPC that should only be handled in vendor-specific parts. And btw I
> don't see vendor-specific parts in the Skylake driver, so not sure how
> those vendor-specific thingies are handled at all.
a) payload size is skipped, this method runs in the dark
b) provides no vendor-request functionality
c) error-payload is never returned
d) wonky toggling of init_block. Host never touches init_block field
once initial message has been carried out - a book only ever has a
single prologue, ain't it?
>
>> The looping has not been added in this update as payloads of such size
>> do not exist in practice. Will need to create custom module specifically
>> for that very case and test against it before that feature can be added.
>
> [1] here you are just saying that the looping is really not required so
> there are no tests at all...
>
> [4] So shouldn't you split the two parts of this patch and separate
> looping from not touching the data that's vendor-specific?
So, looping mainly gets used in _sets_, for _gets_ I've not seen a live
example, really - despite FW supporting such flow. However, I'd like to
verify before adding any looping, possibly by creating a custom module
myself. Followup to your point: existing looping was not tested either.
There is only one _get_ I can think of which might replace custom module
approach.. the MODULES_INFO one. You just need a FW binary with bunch of
features included : ) I'll try out TGL one.
That's why I prefer adding major _get_ fix first and only then a
separate patch for looping - once tested.
>
>>
>> Signed-off-by: Cezary Rojewski <cezary.rojewski at intel.com>
>> ---
>> sound/soc/intel/skylake/skl-messages.c | 3 +-
>> sound/soc/intel/skylake/skl-sst-ipc.c | 54 +++++++++++---------------
>> sound/soc/intel/skylake/skl-sst-ipc.h | 3 +-
>> 3 files changed, 27 insertions(+), 33 deletions(-)
>>
>> diff --git a/sound/soc/intel/skylake/skl-messages.c
>> b/sound/soc/intel/skylake/skl-messages.c
>> index e8cc710f092b..84f0e6f58eb5 100644
>> --- a/sound/soc/intel/skylake/skl-messages.c
>> +++ b/sound/soc/intel/skylake/skl-messages.c
>> @@ -1379,11 +1379,12 @@ int skl_get_module_params(struct skl_dev *skl,
>> u32 *params, int size,
>> u32 param_id, struct skl_module_cfg *mcfg)
>> {
>> struct skl_ipc_large_config_msg msg;
>> + size_t bytes = size;
>> msg.module_id = mcfg->id.module_id;
>> msg.instance_id = mcfg->id.pvt_id;
>> msg.param_data_size = size;
>> msg.large_param_id = param_id;
>> - return skl_ipc_get_large_config(&skl->ipc, &msg, params);
>> + return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes);
>> }
>> diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c
>> b/sound/soc/intel/skylake/skl-sst-ipc.c
>> index a2b69a02aab2..9d269a5f8bd9 100644
>> --- a/sound/soc/intel/skylake/skl-sst-ipc.c
>> +++ b/sound/soc/intel/skylake/skl-sst-ipc.c
>> @@ -969,12 +969,17 @@ int skl_ipc_set_large_config(struct
>> sst_generic_ipc *ipc,
>> EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
>> int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
>> - struct skl_ipc_large_config_msg *msg, u32 *param)
>> + struct skl_ipc_large_config_msg *msg,
>> + unsigned int **payload, size_t *bytes)
>> {
>> struct skl_ipc_header header = {0};
>> - struct sst_ipc_message request = {0}, reply = {0};
>> - int ret = 0;
>> - size_t sz_remaining, rx_size, data_offset;
>> + struct sst_ipc_message request, reply = {0};
>> + unsigned int *buf;
>> + int ret;
>> +
>> + reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL);
>> + if (!reply.data)
>> + return -ENOMEM;
>> header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
>> header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
>> @@ -987,34 +992,21 @@ int skl_ipc_get_large_config(struct
>> sst_generic_ipc *ipc,
>> header.extension |= IPC_FINAL_BLOCK(1);
>> header.extension |= IPC_INITIAL_BLOCK(1);
>> - sz_remaining = msg->param_data_size;
>> - data_offset = 0;
>> -
>> - while (sz_remaining != 0) {
>> - rx_size = sz_remaining > SKL_ADSP_W1_SZ
>> - ? SKL_ADSP_W1_SZ : sz_remaining;
>> - if (rx_size == sz_remaining)
>> - header.extension |= IPC_FINAL_BLOCK(1);
>> -
>> - request.header = *(u64 *)(&header);
>> - reply.data = ((char *)param) + data_offset;
>> - reply.size = msg->param_data_size;
>> - ret = sst_ipc_tx_message_wait(ipc, request, &reply);
>> - if (ret < 0) {
>> - dev_err(ipc->dev,
>> - "ipc: get large config fail, err: %d\n", ret);
>> - return ret;
>> - }
>> - sz_remaining -= rx_size;
>> - data_offset = msg->param_data_size - sz_remaining;
>> + request.header = *(u64 *)&header;
>> + request.data = *payload;
>> + request.size = *bytes;
>> + reply.size = SKL_ADSP_W1_SZ;
>> - /* clear the fields */
>> - header.extension &= IPC_INITIAL_BLOCK_CLEAR;
>> - header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
>> - /* fill the fields */
>> - header.extension |= IPC_INITIAL_BLOCK(1);
>> - header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
>> - }
>> + ret = sst_ipc_tx_message_wait(ipc, request, &reply);
>> + if (ret < 0)
>> + dev_err(ipc->dev, "ipc: get large config fail: %d\n", ret);
>> +
>> + reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK;
>> + buf = krealloc(reply.data, reply.size, GFP_KERNEL);
>> + if (!buf)
>> + return -ENOMEM;
>> + *payload = buf;
>> + *bytes = reply.size;
>> return ret;
>> }
>> diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h
>> b/sound/soc/intel/skylake/skl-sst-ipc.h
>> index 93af08cf41d2..a7ab2c589cc5 100644
>> --- a/sound/soc/intel/skylake/skl-sst-ipc.h
>> +++ b/sound/soc/intel/skylake/skl-sst-ipc.h
>> @@ -139,7 +139,8 @@ int skl_ipc_set_large_config(struct
>> sst_generic_ipc *ipc,
>> struct skl_ipc_large_config_msg *msg, u32 *param);
>> int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
>> - struct skl_ipc_large_config_msg *msg, u32 *param);
>> + struct skl_ipc_large_config_msg *msg,
>> + unsigned int **payload, size_t *bytes);
>> int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
>> u8 dma_id, u8 table_id, bool wait);
>>
More information about the Alsa-devel
mailing list