Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ config HOST_DMA_RELOAD_THRESHOLD
The DMA buffer threshold in milliseconds to trigger host DMA
reloading.

config HOST_DMA_STREAM_SYNCHRONIZATION
bool "Stream DMA Transfers Synchronization"
default y if ACE
default n
help
Enable synchronized Firmware Pointer Increment (FPI) register updates of HD-A gateways
belonging to a group defined by the driver. The driver may also specify an update period
for each group, different than the default one determined by the system tick frequency.
This feature will allow host lower power consumption in scenarios with deep buffering.

config COMP_DAI
bool "DAI component"
default y
Expand Down
113 changes: 113 additions & 0 deletions src/audio/copier/copier_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,91 @@

#include <sof/audio/component_ext.h>
#include <sof/audio/host_copier.h>
#include <sof/tlv.h>
#include <sof/trace/trace.h>
#include <ipc4/copier.h>
#include <sof/audio/module_adapter/module/generic.h>

LOG_MODULE_DECLARE(copier, CONFIG_SOF_LOG_LEVEL);

#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION

/* NOTE: The code that modifies and checks the contents of the list can be executed on different
* cores. But since adding and removing modules is done exclusively via IPC, and we never add or
* remove more than one module, these functions do not require synchronization.
*/
struct fpi_sync_group {
uint32_t id;
uint32_t period;
uint32_t ref_count;
struct list_item item;
};
Comment thread
btian1 marked this conversation as resolved.
Resolved

static struct list_item group_list_head = LIST_INIT(group_list_head);

static struct fpi_sync_group *find_group_by_id(uint32_t id)
{
struct list_item *item;

list_for_item(item, &group_list_head) {
struct fpi_sync_group *group = list_item(item, struct fpi_sync_group, item);

if (group->id == id)
return group;
}

return NULL;
}

int add_to_fpi_sync_group(struct comp_dev *parent_dev,
struct host_data *hd,
struct ipc4_copier_sync_group *sync_group)
{
struct fpi_sync_group *group = find_group_by_id(sync_group->group_id);

if (group) {
if (group->period != sync_group->fpi_update_period_usec) {
comp_err(parent_dev, "incorrect period %u for group %u (currently %u)",
group->id, group->period, sync_group->fpi_update_period_usec);
return -EINVAL;
}

group->ref_count++;
} else {
group = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*group));
if (!group) {
comp_err(parent_dev, "Failed to alloc memory for new group");
return -ENOMEM;
}

group->id = sync_group->group_id;
group->period = sync_group->fpi_update_period_usec;
group->ref_count = 1;
list_item_append(&group->item, &group_list_head);
}

hd->is_grouped = true;
hd->group_id = group->id;
hd->period_in_cycles = k_us_to_cyc_ceil64(group->period);
comp_dbg(parent_dev, "gtw added to group %u with period %u", group->id, group->period);
return 0;
}

void delete_from_fpi_sync_group(struct host_data *hd)
{
struct fpi_sync_group *group = find_group_by_id(hd->group_id);

if (!group)
return;

group->ref_count--;
if (group->ref_count == 0) {
list_item_del(&group->item);
rfree(group);
}
}
#endif

/* Playback only */
static int init_pipeline_reg(struct comp_dev *dev)
{
Expand Down Expand Up @@ -81,6 +160,36 @@ int copier_host_create(struct comp_dev *parent_dev, struct copier_data *cd,
comp_err(parent_dev, "copier: host new failed with exit");
goto e_data;
}
#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION
/* Size of a configuration without optional parameters. */
const uint32_t basic_size = sizeof(*copier_cfg) +
(copier_cfg->gtw_cfg.config_length - 1) * sizeof(uint32_t);
/* Additional data size */
const uint32_t tlv_buff_size = config->ipc_config_size - basic_size;
const uint32_t min_tlv_size = sizeof(struct ipc4_copier_sync_group) + 2 * sizeof(uint32_t);

if (tlv_buff_size >= min_tlv_size) {
const uint32_t tlv_addr = (uint32_t)copier_cfg + basic_size;
uint32_t value_size = 0;
void *value_ptr = NULL;

tlv_value_get((void *)tlv_addr, tlv_buff_size, HDA_SYNC_FPI_UPDATE_GROUP,
&value_ptr, &value_size);

if (value_ptr) {
struct ipc4_copier_sync_group *sync_group;

if (value_size != sizeof(struct ipc4_copier_sync_group))
return -EINVAL;

sync_group = (struct ipc4_copier_sync_group *)((void *)value_ptr);

ret = add_to_fpi_sync_group(parent_dev, hd, sync_group);
Comment thread
tmleman marked this conversation as resolved.
Resolved
if (ret < 0)
return ret;
}
}
#endif

cd->converter[IPC4_COPIER_GATEWAY_PIN] =
get_converter_func(&copier_cfg->base.audio_fmt,
Expand Down Expand Up @@ -122,6 +231,10 @@ int copier_host_create(struct comp_dev *parent_dev, struct copier_data *cd,

void copier_host_free(struct copier_data *cd)
{
#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION
if (cd->hd->is_grouped)
delete_from_fpi_sync_group(cd->hd);
Comment thread
tmleman marked this conversation as resolved.
Resolved
#endif
host_common_free(cd->hd);
rfree(cd->hd);
}
Expand Down
34 changes: 30 additions & 4 deletions src/audio/host-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,29 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev
return ALIGN_DOWN(dma_copy_bytes, hd->dma_copy_align);
}

#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION
static inline bool stream_sync(struct host_data *hd, struct comp_dev *dev)
{
if (!hd->is_grouped)
return true;

uint64_t current_time = k_cycle_get_64();

if (current_time >= hd->next_sync) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having timer logic without wrap-around handling is always a bit iffy, but given we have explicit 64bit counter, it would seem this is safe. Even with a 10x faster system clock, this would still take thousands of years to wrap around. I think current uptime record holder is still the one Cisco switch that is around 26 years now, so we have some safety margin -> https://en.wikipedia.org/wiki/Uptime

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, worth an inline comment here so that no one tries to fix later on.

hd->next_sync = current_time + hd->period_in_cycles;
comp_dbg(dev, "hd(%p) next sync = %llu", hd, hd->next_sync);
return true;
}

return false;
}
#else
static inline bool stream_sync(struct host_data *hd, struct comp_dev *dev)
{
return true;
}
#endif

/**
* Performs copy operation for host component working in normal mode.
* It means DMA works continuously and doesn't need reconfiguration.
Expand Down Expand Up @@ -471,11 +494,14 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal
audio_stream_get_size(&buffer_c->stream) < hd->period_bytes << 3 ||
audio_stream_get_size(&buffer_c->stream) - hd->partial_size <=
(2 + threshold) * hd->period_bytes) {
ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, hd->partial_size);
if (ret < 0)
comp_err(dev, "host_copy_normal(): dma_copy() failed, ret = %u", ret);
if (stream_sync(hd, dev)) {
ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0,
hd->partial_size);
if (ret < 0)
comp_err(dev, "dma_reload() failed, ret = %u", ret);

hd->partial_size = 0;
hd->partial_size = 0;
}
}

buffer_release(buffer_c);
Expand Down
8 changes: 8 additions & 0 deletions src/include/ipc4/copier.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ enum ipc4_copier_features {
IPC4_COPIER_FAST_MODE = 0
};

#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION
#define HDA_SYNC_FPI_UPDATE_GROUP 0
struct ipc4_copier_sync_group {
uint32_t group_id;
uint32_t fpi_update_period_usec;
} __packed __aligned(4);
Comment thread
btian1 marked this conversation as resolved.
Resolved
#endif

struct ipc4_copier_gateway_cfg {
/* ID of Gateway Node. If node_id is valid, i.e. != -1, copier instance is connected to the
* specified gateway using either input pin 0 or output pin 0 depending on
Expand Down
19 changes: 11 additions & 8 deletions src/include/sof/audio/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -544,15 +544,18 @@ struct comp_driver_info {
* Audio component base configuration from IPC at creation.
*/
struct comp_ipc_config {
uint32_t core; /**< core we run on */
Comment thread
lgirdwood marked this conversation as resolved.
Resolved
uint32_t id; /**< component id */
uint32_t pipeline_id; /**< component pipeline id */
uint32_t proc_domain; /**< processing domain - LL or DP */
uint32_t core; /**< core we run on */
uint32_t id; /**< component id */
uint32_t pipeline_id; /**< component pipeline id */
uint32_t proc_domain; /**< processing domain - LL or DP */
enum sof_comp_type type; /**< component type */
uint32_t periods_sink; /**< 0 means variable */
uint32_t periods_source;/**< 0 means variable */
uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */
uint32_t xrun_action; /**< action we should take on XRUN */
uint32_t periods_sink; /**< 0 means variable */
uint32_t periods_source; /**< 0 means variable */
uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */
uint32_t xrun_action; /**< action we should take on XRUN */
#if CONFIG_IPC_MAJOR_4
uint32_t ipc_config_size; /**< size of a config received by ipc */

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we please leave out the formatting changes to see it is easy to see that only 1 field is added? And btw won't this break IPC3? Should this be within #if CONFIG_MAJOR_IPC4?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can comp_ipc_config be changed? not sure why not left some redundancy space for later adding, like uint32_t valid_fmt to align internal usage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@btian1 can you explain exactly what you mean? Sorry, but I don't quite understand what your comment means.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean:

  1. comp_ipc_config, normally, should not add or remove, it need keep stable, since driver and sof both need this, if change, may need change synchronous in SOF and driver。
  2. this structure should have some redundant space for future extension, then for this change, you just need change a variable name, instead of adding a new variable with IPC4 limited.
    uint32_t reserved[4];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I saw in code struct comp_ipc_config is internal SOF struct and its not expose to driver. It's created on FW side during module initialization and therefore I assume that is safe to add new value to it.

https://github.com/thesofproject/sof/blob/main/src/ipc/ipc4/helper.c#L81-L105

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not have a change to check driver, just guess driver side also have a similar copy, if not, how to pass it from driver to fw(sof)?
@ranj063 , do we need update driver side as well?

#endif
};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/include/sof/audio/host_copier.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ struct host_data {
/* stream info */
struct sof_ipc_stream_posn posn; /* TODO: update this */
struct ipc_msg *msg; /**< host notification */
#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION
bool is_grouped;
uint8_t group_id;
uint64_t next_sync;
uint64_t period_in_cycles;
#endif
};

int host_common_new(struct host_data *hd, struct comp_dev *dev,
Expand Down
1 change: 1 addition & 0 deletions src/ipc/ipc4/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init)
ipc_config.id = comp_id;
ipc_config.pipeline_id = module_init->extension.r.ppl_instance_id;
ipc_config.core = module_init->extension.r.core_id;
ipc_config.ipc_config_size = module_init->extension.r.param_block_size * sizeof(uint32_t);

#if CONFIG_ZEPHYR_DP_SCHEDULER
if (module_init->extension.r.proc_domain)
Expand Down