[alsa-devel] [RESEND PATCH v3] ASoC: Intel: Skylake: large_config_get overhaul
Pierre-Louis Bossart
pierre-louis.bossart at linux.intel.com
Thu Aug 8 05:30:02 CEST 2019
On 8/7/19 3:51 PM, Cezary Rojewski wrote:
> 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.
So how about removing this looping first in the existing code and add
the needed changes in a second patch? wouldn't that help make the
changes more self-contained? A large part of your patch below has
indentation differences which make it hard to figure out what the new
approach is.
>
> 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