lnl: sndw: use HDA DMA to transfer stream data #8361
lnl: sndw: use HDA DMA to transfer stream data #8361kv2019i merged 4 commits intothesofproject:mainfrom
Conversation
|
Erm, sorry, whaaaaat? LNL aggregation already works without any firmware support. The aggregation is handled with the host driver programming the PCMsCM registers in the multi-link configuration. The firmware should only deal with ONE stream ID and does not need to know whether any aggregation is handled since the DMA hardware deals with aggregation. Why is a firmware-based solution introduced now? |
plbossart
left a comment
There was a problem hiding this comment.
on top of my earlier comment that aggregation does not need any firmware support, the change is inconsistent for the DMIC/SSP support that already works fine as well.
|
@plbossart I've been anticipating such kind of questions that's why I submitted a draft :) My intention was to use current FW infrastructure to enable SNDW on LNL using HDA DMA and since HDA dai doesn't program any hardware I decided to use it for SNDW configuration on SOF side. |
src/ipc/ipc4/helper.c
Outdated
| if (dma_cfg->channel_map.map[i].device_address == device_id) { | ||
| dai->host_dma_config[dma_cfg_count] = dma_cfg; | ||
| hit = true; | ||
| break; |
There was a problem hiding this comment.
please just do return IPC4_SUCCESS here and remove hit
src/ipc/ipc4/helper.c
Outdated
| struct ipc_dma_config *dma_cfg; | ||
| int dma_cfg_count = 0; | ||
|
|
||
| while ((uint32_t)tlvs < end_addr) { |
There was a problem hiding this comment.
could do
for (tlvs = (struct sof_tlv *)data_buffer; (uint32_t)tlvs < end_addr; tlvs = tlv_next(tlvs))
src/audio/copier/copier.c
Outdated
| goto error_cd; | ||
| } | ||
|
|
||
| cd->gtw_cfg = gtw_cfg; |
There was a problem hiding this comment.
I would assign only in success case - below memcpy_s() - to avoid a dangling pointer
src/audio/copier/copier.c
Outdated
| * config is used to assing dma_channel_id value. | ||
| */ | ||
| if (copier->gtw_cfg.config_length) { | ||
| gtw_cfg_size = (copier->gtw_cfg.config_length << 2); |
src/audio/copier/copier.c
Outdated
|
|
||
| if (memcpy_s(cd->gtw_cfg, gtw_cfg_size, | ||
| &copier->gtw_cfg.config_data, gtw_cfg_size) < 0) { | ||
| ret = -EINVAL; |
src/audio/copier/copier.c
Outdated
| struct module_data *md = &mod->priv; | ||
| struct ipc4_copier_module_cfg *copier = (struct ipc4_copier_module_cfg *)md->cfg.init_data; | ||
| struct comp_ipc_config *config = &dev->ipc_config; | ||
| uint32_t *gtw_cfg; |
src/include/ipc4/copier.h
Outdated
| * from the IPC data. | ||
| */ | ||
| struct ipc4_copier_module_cfg config; | ||
| uint32_t *gtw_cfg; |
src/audio/copier/copier_dai.c
Outdated
| } | ||
|
|
||
| static int copier_alh_assign_dai_index(struct comp_dev *dev, | ||
| uint32_t *gtw_cfg_data, |
There was a problem hiding this comment.
void * and remove the cast in line 77
src/ipc/ipc4/dai.c
Outdated
| } | ||
|
|
||
| const struct sof_alh_configuration_blob *alh_blob = | ||
| (const struct sof_alh_configuration_blob *)cd->gtw_cfg; |
There was a problem hiding this comment.
this type-cast would go too
b31b017 to
3bb6ca5
Compare
src/ipc/ipc4/helper.c
Outdated
|
|
||
| for (tlvs = (struct sof_tlv *)data_buffer; (uint32_t)tlvs < end_addr; | ||
| tlvs = tlv_next(tlvs)) { | ||
| dma_cfg = (struct ipc_dma_config *)tlv_value_ptr_get( |
There was a problem hiding this comment.
no need to type-cast a void * pointer to another pointer type
src/ipc/ipc4/helper.c
Outdated
|
|
||
| for (uint32_t i = 0; i < dma_cfg->channel_map.device_count; i++) { | ||
| if (dma_cfg->channel_map.map[i].device_address == device_id) { | ||
| dai->host_dma_config[dma_cfg_count] = dma_cfg; |
There was a problem hiding this comment.
this is a somewhat strange counter: dma_cfg_count how many valid (with a non-NULL dma_cfg pointer) didn't match the requested device and then assigns to an array with that index... The connection isn't obvious. Could you clarify?
There was a problem hiding this comment.
device_id corresponds to SNDW master id (alh_id or channel_map.map[i].device_address) in gtw_cfg and it is not necessary match gtw_cfg number in Copier module blob. E.g. driver could send a request to configure aggregation on SNDW master 1 (alh_id=1) and 3 (alh_id=3) then two gtw_cfg will be appended to the init instance IPC and will receive 0 and 1 indexes in this loop. To put them one by one in host_dma_config[] I added an additional counter.
There was a problem hiding this comment.
that is absolutely not what we discussed with @mmaka1. device_address was supposed to be the PCMsCMy FIFO address.
There was a problem hiding this comment.
Yes, device_address should be PCMsCMy, but Windows drv always set this value and I need to deal with it.
There was a problem hiding this comment.
I am still lost by all this.
what exactly is this 'device_id'
a) the link_id as I can read in the November 3 comment
b) the address of the PCMsCMy register
c) the PDI index written in PCMsCMy?
Also we all agree that the firmware does not program the PCMsCMy register, so what exactly does the firmware do with the device_id.
How many engineers does it take to define what a 'device' is?
Two additional questions: what happens if we do
One additional question: the 'device_id' aka PDI ID is specific to a link. The DMA configuration is not link specific, we can use whatever stream_tag we want.
So how do we know which PDI
src/audio/copier/copier_dai.c
Outdated
| } | ||
| dai_index[0] = dai->host_dma_config[0]->stream_id; | ||
|
|
||
| return ret; |
src/ipc/ipc4/dai.c
Outdated
|
|
||
| if (!cd->gtw_cfg) { | ||
| comp_err(dev, "No gateway config found!"); | ||
| return channel; |
There was a problem hiding this comment.
I think it would be more obvious to have return DMA_CHAN_INVALID here and move line 93 to around line 100 below
3bb6ca5 to
b615983
Compare
RanderWang
left a comment
There was a problem hiding this comment.
Looks good to me. BTW we support llp update with GP-DMA, how about HD-DMA ?
|
@plbossart @iganakov do you guys have alignment now or still opens around the latest patch updates ? |
No alignment, there's no clarity on what exactly the gateway configuration should be. Both @bardliao and I looked into this - no reply on our comments so far. |
| if (copier->gtw_cfg.config_length) { | ||
| gtw_cfg_size = copier->gtw_cfg.config_length << 2; | ||
| gtw_cfg = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, | ||
| gtw_cfg_size); |
There was a problem hiding this comment.
no need for rzalloc() - it's completely overwritten 6 lines below. Just use rmalloc()
| * } | ||
| * } | ||
| * } | ||
| */ |
There was a problem hiding this comment.
is this... description not valid any more? I'm not entirely sure what it meant, but some documentation is often better than no documentation
There was a problem hiding this comment.
This comment belongs to struct ipc4_copier_gateway_cfg for ALH node_id. This structure is well commented in alh.h an copier.h headers. So I think it's not necessary to have it here.
|
@lgirdwood @plbossart sorry guys I was on a sick leave. I'm in touch with @bardliao we're making some additional experiments |
kv2019i
left a comment
There was a problem hiding this comment.
Hmm. A generic concern is that this is exploding amount of seemingly Intel specific code in generic sof/src/audio code. This is hinting the split of what is done in Zephyr versus SOF is not right with the DAI interfaces, if we need to do this much platform specific ifdefs in generic SOF code. Many bits have existed before this PR, but this PR does double/triple the size.
src/ipc/ipc4/helper.c
Outdated
| int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, | ||
| uint32_t size, uint32_t device_id) | ||
| { | ||
| #if defined(CONFIG_ACE_VERSION_2_0) |
There was a problem hiding this comment.
This is very Intel specific code in a vendor-neutral file. At least a todo marker is needed that this need to be a generic option that can be enabled for multiple platforms (one such being Intel ACE2.0 and newer).
There was a problem hiding this comment.
@kv2019i I found a way to make code more generic, please check a new version.
src/audio/copier/copier_dai.c
Outdated
| return -EINVAL; | ||
| } | ||
|
|
||
| #if defined(CONFIG_ACE_VERSION_2_0) |
There was a problem hiding this comment.
Here again, we have very Intel specific code in copier_dai.c which would need to be generic. We've had DAI type specific code segments before in src/audio , but this is expanding the amount of code quite significantly.
There was a problem hiding this comment.
I transformed this code to be generic one
|
@iganakov thinking aloud, do we need a new boot ID flag to indicate the presence of this feature i.e. supported modes ? |
|
@lgirdwood We have internal discussions about common blob format for Linux and Windows. I'll update this PR when proper solution will appear. |
Great - @plbossart what are the next steps now ? |
|
Just to be clear, what tests did you run @bardliao? we have 3 possible configurations: a) existing firmware with thesofproject/linux#4752 I am mostly concerned about a) since that's a clear example of "we don't break user setups". |
plbossart
left a comment
There was a problem hiding this comment.
I don't really have any comments on the code proper, but there's no description of what it does and what the TLV needs to be.
src/ipc/ipc4/helper.c
Outdated
|
|
||
| for (uint32_t i = 0; i < dma_cfg->channel_map.device_count; i++) { | ||
| if (dma_cfg->channel_map.map[i].device_address == device_id) { | ||
| dai->host_dma_config[dma_cfg_count] = dma_cfg; |
There was a problem hiding this comment.
I am still lost by all this.
what exactly is this 'device_id'
a) the link_id as I can read in the November 3 comment
b) the address of the PCMsCMy register
c) the PDI index written in PCMsCMy?
Also we all agree that the firmware does not program the PCMsCMy register, so what exactly does the firmware do with the device_id.
How many engineers does it take to define what a 'device' is?
Two additional questions: what happens if we do
One additional question: the 'device_id' aka PDI ID is specific to a link. The DMA configuration is not link specific, we can use whatever stream_tag we want.
So how do we know which PDI
I tested a) The existing firmware (v2.7) with thesofproject/linux#4752 |
src/ipc/ipc4/helper.c
Outdated
| } | ||
| } | ||
|
|
||
| dma_cfg_count++; |
There was a problem hiding this comment.
@iganakov We should only do dma_cfg_count++ when we assign dai->host_dma_config[dma_cfg_count] = dma_cfg;.
IMHO, dma_cfg_count should be an argument of ipc4_find_dma_config_multiple not a local variable. ipc4_find_dma_config_multiple will return immediately when it find the dma config with the device_id. We need to specify dai->host_dma_config[] index from the caller.
I do meet an issue if the dma config is not found in the first tlv. In that case, we don't assign dai->host_dma_config[dma_cfg_count] = dma_cfg; in the first for (uint32_t i = 0; i < dma_cfg->channel_map.device_count; i++) loop, and dma_cfg_count++. As a result, dai->host_dma_config[0] = NULL and dma_cfg is assigned to dai->host_dma_config[1] that is not what we want.
There was a problem hiding this comment.
Good catch. I'll change ipc4_find_dma_config_multiple() in next revision of this patch. Thanks @bardliao
|
@lgirdwood I prepared some minor improvements and will update this PR soon. As I know @bardliao modified Linux blob and is able to use FW aggregation for playback but still has some issues with capture. |
a8b32b1 to
5c9fe39
Compare
|
@bardliao any update for capture ? |
plbossart
left a comment
There was a problem hiding this comment.
I still have objections on the clarity of the code
- What is a device?
- Can we clarify the design and why a DMA 'stream_id' becomes a 'dai_index'
when it looks confusing it's awful to maintain...
I am still struggling with aggregation capture. I always get pcm IO error even with exact the same blob that was verified with slim driver. |
Add function which retrieves pointer to the TLV structure value of the specified type Signed-off-by: Ievgen Ganakov <ievgen.ganakov@intel.com>
Add host_dma_config array to be able to keep multiple DMA tlv pointers. This change is needed to enable SNDW FW aggregation using HD-A DMA on LNL Signed-off-by: Ievgen Ganakov <ievgen.ganakov@intel.com>
Add helper function to parse muiltiple DMA config tlv structures added to copier Init Instance IPC in case of SNDW FW aggregation. To be able to find correct config we need to iterate over the sequence of DMA tlv with the same tlv type. Thus, we need to check if device_address value (which contains PDI) is equal to device_id parameter (passed with alh_id value). Signed-off-by: Ievgen Ganakov <ievgen.ganakov@intel.com>
5c9fe39 to
37e76e8
Compare
Since LNL soundwire uses HD-A DMA to transfer data. Add LNL specific configuration to select HD-A DMA in case of SoundWire audio interface. Refactor copier dai code for sndw/alh node id type. Add support for sndw link aggregation mode for LNL platform based on DMA config being sent during Copier Init Instance IPC. Signed-off-by: Ievgen Ganakov <ievgen.ganakov@intel.com>
37e76e8 to
3787071
Compare
|
Causing regression: |
Since LNL SoundWire interface uses HDA DMA to transfer stream data.
This approach uses HDA dai and HDA DMA. No changes needed on Zephyr side.
Following solution involves FW based SoundWire link aggregation mechanism which
is also used on MTL for backward compatibility with Windows driver.
This is a working solution. It was tested in E2E scenarios with Windows driver.