Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a87a2b5
ASoC: SOF: Move the definition of enum snd_sof_fw_state to global header
ujfalusi Aug 13, 2021
4d512ec
ASoC: SOF: Introduce a macro to set the firmware state
ujfalusi Aug 16, 2021
44b2a43
ASoC: SOF: debug: Print out the fw_state along with the DSP dump
ujfalusi Aug 18, 2021
9115f5b
ASoC: SOF: Introduce new firmware state: SOF_FW_CRASHED
ujfalusi Aug 17, 2021
476d4c0
ASoC: soc-component: Add support module get/put on open for compresse…
ujfalusi Jul 23, 2021
7274b1c
ASoC: SOF: Introduce IPC SOF client support
ranj063 Oct 22, 2020
6a772ce
ASoC: SOF: core/ops: Add support for client registration
ranj063 Oct 22, 2020
a858cfa
ASoC: SOF: core: Unregister machine driver before IPC and debugfs
ujfalusi Jul 23, 2021
49abfdc
ASoC: SOF: ipc: Read and pass the whole message to handlers for IPC e…
ujfalusi Jul 6, 2021
11f3b3a
ASoC: SOF: clients: Add support for IPC rx and firmware state change
ujfalusi Jul 6, 2021
20c9323
ASoC: SOF: clients: Add support for auxdev suspend/resume handling
ujfalusi Jul 9, 2021
9e32894
ASoC: SOF: clients: Add API to get the SOF firmware version
ujfalusi Jul 7, 2021
bcaad35
ASoC: SOF: clients: Add API to manage the module refcount of SOF core
ujfalusi Jul 21, 2021
92a48c2
ASoC: SOF: intel: hda-trace: Pass the dma buffer pointer to hda_dsp_t…
ujfalusi Jul 9, 2021
9e675f2
ASoC: SOF: Split up utils.c into sof-utils and iomem-utils
ujfalusi Jul 15, 2021
deb5a0c
ASoC: SOF: Convert the generic IPC flood test into SOF client
ranj063 Oct 22, 2020
cba8df9
ASoC: SOF: sof-client-ipc-test: Protection against removal while in use
ujfalusi Jul 22, 2021
64a91b8
ASoC: SOF: sof-client-ipc-test: Block the test if the firmware has cr…
ujfalusi Aug 20, 2021
5f585a8
ASoC: SOF: Convert the generic probe support to SOF client
ujfalusi Jun 9, 2021
d6a888d
ASoC: SOF: sof-client-probes: Add module parameter to enable probes s…
ujfalusi Aug 9, 2021
6677eec
ASoC: SOF: sof-client-probes: Protection against removal while in use
ujfalusi Jul 22, 2021
68d6c63
ASoC: SOF: sof-client-probes: Block the capture if the firmware is cr…
ujfalusi Aug 20, 2021
39459f7
ASoC: SOF: Add optional SOF client for dma-trace support
ujfalusi Jul 6, 2021
9e6b984
ASoC: SOF: imx: Enable SOF client version of dma-trace
ujfalusi Aug 18, 2021
e8bab41
ASoC: SOF: Switch to the client driver for dma-trace support
ujfalusi Jul 19, 2021
5c75bc5
ASoC: SOF: sof-client-dma-trace: Add protection against file/module r…
ujfalusi Jul 21, 2021
b3089af
ASoC: SOF: sof-client-dma-trace: Block the dtrace if the firmware has…
ujfalusi Aug 20, 2021
b269552
ASoC: SOF: sof-client-dma-trace: Simplify count adjustment in trace_read
ujfalusi Jul 16, 2021
fd4a66c
ASoC: SOF: sof-client-dma-trace: Coding style cleanups
ujfalusi Jul 16, 2021
5e3f492
ASoC: SOF: sof-client-ipc-test: Code cleanup for consistency
ujfalusi Jul 22, 2021
f763eea
ASoC: SOF: sof-client-probes: Code cleanup for consistency
ujfalusi Jul 22, 2021
3bd20bb
ASoC: SOF: sof-client-dma-trace: Code cleanup for consistency
ujfalusi Jul 22, 2021
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
23 changes: 22 additions & 1 deletion sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,23 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
}
EXPORT_SYMBOL(snd_sof_get_status);

/* Helper to manage DSP state */
void sof_set_fw_state(struct snd_sof_dev *sdev, enum snd_sof_fw_state new_state)
{
sdev->fw_state = new_state;

switch (new_state) {
case SOF_FW_BOOT_NOT_STARTED:
case SOF_FW_BOOT_COMPLETE:
case SOF_FW_CRASHED:
sof_client_fw_state_dispatcher(sdev);
fallthrough;
default:
break;
}
}
EXPORT_SYMBOL(sof_set_fw_state);

/*
* FW Boot State Transition Diagram
*
Expand Down Expand Up @@ -308,7 +325,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)

sdev->pdata = plat_data;
sdev->first_boot = true;
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
#endif
Expand All @@ -330,10 +346,13 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
INIT_LIST_HEAD(&sdev->dai_list);
INIT_LIST_HEAD(&sdev->route_list);
INIT_LIST_HEAD(&sdev->ipc_client_list);
INIT_LIST_HEAD(&sdev->ipc_rx_handler_list);
INIT_LIST_HEAD(&sdev->fw_state_handler_list);
spin_lock_init(&sdev->ipc_lock);
spin_lock_init(&sdev->hw_lock);
mutex_init(&sdev->power_state_access);
mutex_init(&sdev->ipc_client_mutex);
mutex_init(&sdev->client_event_handler_mutex);
Comment thread
plbossart marked this conversation as resolved.

/* set default timeouts if none provided */
if (plat_data->desc->ipc_timeout == 0)
Expand All @@ -345,6 +364,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
else
sdev->boot_timeout = plat_data->desc->boot_timeout;

sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
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.

squash this change in previous patch?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The main reason for moving this is the introduction of the notification for clients which uses sdev->client_event_handler_mutex and sdev->fw_state_handler_list. We can not set the fw_state before those are initialized.
This is why this change is in this commit.


if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
INIT_WORK(&sdev->probe_work, sof_probe_work);
schedule_work(&sdev->probe_work);
Expand Down
24 changes: 14 additions & 10 deletions sound/soc/sof/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,21 +463,25 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
break;
}

if (rx_callback) {
/* read the full message as there we have rx handler for it */
full_msg = kmalloc(hdr.size, GFP_KERNEL);
if (!full_msg)
return;
/* read the full message as there we have rx handler for it */
full_msg = kmalloc(hdr.size, GFP_KERNEL);
if (!full_msg)
return;

err = snd_sof_ipc_msg_data(sdev, NULL, full_msg, hdr.size);
if (err < 0)
dev_err(sdev->dev, "failed to read message\n");
else
err = snd_sof_ipc_msg_data(sdev, NULL, full_msg, hdr.size);
if (err < 0) {
dev_err(sdev->dev, "failed to read message\n");
} else {
/* Call local handler for the message */
if (rx_callback)
rx_callback(sdev, full_msg);

kfree(full_msg);
/* Notify registered clients */
sof_client_ipc_rx_dispatcher(sdev, full_msg);
}

kfree(full_msg);
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.

I don't get why you are transposing the logic by doing ipc_msg_data() and then testing the callback.
Couldn't this done in an earlier patch if this is necessary so that this patch only adds the state notification?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Before this patch I only allocated memory for the full_msg and retrieved the message from firmware if we had a handler for it. True, that it is unlikely, but it sounded the right thing to do. I could have done it with goto like this:

+ if (!rx_callback)
+ 	goto out;

+ /* read the full message as there we have rx handler for it */
+ full_msg = kmalloc(hdr.size, GFP_KERNEL);
+ if (!full_msg)
+ 	return;

+ err = snd_sof_ipc_msg_data(sdev, NULL, full_msg, hdr.size);
+ if (err < 0)
+ 	dev_err(sdev->dev, "failed to read message\n");
+ else
+ 	rx_callback(sdev, full_msg);

+ kfree(full_msg);

+ out:
ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd);

if you prefer that.

Here we always need to allocate the full_msg as we don't know if there is a client waiting for the exact notification.


ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd);
}
EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);
Expand Down
155 changes: 155 additions & 0 deletions sound/soc/sof/sof-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,32 @@
#include "sof-client.h"
#include "sof-priv.h"

/**
* struct sof_ipc_event_entry - IPC client event description
* @ipc_msg_type: IPC msg type of the event the client is interested
* @cdev: sof_client_dev of the requesting client
* @callback: Callback function of the client
* @list: item in SOF core client event list
*/
struct sof_ipc_event_entry {
Comment thread
plbossart marked this conversation as resolved.
u32 ipc_msg_type;
struct sof_client_dev *cdev;
sof_client_event_callback callback;
struct list_head list;
};

/**
* struct sof_state_event_entry - DSP panic event subscription entry
* @cdev: sof_client_dev of the requesting client
* @callback: Callback function of the client
* @list: item in SOF core client event list
*/
struct sof_state_event_entry {
struct sof_client_dev *cdev;
sof_client_fw_state_callback callback;
struct list_head list;
};

static void sof_client_auxdev_release(struct device *dev)
{
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
Expand Down Expand Up @@ -150,3 +176,132 @@ struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev)
return cdev->sdev->dev;
}
EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT);

/* IPC event handling */
void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *full_msg)
{
struct sof_ipc_cmd_hdr *hdr = full_msg;
u32 msg_type = hdr->cmd & SOF_GLB_TYPE_MASK;
struct sof_ipc_event_entry *event;

mutex_lock(&sdev->client_event_handler_mutex);

list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) {
if (event->ipc_msg_type == msg_type)
event->callback(event->cdev, full_msg);
}

mutex_unlock(&sdev->client_event_handler_mutex);
}

int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev,
u32 ipc_msg_type,
sof_client_event_callback callback)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct sof_ipc_event_entry *event;

if (!callback || !(ipc_msg_type & SOF_GLB_TYPE_MASK))
return -EINVAL;

event = kmalloc(sizeof(*event), GFP_KERNEL);
if (!event)
return -ENOMEM;

event->ipc_msg_type = ipc_msg_type;
event->cdev = cdev;
event->callback = callback;

/* add to list of SOF client devices */
mutex_lock(&sdev->client_event_handler_mutex);
list_add(&event->list, &sdev->ipc_rx_handler_list);
mutex_unlock(&sdev->client_event_handler_mutex);

return 0;
}
EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT);

void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev,
u32 ipc_msg_type)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct sof_ipc_event_entry *event;

mutex_lock(&sdev->client_event_handler_mutex);

list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) {
if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) {
list_del(&event->list);
kfree(event);
break;
}
}

mutex_unlock(&sdev->client_event_handler_mutex);
}
EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT);

/*DSP state notification and query */
void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev)
{
struct sof_state_event_entry *event;

mutex_lock(&sdev->client_event_handler_mutex);

list_for_each_entry(event, &sdev->fw_state_handler_list, list)
event->callback(event->cdev, sdev->fw_state);

mutex_unlock(&sdev->client_event_handler_mutex);
}

int sof_client_register_fw_state_handler(struct sof_client_dev *cdev,
sof_client_fw_state_callback callback)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct sof_state_event_entry *event;

if (!callback)
return -EINVAL;

event = kmalloc(sizeof(*event), GFP_KERNEL);
if (!event)
return -ENOMEM;

event->cdev = cdev;
event->callback = callback;

/* add to list of SOF client devices */
mutex_lock(&sdev->client_event_handler_mutex);
list_add(&event->list, &sdev->fw_state_handler_list);
mutex_unlock(&sdev->client_event_handler_mutex);

return 0;
}
EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT);

void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct sof_state_event_entry *event;

mutex_lock(&sdev->client_event_handler_mutex);

list_for_each_entry(event, &sdev->fw_state_handler_list, list) {
if (event->cdev == cdev) {
list_del(&event->list);
kfree(event);
break;
}
}

mutex_unlock(&sdev->client_event_handler_mutex);
}
EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT);

enum snd_sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);

return sdev->fw_state;
}
EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT);
21 changes: 21 additions & 0 deletions sound/soc/sof/sof-client.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include <linux/auxiliary_bus.h>
#include <linux/device.h>
#include <linux/list.h>
#include <sound/sof.h>

struct sof_ipc_cmd_hdr;
struct snd_sof_dev;
struct dentry;

Expand Down Expand Up @@ -38,4 +40,23 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev);
struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev);

/* IPC notification */
typedef void (*sof_client_event_callback)(struct sof_client_dev *cdev,
void *full_msg);

int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev,
u32 ipc_msg_type,
sof_client_event_callback callback);
void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev,
u32 ipc_msg_type);

/* DSP state notification and query */
typedef void (*sof_client_fw_state_callback)(struct sof_client_dev *cdev,
enum snd_sof_fw_state state);

int sof_client_register_fw_state_handler(struct sof_client_dev *cdev,
sof_client_fw_state_callback callback);
void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev);
enum snd_sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev);

#endif /* __SOC_SOF_CLIENT_H */
32 changes: 27 additions & 5 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,21 @@ struct snd_sof_dev {
/* mutex to protect client list */
struct mutex ipc_client_mutex;

/*
* Used for tracking the IPC client's RX registration for DSP initiated
* message handling.
*/
struct list_head ipc_rx_handler_list;

/*
* Used for tracking the IPC client's registration for DSP state change
* notification
*/
struct list_head fw_state_handler_list;

/* to protect the ipc_rx_handler_list and dsp_state_handler_list list */
struct mutex client_event_handler_mutex;

void *private; /* core does not touch this */
};

Expand Down Expand Up @@ -592,11 +607,7 @@ extern const struct dsp_arch_ops sof_xtensa_arch_ops;
/*
* Firmware state tracking
*/
static inline void sof_set_fw_state(struct snd_sof_dev *sdev,
enum snd_sof_fw_state new_state)
{
sdev->fw_state = new_state;
}
void sof_set_fw_state(struct snd_sof_dev *sdev, enum snd_sof_fw_state new_state);

/*
* Utilities
Expand Down Expand Up @@ -637,6 +648,8 @@ int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id,
void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id);
int sof_register_clients(struct snd_sof_dev *sdev);
void sof_unregister_clients(struct snd_sof_dev *sdev);
void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *full_msg);
void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev);
#else /* CONFIG_SND_SOC_SOF_CLIENT */
static inline int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name,
u32 id, const void *data, size_t size)
Expand All @@ -657,6 +670,15 @@ static inline int sof_register_clients(struct snd_sof_dev *sdev)
static inline void sof_unregister_clients(struct snd_sof_dev *sdev)
{
}

static inline void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev,
void *full_msg)
{
}

static inline void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev)
{
}
#endif /* CONFIG_SND_SOC_SOF_CLIENT */

#endif