-
Notifications
You must be signed in to change notification settings - Fork 318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lnl: sndw: use HDA DMA to transfer stream data #8361
lnl: sndw: use HDA DMA to transfer stream data #8361
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? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
superfluous parentheses
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
propagate error
src/audio/copier/copier.c
Outdated
@@ -64,6 +64,8 @@ static int copier_init(struct processing_module *mod) | |||
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void *
src/include/ipc4/copier.h
Outdated
@@ -242,6 +242,7 @@ struct copier_data { | |||
* from the IPC data. | |||
*/ | |||
struct ipc4_copier_module_cfg config; | |||
uint32_t *gtw_cfg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void *
src/audio/copier/copier_dai.c
Outdated
@@ -64,6 +64,79 @@ static int copier_set_alh_multi_gtw_channel_map(struct comp_dev *dev, | |||
return 0; | |||
} | |||
|
|||
static int copier_alh_assign_dai_index(struct comp_dev *dev, | |||
uint32_t *gtw_cfg_data, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to type-cast a void *
pointer to another pointer type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here it's always return 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be more obvious to have return DMA_CHAN_INVALID
here and move line 93 to around line 100 below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, fixed
3bb6ca5
to
b615983
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
src/audio/copier/copier.c
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for rzalloc()
- it's completely overwritten 6 lines below. Just use rmalloc()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in PR #8574
* } | ||
* } | ||
* } | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bardliao must approve this one.
I would still add a comment, see below.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @iganakov
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.