Skip to content

Commit 69cfa48

Browse files
ujfalusikv2019i
authored andcommitted
ASoC: SOF: Introduce IPC SOF client support
A client in the SOF (Sound Open Firmware) context is a driver that needs to communicate with the DSP via IPC messages. The SOF core is responsible for serializing the IPC messages to the DSP from the different clients. One example of an SOF client would be an IPC test client that floods the DSP with test IPC messages to validate if the serialization works as expected. Multi-client support will also add the ability to split the existing audio cards into multiple ones, so as to e.g. to deal with HDMI with a dedicated client instead of adding HDMI to all cards. This patch introduces descriptors for SOF client driver and SOF client device along with APIs for registering and unregistering a SOF client driver, sending IPCs from a client device and accessing the SOF core debugfs root entry. Along with this, add a couple of new members to struct snd_sof_dev that will be used for maintaining the list of clients. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Co-developed-by: Fred Oh <fred.oh@linux.intel.com> Signed-off-by: Fred Oh <fred.oh@linux.intel.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent 2561ff5 commit 69cfa48

7 files changed

Lines changed: 540 additions & 21 deletions

File tree

sound/soc/sof/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ config SND_SOC_SOF_DEBUG_PROBES
6161
Say Y if you want to enable probes.
6262
If unsure, select "N".
6363

64+
config SND_SOC_SOF_CLIENT
65+
tristate
66+
select AUXILIARY_BUS
67+
help
68+
This option is not user-selectable but automagically handled by
69+
'select' statements at a higher level.
70+
6471
config SND_SOC_SOF_DEVELOPER_SUPPORT
6572
bool "SOF developer options support"
6673
depends on EXPERT

sound/soc/sof/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
44
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o ipc4.o
5+
snd-sof-$(CONFIG_SND_SOC_SOF_CLIENT) += sof-client.o
56

67
snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o
78
snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o

sound/soc/sof/core.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,27 @@ void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level,
122122
}
123123
EXPORT_SYMBOL(sof_print_oops_and_stack);
124124

125+
/* Helper to manage DSP state */
126+
void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state)
127+
{
128+
if (sdev->fw_state == new_state)
129+
return;
130+
131+
dev_dbg(sdev->dev, "fw_state change: %d -> %d\n", sdev->fw_state, new_state);
132+
sdev->fw_state = new_state;
133+
134+
switch (new_state) {
135+
case SOF_FW_BOOT_NOT_STARTED:
136+
case SOF_FW_BOOT_COMPLETE:
137+
case SOF_FW_CRASHED:
138+
sof_client_fw_state_dispatcher(sdev);
139+
fallthrough;
140+
default:
141+
break;
142+
}
143+
}
144+
EXPORT_SYMBOL(sof_set_fw_state);
145+
125146
/*
126147
* FW Boot State Transition Diagram
127148
*
@@ -266,6 +287,12 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
266287
goto fw_trace_err;
267288
}
268289

290+
ret = sof_register_clients(sdev);
291+
if (ret < 0) {
292+
dev_err(sdev->dev, "failed to register clients %d\n", ret);
293+
goto sof_machine_err;
294+
}
295+
269296
/*
270297
* Some platforms in SOF, ex: BYT, may not have their platform PM
271298
* callbacks set. Increment the usage count so as to
@@ -281,6 +308,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
281308

282309
return 0;
283310

311+
sof_machine_err:
312+
snd_sof_machine_unregister(sdev, plat_data);
284313
fw_trace_err:
285314
snd_sof_free_trace(sdev);
286315
fw_run_err:
@@ -329,7 +358,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
329358

330359
sdev->pdata = plat_data;
331360
sdev->first_boot = true;
332-
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
333361
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
334362
sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
335363
#endif
@@ -350,9 +378,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
350378
INIT_LIST_HEAD(&sdev->widget_list);
351379
INIT_LIST_HEAD(&sdev->dai_list);
352380
INIT_LIST_HEAD(&sdev->route_list);
381+
INIT_LIST_HEAD(&sdev->ipc_client_list);
382+
INIT_LIST_HEAD(&sdev->ipc_rx_handler_list);
383+
INIT_LIST_HEAD(&sdev->fw_state_handler_list);
353384
spin_lock_init(&sdev->ipc_lock);
354385
spin_lock_init(&sdev->hw_lock);
355386
mutex_init(&sdev->power_state_access);
387+
mutex_init(&sdev->ipc_client_mutex);
388+
mutex_init(&sdev->client_event_handler_mutex);
356389

357390
/* set default timeouts if none provided */
358391
if (plat_data->desc->ipc_timeout == 0)
@@ -364,6 +397,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
364397
else
365398
sdev->boot_timeout = plat_data->desc->boot_timeout;
366399

400+
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
401+
367402
if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
368403
INIT_WORK(&sdev->probe_work, sof_probe_work);
369404
schedule_work(&sdev->probe_work);
@@ -391,6 +426,12 @@ int snd_sof_device_remove(struct device *dev)
391426
if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
392427
cancel_work_sync(&sdev->probe_work);
393428

429+
/*
430+
* Unregister any registered client device first before IPC and debugfs
431+
* to allow client drivers to be removed cleanly
432+
*/
433+
sof_unregister_clients(sdev);
434+
394435
/*
395436
* Unregister machine driver. This will unbind the snd_card which
396437
* will remove the component driver and unload the topology

sound/soc/sof/ipc.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -541,22 +541,25 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
541541
break;
542542
}
543543

544-
if (rx_callback) {
545-
/* read the full message as we have rx handler for it */
546-
msg_buf = kmalloc(hdr.size, GFP_KERNEL);
547-
if (!msg_buf)
548-
return;
544+
/* read the full message */
545+
msg_buf = kmalloc(hdr.size, GFP_KERNEL);
546+
if (!msg_buf)
547+
return;
549548

550-
err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size);
551-
if (err < 0)
552-
dev_err(sdev->dev, "%s: Failed to read message: %d\n",
553-
__func__, err);
554-
else
549+
err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size);
550+
if (err < 0) {
551+
dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err);
552+
} else {
553+
/* Call local handler for the message */
554+
if (rx_callback)
555555
rx_callback(sdev, msg_buf);
556556

557-
kfree(msg_buf);
557+
/* Notify registered clients */
558+
sof_client_ipc_rx_dispatcher(sdev, msg_buf);
558559
}
559560

561+
kfree(msg_buf);
562+
560563
ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd);
561564
}
562565
EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);

0 commit comments

Comments
 (0)