All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations
@ 2022-05-16 10:11 Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 01/15] ASoC: Intel: avs: Account for libraries when booting basefw Cezary Rojewski
                   ` (15 more replies)
  0 siblings, 16 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Part three of main AVS driver series. This series was originally part of
the initial series which was later divided [1] into smaller,
easier-to-review chunks. Thus, many patches found here were already
present on the list.

This series consists of code typical to many drivers - PCI driver
operations, trace ability, PM operations - as well as PCM handlers for
all standard audio interfaces, that is, HDA, I2S and DMIC are found
here.

Series starts with updating firmware boot flow - libraries are no longer
ignored. This change is dependent on already merged topology code [2]
and because of that could not be part of the initial series [1].

PCM operations are split into four changes. First component operations
alone i.e. operations which are usually agnostic towards path position
(FE/BE). Then it continues with "generic" FE operations - there is no
interface split here as from Intel ADSP point of view, FE, or HOST side
as it's called in the specs, involves HD-Audio operations only.
BE (also known as LINK) side on the other hand is divided into
"non-HD-Audio" and HD-Audio part. The former represents transfer over
DMIC and I2S interfaces both.

While patches implementing standard PCI driver operations along (again
standard) HD-Audio initialization routines followed up by power
management handlers are two major ones, series covers also other
important subjects such as:

While patches implementing standard PCI driver operations along (again
standard) HD-Audio initialization routines followed up by power
management handlers are two major ones, series covers also other
important subjects such as:

- event tracing
- preparation for firmware tracing (debugability)
- coredump (debugability)
- recovery flow (attempt recovery after IPC timeout or exception)
- D0ix (D0 device substate, complements standard power management)

Series is finalized by actual addition of supported platforms: SKL and
APL-based. Platform-specific files are limited to firmware-specific
bits, that is, bits that are specific to given firmware generation.
Everything else is shared and is part of already upstream messaging
code found in ipc.c, messages.c and messages.h files.


Changes in v3:
- addressed (hopefully) trace-code compilation under .configs with
  CONFIG_FTRACE dropped

Changes in v2:
- usage of avs_releast_last_firmware() dropped in error path for library
  loading procedure as suggested by Pierre
- 'link_mask' usage replaced with 'i2s_link_mask' as requested by
  Pierre. Existing code addressed with new patch:
  "ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask"
- fixed possible race during recovery flow (->recovering flag is now
  atomic and tested in single location only).
- dropped platform prefixes for basically all i2s board descriptors
- 'ssp_test' renamed to 'i2s_test' to match naming convention of other
  boards
- simplified PM implementation for current series, 'low_power' bits
  moved to future series
- replaced SND_INTEL_DSP_DRIVER_SST with _AVS as suggested by Mark.
  Required changes to intel-dspcfg will be added in future series
- number of typos across commit messages addressed


[1]: https://lore.kernel.org/all/20220311153544.136854-1-cezary.rojewski@intel.com/
[2]: https://lore.kernel.org/all/20220331135246.993089-1-cezary.rojewski@intel.com/


Cezary Rojewski (14):
  ASoC: Intel: avs: Account for libraries when booting basefw
  ASoC: Intel: avs: Generic soc component driver
  ASoC: Intel: avs: Generic PCM FE operations
  ASoC: Intel: avs: non-HDA PCM BE operations
  ASoC: Intel: avs: HDA PCM BE operations
  ASoC: Intel: avs: Coredump and recovery flow
  ASoC: Intel: avs: Prepare for firmware tracing
  ASoC: Intel: avs: D0ix power state support
  ASoC: Intel: avs: Event tracing
  ASoC: Intel: avs: Machine board registration
  ASoC: Intel: avs: PCI driver implementation
  ASoC: Intel: avs: Power management
  ASoC: Intel: avs: SKL-based platforms support
  ASoC: Intel: avs: APL-based platforms support

Piotr Maziarz (1):
  ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask

 include/sound/intel-dsp-config.h      |    3 +-
 include/sound/soc-acpi.h              |    2 +
 sound/soc/intel/Kconfig               |    2 +
 sound/soc/intel/avs/Makefile          |    7 +-
 sound/soc/intel/avs/apl.c             |  250 ++++++
 sound/soc/intel/avs/avs.h             |   79 ++
 sound/soc/intel/avs/board_selection.c |  501 +++++++++++
 sound/soc/intel/avs/core.c            |  631 +++++++++++++
 sound/soc/intel/avs/dsp.c             |   27 +-
 sound/soc/intel/avs/ipc.c             |  253 +++++-
 sound/soc/intel/avs/loader.c          |   84 ++
 sound/soc/intel/avs/messages.c        |   35 +-
 sound/soc/intel/avs/messages.h        |   51 ++
 sound/soc/intel/avs/pcm.c             | 1182 +++++++++++++++++++++++++
 sound/soc/intel/avs/registers.h       |    8 +
 sound/soc/intel/avs/skl.c             |  125 +++
 sound/soc/intel/avs/topology.c        |   14 +-
 sound/soc/intel/avs/trace.c           |   33 +
 sound/soc/intel/avs/trace.h           |  154 ++++
 sound/soc/intel/avs/utils.c           |   23 +
 20 files changed, 3443 insertions(+), 21 deletions(-)
 create mode 100644 sound/soc/intel/avs/apl.c
 create mode 100644 sound/soc/intel/avs/board_selection.c
 create mode 100644 sound/soc/intel/avs/pcm.c
 create mode 100644 sound/soc/intel/avs/skl.c
 create mode 100644 sound/soc/intel/avs/trace.c
 create mode 100644 sound/soc/intel/avs/trace.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v3 01/15] ASoC: Intel: avs: Account for libraries when booting basefw
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 02/15] ASoC: Intel: avs: Generic soc component driver Cezary Rojewski
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Not all modules are part of base firmware. Some are part of loadable
libraries. These need to be loaded after base firmware reports ready
status through FW_READY notification.

Their loading process is similar to the base firmware's one. Request the
binary file, verify and strip the manifest and load the actual code into
DSP memory with help of CLDMA or HD-Audio render stream, depending on
audio device generation.

List of libraries needed for loading is obtained through the topology -
vendor sections specifying the name of firmware files to request.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/avs.h    |  3 ++
 sound/soc/intel/avs/loader.c | 80 ++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index c57a07a18d8e..14b4a780a91c 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -19,6 +19,8 @@
 
 struct avs_dev;
 struct avs_tplg;
+struct avs_tplg_library;
+struct avs_soc_component;
 
 /*
  * struct avs_dsp_ops - Platform-specific DSP operations
@@ -241,6 +243,7 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable);
 void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable);
 void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable);
 
+int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, u32 num_libs);
 int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge);
 int avs_dsp_first_boot_firmware(struct avs_dev *adev);
 
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index c47f85161d95..8aa658c52325 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -15,6 +15,7 @@
 #include "cldma.h"
 #include "messages.h"
 #include "registers.h"
+#include "topology.h"
 
 #define AVS_ROM_STS_MASK		0xFF
 #define AVS_ROM_INIT_DONE		0x1
@@ -466,6 +467,71 @@ int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
 	return 0;
 }
 
+int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, u32 num_libs)
+{
+	int start, id, i = 0;
+	int ret;
+
+	/* Calculate the id to assign for the next lib. */
+	for (id = 0; id < adev->fw_cfg.max_libs_count; id++)
+		if (adev->lib_names[id][0] == '\0')
+			break;
+	if (id + num_libs >= adev->fw_cfg.max_libs_count)
+		return -EINVAL;
+
+	start = id;
+	while (i < num_libs) {
+		struct avs_fw_manifest *man;
+		const struct firmware *fw;
+		struct firmware stripped_fw;
+		char *filename;
+		int j;
+
+		filename = kasprintf(GFP_KERNEL, "%s/%s/%s", AVS_ROOT_DIR, adev->spec->name,
+				     libs[i].name);
+		if (!filename)
+			return -ENOMEM;
+
+		/*
+		 * If any call after this one fails, requested firmware is not released with
+		 * avs_release_last_firmware() as failing to load code results in need for reload
+		 * of entire driver module. And then avs_release_firmwares() is in place already.
+		 */
+		ret = avs_request_firmware(adev, &fw, filename);
+		kfree(filename);
+		if (ret < 0)
+			return ret;
+
+		stripped_fw = *fw;
+		ret = avs_fw_manifest_strip_verify(adev, &stripped_fw, NULL);
+		if (ret) {
+			dev_err(adev->dev, "invalid library data: %d\n", ret);
+			return ret;
+		}
+
+		ret = avs_fw_manifest_offset(&stripped_fw);
+		if (ret < 0)
+			return ret;
+		man = (struct avs_fw_manifest *)(stripped_fw.data + ret);
+
+		/* Don't load anything that's already in DSP memory. */
+		for (j = 0; j < id; j++)
+			if (!strncmp(adev->lib_names[j], man->name, AVS_LIB_NAME_SIZE))
+				goto next_lib;
+
+		ret = avs_dsp_op(adev, load_lib, &stripped_fw, id);
+		if (ret)
+			return ret;
+
+		strncpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE);
+		id++;
+next_lib:
+		i++;
+	}
+
+	return start == id ? 1 : 0;
+}
+
 static int avs_dsp_load_basefw(struct avs_dev *adev)
 {
 	const struct avs_fw_version *min_req;
@@ -519,6 +585,7 @@ static int avs_dsp_load_basefw(struct avs_dev *adev)
 
 int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
 {
+	struct avs_soc_component *acomp;
 	int ret, i;
 
 	/* Forgo full boot if flash from IMR succeeds. */
@@ -538,7 +605,20 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
 	avs_hda_l1sen_enable(adev, false);
 
 	ret = avs_dsp_load_basefw(adev);
+	if (ret)
+		goto reenable_gating;
+
+	mutex_lock(&adev->comp_list_mutex);
+	list_for_each_entry(acomp, &adev->comp_list, node) {
+		struct avs_tplg *tplg = acomp->tplg;
+
+		ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
+		if (ret < 0)
+			break;
+	}
+	mutex_unlock(&adev->comp_list_mutex);
 
+reenable_gating:
 	avs_hda_l1sen_enable(adev, true);
 	avs_hda_clock_gating_enable(adev, true);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 02/15] ASoC: Intel: avs: Generic soc component driver
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 01/15] ASoC: Intel: avs: Account for libraries when booting basefw Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 03/15] ASoC: Intel: avs: Generic PCM FE operations Cezary Rojewski
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Prepare for concrete PCM operations over HDA, DMIC and I2S interfaces by
providing generic soc component implementation. Interface-specific
components re-use this code as majority of flow is shared.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/sound/soc-acpi.h     |   2 +
 sound/soc/intel/avs/Makefile |   2 +-
 sound/soc/intel/avs/pcm.c    | 275 +++++++++++++++++++++++++++++++++++
 3 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/pcm.c

diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h
index d33cf8df14b1..b38fd25c5729 100644
--- a/include/sound/soc-acpi.h
+++ b/include/sound/soc-acpi.h
@@ -156,6 +156,7 @@ struct snd_soc_acpi_link_adr {
  * @links: array of link _ADR descriptors, null terminated.
  * @drv_name: machine driver name
  * @fw_filename: firmware file name. Used when SOF is not enabled.
+ * @tplg_filename: topology file name. Used when SOF is not enabled.
  * @board: board name
  * @machine_quirk: pointer to quirk, usually based on DMI information when
  * ACPI ID alone is not sufficient, wrong or misleading
@@ -174,6 +175,7 @@ struct snd_soc_acpi_mach {
 	const struct snd_soc_acpi_link_adr *links;
 	const char *drv_name;
 	const char *fw_filename;
+	const char *tplg_filename;
 	const char *board;
 	struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
 	const void *quirk_data;
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 952f51977656..62b3581d6cdb 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
-		    topology.o path.o
+		    topology.o path.o pcm.o
 snd-soc-avs-objs += cldma.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
new file mode 100644
index 000000000000..cda2ec6f5da3
--- /dev/null
+++ b/sound/soc/intel/avs/pcm.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <sound/hda_register.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-component.h>
+#include "avs.h"
+#include "path.h"
+#include "topology.h"
+
+struct avs_dma_data {
+	struct avs_tplg_path_template *template;
+	struct avs_path *path;
+	/*
+	 * link stream is stored within substream's runtime
+	 * private_data to fulfill the needs of codec BE path
+	 *
+	 * host stream assigned
+	 */
+	struct hdac_ext_stream *host_stream;
+};
+
+static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count,
+				  loff_t *ppos)
+{
+	struct snd_soc_component *component = file->private_data;
+	struct snd_soc_card *card = component->card;
+	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+	char buf[64];
+	size_t len;
+
+	len = snprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix,
+		       mach->tplg_filename);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations topology_name_fops = {
+	.open = simple_open,
+	.read = topology_name_read,
+	.llseek = default_llseek,
+};
+
+static int avs_component_load_libraries(struct avs_soc_component *acomp)
+{
+	struct avs_tplg *tplg = acomp->tplg;
+	struct avs_dev *adev = to_avs_dev(acomp->base.dev);
+	int ret;
+
+	if (!tplg->num_libs)
+		return 0;
+
+	/* Parent device may be asleep and library loading involves IPCs. */
+	ret = pm_runtime_resume_and_get(adev->dev);
+	if (ret < 0)
+		return ret;
+
+	avs_hda_clock_gating_enable(adev, false);
+	avs_hda_l1sen_enable(adev, false);
+
+	ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
+
+	avs_hda_l1sen_enable(adev, true);
+	avs_hda_clock_gating_enable(adev, true);
+
+	if (!ret)
+		ret = avs_module_info_init(adev, false);
+
+	pm_runtime_mark_last_busy(adev->dev);
+	pm_runtime_put_autosuspend(adev->dev);
+
+	return ret;
+}
+
+static int avs_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_card *card = component->card;
+	struct snd_soc_acpi_mach *mach;
+	struct avs_soc_component *acomp;
+	struct avs_dev *adev;
+	char *filename;
+	int ret;
+
+	dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name);
+	mach = dev_get_platdata(card->dev);
+	acomp = to_avs_soc_component(component);
+	adev = to_avs_dev(component->dev);
+
+	acomp->tplg = avs_tplg_new(component);
+	if (!acomp->tplg)
+		return -ENOMEM;
+
+	if (!mach->tplg_filename)
+		goto finalize;
+
+	/* Load specified topology and create debugfs for it. */
+	filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
+			     mach->tplg_filename);
+	if (!filename)
+		return -ENOMEM;
+
+	ret = avs_load_topology(component, filename);
+	kfree(filename);
+	if (ret < 0)
+		return ret;
+
+	ret = avs_component_load_libraries(acomp);
+	if (ret < 0) {
+		dev_err(card->dev, "libraries loading failed: %d\n", ret);
+		goto err_load_libs;
+	}
+
+finalize:
+	debugfs_create_file("topology_name", 0444, component->debugfs_root, component,
+			    &topology_name_fops);
+
+	mutex_lock(&adev->comp_list_mutex);
+	list_add_tail(&acomp->node, &adev->comp_list);
+	mutex_unlock(&adev->comp_list_mutex);
+
+	return 0;
+
+err_load_libs:
+	avs_remove_topology(component);
+	return ret;
+}
+
+static void avs_component_remove(struct snd_soc_component *component)
+{
+	struct avs_soc_component *acomp = to_avs_soc_component(component);
+	struct snd_soc_acpi_mach *mach;
+	struct avs_dev *adev = to_avs_dev(component->dev);
+	int ret;
+
+	mach = dev_get_platdata(component->card->dev);
+
+	mutex_lock(&adev->comp_list_mutex);
+	list_del(&acomp->node);
+	mutex_unlock(&adev->comp_list_mutex);
+
+	if (mach->tplg_filename) {
+		ret = avs_remove_topology(component);
+		if (ret < 0)
+			dev_err(component->dev, "unload topology failed: %d\n", ret);
+	}
+}
+
+static int avs_component_open(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct snd_pcm_hardware hwparams;
+
+	/* only FE DAI links are handled here */
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	hwparams.info = SNDRV_PCM_INFO_MMAP |
+			SNDRV_PCM_INFO_MMAP_VALID |
+			SNDRV_PCM_INFO_INTERLEAVED |
+			SNDRV_PCM_INFO_PAUSE |
+			SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
+
+	hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE;
+	hwparams.period_bytes_min = 128;
+	hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2;
+	hwparams.periods_min = 2;
+	hwparams.periods_max = AZX_MAX_FRAG;
+	hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE;
+	hwparams.fifo_size = 0;
+
+	return snd_soc_set_runtime_hwparams(substream, &hwparams);
+}
+
+static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
+{
+	return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
+		     (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index));
+}
+
+static snd_pcm_uframes_t
+avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct avs_dma_data *data;
+	struct hdac_ext_stream *host_stream;
+	unsigned int pos;
+
+	data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+	if (!data->host_stream)
+		return 0;
+
+	host_stream = data->host_stream;
+	pos = avs_hda_stream_dpib_read(host_stream);
+
+	if (pos >= hdac_stream(host_stream)->bufsize)
+		pos = 0;
+
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+static int avs_component_mmap(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream,
+			      struct vm_area_struct *vma)
+{
+	return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+#define MAX_PREALLOC_SIZE	(32 * 1024 * 1024)
+
+static int avs_component_construct(struct snd_soc_component *component,
+				   struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_pcm *pcm = rtd->pcm;
+
+	if (dai->driver->playback.channels_min)
+		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+					   SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,
+					   MAX_PREALLOC_SIZE);
+
+	if (dai->driver->capture.channels_min)
+		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+					   SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,
+					   MAX_PREALLOC_SIZE);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver avs_component_driver = {
+	.name			= "avs-pcm",
+	.probe			= avs_component_probe,
+	.remove			= avs_component_remove,
+	.open			= avs_component_open,
+	.pointer		= avs_component_pointer,
+	.mmap			= avs_component_mmap,
+	.pcm_construct		= avs_component_construct,
+	.module_get_upon_open	= 1, /* increment refcount when a pcm is opened */
+	.topology_name_prefix	= "intel/avs",
+	.non_legacy_dai_naming	= true,
+};
+
+__maybe_unused
+static int avs_soc_component_register(struct device *dev, const char *name,
+				      const struct snd_soc_component_driver *drv,
+				      struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
+{
+	struct avs_soc_component *acomp;
+	int ret;
+
+	acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL);
+	if (!acomp)
+		return -ENOMEM;
+
+	ret = snd_soc_component_initialize(&acomp->base, drv, dev);
+	if (ret < 0)
+		return ret;
+
+	/* force name change after ASoC is done with its init */
+	acomp->base.name = name;
+	INIT_LIST_HEAD(&acomp->node);
+
+	return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 03/15] ASoC: Intel: avs: Generic PCM FE operations
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 01/15] ASoC: Intel: avs: Account for libraries when booting basefw Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 02/15] ASoC: Intel: avs: Generic soc component driver Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 04/15] ASoC: Intel: avs: non-HDA PCM BE operations Cezary Rojewski
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Each stream in AVS is represented by FE and BE domain. FE path stands
for HOST part of the stream while BE stands for LINK (hardware) one.
While BE portion is interface specific, FE is not. Handle all standard
DAI operations to implement FE part of the stream.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/pcm.c      | 338 +++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/topology.c |   2 -
 2 files changed, 338 insertions(+), 2 deletions(-)

diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index cda2ec6f5da3..9d01ed37c11e 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -10,6 +10,7 @@
 #include <linux/device.h>
 #include <sound/hda_register.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/pcm_params.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 #include <sound/soc-component.h>
@@ -29,6 +30,343 @@ struct avs_dma_data {
 	struct hdac_ext_stream *host_stream;
 };
 
+static struct avs_tplg_path_template *
+avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
+{
+	struct snd_soc_dapm_widget *dw;
+	struct snd_soc_dapm_path *dp;
+	enum snd_soc_dapm_direction dir;
+
+	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+		dw = dai->capture_widget;
+		dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN;
+	} else {
+		dw = dai->playback_widget;
+		dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT;
+	}
+
+	dp = list_first_entry_or_null(&dw->edges[dir], typeof(*dp), list_node[dir]);
+	if (!dp)
+		return NULL;
+
+	/* Get the other widget, with actual path template data */
+	dw = (dp->source == dw) ? dp->sink : dp->source;
+
+	return dw->priv;
+}
+
+static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe)
+{
+	struct avs_tplg_path_template *template;
+	struct avs_dma_data *data;
+
+	template = avs_dai_find_path_template(dai, is_fe, substream->stream);
+	if (!template) {
+		dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n",
+			snd_pcm_stream_str(substream), dai->name);
+		return -EINVAL;
+	}
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->template = template;
+	snd_soc_dai_set_dma_data(dai, substream, data);
+
+	return 0;
+}
+
+static int avs_dai_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *fe_hw_params,
+			     struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai,
+			     int dma_id)
+{
+	struct avs_dma_data *data;
+	struct avs_path *path;
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	int ret;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+
+	dev_dbg(dai->dev, "%s FE hw_params str %p rtd %p",
+		__func__, substream, substream->runtime);
+	dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n",
+		params_rate(fe_hw_params), params_channels(fe_hw_params),
+		params_width(fe_hw_params), params_physical_width(fe_hw_params));
+
+	dev_dbg(dai->dev, "%s BE hw_params str %p rtd %p",
+		__func__, substream, substream->runtime);
+	dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n",
+		params_rate(be_hw_params), params_channels(be_hw_params),
+		params_width(be_hw_params), params_physical_width(be_hw_params));
+
+	path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params);
+	if (IS_ERR(path)) {
+		ret = PTR_ERR(path);
+		dev_err(dai->dev, "create path failed: %d\n", ret);
+		return ret;
+	}
+
+	data->path = path;
+	return 0;
+}
+
+static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+	int ret;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (!data->path)
+		return 0;
+
+	ret = avs_path_reset(data->path);
+	if (ret < 0) {
+		dev_err(dai->dev, "reset path failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = avs_path_pause(data->path);
+	if (ret < 0)
+		dev_err(dai->dev, "pause path failed: %d\n", ret);
+	return ret;
+}
+
+static const unsigned int rates[] = {
+	8000, 11025, 12000, 16000,
+	22050, 24000, 32000, 44100,
+	48000, 64000, 88200, 96000,
+	128000, 176400, 192000,
+};
+
+static const struct snd_pcm_hw_constraint_list hw_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list = rates,
+	.mask = 0,
+};
+
+static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct avs_dma_data *data;
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	struct hdac_bus *bus = &adev->base.core;
+	struct hdac_ext_stream *host_stream;
+	int ret;
+
+	ret = avs_dai_startup(substream, dai, true);
+	if (ret)
+		return ret;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+
+	host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST);
+	if (!host_stream) {
+		kfree(data);
+		return -EBUSY;
+	}
+
+	data->host_stream = host_stream;
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	/* avoid wrap-around with wall-clock */
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates);
+	snd_pcm_set_sync(substream);
+
+	dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p",
+		__func__, hdac_stream(host_stream)->stream_tag, substream);
+
+	return 0;
+}
+
+static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+	snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST);
+	kfree(data);
+}
+
+static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
+{
+	struct snd_pcm_hw_params *be_hw_params = NULL;
+	struct snd_soc_pcm_runtime *fe, *be;
+	struct snd_soc_dpcm *dpcm;
+	struct avs_dma_data *data;
+	struct hdac_ext_stream *host_stream;
+	int ret;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (data->path)
+		return 0;
+
+	host_stream = data->host_stream;
+
+	hdac_stream(host_stream)->bufsize = 0;
+	hdac_stream(host_stream)->period_bytes = 0;
+	hdac_stream(host_stream)->format_val = 0;
+
+	fe = asoc_substream_to_rtd(substream);
+	for_each_dpcm_be(fe, substream->stream, dpcm) {
+		be = dpcm->be;
+		be_hw_params = &be->dpcm[substream->stream].hw_params;
+	}
+
+	ret = avs_dai_hw_params(substream, hw_params, be_hw_params, dai,
+				hdac_stream(host_stream)->stream_tag - 1);
+	if (ret)
+		goto create_err;
+
+	ret = avs_path_bind(data->path);
+	if (ret < 0) {
+		dev_err(dai->dev, "bind FE <-> BE failed: %d\n", ret);
+		goto bind_err;
+	}
+
+	return 0;
+
+bind_err:
+	avs_path_free(data->path);
+	data->path = NULL;
+create_err:
+	snd_pcm_lib_free_pages(substream);
+	return ret;
+}
+
+static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+	struct hdac_ext_stream *host_stream;
+	int ret;
+
+	dev_dbg(dai->dev, "%s fe HW_FREE str %p rtd %p",
+		__func__, substream, substream->runtime);
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (!data->path)
+		return 0;
+
+	host_stream = data->host_stream;
+
+	ret = avs_path_unbind(data->path);
+	if (ret < 0)
+		dev_err(dai->dev, "unbind FE <-> BE failed: %d\n", ret);
+
+	avs_path_free(data->path);
+	data->path = NULL;
+	snd_hdac_stream_cleanup(hdac_stream(host_stream));
+	hdac_stream(host_stream)->prepared = false;
+
+	ret = snd_pcm_lib_free_pages(substream);
+	if (ret < 0)
+		dev_dbg(dai->dev, "Failed to free pages!\n");
+
+	return ret;
+}
+
+static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct avs_dma_data *data;
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	struct hdac_ext_stream *host_stream;
+	struct hdac_bus *bus;
+	unsigned int format_val;
+	int ret;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	host_stream = data->host_stream;
+
+	if (hdac_stream(host_stream)->prepared)
+		return 0;
+
+	bus = hdac_stream(host_stream)->bus;
+	snd_hdac_ext_stream_decouple(bus, data->host_stream, true);
+	snd_hdac_stream_reset(hdac_stream(host_stream));
+
+	format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
+						 runtime->sample_bits, 0);
+
+	ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_hdac_stream_setup(hdac_stream(host_stream));
+	if (ret < 0)
+		return ret;
+
+	ret = avs_dai_prepare(adev, substream, dai);
+	if (ret)
+		return ret;
+
+	hdac_stream(host_stream)->prepared = true;
+	return 0;
+}
+
+static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+	struct hdac_ext_stream *host_stream;
+	struct hdac_bus *bus;
+	unsigned long flags;
+	int ret = 0;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	host_stream = data->host_stream;
+	bus = hdac_stream(host_stream)->bus;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		spin_lock_irqsave(&bus->reg_lock, flags);
+		snd_hdac_stream_start(hdac_stream(host_stream), true);
+		spin_unlock_irqrestore(&bus->reg_lock, flags);
+
+		ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
+		if (ret < 0)
+			dev_err(dai->dev, "run FE path failed: %d\n", ret);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = avs_path_pause(data->path);
+		if (ret < 0)
+			dev_err(dai->dev, "pause FE path failed: %d\n", ret);
+
+		spin_lock_irqsave(&bus->reg_lock, flags);
+		snd_hdac_stream_stop(hdac_stream(host_stream));
+		spin_unlock_irqrestore(&bus->reg_lock, flags);
+
+		if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+			ret = avs_path_reset(data->path);
+			if (ret < 0)
+				dev_err(dai->dev, "reset FE path failed: %d\n", ret);
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+const struct snd_soc_dai_ops avs_dai_fe_ops = {
+	.startup = avs_dai_fe_startup,
+	.shutdown = avs_dai_fe_shutdown,
+	.hw_params = avs_dai_fe_hw_params,
+	.hw_free = avs_dai_fe_hw_free,
+	.prepare = avs_dai_fe_prepare,
+	.trigger = avs_dai_fe_trigger,
+};
+
 static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count,
 				  loff_t *ppos)
 {
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index d3fd5e145ee1..4ea799658ed9 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -15,8 +15,6 @@
 #include "avs.h"
 #include "topology.h"
 
-const struct snd_soc_dai_ops avs_dai_fe_ops;
-
 /* Get pointer to vendor array at the specified offset. */
 #define avs_tplg_vendor_array_at(array, offset) \
 	((struct snd_soc_tplg_vendor_array *)((u8 *)array + offset))
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 04/15] ASoC: Intel: avs: non-HDA PCM BE operations
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (2 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 03/15] ASoC: Intel: avs: Generic PCM FE operations Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 05/15] ASoC: Intel: avs: HDA " Cezary Rojewski
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

DMIC and I2S interfaces differ in DMA operations from the HDAudio
interface. With that in mind, implement all DAI operations to handle
non-HDA BE interfaces.

To prevent code duplication in newly added code, I2S platform
registering is dynamic - makes use of specified port_mask and TDMs
array to populate as many DAIs as required.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/avs.h |   4 +
 sound/soc/intel/avs/pcm.c | 222 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 225 insertions(+), 1 deletion(-)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 14b4a780a91c..b4fd67fac17d 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -270,4 +270,8 @@ struct avs_soc_component {
 
 extern const struct snd_soc_dai_ops avs_dai_fe_ops;
 
+int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
+int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
+			      unsigned long *tdms);
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 9d01ed37c11e..079fa19f7d7b 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -112,6 +112,23 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static int avs_dai_be_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai,
+				int dma_id)
+{
+	struct snd_pcm_hw_params *fe_hw_params = NULL;
+	struct snd_soc_pcm_runtime *fe, *be;
+	struct snd_soc_dpcm *dpcm;
+
+	be = asoc_substream_to_rtd(substream);
+	for_each_dpcm_fe(be, substream->stream, dpcm) {
+		fe = dpcm->fe;
+		fe_hw_params = &fe->dpcm[substream->stream].hw_params;
+	}
+
+	return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id);
+}
+
 static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
@@ -134,6 +151,100 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst
 	return ret;
 }
 
+static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	return avs_dai_startup(substream, dai, false);
+}
+
+static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+	kfree(data);
+}
+
+static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (data->path)
+		return 0;
+
+	/* Actual port-id comes from topology. */
+	return avs_dai_be_hw_params(substream, hw_params, dai, 0);
+}
+
+static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+
+	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (data->path) {
+		avs_path_free(data->path);
+		data->path = NULL;
+	}
+
+	return 0;
+}
+
+static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
+}
+
+static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,
+				     struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+	int ret = 0;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
+		if (ret < 0)
+			dev_err(dai->dev, "run BE path failed: %d\n", ret);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = avs_path_pause(data->path);
+		if (ret < 0)
+			dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+
+		if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+			ret = avs_path_reset(data->path);
+			if (ret < 0)
+				dev_err(dai->dev, "reset BE path failed: %d\n", ret);
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
+	.startup = avs_dai_nonhda_be_startup,
+	.shutdown = avs_dai_nonhda_be_shutdown,
+	.hw_params = avs_dai_nonhda_be_hw_params,
+	.hw_free = avs_dai_nonhda_be_hw_free,
+	.prepare = avs_dai_nonhda_be_prepare,
+	.trigger = avs_dai_nonhda_be_trigger,
+};
+
 static const unsigned int rates[] = {
 	8000, 11025, 12000, 16000,
 	22050, 24000, 32000, 44100,
@@ -589,7 +700,6 @@ static const struct snd_soc_component_driver avs_component_driver = {
 	.non_legacy_dai_naming	= true,
 };
 
-__maybe_unused
 static int avs_soc_component_register(struct device *dev, const char *name,
 				      const struct snd_soc_component_driver *drv,
 				      struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
@@ -611,3 +721,113 @@ static int avs_soc_component_register(struct device *dev, const char *name,
 
 	return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
 }
+
+static struct snd_soc_dai_driver dmic_cpu_dais[] = {
+{
+	.name = "DMIC Pin",
+	.ops = &avs_dai_nonhda_be_ops,
+	.capture = {
+		.stream_name	= "DMIC Rx",
+		.channels_min	= 1,
+		.channels_max	= 4,
+		.rates		= SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+{
+	.name = "DMIC WoV Pin",
+	.ops = &avs_dai_nonhda_be_ops,
+	.capture = {
+		.stream_name	= "DMIC WoV Rx",
+		.channels_min	= 1,
+		.channels_max	= 4,
+		.rates		= SNDRV_PCM_RATE_16000,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+
+int avs_dmic_platform_register(struct avs_dev *adev, const char *name)
+{
+	return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais,
+					  ARRAY_SIZE(dmic_cpu_dais));
+}
+
+static const struct snd_soc_dai_driver i2s_dai_template = {
+	.ops = &avs_dai_nonhda_be_ops,
+	.playback = {
+		.channels_min	= 1,
+		.channels_max	= 8,
+		.rates		= SNDRV_PCM_RATE_8000_192000 |
+				  SNDRV_PCM_RATE_KNOT,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.capture = {
+		.channels_min	= 1,
+		.channels_max	= 8,
+		.rates		= SNDRV_PCM_RATE_8000_192000 |
+				  SNDRV_PCM_RATE_KNOT,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	},
+};
+
+int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
+			      unsigned long *tdms)
+{
+	struct snd_soc_dai_driver *cpus, *dai;
+	size_t ssp_count, cpu_count;
+	int i, j;
+
+	ssp_count = adev->hw_cfg.i2s_caps.ctrl_count;
+	cpu_count = hweight_long(port_mask);
+	if (tdms)
+		for_each_set_bit(i, &port_mask, ssp_count)
+			cpu_count += hweight_long(tdms[i]);
+
+	cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL);
+	if (!cpus)
+		return -ENOMEM;
+
+	dai = cpus;
+	for_each_set_bit(i, &port_mask, ssp_count) {
+		memcpy(dai, &i2s_dai_template, sizeof(*dai));
+
+		dai->name =
+			devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i);
+		dai->playback.stream_name =
+			devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i);
+		dai->capture.stream_name =
+			devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i);
+
+		if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
+			return -ENOMEM;
+		dai++;
+	}
+
+	if (!tdms)
+		goto plat_register;
+
+	for_each_set_bit(i, &port_mask, ssp_count) {
+		for_each_set_bit(j, &tdms[i], ssp_count) {
+			memcpy(dai, &i2s_dai_template, sizeof(*dai));
+
+			dai->name =
+				devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d:%d Pin", i, j);
+			dai->playback.stream_name =
+				devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Tx", i, j);
+			dai->capture.stream_name =
+				devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Rx", i, j);
+
+			if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
+				return -ENOMEM;
+			dai++;
+		}
+	}
+
+plat_register:
+	return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count);
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 05/15] ASoC: Intel: avs: HDA PCM BE operations
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (3 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 04/15] ASoC: Intel: avs: non-HDA PCM BE operations Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 06/15] ASoC: Intel: avs: Coredump and recovery flow Cezary Rojewski
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

HDA streaming in DSP world means enlisting HDAudio links as BE
interfaces. Another difference when compared to its DMIC and I2S friends
is lack of NHLT blob usage - no additional hardware configuration is
needed.

Similarly to I2S component, HDA populates its DAIs dynamically, here by
the means of codec->pcm_list_head. Allows for cutting the number of soc
components required to support the interface.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/avs.h |   1 +
 sound/soc/intel/avs/pcm.c | 349 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 350 insertions(+)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index b4fd67fac17d..e628f78d1864 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -273,5 +273,6 @@ extern const struct snd_soc_dai_ops avs_dai_fe_ops;
 int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
 int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
 			      unsigned long *tdms);
+int avs_hda_platform_register(struct avs_dev *adev, const char *name);
 
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 079fa19f7d7b..668f533578a6 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -245,6 +245,155 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
 	.trigger = avs_dai_nonhda_be_trigger,
 };
 
+static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	return avs_dai_startup(substream, dai, false);
+}
+
+static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	return avs_dai_nonhda_be_shutdown(substream, dai);
+}
+
+static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+	struct hdac_ext_stream *link_stream;
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (data->path)
+		return 0;
+
+	link_stream = substream->runtime->private_data;
+
+	return avs_dai_be_hw_params(substream, hw_params, dai,
+				    hdac_stream(link_stream)->stream_tag - 1);
+}
+
+static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct avs_dma_data *data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct hdac_ext_stream *link_stream;
+	struct hdac_ext_link *link;
+	struct hda_codec *codec;
+
+	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	if (!data->path)
+		return 0;
+
+	link_stream = substream->runtime->private_data;
+	link_stream->link_prepared = false;
+	avs_path_free(data->path);
+	data->path = NULL;
+
+	/* clear link <-> stream mapping */
+	codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
+	link = snd_hdac_ext_bus_link_at(&codec->bus->core, codec->core.addr);
+	if (!link)
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
+
+	return 0;
+}
+
+static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct hdac_ext_stream *link_stream = runtime->private_data;
+	struct hdac_ext_link *link;
+	struct hda_codec *codec;
+	struct hdac_bus *bus;
+	unsigned int format_val;
+	int ret;
+
+	if (link_stream->link_prepared)
+		return 0;
+
+	codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
+	bus = &codec->bus->core;
+	format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
+						 runtime->sample_bits, 0);
+
+	snd_hdac_ext_stream_decouple(bus, link_stream, true);
+	snd_hdac_ext_link_stream_reset(link_stream);
+	snd_hdac_ext_link_stream_setup(link_stream, format_val);
+
+	link = snd_hdac_ext_bus_link_at(bus, codec->core.addr);
+	if (!link)
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
+
+	ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
+	if (ret)
+		return ret;
+
+	link_stream->link_prepared = true;
+	return 0;
+}
+
+static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
+				  struct snd_soc_dai *dai)
+{
+	struct hdac_ext_stream *link_stream;
+	struct avs_dma_data *data;
+	int ret = 0;
+
+	dev_dbg(dai->dev, "entry %s cmd=%d\n", __func__, cmd);
+
+	data = snd_soc_dai_get_dma_data(dai, substream);
+	link_stream = substream->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		snd_hdac_ext_link_stream_start(link_stream);
+
+		ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
+		if (ret < 0)
+			dev_err(dai->dev, "run BE path failed: %d\n", ret);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = avs_path_pause(data->path);
+		if (ret < 0)
+			dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+
+		snd_hdac_ext_link_stream_clear(link_stream);
+
+		if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+			ret = avs_path_reset(data->path);
+			if (ret < 0)
+				dev_err(dai->dev, "reset BE path failed: %d\n", ret);
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dai_ops avs_dai_hda_be_ops = {
+	.startup = avs_dai_hda_be_startup,
+	.shutdown = avs_dai_hda_be_shutdown,
+	.hw_params = avs_dai_hda_be_hw_params,
+	.hw_free = avs_dai_hda_be_hw_free,
+	.prepare = avs_dai_hda_be_prepare,
+	.trigger = avs_dai_hda_be_trigger,
+};
+
 static const unsigned int rates[] = {
 	8000, 11025, 12000, 16000,
 	22050, 24000, 32000, 44100,
@@ -831,3 +980,203 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
 plat_register:
 	return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count);
 }
+
+/* HD-Audio CPU DAI template */
+static const struct snd_soc_dai_driver hda_cpu_dai = {
+	.ops = &avs_dai_hda_be_ops,
+	.playback = {
+		.channels_min	= 1,
+		.channels_max	= 8,
+		.rates		= SNDRV_PCM_RATE_8000_192000,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.capture = {
+		.channels_min	= 1,
+		.channels_max	= 8,
+		.rates		= SNDRV_PCM_RATE_8000_192000,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	},
+};
+
+static void avs_component_hda_unregister_dais(struct snd_soc_component *component)
+{
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_dai *dai, *save;
+	struct hda_codec *codec;
+	char name[32];
+
+	mach = dev_get_platdata(component->card->dev);
+	codec = mach->pdata;
+	sprintf(name, "%s-cpu", dev_name(&codec->core.dev));
+
+	for_each_component_dais_safe(component, dai, save) {
+		if (!strstr(dai->driver->name, name))
+			continue;
+
+		if (dai->playback_widget)
+			snd_soc_dapm_free_widget(dai->playback_widget);
+		if (dai->capture_widget)
+			snd_soc_dapm_free_widget(dai->capture_widget);
+		snd_soc_unregister_dai(dai);
+	}
+}
+
+static int avs_component_hda_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_dai_driver *dais;
+	struct snd_soc_acpi_mach *mach;
+	struct hda_codec *codec;
+	struct hda_pcm *pcm;
+	const char *cname;
+	int pcm_count = 0, ret, i;
+
+	mach = dev_get_platdata(component->card->dev);
+	if (!mach)
+		return -EINVAL;
+
+	codec = mach->pdata;
+	if (list_empty(&codec->pcm_list_head))
+		return -EINVAL;
+	list_for_each_entry(pcm, &codec->pcm_list_head, list)
+		pcm_count++;
+
+	dais = devm_kcalloc(component->dev, pcm_count, sizeof(*dais),
+			    GFP_KERNEL);
+	if (!dais)
+		return -ENOMEM;
+
+	cname = dev_name(&codec->core.dev);
+	dapm = snd_soc_component_get_dapm(component);
+	pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+	for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+		struct snd_soc_dai *dai;
+
+		memcpy(&dais[i], &hda_cpu_dai, sizeof(*dais));
+		dais[i].id = i;
+		dais[i].name = devm_kasprintf(component->dev, GFP_KERNEL,
+					      "%s-cpu%d", cname, i);
+		if (!dais[i].name) {
+			ret = -ENOMEM;
+			goto exit;
+		}
+
+		if (pcm->stream[0].substreams) {
+			dais[i].playback.stream_name =
+				devm_kasprintf(component->dev, GFP_KERNEL,
+					       "%s-cpu%d Tx", cname, i);
+			if (!dais[i].playback.stream_name) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+		}
+
+		if (pcm->stream[1].substreams) {
+			dais[i].capture.stream_name =
+				devm_kasprintf(component->dev, GFP_KERNEL,
+					       "%s-cpu%d Rx", cname, i);
+			if (!dais[i].capture.stream_name) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+		}
+
+		dai = snd_soc_register_dai(component, &dais[i], false);
+		if (!dai) {
+			dev_err(component->dev, "register dai for %s failed\n",
+				pcm->name);
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+		if (ret < 0) {
+			dev_err(component->dev, "create widgets failed: %d\n",
+				ret);
+			goto exit;
+		}
+	}
+
+	ret = avs_component_probe(component);
+exit:
+	if (ret)
+		avs_component_hda_unregister_dais(component);
+
+	return ret;
+}
+
+static void avs_component_hda_remove(struct snd_soc_component *component)
+{
+	avs_component_hda_unregister_dais(component);
+	avs_component_remove(component);
+}
+
+static int avs_component_hda_open(struct snd_soc_component *component,
+				  struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct hdac_ext_stream *link_stream;
+	struct hda_codec *codec;
+
+	/* only BE DAI links are handled here */
+	if (!rtd->dai_link->no_pcm)
+		return avs_component_open(component, substream);
+
+	codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
+	link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream,
+					     HDAC_EXT_STREAM_TYPE_LINK);
+	if (!link_stream)
+		return -EBUSY;
+
+	substream->runtime->private_data = link_stream;
+	return 0;
+}
+
+static int avs_component_hda_close(struct snd_soc_component *component,
+				   struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct hdac_ext_stream *link_stream;
+
+	/* only BE DAI links are handled here */
+	if (!rtd->dai_link->no_pcm)
+		return 0;
+
+	link_stream = substream->runtime->private_data;
+	snd_hdac_ext_stream_release(link_stream, HDAC_EXT_STREAM_TYPE_LINK);
+	substream->runtime->private_data = NULL;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver avs_hda_component_driver = {
+	.name			= "avs-hda-pcm",
+	.probe			= avs_component_hda_probe,
+	.remove			= avs_component_hda_remove,
+	.open			= avs_component_hda_open,
+	.close			= avs_component_hda_close,
+	.pointer		= avs_component_pointer,
+	.mmap			= avs_component_mmap,
+	.pcm_construct		= avs_component_construct,
+	/*
+	 * hda platform component's probe() is dependent on
+	 * codec->pcm_list_head, it needs to be initialized after codec
+	 * component. remove_order is here for completeness sake
+	 */
+	.probe_order		= SND_SOC_COMP_ORDER_LATE,
+	.remove_order		= SND_SOC_COMP_ORDER_EARLY,
+	.module_get_upon_open	= 1,
+	.topology_name_prefix	= "intel/avs",
+	.non_legacy_dai_naming	= true,
+};
+
+int avs_hda_platform_register(struct avs_dev *adev, const char *name)
+{
+	return avs_soc_component_register(adev->dev, name,
+					  &avs_hda_component_driver, NULL, 0);
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 06/15] ASoC: Intel: avs: Coredump and recovery flow
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (4 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 05/15] ASoC: Intel: avs: HDA " Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 07/15] ASoC: Intel: avs: Prepare for firmware tracing Cezary Rojewski
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

In rare occasions, under stress conditions or hardware malfunction, DSP
firmware may fail. Software is notified about such situation with
EXCEPTION_CAUGHT notification. IPC timeout is also counted as critical
device failure. More often than not, driver can recover from such
situations by performing full reset: killing and restarting ADSP.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/Kconfig        |  1 +
 sound/soc/intel/avs/avs.h      |  4 ++
 sound/soc/intel/avs/ipc.c      | 97 +++++++++++++++++++++++++++++++++-
 sound/soc/intel/avs/messages.h |  5 ++
 4 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 039b45a4a799..1aaf9bdf721c 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -219,6 +219,7 @@ config SND_SOC_INTEL_AVS
 	select SND_HDA_EXT_CORE
 	select SND_HDA_DSP_LOADER
 	select SND_INTEL_DSP_CONFIG
+	select WANT_DEV_COREDUMP
 	help
 	  Enable support for Intel(R) cAVS 1.5 platforms with DSP
 	  capabilities. This includes Skylake, Kabylake, Amberlake and
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index e628f78d1864..9096f6c3d598 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -42,6 +42,7 @@ struct avs_dsp_ops {
 	int (* const load_basefw)(struct avs_dev *, struct firmware *);
 	int (* const load_lib)(struct avs_dev *, struct firmware *, u32);
 	int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32);
+	int (* const coredump)(struct avs_dev *, union avs_notify_msg *);
 };
 
 #define avs_dsp_op(adev, op, ...) \
@@ -164,12 +165,15 @@ struct avs_ipc {
 	struct avs_ipc_msg rx;
 	u32 default_timeout_ms;
 	bool ready;
+	atomic_t recovering;
 
 	bool rx_completed;
 	spinlock_t rx_lock;
 	struct mutex msg_mutex;
 	struct completion done_completion;
 	struct completion busy_completion;
+
+	struct work_struct recovery_work;
 };
 
 #define AVS_EIPC	EREMOTEIO
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 68aaf01edbf2..98cdc05071fb 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -14,6 +14,89 @@
 
 #define AVS_IPC_TIMEOUT_MS	300
 
+static void avs_dsp_recovery(struct avs_dev *adev)
+{
+	struct avs_soc_component *acomp;
+	unsigned int core_mask;
+	int ret;
+
+	mutex_lock(&adev->comp_list_mutex);
+	/* disconnect all running streams */
+	list_for_each_entry(acomp, &adev->comp_list, node) {
+		struct snd_soc_pcm_runtime *rtd;
+		struct snd_soc_card *card;
+
+		card = acomp->base.card;
+		if (!card)
+			continue;
+
+		for_each_card_rtds(card, rtd) {
+			struct snd_pcm *pcm;
+			int dir;
+
+			pcm = rtd->pcm;
+			if (!pcm || rtd->dai_link->no_pcm)
+				continue;
+
+			for_each_pcm_streams(dir) {
+				struct snd_pcm_substream *substream;
+
+				substream = pcm->streams[dir].substream;
+				if (!substream || !substream->runtime)
+					continue;
+
+				snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+			}
+		}
+	}
+	mutex_unlock(&adev->comp_list_mutex);
+
+	/* forcibly shutdown all cores */
+	core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0);
+	avs_dsp_core_disable(adev, core_mask);
+
+	/* attempt dsp reboot */
+	ret = avs_dsp_boot_firmware(adev, true);
+	if (ret < 0)
+		dev_err(adev->dev, "dsp reboot failed: %d\n", ret);
+
+	pm_runtime_mark_last_busy(adev->dev);
+	pm_runtime_enable(adev->dev);
+	pm_request_autosuspend(adev->dev);
+
+	atomic_set(&adev->ipc->recovering, 0);
+}
+
+static void avs_dsp_recovery_work(struct work_struct *work)
+{
+	struct avs_ipc *ipc = container_of(work, struct avs_ipc, recovery_work);
+
+	avs_dsp_recovery(to_avs_dev(ipc->dev));
+}
+
+static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+	struct avs_ipc *ipc = adev->ipc;
+
+	/* Account for the double-exception case. */
+	ipc->ready = false;
+
+	if (!atomic_add_unless(&ipc->recovering, 1, 1)) {
+		dev_err(adev->dev, "dsp recovery is already in progress\n");
+		return;
+	}
+
+	dev_crit(adev->dev, "communication severed, rebooting dsp..\n");
+
+	/* Re-enabled on recovery completion. */
+	pm_runtime_disable(adev->dev);
+
+	/* Process received notification. */
+	avs_dsp_op(adev, coredump, msg);
+
+	schedule_work(&ipc->recovery_work);
+}
+
 static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
 {
 	struct avs_ipc *ipc = adev->ipc;
@@ -57,6 +140,9 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 		data_size = sizeof(struct avs_notify_res_data);
 		break;
 
+	case AVS_NOTIFY_EXCEPTION_CAUGHT:
+		break;
+
 	case AVS_NOTIFY_MODULE_EVENT:
 		/* To know the total payload size, header needs to be read first. */
 		memcpy_fromio(&mod_data, avs_uplink_addr(adev), sizeof(mod_data));
@@ -84,6 +170,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 		complete(&adev->fw_ready);
 		break;
 
+	case AVS_NOTIFY_EXCEPTION_CAUGHT:
+		avs_dsp_exception_caught(adev, &msg);
+		break;
+
 	default:
 		break;
 	}
@@ -278,9 +368,10 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
 	ret = avs_ipc_wait_busy_completion(ipc, timeout);
 	if (ret) {
 		if (ret == -ETIMEDOUT) {
-			dev_crit(adev->dev, "communication severed: %d, rebooting dsp..\n", ret);
+			union avs_notify_msg msg = AVS_NOTIFICATION(EXCEPTION_CAUGHT);
 
-			avs_ipc_block(ipc);
+			/* Same treatment as on exception, just stack_dump=0. */
+			avs_dsp_exception_caught(adev, &msg);
 		}
 		goto exit;
 	}
@@ -368,6 +459,7 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
 	ipc->dev = dev;
 	ipc->ready = false;
 	ipc->default_timeout_ms = AVS_IPC_TIMEOUT_MS;
+	INIT_WORK(&ipc->recovery_work, avs_dsp_recovery_work);
 	init_completion(&ipc->done_completion);
 	init_completion(&ipc->busy_completion);
 	spin_lock_init(&ipc->rx_lock);
@@ -379,4 +471,5 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
 void avs_ipc_block(struct avs_ipc *ipc)
 {
 	ipc->ready = false;
+	cancel_work_sync(&ipc->recovery_work);
 }
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 0395dd7150eb..94875a153124 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -187,6 +187,7 @@ enum avs_notify_msg_type {
 	AVS_NOTIFY_PHRASE_DETECTED = 4,
 	AVS_NOTIFY_RESOURCE_EVENT = 5,
 	AVS_NOTIFY_FW_READY = 8,
+	AVS_NOTIFY_EXCEPTION_CAUGHT = 10,
 	AVS_NOTIFY_MODULE_EVENT = 12,
 };
 
@@ -205,6 +206,10 @@ union avs_notify_msg {
 		};
 		union {
 			u32 val;
+			struct {
+				u32 core_id:2;
+				u32 stack_dump_size:16;
+			} coredump;
 		} ext;
 	};
 } __packed;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 07/15] ASoC: Intel: avs: Prepare for firmware tracing
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (5 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 06/15] ASoC: Intel: avs: Coredump and recovery flow Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 08/15] ASoC: Intel: avs: D0ix power state support Cezary Rojewski
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Firmware provides its own debug functionality. While coredump is one of
these, traces are the main area of interest. kfifo is enlisted to cache
log data that is being pumped to driver through SRAM. Separate DSP
operations are declared as actual feature implementation differs between
firmware generations.

As log gathering involves usage of IPCs, add all necessary: ENABLE_LOGS
and SYSTEM_TIME.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/avs.h       | 32 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/ipc.c       |  5 +++++
 sound/soc/intel/avs/messages.c  | 31 +++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h  | 21 +++++++++++++++++++++
 sound/soc/intel/avs/registers.h |  1 +
 sound/soc/intel/avs/utils.c     | 23 +++++++++++++++++++++++
 6 files changed, 113 insertions(+)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 9096f6c3d598..263ceb39d25d 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -11,6 +11,7 @@
 
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/kfifo.h>
 #include <sound/hda_codec.h>
 #include <sound/hda_register.h>
 #include <sound/soc-component.h>
@@ -42,6 +43,10 @@ struct avs_dsp_ops {
 	int (* const load_basefw)(struct avs_dev *, struct firmware *);
 	int (* const load_lib)(struct avs_dev *, struct firmware *, u32);
 	int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32);
+	int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long,
+				  u32 *);
+	int (* const log_buffer_offset)(struct avs_dev *, u32);
+	int (* const log_buffer_status)(struct avs_dev *, union avs_notify_msg *);
 	int (* const coredump)(struct avs_dev *, union avs_notify_msg *);
 };
 
@@ -75,6 +80,16 @@ struct avs_fw_entry {
 	struct list_head node;
 };
 
+struct avs_debug {
+	struct kfifo trace_fifo;
+	spinlock_t fifo_lock;	/* serialize I/O for trace_fifo */
+	spinlock_t trace_lock;	/* serialize debug window I/O between each LOG_BUFFER_STATUS */
+	wait_queue_head_t trace_waitq;
+	u32 aging_timer_period;
+	u32 fifo_full_timer_period;
+	u32 logged_resources;	/* context dependent: core or library */
+};
+
 /*
  * struct avs_dev - Intel HD-Audio driver data
  *
@@ -115,6 +130,8 @@ struct avs_dev {
 	struct list_head path_list;
 	spinlock_t path_list_lock;
 	struct mutex path_mutex;
+
+	struct avs_debug dbg;
 };
 
 /* from hda_bus to avs_dev */
@@ -279,4 +296,19 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
 			      unsigned long *tdms);
 int avs_hda_platform_register(struct avs_dev *adev, const char *name);
 
+/* Firmware tracing helpers */
+
+unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
+				   spinlock_t *lock);
+
+#define avs_log_buffer_size(adev) \
+	((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
+
+#define avs_log_buffer_addr(adev, core) \
+({ \
+	s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \
+	(__offset < 0) ? NULL : \
+			 (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
+})
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 98cdc05071fb..feb900ba1db9 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -140,6 +140,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 		data_size = sizeof(struct avs_notify_res_data);
 		break;
 
+	case AVS_NOTIFY_LOG_BUFFER_STATUS:
 	case AVS_NOTIFY_EXCEPTION_CAUGHT:
 		break;
 
@@ -170,6 +171,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 		complete(&adev->fw_ready);
 		break;
 
+	case AVS_NOTIFY_LOG_BUFFER_STATUS:
+		avs_dsp_op(adev, log_buffer_status, &msg);
+		break;
+
 	case AVS_NOTIFY_EXCEPTION_CAUGHT:
 		avs_dsp_exception_caught(adev, &msg);
 		break;
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 004da166a943..3da33150aabf 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -677,6 +677,37 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
 	return 0;
 }
 
+int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
+{
+	int ret;
+
+	ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+				       AVS_BASEFW_ENABLE_LOGS, log_info, size);
+	if (ret)
+		dev_err(adev->dev, "enable logs failed: %d\n", ret);
+
+	return ret;
+}
+
+int avs_ipc_set_system_time(struct avs_dev *adev)
+{
+	struct avs_sys_time sys_time;
+	int ret;
+	u64 us;
+
+	/* firmware expects UTC time in micro seconds */
+	us = ktime_to_us(ktime_get());
+	sys_time.val_l = us & UINT_MAX;
+	sys_time.val_u = us >> 32;
+
+	ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+				       AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
+	if (ret)
+		dev_err(adev->dev, "set system time failed: %d\n", ret);
+
+	return ret;
+}
+
 int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
 				   u8 instance_id, u32 sink_id,
 				   const struct avs_audio_format *src_fmt,
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 94875a153124..257482e160bc 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -186,6 +186,7 @@ union avs_reply_msg {
 enum avs_notify_msg_type {
 	AVS_NOTIFY_PHRASE_DETECTED = 4,
 	AVS_NOTIFY_RESOURCE_EVENT = 5,
+	AVS_NOTIFY_LOG_BUFFER_STATUS = 6,
 	AVS_NOTIFY_FW_READY = 8,
 	AVS_NOTIFY_EXCEPTION_CAUGHT = 10,
 	AVS_NOTIFY_MODULE_EVENT = 12,
@@ -203,6 +204,10 @@ union avs_notify_msg {
 				u32 msg_direction:1;
 				u32 msg_target:1;
 			};
+			struct {
+				u16 rsvd:12;
+				u16 core:4;
+			} log;
 		};
 		union {
 			u32 val;
@@ -329,12 +334,21 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming);
 #define AVS_BASEFW_INST_ID	0
 
 enum avs_basefw_runtime_param {
+	AVS_BASEFW_ENABLE_LOGS = 6,
 	AVS_BASEFW_FIRMWARE_CONFIG = 7,
 	AVS_BASEFW_HARDWARE_CONFIG = 8,
 	AVS_BASEFW_MODULES_INFO = 9,
 	AVS_BASEFW_LIBRARIES_INFO = 16,
+	AVS_BASEFW_SYSTEM_TIME = 20,
+};
+
+enum avs_log_enable {
+	AVS_LOG_DISABLE = 0,
+	AVS_LOG_ENABLE = 1
 };
 
+int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size);
+
 struct avs_fw_version {
 	u16 major;
 	u16 minor;
@@ -502,6 +516,13 @@ static inline bool avs_module_entry_is_loaded(struct avs_module_entry *mentry)
 
 int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info);
 
+struct avs_sys_time {
+	u32 val_l;
+	u32 val_u;
+} __packed;
+
+int avs_ipc_set_system_time(struct avs_dev *adev);
+
 /* Module configuration */
 
 #define AVS_MIXIN_MOD_UUID \
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 3fd02389ed2b..f951d3441cdf 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -58,6 +58,7 @@
 #define AVS_UPLINK_WINDOW		AVS_FW_REGS_WINDOW
 /* HOST -> DSP communication window */
 #define AVS_DOWNLINK_WINDOW		1
+#define AVS_DEBUG_WINDOW		2
 
 /* registry I/O helpers */
 #define avs_sram_offset(adev, window_idx) \
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index 6473e3ae4c6e..13611dee9787 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -7,6 +7,7 @@
 //
 
 #include <linux/firmware.h>
+#include <linux/kfifo.h>
 #include <linux/slab.h>
 #include "avs.h"
 #include "messages.h"
@@ -299,3 +300,25 @@ void avs_release_firmwares(struct avs_dev *adev)
 		kfree(entry);
 	}
 }
+
+unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
+				   spinlock_t *lock)
+{
+	struct __kfifo *__fifo = &fifo->kfifo;
+	unsigned long flags;
+	unsigned int l, off;
+
+	spin_lock_irqsave(lock, flags);
+	len = min(len, kfifo_avail(fifo));
+	off = __fifo->in & __fifo->mask;
+	l = min(len, kfifo_size(fifo) - off);
+
+	memcpy_fromio(__fifo->data + off, src, l);
+	memcpy_fromio(__fifo->data, src + l, len - l);
+	/* Make sure data copied from SRAM is visible to all CPUs. */
+	smp_mb();
+	__fifo->in += len;
+	spin_unlock_irqrestore(lock, flags);
+
+	return len;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 08/15] ASoC: Intel: avs: D0ix power state support
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (6 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 07/15] ASoC: Intel: avs: Prepare for firmware tracing Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 09/15] ASoC: Intel: avs: Event tracing Cezary Rojewski
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Audio DSP device supports D0 substates in form of D0ix, allowing for
preserving more power even when device is still considered active (D0).
When entered, certain domains which are not being currently used become
power gated. Entering and leaving D0ix is a complex process and differs
between firmware generations.

Conditions that disallow D0i3 and require immediate D0i0 transition
include but may not be limited to: IPC traffic, firmware tracing and
SRAM I/O. To make D0ix toggling sane, delay D0i3 transition and refresh
the timer each time an IPC is requested.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/avs.h      |  14 ++++
 sound/soc/intel/avs/dsp.c      |  14 ++++
 sound/soc/intel/avs/ipc.c      | 121 ++++++++++++++++++++++++++++++++-
 sound/soc/intel/avs/messages.c |   4 +-
 4 files changed, 150 insertions(+), 3 deletions(-)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 263ceb39d25d..583f46d5a9bc 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -22,6 +22,7 @@ struct avs_dev;
 struct avs_tplg;
 struct avs_tplg_library;
 struct avs_soc_component;
+struct avs_ipc_msg;
 
 /*
  * struct avs_dsp_ops - Platform-specific DSP operations
@@ -48,6 +49,8 @@ struct avs_dsp_ops {
 	int (* const log_buffer_offset)(struct avs_dev *, u32);
 	int (* const log_buffer_status)(struct avs_dev *, union avs_notify_msg *);
 	int (* const coredump)(struct avs_dev *, union avs_notify_msg *);
+	bool (* const d0ix_toggle)(struct avs_dev *, struct avs_ipc_msg *, bool);
+	int (* const set_d0ix)(struct avs_dev *, bool);
 };
 
 #define avs_dsp_op(adev, op, ...) \
@@ -191,6 +194,9 @@ struct avs_ipc {
 	struct completion busy_completion;
 
 	struct work_struct recovery_work;
+	struct delayed_work d0ix_work;
+	atomic_t d0ix_disable_depth;
+	bool in_d0ix;
 };
 
 #define AVS_EIPC	EREMOTEIO
@@ -227,6 +233,11 @@ int avs_dsp_send_msg_timeout(struct avs_dev *adev,
 			     struct avs_ipc_msg *reply, int timeout);
 int avs_dsp_send_msg(struct avs_dev *adev,
 		     struct avs_ipc_msg *request, struct avs_ipc_msg *reply);
+/* Two variants below are for messages that control DSP power states. */
+int avs_dsp_send_pm_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
+				struct avs_ipc_msg *reply, int timeout, bool wake_d0i0);
+int avs_dsp_send_pm_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
+			struct avs_ipc_msg *reply, bool wake_d0i0);
 int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev,
 				 struct avs_ipc_msg *request, int timeout);
 int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request);
@@ -234,6 +245,9 @@ void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable);
 int avs_ipc_init(struct avs_ipc *ipc, struct device *dev);
 void avs_ipc_block(struct avs_ipc *ipc);
 
+int avs_dsp_disable_d0ix(struct avs_dev *adev);
+int avs_dsp_enable_d0ix(struct avs_dev *adev);
+
 /* Firmware resources management */
 
 int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry);
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 3ff17bd22a5a..2f18b137ff42 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -152,6 +152,15 @@ static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
 
 	adev->core_refs[core_id]++;
 	if (adev->core_refs[core_id] == 1) {
+		/*
+		 * No cores other than main-core can be running for DSP
+		 * to achieve d0ix. Conscious SET_D0IX IPC failure is permitted,
+		 * simply d0ix power state will no longer be attempted.
+		 */
+		ret = avs_dsp_disable_d0ix(adev);
+		if (ret && ret != -AVS_EIPC)
+			goto err_disable_d0ix;
+
 		ret = avs_dsp_enable(adev, mask);
 		if (ret)
 			goto err_enable_dsp;
@@ -160,6 +169,8 @@ static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
 	return 0;
 
 err_enable_dsp:
+	avs_dsp_enable_d0ix(adev);
+err_disable_d0ix:
 	adev->core_refs[core_id]--;
 err:
 	dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
@@ -185,6 +196,9 @@ static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
 		ret = avs_dsp_disable(adev, mask);
 		if (ret)
 			goto err;
+
+		/* Match disable_d0ix in avs_dsp_get_core(). */
+		avs_dsp_enable_d0ix(adev);
 	}
 
 	return 0;
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index feb900ba1db9..2cf4cb4f0c56 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -13,6 +13,82 @@
 #include "registers.h"
 
 #define AVS_IPC_TIMEOUT_MS	300
+#define AVS_D0IX_DELAY_MS	300
+
+static int
+avs_dsp_set_d0ix(struct avs_dev *adev, bool enable)
+{
+	struct avs_ipc *ipc = adev->ipc;
+	int ret;
+
+	/* Is transition required? */
+	if (ipc->in_d0ix == enable)
+		return 0;
+
+	ret = avs_dsp_op(adev, set_d0ix, enable);
+	if (ret) {
+		/* Prevent further d0ix attempts on conscious IPC failure. */
+		if (ret == -AVS_EIPC)
+			atomic_inc(&ipc->d0ix_disable_depth);
+
+		ipc->in_d0ix = false;
+		return ret;
+	}
+
+	ipc->in_d0ix = enable;
+	return 0;
+}
+
+static void avs_dsp_schedule_d0ix(struct avs_dev *adev, struct avs_ipc_msg *tx)
+{
+	if (atomic_read(&adev->ipc->d0ix_disable_depth))
+		return;
+
+	mod_delayed_work(system_power_efficient_wq, &adev->ipc->d0ix_work,
+			 msecs_to_jiffies(AVS_D0IX_DELAY_MS));
+}
+
+static void avs_dsp_d0ix_work(struct work_struct *work)
+{
+	struct avs_ipc *ipc = container_of(work, struct avs_ipc, d0ix_work.work);
+
+	avs_dsp_set_d0ix(to_avs_dev(ipc->dev), true);
+}
+
+static int avs_dsp_wake_d0i0(struct avs_dev *adev, struct avs_ipc_msg *tx)
+{
+	struct avs_ipc *ipc = adev->ipc;
+
+	if (!atomic_read(&ipc->d0ix_disable_depth)) {
+		cancel_delayed_work_sync(&ipc->d0ix_work);
+		return avs_dsp_set_d0ix(adev, false);
+	}
+
+	return 0;
+}
+
+int avs_dsp_disable_d0ix(struct avs_dev *adev)
+{
+	struct avs_ipc *ipc = adev->ipc;
+
+	/* Prevent PG only on the first disable. */
+	if (atomic_add_return(1, &ipc->d0ix_disable_depth) == 1) {
+		cancel_delayed_work_sync(&ipc->d0ix_work);
+		return avs_dsp_set_d0ix(adev, false);
+	}
+
+	return 0;
+}
+
+int avs_dsp_enable_d0ix(struct avs_dev *adev)
+{
+	struct avs_ipc *ipc = adev->ipc;
+
+	if (atomic_dec_and_test(&ipc->d0ix_disable_depth))
+		queue_delayed_work(system_power_efficient_wq, &ipc->d0ix_work,
+				   msecs_to_jiffies(AVS_D0IX_DELAY_MS));
+	return 0;
+}
 
 static void avs_dsp_recovery(struct avs_dev *adev)
 {
@@ -88,6 +164,8 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
 
 	dev_crit(adev->dev, "communication severed, rebooting dsp..\n");
 
+	cancel_delayed_work_sync(&ipc->d0ix_work);
+	ipc->in_d0ix = false;
 	/* Re-enabled on recovery completion. */
 	pm_runtime_disable(adev->dev);
 
@@ -393,10 +471,35 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
 	return ret;
 }
 
+static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *request,
+				     struct avs_ipc_msg *reply, int timeout, bool wake_d0i0,
+				     bool schedule_d0ix)
+{
+	int ret;
+
+	if (wake_d0i0) {
+		ret = avs_dsp_wake_d0i0(adev, request);
+		if (ret)
+			return ret;
+	}
+
+	ret = avs_dsp_do_send_msg(adev, request, reply, timeout);
+	if (ret)
+		return ret;
+
+	if (schedule_d0ix)
+		avs_dsp_schedule_d0ix(adev, request);
+
+	return 0;
+}
+
 int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
 			     struct avs_ipc_msg *reply, int timeout)
 {
-	return avs_dsp_do_send_msg(adev, request, reply, timeout);
+	bool wake_d0i0 = avs_dsp_op(adev, d0ix_toggle, request, true);
+	bool schedule_d0ix = avs_dsp_op(adev, d0ix_toggle, request, false);
+
+	return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, schedule_d0ix);
 }
 
 int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
@@ -405,6 +508,19 @@ int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
 	return avs_dsp_send_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms);
 }
 
+int avs_dsp_send_pm_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
+				struct avs_ipc_msg *reply, int timeout, bool wake_d0i0)
+{
+	return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, false);
+}
+
+int avs_dsp_send_pm_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
+			struct avs_ipc_msg *reply, bool wake_d0i0)
+{
+	return avs_dsp_send_pm_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms,
+					   wake_d0i0);
+}
+
 static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout)
 {
 	struct avs_ipc *ipc = adev->ipc;
@@ -465,6 +581,7 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
 	ipc->ready = false;
 	ipc->default_timeout_ms = AVS_IPC_TIMEOUT_MS;
 	INIT_WORK(&ipc->recovery_work, avs_dsp_recovery_work);
+	INIT_DELAYED_WORK(&ipc->d0ix_work, avs_dsp_d0ix_work);
 	init_completion(&ipc->done_completion);
 	init_completion(&ipc->busy_completion);
 	spin_lock_init(&ipc->rx_lock);
@@ -477,4 +594,6 @@ void avs_ipc_block(struct avs_ipc *ipc)
 {
 	ipc->ready = false;
 	cancel_work_sync(&ipc->recovery_work);
+	cancel_delayed_work_sync(&ipc->d0ix_work);
+	ipc->in_d0ix = false;
 }
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 3da33150aabf..6404fce8cde4 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -432,7 +432,7 @@ int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup)
 	request.data = &dx;
 	request.size = sizeof(dx);
 
-	ret = avs_dsp_send_msg(adev, &request, NULL);
+	ret = avs_dsp_send_pm_msg(adev, &request, NULL, true);
 	if (ret)
 		avs_ipc_err(adev, &request, "set dx", ret);
 
@@ -456,7 +456,7 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming)
 
 	request.header = msg.val;
 
-	ret = avs_dsp_send_msg(adev, &request, NULL);
+	ret = avs_dsp_send_pm_msg(adev, &request, NULL, false);
 	if (ret)
 		avs_ipc_err(adev, &request, "set d0ix", ret);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 09/15] ASoC: Intel: avs: Event tracing
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (7 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 08/15] ASoC: Intel: avs: D0ix power state support Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 10/15] ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask Cezary Rojewski
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Define tracing macros for easy avs debug. These cover all IPC message
types: requests, replies and notifications as well as DSP-core
operations and d0ix toggling.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/Makefile |   4 +
 sound/soc/intel/avs/dsp.c    |  10 +++
 sound/soc/intel/avs/ipc.c    |  30 ++++++-
 sound/soc/intel/avs/trace.c  |  33 ++++++++
 sound/soc/intel/avs/trace.h  | 154 +++++++++++++++++++++++++++++++++++
 5 files changed, 228 insertions(+), 3 deletions(-)
 create mode 100644 sound/soc/intel/avs/trace.c
 create mode 100644 sound/soc/intel/avs/trace.h

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 62b3581d6cdb..38285e73e75d 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -4,4 +4,8 @@ snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
 		    topology.o path.o pcm.o
 snd-soc-avs-objs += cldma.o
 
+snd-soc-avs-objs += trace.o
+# tell define_trace.h where to find the trace header
+CFLAGS_trace.o := -I$(src)
+
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 2f18b137ff42..8f111250c5b1 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -10,6 +10,7 @@
 #include <sound/hdaudio_ext.h>
 #include "avs.h"
 #include "registers.h"
+#include "trace.h"
 
 #define AVS_ADSPCS_INTERVAL_US		500
 #define AVS_ADSPCS_TIMEOUT_US		50000
@@ -19,6 +20,9 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
 	u32 value, mask, reg;
 	int ret;
 
+	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
+	trace_avs_dsp_core_op(value, core_mask, "power", power);
+
 	mask = AVS_ADSPCS_SPA_MASK(core_mask);
 	value = power ? mask : 0;
 
@@ -43,6 +47,9 @@ int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
 	u32 value, mask, reg;
 	int ret;
 
+	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
+	trace_avs_dsp_core_op(value, core_mask, "reset", reset);
+
 	mask = AVS_ADSPCS_CRST_MASK(core_mask);
 	value = reset ? mask : 0;
 
@@ -64,6 +71,9 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
 	u32 value, mask, reg;
 	int ret;
 
+	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
+	trace_avs_dsp_core_op(value, core_mask, "stall", stall);
+
 	mask = AVS_ADSPCS_CSTALL_MASK(core_mask);
 	value = stall ? mask : 0;
 
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 2cf4cb4f0c56..d755ba8b8518 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -6,11 +6,13 @@
 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
 //
 
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/slab.h>
 #include <sound/hdaudio_ext.h>
 #include "avs.h"
 #include "messages.h"
 #include "registers.h"
+#include "trace.h"
 
 #define AVS_IPC_TIMEOUT_MS	300
 #define AVS_D0IX_DELAY_MS	300
@@ -179,6 +181,10 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
 {
 	struct avs_ipc *ipc = adev->ipc;
 	union avs_reply_msg msg = AVS_MSG(header);
+	u64 reg;
+
+	reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
+	trace_avs_ipc_reply_msg(header, reg);
 
 	ipc->rx.header = header;
 	/* Abort copying payload if request processing was unsuccessful. */
@@ -189,6 +195,7 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
 			ipc->rx.size = msg.ext.large_config.data_off_size;
 
 		memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), ipc->rx.size);
+		trace_avs_msg_payload(ipc->rx.data, ipc->rx.size);
 	}
 }
 
@@ -198,6 +205,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 	union avs_notify_msg msg = AVS_MSG(header);
 	size_t data_size = 0;
 	void *data = NULL;
+	u64 reg;
+
+	reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
+	trace_avs_ipc_notify_msg(header, reg);
 
 	/* Ignore spurious notifications until handshake is established. */
 	if (!adev->ipc->ready && msg.notify_msg_type != AVS_NOTIFY_FW_READY) {
@@ -239,6 +250,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 			return;
 
 		memcpy_fromio(data, avs_uplink_addr(adev), data_size);
+		trace_avs_msg_payload(data, data_size);
 	}
 
 	/* Perform notification-specific operations. */
@@ -422,9 +434,15 @@ static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg *reply)
 	reinit_completion(&ipc->busy_completion);
 }
 
-static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx)
+static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx, bool read_fwregs)
 {
+	u64 reg = ULONG_MAX;
+
 	tx->header |= SKL_ADSP_HIPCI_BUSY;
+	if (read_fwregs)
+		reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
+
+	trace_avs_request(tx, reg);
 
 	if (tx->size)
 		memcpy_toio(avs_downlink_addr(adev), tx->data, tx->size);
@@ -445,7 +463,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
 
 	spin_lock(&ipc->rx_lock);
 	avs_ipc_msg_init(ipc, reply);
-	avs_dsp_send_tx(adev, request);
+	avs_dsp_send_tx(adev, request, true);
 	spin_unlock(&ipc->rx_lock);
 
 	ret = avs_ipc_wait_busy_completion(ipc, timeout);
@@ -477,6 +495,7 @@ static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *r
 {
 	int ret;
 
+	trace_avs_d0ix("wake", wake_d0i0, request->header);
 	if (wake_d0i0) {
 		ret = avs_dsp_wake_d0i0(adev, request);
 		if (ret)
@@ -487,6 +506,7 @@ static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *r
 	if (ret)
 		return ret;
 
+	trace_avs_d0ix("schedule", schedule_d0ix, request->header);
 	if (schedule_d0ix)
 		avs_dsp_schedule_d0ix(adev, request);
 
@@ -530,7 +550,11 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
 
 	spin_lock(&ipc->rx_lock);
 	avs_ipc_msg_init(ipc, NULL);
-	avs_dsp_send_tx(adev, request);
+	/*
+	 * with hw still stalled, memory windows may not be
+	 * configured properly so avoid accessing SRAM
+	 */
+	avs_dsp_send_tx(adev, request, false);
 	spin_unlock(&ipc->rx_lock);
 
 	/* ROM messages must be sent before main core is unstalled */
diff --git a/sound/soc/intel/avs/trace.c b/sound/soc/intel/avs/trace.c
new file mode 100644
index 000000000000..fcb7cfc823d6
--- /dev/null
+++ b/sound/soc/intel/avs/trace.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//         Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/types.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#define BYTES_PER_LINE 16
+#define MAX_CHUNK_SIZE ((PAGE_SIZE - 150) /* Place for trace header */	\
+			/ (2 * BYTES_PER_LINE + 4) /* chars per line */	\
+			* BYTES_PER_LINE)
+
+void trace_avs_msg_payload(const void *data, size_t size)
+{
+	size_t remaining = size;
+	size_t offset = 0;
+
+	while (remaining > 0) {
+		u32 chunk;
+
+		chunk = min(remaining, (size_t)MAX_CHUNK_SIZE);
+		trace_avs_ipc_msg_payload(data, chunk, offset, size);
+
+		remaining -= chunk;
+		offset += chunk;
+	}
+}
diff --git a/sound/soc/intel/avs/trace.h b/sound/soc/intel/avs/trace.h
new file mode 100644
index 000000000000..855b06bb14b0
--- /dev/null
+++ b/sound/soc/intel/avs/trace.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM intel_avs
+
+#if !defined(_TRACE_INTEL_AVS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INTEL_AVS_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(avs_dsp_core_op,
+
+	TP_PROTO(unsigned int reg, unsigned int mask, const char *op, bool flag),
+
+	TP_ARGS(reg, mask, op, flag),
+
+	TP_STRUCT__entry(
+		__field(unsigned int,	reg	)
+		__field(unsigned int,	mask	)
+		__string(op,		op	)
+		__field(bool,		flag	)
+	),
+
+	TP_fast_assign(
+		__entry->reg = reg;
+		__entry->mask = mask;
+		__assign_str(op, op);
+		__entry->flag = flag;
+	),
+
+	TP_printk("%s: %d, core mask: 0x%X, prev state: 0x%08X",
+		  __get_str(op), __entry->flag, __entry->mask, __entry->reg)
+);
+
+#ifndef __TRACE_INTEL_AVS_TRACE_HELPER
+#define __TRACE_INTEL_AVS_TRACE_HELPER
+
+void trace_avs_msg_payload(const void *data, size_t size);
+
+#define trace_avs_request(msg, fwregs) \
+({ \
+	trace_avs_ipc_request_msg((msg)->header, fwregs); \
+	trace_avs_msg_payload((msg)->data, (msg)->size); \
+})
+
+#define trace_avs_reply(msg, fwregs) \
+({ \
+	trace_avs_ipc_reply_msg((msg)->header, fwregs); \
+	trace_avs_msg_payload((msg)->data, (msg)->size); \
+})
+
+#define trace_avs_notify(msg, fwregs) \
+({ \
+	trace_avs_ipc_notify_msg((msg)->header, fwregs); \
+	trace_avs_msg_payload((msg)->data, (msg)->size); \
+})
+#endif
+
+DECLARE_EVENT_CLASS(avs_ipc_msg_hdr,
+
+	TP_PROTO(u64 header, u64 fwregs),
+
+	TP_ARGS(header, fwregs),
+
+	TP_STRUCT__entry(
+		__field(u64,	header)
+		__field(u64,	fwregs)
+	),
+
+	TP_fast_assign(
+		__entry->header = header;
+		__entry->fwregs = fwregs;
+	),
+
+	TP_printk("primary: 0x%08X, extension: 0x%08X,\n"
+		  "fwstatus: 0x%08X, fwerror: 0x%08X",
+		  lower_32_bits(__entry->header), upper_32_bits(__entry->header),
+		  lower_32_bits(__entry->fwregs), upper_32_bits(__entry->fwregs))
+);
+
+DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_request_msg,
+	TP_PROTO(u64 header, u64 fwregs),
+	TP_ARGS(header, fwregs)
+);
+
+DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_reply_msg,
+	TP_PROTO(u64 header, u64 fwregs),
+	TP_ARGS(header, fwregs)
+);
+
+DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_notify_msg,
+	TP_PROTO(u64 header, u64 fwregs),
+	TP_ARGS(header, fwregs)
+);
+
+TRACE_EVENT_CONDITION(avs_ipc_msg_payload,
+
+	TP_PROTO(const u8 *data, size_t size, size_t offset, size_t total),
+
+	TP_ARGS(data, size, offset, total),
+
+	TP_CONDITION(data && size),
+
+	TP_STRUCT__entry(
+		__dynamic_array(u8,	buf,	size	)
+		__field(size_t,		offset		)
+		__field(size_t,		pos		)
+		__field(size_t,		total		)
+	),
+
+	TP_fast_assign(
+		memcpy(__get_dynamic_array(buf), data + offset, size);
+		__entry->offset = offset;
+		__entry->pos = offset + size;
+		__entry->total = total;
+	),
+
+	TP_printk("range %zu-%zu out of %zu bytes%s",
+		  __entry->offset, __entry->pos, __entry->total,
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 16, 4,
+				   __get_dynamic_array(buf),
+				   __get_dynamic_array_len(buf), false))
+);
+
+TRACE_EVENT(avs_d0ix,
+
+	TP_PROTO(const char *op, bool proceed, u64 header),
+
+	TP_ARGS(op, proceed, header),
+
+	TP_STRUCT__entry(
+		__string(op,	op	)
+		__field(bool,	proceed	)
+		__field(u64,	header	)
+	),
+
+	TP_fast_assign(
+		__assign_str(op, op);
+		__entry->proceed = proceed;
+		__entry->header = header;
+	),
+
+	TP_printk("%s%s for request: 0x%08X 0x%08X",
+		  __entry->proceed ? "" : "ignore ", __get_str(op),
+		  lower_32_bits(__entry->header), upper_32_bits(__entry->header))
+);
+
+#endif /* _TRACE_INTEL_AVS_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 10/15] ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (8 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 09/15] ASoC: Intel: avs: Event tracing Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, Piotr Maziarz, cujomalainey, lma

From: Piotr Maziarz <piotrx.maziarz@linux.intel.com>

'link_mask' field is intended for SoundWire, I2S should use
'i2s_link_mask' instead.

Signed-off-by: Piotr Maziarz <piotrx.maziarz@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/topology.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 4ea799658ed9..0d11cc8aab0b 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -381,11 +381,11 @@ static int parse_link_formatted_string(struct snd_soc_component *comp, void *ele
 	 * Dynamic naming - string formats, e.g.: ssp%d - supported only for
 	 * topologies describing single device e.g.: an I2S codec on SSP0.
 	 */
-	if (hweight_long(mach->link_mask) != 1)
+	if (hweight_long(mach->mach_params.i2s_link_mask) != 1)
 		return avs_parse_string_token(comp, elem, object, offset);
 
 	snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
-		 __ffs(mach->link_mask));
+		 __ffs(mach->mach_params.i2s_link_mask));
 
 	return 0;
 }
@@ -1350,8 +1350,8 @@ static int avs_route_load(struct snd_soc_component *comp, int index,
 	u32 port;
 
 	/* See parse_link_formatted_string() for dynamic naming when(s). */
-	if (hweight_long(mach->link_mask) == 1) {
-		port = __ffs(mach->link_mask);
+	if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
+		port = __ffs(mach->mach_params.i2s_link_mask);
 
 		snprintf(buf, len, route->source, port);
 		strncpy((char *)route->source, buf, len);
@@ -1382,10 +1382,10 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
 	mach = dev_get_platdata(comp->card->dev);
 
 	/* See parse_link_formatted_string() for dynamic naming when(s). */
-	if (hweight_long(mach->link_mask) == 1) {
+	if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
 		kfree(w->name);
 		/* w->name is freed later by soc_tplg_dapm_widget_create() */
-		w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->link_mask));
+		w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
 		if (!w->name)
 			return -ENOMEM;
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (9 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 10/15] ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-26 16:24   ` Guenter Roeck
  2022-05-16 10:11 ` [PATCH v3 12/15] ASoC: Intel: avs: PCI driver implementation Cezary Rojewski
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

AVS driver operates with granular audio card division in mind.
Super-card approach (e.g.: I2S, DMIC and HDA DAIs combined) is
deprecated in favour of individual cards - one per each device. This
provides necessary dynamism, especially for configurations with number
of codecs present and makes it easier to survive auxiliary devices
failures - one card failing to probe does not prevent others from
succeeding.

All boards spawned by AVS are unregistered on ->remove(). This includes
dummy codecs such as DMIC.

As all machine boards found in sound/soc/intel/boards are irreversibly
tied to 'super-card' approach, new boards are going to be introduced.
This temporarily increases number of boards available under /intel
directory until skylake-driver becomes deprecated and removed.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/Makefile          |   2 +-
 sound/soc/intel/avs/avs.h             |   3 +
 sound/soc/intel/avs/board_selection.c | 501 ++++++++++++++++++++++++++
 3 files changed, 505 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/board_selection.c

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 38285e73e75d..592d4dc02c56 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
-		    topology.o path.o pcm.o
+		    topology.o path.o pcm.o board_selection.o
 snd-soc-avs-objs += cldma.o
 
 snd-soc-avs-objs += trace.o
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 583f46d5a9bc..92e8d647b3f9 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -310,6 +310,9 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
 			      unsigned long *tdms);
 int avs_hda_platform_register(struct avs_dev *adev, const char *name);
 
+int avs_register_all_boards(struct avs_dev *adev);
+void avs_unregister_all_boards(struct avs_dev *adev);
+
 /* Firmware tracing helpers */
 
 unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
new file mode 100644
index 000000000000..80cb0164678a
--- /dev/null
+++ b/sound/soc/intel/avs/board_selection.c
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_register.h>
+#include <sound/intel-nhlt.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-component.h>
+#include "avs.h"
+
+static bool i2s_test;
+module_param(i2s_test, bool, 0444);
+MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
+
+static const struct dmi_system_id kbl_dmi_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
+		},
+	},
+	{}
+};
+
+static const struct dmi_system_id kblr_dmi_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
+		},
+	},
+	{}
+};
+
+static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
+{
+	struct snd_soc_acpi_mach *mach = arg;
+	const struct dmi_system_id *dmi_id;
+	struct dmi_system_id *dmi_table;
+
+	if (mach->quirk_data == NULL)
+		return mach;
+
+	dmi_table = (struct dmi_system_id *)mach->quirk_data;
+
+	dmi_id = dmi_first_match(dmi_table);
+	if (!dmi_id)
+		return NULL;
+
+	return mach;
+}
+
+#define AVS_SSP(x)		(BIT(x))
+#define AVS_SSP_RANGE(a, b)	(GENMASK(b, a))
+
+/* supported I2S board codec configurations */
+static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {
+	{
+		.id = "INT343A",
+		.drv_name = "avs_rt286",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.tplg_filename = "rt286-tplg.bin",
+	},
+	{
+		.id = "10508825",
+		.drv_name = "avs_nau8825",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(1),
+		},
+		.tplg_filename = "nau8825-tplg.bin",
+	},
+	{
+		.id = "INT343B",
+		.drv_name = "avs_ssm4567",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.tplg_filename = "ssm4567-tplg.bin",
+	},
+	{
+		.id = "MX98357A",
+		.drv_name = "avs_max98357a",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.tplg_filename = "max98357a-tplg.bin",
+	},
+	{},
+};
+
+static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
+	{
+		.id = "INT343A",
+		.drv_name = "avs_rt286",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.quirk_data = &kbl_dmi_table,
+		.machine_quirk = dmi_match_quirk,
+		.tplg_filename = "rt286-tplg.bin",
+	},
+	{
+		.id = "INT343A",
+		.drv_name = "avs_rt298",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.quirk_data = &kblr_dmi_table,
+		.machine_quirk = dmi_match_quirk,
+		.tplg_filename = "rt298-tplg.bin",
+	},
+	{
+		.id = "MX98373",
+		.drv_name = "avs_max98373",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.tplg_filename = "max98373-tplg.bin",
+	},
+	{
+		.id = "DLGS7219",
+		.drv_name = "avs_da7219",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(1),
+		},
+		.tplg_filename = "da7219-tplg.bin",
+	},
+	{},
+};
+
+static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
+	{
+		.id = "INT343A",
+		.drv_name = "avs_rt298",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(5),
+		},
+		.tplg_filename = "rt298-tplg.bin",
+	},
+	{
+		.id = "INT34C3",
+		.drv_name = "avs_tdf8532",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP_RANGE(0, 5),
+		},
+		.pdata = (unsigned long[]){ 0, 0, 0x14, 0, 0, 0 }, /* SSP2 TDMs */
+		.tplg_filename = "tdf8532-tplg.bin",
+	},
+	{
+		.id = "MX98357A",
+		.drv_name = "avs_max98357a",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(5),
+		},
+		.tplg_filename = "max98357a-tplg.bin",
+	},
+	{
+		.id = "DLGS7219",
+		.drv_name = "avs_da7219",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(1),
+		},
+		.tplg_filename = "da7219-tplg.bin",
+	},
+	{},
+};
+
+static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
+	{
+		.id = "INT343A",
+		.drv_name = "avs_rt298",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(2),
+		},
+		.tplg_filename = "rt298-tplg.bin",
+	},
+	{},
+};
+
+static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
+	{
+		.drv_name = "avs_i2s_test",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(0),
+		},
+		.tplg_filename = "i2s-test-tplg.bin",
+	},
+	{
+		.drv_name = "avs_i2s_test",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(1),
+		},
+		.tplg_filename = "i2s-test-tplg.bin",
+	},
+	{
+		.drv_name = "avs_i2s_test",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(2),
+		},
+		.tplg_filename = "i2s-test-tplg.bin",
+	},
+	{
+		.drv_name = "avs_i2s_test",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(3),
+		},
+		.tplg_filename = "i2s-test-tplg.bin",
+	},
+	{
+		.drv_name = "avs_i2s_test",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(4),
+		},
+		.tplg_filename = "i2s-test-tplg.bin",
+	},
+	{
+		.drv_name = "avs_i2s_test",
+		.mach_params = {
+			.i2s_link_mask = AVS_SSP(5),
+		},
+		.tplg_filename = "i2s-test-tplg.bin",
+	},
+	/* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */
+};
+
+struct avs_acpi_boards {
+	int id;
+	struct snd_soc_acpi_mach *machs;
+};
+
+#define AVS_MACH_ENTRY(_id, _mach) \
+	{ .id = (_id), .machs = (_mach), }
+
+/* supported I2S boards per platform */
+static const struct avs_acpi_boards i2s_boards[] = {
+	AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */
+	AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */
+	AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */
+	AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */
+	{},
+};
+
+static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
+{
+	int id, i;
+
+	id = adev->base.pci->device;
+	for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
+		if (i2s_boards[i].id == id)
+			return &i2s_boards[i];
+	return NULL;
+}
+
+/* platform devices owned by AVS audio are removed with this hook */
+static void board_pdev_unregister(void *data)
+{
+	platform_device_unregister(data);
+}
+
+static int avs_register_dmic_board(struct avs_dev *adev)
+{
+	struct platform_device *codec, *board;
+	struct snd_soc_acpi_mach mach = {{0}};
+	int ret;
+
+	if (!adev->nhlt ||
+	    !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_DMIC)) {
+		dev_dbg(adev->dev, "no DMIC endpoints present\n");
+		return 0;
+	}
+
+	codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
+	if (IS_ERR(codec)) {
+		dev_err(adev->dev, "dmic codec register failed\n");
+		return PTR_ERR(codec);
+	}
+
+	ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
+	if (ret < 0) {
+		platform_device_unregister(codec);
+		return ret;
+	}
+
+	ret = avs_dmic_platform_register(adev, "dmic-platform");
+	if (ret < 0)
+		return ret;
+
+	mach.tplg_filename = "dmic-tplg.bin";
+	mach.mach_params.platform = "dmic-platform";
+
+	board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
+					(const void *)&mach, sizeof(mach));
+	if (IS_ERR(board)) {
+		dev_err(adev->dev, "dmic board register failed\n");
+		return PTR_ERR(board);
+	}
+
+	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
+	if (ret < 0) {
+		platform_device_unregister(board);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
+{
+	struct platform_device *board;
+	int num_ssps;
+	char *name;
+	int ret;
+
+	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
+	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
+		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
+			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
+		return -ENODEV;
+	}
+
+	name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
+			      mach->mach_params.i2s_link_mask);
+	if (!name)
+		return -ENOMEM;
+
+	ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
+	if (ret < 0)
+		return ret;
+
+	mach->mach_params.platform = name;
+
+	board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
+					      (const void *)mach, sizeof(*mach));
+	if (IS_ERR(board)) {
+		dev_err(adev->dev, "ssp board register failed\n");
+		return PTR_ERR(board);
+	}
+
+	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
+	if (ret < 0) {
+		platform_device_unregister(board);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int avs_register_i2s_boards(struct avs_dev *adev)
+{
+	const struct avs_acpi_boards *boards;
+	struct snd_soc_acpi_mach *mach;
+	int ret;
+
+	if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) {
+		dev_dbg(adev->dev, "no I2S endpoints present\n");
+		return 0;
+	}
+
+	if (i2s_test) {
+		int i, num_ssps;
+
+		num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
+		/* constrain just in case FW says there can be more SSPs than possible */
+		num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
+
+		mach = avs_test_i2s_machines;
+
+		for (i = 0; i < num_ssps; i++) {
+			ret = avs_register_i2s_board(adev, &mach[i]);
+			if (ret < 0)
+				dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
+					 ret);
+		}
+		return 0;
+	}
+
+	boards = avs_get_i2s_boards(adev);
+	if (!boards) {
+		dev_dbg(adev->dev, "no I2S endpoints supported\n");
+		return 0;
+	}
+
+	for (mach = boards->machs; mach->id[0]; mach++) {
+		if (!acpi_dev_present(mach->id, NULL, -1))
+			continue;
+
+		if (mach->machine_quirk)
+			if (!mach->machine_quirk(mach))
+				continue;
+
+		ret = avs_register_i2s_board(adev, mach);
+		if (ret < 0)
+			dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
+	}
+
+	return 0;
+}
+
+static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
+{
+	struct snd_soc_acpi_mach mach = {{0}};
+	struct platform_device *board;
+	struct hdac_device *hdev = &codec->core;
+	char *pname;
+	int ret, id;
+
+	pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
+	if (!pname)
+		return -ENOMEM;
+
+	ret = avs_hda_platform_register(adev, pname);
+	if (ret < 0)
+		return ret;
+
+	mach.pdata = codec;
+	mach.mach_params.platform = pname;
+	mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
+					    hdev->vendor_id);
+	if (!mach.tplg_filename)
+		return -ENOMEM;
+
+	id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
+	board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
+					      sizeof(mach));
+	if (IS_ERR(board)) {
+		dev_err(adev->dev, "hda board register failed\n");
+		return PTR_ERR(board);
+	}
+
+	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
+	if (ret < 0) {
+		platform_device_unregister(board);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int avs_register_hda_boards(struct avs_dev *adev)
+{
+	struct hdac_bus *bus = &adev->base.core;
+	struct hdac_device *hdev;
+	int ret;
+
+	if (!bus->num_codecs) {
+		dev_dbg(adev->dev, "no HDA endpoints present\n");
+		return 0;
+	}
+
+	list_for_each_entry(hdev, &bus->codec_list, list) {
+		struct hda_codec *codec;
+
+		codec = dev_to_hda_codec(&hdev->dev);
+
+		ret = avs_register_hda_board(adev, codec);
+		if (ret < 0)
+			dev_warn(adev->dev, "register hda-%08x failed: %d\n",
+				 codec->core.vendor_id, ret);
+	}
+
+	return 0;
+}
+
+int avs_register_all_boards(struct avs_dev *adev)
+{
+	int ret;
+
+	ret = avs_register_dmic_board(adev);
+	if (ret < 0)
+		dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
+			 ret);
+
+	ret = avs_register_i2s_boards(adev);
+	if (ret < 0)
+		dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
+			 ret);
+
+	ret = avs_register_hda_boards(adev);
+	if (ret < 0)
+		dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
+			 ret);
+
+	return 0;
+}
+
+void avs_unregister_all_boards(struct avs_dev *adev)
+{
+	snd_soc_unregister_component(adev->dev);
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 12/15] ASoC: Intel: avs: PCI driver implementation
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (10 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 13/15] ASoC: Intel: avs: Power management Cezary Rojewski
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

HD-Audio bus is a PCI device. Add all functions necessary to probe such
device along with its removal sequence. Behaviour implemented for all
standard operations is similar to existing solutions: sound/pci/hda and
sound/soc/intel/skylake.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/sound/intel-dsp-config.h |   3 +-
 sound/soc/intel/Kconfig          |   1 +
 sound/soc/intel/avs/avs.h        |   1 +
 sound/soc/intel/avs/core.c       | 494 +++++++++++++++++++++++++++++++
 sound/soc/intel/avs/dsp.c        |   3 -
 sound/soc/intel/avs/registers.h  |   1 +
 6 files changed, 499 insertions(+), 4 deletions(-)

diff --git a/include/sound/intel-dsp-config.h b/include/sound/intel-dsp-config.h
index d4609077c258..34c975910574 100644
--- a/include/sound/intel-dsp-config.h
+++ b/include/sound/intel-dsp-config.h
@@ -15,7 +15,8 @@ enum {
 	SND_INTEL_DSP_DRIVER_LEGACY,
 	SND_INTEL_DSP_DRIVER_SST,
 	SND_INTEL_DSP_DRIVER_SOF,
-	SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_SOF
+	SND_INTEL_DSP_DRIVER_AVS,
+	SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_AVS
 };
 
 #if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 1aaf9bdf721c..7c85d1bb9c12 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -216,6 +216,7 @@ config SND_SOC_INTEL_AVS
 	depends on COMMON_CLK
 	select SND_SOC_ACPI if ACPI
 	select SND_SOC_TOPOLOGY
+	select SND_HDA
 	select SND_HDA_EXT_CORE
 	select SND_HDA_DSP_LOADER
 	select SND_INTEL_DSP_CONFIG
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 92e8d647b3f9..7e175ee4cd03 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -126,6 +126,7 @@ struct avs_dev {
 	char **lib_names;
 
 	struct completion fw_ready;
+	struct work_struct probe_work;
 
 	struct nhlt_acpi_table *nhlt;
 	struct list_head comp_list;
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index a4d063d12fec..3f51809b97c7 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -14,9 +14,17 @@
 // foundation of this driver
 //
 
+#include <linux/module.h>
 #include <linux/pci.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_register.h>
 #include <sound/hdaudio.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/intel-dsp-config.h>
+#include <sound/intel-nhlt.h>
 #include "avs.h"
+#include "cldma.h"
 
 static void
 avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
@@ -59,3 +67,489 @@ void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
 	value = enable ? AZX_VS_EM2_L1SEN : 0;
 	snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
 }
+
+static int avs_hdac_bus_init_streams(struct hdac_bus *bus)
+{
+	unsigned int cp_streams, pb_streams;
+	unsigned int gcap;
+
+	gcap = snd_hdac_chip_readw(bus, GCAP);
+	cp_streams = (gcap >> 8) & 0x0F;
+	pb_streams = (gcap >> 12) & 0x0F;
+	bus->num_streams = cp_streams + pb_streams;
+
+	snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
+	snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
+
+	return snd_hdac_bus_alloc_stream_pages(bus);
+}
+
+static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
+{
+	struct hdac_ext_link *hlink;
+	bool ret;
+
+	avs_hdac_clock_gating_enable(bus, false);
+	ret = snd_hdac_bus_init_chip(bus, full_reset);
+
+	/* Reset stream-to-link mapping */
+	list_for_each_entry(hlink, &bus->hlink_list, list)
+		writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
+
+	avs_hdac_clock_gating_enable(bus, true);
+
+	/* Set DUM bit to address incorrect position reporting for capture
+	 * streams. In order to do so, CTRL needs to be out of reset state
+	 */
+	snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
+
+	return ret;
+}
+
+static int probe_codec(struct hdac_bus *bus, int addr)
+{
+	struct hda_codec *codec;
+	unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+			   (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+	unsigned int res = -1;
+	int ret;
+
+	mutex_lock(&bus->cmd_mutex);
+	snd_hdac_bus_send_cmd(bus, cmd);
+	snd_hdac_bus_get_response(bus, addr, &res);
+	mutex_unlock(&bus->cmd_mutex);
+	if (res == -1)
+		return -EIO;
+
+	dev_dbg(bus->dev, "codec #%d probed OK: 0x%x\n", addr, res);
+
+	codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "hdaudioB%dD%d", bus->idx, addr);
+	if (IS_ERR(codec)) {
+		dev_err(bus->dev, "init codec failed: %ld\n", PTR_ERR(codec));
+		return PTR_ERR(codec);
+	}
+	/*
+	 * Allow avs_core suspend by forcing suspended state on all
+	 * of its codec child devices. Component interested in
+	 * dealing with hda codecs directly takes pm responsibilities
+	 */
+	pm_runtime_set_suspended(hda_codec_dev(codec));
+
+	/* configure effectively creates new ASoC component */
+	ret = snd_hda_codec_configure(codec);
+	if (ret < 0) {
+		dev_err(bus->dev, "failed to config codec %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus)
+{
+	int c;
+
+	/* First try to probe all given codec slots */
+	for (c = 0; c < HDA_MAX_CODECS; c++) {
+		if (!(bus->codec_mask & BIT(c)))
+			continue;
+
+		if (!probe_codec(bus, c))
+			/* success, continue probing */
+			continue;
+
+		/*
+		 * Some BIOSen give you wrong codec addresses
+		 * that don't exist
+		 */
+		dev_warn(bus->dev, "Codec #%d probe error; disabling it...\n", c);
+		bus->codec_mask &= ~BIT(c);
+		/*
+		 * More badly, accessing to a non-existing
+		 * codec often screws up the controller bus,
+		 * and disturbs the further communications.
+		 * Thus if an error occurs during probing,
+		 * better to reset the controller bus to get
+		 * back to the sanity state.
+		 */
+		snd_hdac_bus_stop_chip(bus);
+		avs_hdac_bus_init_chip(bus, true);
+	}
+}
+
+static void avs_hda_probe_work(struct work_struct *work)
+{
+	struct avs_dev *adev = container_of(work, struct avs_dev, probe_work);
+	struct hdac_bus *bus = &adev->base.core;
+	struct hdac_ext_link *hlink;
+	int ret;
+
+	pm_runtime_set_active(bus->dev); /* clear runtime_error flag */
+
+	ret = snd_hdac_i915_init(bus);
+	if (ret < 0)
+		dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret);
+
+	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
+	avs_hdac_bus_init_chip(bus, true);
+	avs_hdac_bus_probe_codecs(bus);
+	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+
+	/* with all codecs probed, links can be powered down */
+	list_for_each_entry(hlink, &bus->hlink_list, list)
+		snd_hdac_ext_bus_link_put(bus, hlink);
+
+	snd_hdac_ext_bus_ppcap_enable(bus, true);
+	snd_hdac_ext_bus_ppcap_int_enable(bus, true);
+
+	ret = avs_dsp_first_boot_firmware(adev);
+	if (ret < 0)
+		return;
+
+	adev->nhlt = intel_nhlt_init(adev->dev);
+	if (!adev->nhlt)
+		dev_info(bus->dev, "platform has no NHLT\n");
+
+	avs_register_all_boards(adev);
+
+	/* configure PM */
+	pm_runtime_set_autosuspend_delay(bus->dev, 2000);
+	pm_runtime_use_autosuspend(bus->dev);
+	pm_runtime_mark_last_busy(bus->dev);
+	pm_runtime_put_autosuspend(bus->dev);
+	pm_runtime_allow(bus->dev);
+}
+
+static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size)
+{
+	u64 prev_pos, pos, num_bytes;
+
+	div64_u64_rem(stream->curr_pos, buffer_size, &prev_pos);
+	pos = snd_hdac_stream_get_pos_posbuf(stream);
+
+	if (pos < prev_pos)
+		num_bytes = (buffer_size - prev_pos) +  pos;
+	else
+		num_bytes = pos - prev_pos;
+
+	stream->curr_pos += num_bytes;
+}
+
+/* called from IRQ */
+static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
+{
+	if (stream->substream) {
+		snd_pcm_period_elapsed(stream->substream);
+	} else if (stream->cstream) {
+		u64 buffer_size = stream->cstream->runtime->buffer_size;
+
+		hdac_stream_update_pos(stream, buffer_size);
+		snd_compr_fragment_elapsed(stream->cstream);
+	}
+}
+
+static irqreturn_t hdac_bus_irq_handler(int irq, void *context)
+{
+	struct hdac_bus *bus = context;
+	u32 mask, int_enable;
+	u32 status;
+	int ret = IRQ_NONE;
+
+	if (!pm_runtime_active(bus->dev))
+		return ret;
+
+	spin_lock(&bus->reg_lock);
+
+	status = snd_hdac_chip_readl(bus, INTSTS);
+	if (status == 0 || status == UINT_MAX) {
+		spin_unlock(&bus->reg_lock);
+		return ret;
+	}
+
+	/* clear rirb int */
+	status = snd_hdac_chip_readb(bus, RIRBSTS);
+	if (status & RIRB_INT_MASK) {
+		if (status & RIRB_INT_RESPONSE)
+			snd_hdac_bus_update_rirb(bus);
+		snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
+	}
+
+	mask = (0x1 << bus->num_streams) - 1;
+
+	status = snd_hdac_chip_readl(bus, INTSTS);
+	status &= mask;
+	if (status) {
+		/* Disable stream interrupts; Re-enable in bottom half */
+		int_enable = snd_hdac_chip_readl(bus, INTCTL);
+		snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask)));
+		ret = IRQ_WAKE_THREAD;
+	} else {
+		ret = IRQ_HANDLED;
+	}
+
+	spin_unlock(&bus->reg_lock);
+	return ret;
+}
+
+static irqreturn_t hdac_bus_irq_thread(int irq, void *context)
+{
+	struct hdac_bus *bus = context;
+	u32 status;
+	u32 int_enable;
+	u32 mask;
+	unsigned long flags;
+
+	status = snd_hdac_chip_readl(bus, INTSTS);
+
+	snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream);
+
+	/* Re-enable stream interrupts */
+	mask = (0x1 << bus->num_streams) - 1;
+	spin_lock_irqsave(&bus->reg_lock, flags);
+	int_enable = snd_hdac_chip_readl(bus, INTCTL);
+	snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask));
+	spin_unlock_irqrestore(&bus->reg_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int avs_hdac_acquire_irq(struct avs_dev *adev)
+{
+	struct hdac_bus *bus = &adev->base.core;
+	struct pci_dev *pci = to_pci_dev(bus->dev);
+	int ret;
+
+	/* request one and check that we only got one interrupt */
+	ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY);
+	if (ret != 1) {
+		dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret);
+		return ret;
+	}
+
+	ret = pci_request_irq(pci, 0, hdac_bus_irq_handler, hdac_bus_irq_thread, bus,
+			      KBUILD_MODNAME);
+	if (ret < 0) {
+		dev_err(adev->dev, "Failed to request stream IRQ handler: %d\n", ret);
+		goto free_vector;
+	}
+
+	ret = pci_request_irq(pci, 0, avs_dsp_irq_handler, avs_dsp_irq_thread, adev,
+			      KBUILD_MODNAME);
+	if (ret < 0) {
+		dev_err(adev->dev, "Failed to request IPC IRQ handler: %d\n", ret);
+		goto free_stream_irq;
+	}
+
+	return 0;
+
+free_stream_irq:
+	pci_free_irq(pci, 0, bus);
+free_vector:
+	pci_free_irq_vectors(pci);
+	return ret;
+}
+
+static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct pci_device_id *id)
+{
+	struct hda_bus *bus = &adev->base;
+	struct avs_ipc *ipc;
+	struct device *dev = &pci->dev;
+	int ret;
+
+	ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, NULL);
+	if (ret < 0)
+		return ret;
+
+	bus->core.use_posbuf = 1;
+	bus->core.bdl_pos_adj = 0;
+	bus->core.sync_write = 1;
+	bus->pci = pci;
+	bus->mixer_assigned = -1;
+	mutex_init(&bus->prepare_mutex);
+
+	ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
+	if (!ipc)
+		return -ENOMEM;
+	ret = avs_ipc_init(ipc, dev);
+	if (ret < 0)
+		return ret;
+
+	adev->dev = dev;
+	adev->spec = (const struct avs_spec *)id->driver_data;
+	adev->ipc = ipc;
+	adev->hw_cfg.dsp_cores = hweight_long(AVS_MAIN_CORE_MASK);
+	INIT_WORK(&adev->probe_work, avs_hda_probe_work);
+	INIT_LIST_HEAD(&adev->comp_list);
+	INIT_LIST_HEAD(&adev->path_list);
+	INIT_LIST_HEAD(&adev->fw_list);
+	init_completion(&adev->fw_ready);
+	spin_lock_init(&adev->path_list_lock);
+	mutex_init(&adev->modres_mutex);
+	mutex_init(&adev->comp_list_mutex);
+	mutex_init(&adev->path_mutex);
+
+	return 0;
+}
+
+static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+	struct hdac_bus *bus;
+	struct avs_dev *adev;
+	struct device *dev = &pci->dev;
+	int ret;
+
+	ret = snd_intel_dsp_driver_probe(pci);
+	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS)
+		return -ENODEV;
+
+	ret = pcim_enable_device(pci);
+	if (ret < 0)
+		return ret;
+
+	adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
+	if (!adev)
+		return -ENOMEM;
+	ret = avs_bus_init(adev, pci, id);
+	if (ret < 0) {
+		dev_err(dev, "failed to init avs bus: %d\n", ret);
+		return ret;
+	}
+
+	ret = pci_request_regions(pci, "AVS HDAudio");
+	if (ret < 0)
+		return ret;
+
+	bus = &adev->base.core;
+	bus->addr = pci_resource_start(pci, 0);
+	bus->remap_addr = pci_ioremap_bar(pci, 0);
+	if (!bus->remap_addr) {
+		dev_err(bus->dev, "ioremap error\n");
+		ret = -ENXIO;
+		goto err_remap_bar0;
+	}
+
+	adev->dsp_ba = pci_ioremap_bar(pci, 4);
+	if (!adev->dsp_ba) {
+		dev_err(bus->dev, "ioremap error\n");
+		ret = -ENXIO;
+		goto err_remap_bar4;
+	}
+
+	snd_hdac_bus_parse_capabilities(bus);
+	if (bus->mlcap)
+		snd_hdac_ext_bus_get_ml_capabilities(bus);
+
+	if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
+		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+	} else {
+		dma_set_mask(dev, DMA_BIT_MASK(32));
+		dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	}
+
+	ret = avs_hdac_bus_init_streams(bus);
+	if (ret < 0) {
+		dev_err(dev, "failed to init streams: %d\n", ret);
+		goto err_init_streams;
+	}
+
+	ret = avs_hdac_acquire_irq(adev);
+	if (ret < 0) {
+		dev_err(bus->dev, "failed to acquire irq: %d\n", ret);
+		goto err_acquire_irq;
+	}
+
+	pci_set_master(pci);
+	pci_set_drvdata(pci, bus);
+	device_disable_async_suspend(dev);
+
+	schedule_work(&adev->probe_work);
+
+	return 0;
+
+err_acquire_irq:
+	snd_hdac_bus_free_stream_pages(bus);
+	snd_hdac_stream_free_all(bus);
+err_init_streams:
+	iounmap(adev->dsp_ba);
+err_remap_bar4:
+	iounmap(bus->remap_addr);
+err_remap_bar0:
+	pci_release_regions(pci);
+	return ret;
+}
+
+static void avs_pci_remove(struct pci_dev *pci)
+{
+	struct hdac_device *hdev, *save;
+	struct hdac_bus *bus = pci_get_drvdata(pci);
+	struct avs_dev *adev = hdac_to_avs(bus);
+
+	cancel_work_sync(&adev->probe_work);
+	avs_ipc_block(adev->ipc);
+
+	avs_unregister_all_boards(adev);
+
+	if (adev->nhlt)
+		intel_nhlt_free(adev->nhlt);
+
+	if (avs_platattr_test(adev, CLDMA))
+		hda_cldma_free(&code_loader);
+
+	snd_hdac_stop_streams_and_chip(bus);
+	avs_dsp_op(adev, int_control, false);
+	snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+
+	/* it is safe to remove all codecs from the system now */
+	list_for_each_entry_safe(hdev, save, &bus->codec_list, list)
+		snd_hda_codec_unregister(hdac_to_hda_codec(hdev));
+
+	snd_hdac_bus_free_stream_pages(bus);
+	snd_hdac_stream_free_all(bus);
+	/* reverse ml_capabilities */
+	snd_hdac_link_free_all(bus);
+	snd_hdac_ext_bus_exit(bus);
+
+	avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0));
+	snd_hdac_ext_bus_ppcap_enable(bus, false);
+
+	/* snd_hdac_stop_streams_and_chip does that already? */
+	snd_hdac_bus_stop_chip(bus);
+	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+	if (bus->audio_component)
+		snd_hdac_i915_exit(bus);
+
+	avs_module_info_free(adev);
+	pci_free_irq(pci, 0, adev);
+	pci_free_irq(pci, 0, bus);
+	pci_free_irq_vectors(pci);
+	iounmap(bus->remap_addr);
+	iounmap(adev->dsp_ba);
+	pci_release_regions(pci);
+
+	/* Firmware is not needed anymore */
+	avs_release_firmwares(adev);
+
+	/* pm_runtime_forbid() can rpm_resume() which we do not want */
+	pm_runtime_disable(&pci->dev);
+	pm_runtime_forbid(&pci->dev);
+	pm_runtime_enable(&pci->dev);
+	pm_runtime_get_noresume(&pci->dev);
+}
+
+static const struct pci_device_id avs_ids[] = {
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, avs_ids);
+
+static struct pci_driver avs_pci_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = avs_ids,
+	.probe = avs_pci_probe,
+	.remove = avs_pci_remove,
+};
+module_pci_driver(avs_pci_driver);
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>");
+MODULE_DESCRIPTION("Intel cAVS sound driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 8f111250c5b1..06d2f7af520f 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -6,7 +6,6 @@
 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
 //
 
-#include <linux/module.h>
 #include <sound/hdaudio_ext.h>
 #include "avs.h"
 #include "registers.h"
@@ -322,5 +321,3 @@ int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
 	ida_free(&adev->ppl_ida, instance_id);
 	return ret;
 }
-
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index f951d3441cdf..b2100dc630e4 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -14,6 +14,7 @@
 #define AZX_PGCTL_LSRMD_MASK		BIT(4)
 #define AZX_CGCTL_MISCBDCGE_MASK	BIT(6)
 #define AZX_VS_EM2_L1SEN		BIT(13)
+#define AZX_VS_EM2_DUM			BIT(23)
 
 /* Intel HD Audio General DSP Registers */
 #define AVS_ADSP_GEN_BASE		0x0
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 13/15] ASoC: Intel: avs: Power management
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (11 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 12/15] ASoC: Intel: avs: PCI driver implementation Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 14/15] ASoC: Intel: avs: SKL-based platforms support Cezary Rojewski
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

To preserve power during sleep operations, handle suspend (S3),
hibernation (S4) and runtime (RTD3) transitions. As flow for all of
is shared, define common handlers to reduce code size.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/core.c | 101 +++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 3f51809b97c7..43ce6453e5cc 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -536,6 +536,104 @@ static void avs_pci_remove(struct pci_dev *pci)
 	pm_runtime_get_noresume(&pci->dev);
 }
 
+static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
+{
+	struct hdac_bus *bus = &adev->base.core;
+	int ret;
+
+	flush_work(&adev->probe_work);
+
+	snd_hdac_ext_bus_link_power_down_all(bus);
+
+	ret = avs_ipc_set_dx(adev, AVS_MAIN_CORE_MASK, false);
+	/*
+	 * pm_runtime is blocked on DSP failure but system-wide suspend is not.
+	 * Do not block entire system from suspending if that's the case.
+	 */
+	if (ret && ret != -EPERM) {
+		dev_err(adev->dev, "set dx failed: %d\n", ret);
+		return AVS_IPC_RET(ret);
+	}
+
+	avs_dsp_op(adev, int_control, false);
+	snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+
+	ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+	if (ret < 0) {
+		dev_err(adev->dev, "core_mask %ld disable failed: %d\n", AVS_MAIN_CORE_MASK, ret);
+		return ret;
+	}
+
+	snd_hdac_ext_bus_ppcap_enable(bus, false);
+	/* disable LP SRAM retention */
+	avs_hda_power_gating_enable(adev, false);
+	snd_hdac_bus_stop_chip(bus);
+	/* disable CG when putting controller to reset */
+	avs_hdac_clock_gating_enable(bus, false);
+	snd_hdac_bus_enter_link_reset(bus);
+	avs_hdac_clock_gating_enable(bus, true);
+
+	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+
+	return 0;
+}
+
+static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
+{
+	struct hdac_bus *bus = &adev->base.core;
+	struct hdac_ext_link *hlink;
+	int ret;
+
+	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
+	avs_hdac_bus_init_chip(bus, true);
+
+	snd_hdac_ext_bus_ppcap_enable(bus, true);
+	snd_hdac_ext_bus_ppcap_int_enable(bus, true);
+
+	ret = avs_dsp_boot_firmware(adev, purge);
+	if (ret < 0) {
+		dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+		return ret;
+	}
+
+	/* turn off the links that were off before suspend */
+	list_for_each_entry(hlink, &bus->hlink_list, list) {
+		if (!hlink->ref_count)
+			snd_hdac_ext_bus_link_power_down(hlink);
+	}
+
+	/* check dma status and clean up CORB/RIRB buffers */
+	if (!bus->cmd_dma_state)
+		snd_hdac_bus_stop_cmd_io(bus);
+
+	return 0;
+}
+
+static int __maybe_unused avs_suspend(struct device *dev)
+{
+	return avs_suspend_common(to_avs_dev(dev));
+}
+
+static int __maybe_unused avs_resume(struct device *dev)
+{
+	return avs_resume_common(to_avs_dev(dev), true);
+}
+
+static int __maybe_unused avs_runtime_suspend(struct device *dev)
+{
+	return avs_suspend_common(to_avs_dev(dev));
+}
+
+static int __maybe_unused avs_runtime_resume(struct device *dev)
+{
+	return avs_resume_common(to_avs_dev(dev), true);
+}
+
+static const struct dev_pm_ops avs_dev_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume)
+	SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
+};
+
 static const struct pci_device_id avs_ids[] = {
 	{ 0 }
 };
@@ -546,6 +644,9 @@ static struct pci_driver avs_pci_driver = {
 	.id_table = avs_ids,
 	.probe = avs_pci_probe,
 	.remove = avs_pci_remove,
+	.driver = {
+		.pm = &avs_dev_pm,
+	},
 };
 module_pci_driver(avs_pci_driver);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 14/15] ASoC: Intel: avs: SKL-based platforms support
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (12 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 13/15] ASoC: Intel: avs: Power management Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-16 10:11 ` [PATCH v3 15/15] ASoC: Intel: avs: APL-based " Cezary Rojewski
  2022-05-17 17:21 ` [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Mark Brown
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Define handlers specific to cAVS 1.5 platforms, that is SKL, KBL, AML
and all other variants based on this very version of AudioDSP
architecture. Most are specific to SKL-alike platforms with only
skl_log_buffer_offset() being exposed and used later by younger
equivalents.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/Makefile    |   1 +
 sound/soc/intel/avs/avs.h       |   4 +
 sound/soc/intel/avs/core.c      |  18 +++++
 sound/soc/intel/avs/messages.h  |  18 +++++
 sound/soc/intel/avs/registers.h |   4 +
 sound/soc/intel/avs/skl.c       | 125 ++++++++++++++++++++++++++++++++
 6 files changed, 170 insertions(+)
 create mode 100644 sound/soc/intel/avs/skl.c

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 592d4dc02c56..7d09385bc970 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -3,6 +3,7 @@
 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
 		    topology.o path.o pcm.o board_selection.o
 snd-soc-avs-objs += cldma.o
+snd-soc-avs-objs += skl.o
 
 snd-soc-avs-objs += trace.o
 # tell define_trace.h where to find the trace header
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 7e175ee4cd03..237e4422dcad 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -56,6 +56,8 @@ struct avs_dsp_ops {
 #define avs_dsp_op(adev, op, ...) \
 	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
 
+extern const struct avs_dsp_ops skl_dsp_ops;
+
 #define AVS_PLATATTR_CLDMA		BIT_ULL(0)
 #define AVS_PLATATTR_IMR		BIT_ULL(1)
 
@@ -249,6 +251,8 @@ void avs_ipc_block(struct avs_ipc *ipc);
 int avs_dsp_disable_d0ix(struct avs_dev *adev);
 int avs_dsp_enable_d0ix(struct avs_dev *adev);
 
+int skl_log_buffer_offset(struct avs_dev *adev, u32 core);
+
 /* Firmware resources management */
 
 int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry);
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 43ce6453e5cc..7e78a9a9d166 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -634,7 +634,25 @@ static const struct dev_pm_ops avs_dev_pm = {
 	SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
 };
 
+static const struct avs_spec skl_desc = {
+	.name = "skl",
+	.min_fw_version = {
+		.major = 9,
+		.minor = 21,
+		.hotfix = 0,
+		.build = 4732,
+	},
+	.dsp_ops = &skl_dsp_ops,
+	.core_init_mask = 1,
+	.attributes = AVS_PLATATTR_CLDMA,
+	.sram_base_offset = SKL_ADSP_SRAM_BASE_OFFSET,
+	.sram_window_size = SKL_ADSP_SRAM_WINDOW_SIZE,
+	.rom_status = SKL_ADSP_SRAM_BASE_OFFSET,
+};
+
 static const struct pci_device_id avs_ids[] = {
+	{ PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
+	{ PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, avs_ids);
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 257482e160bc..981ec024b152 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -347,6 +347,24 @@ enum avs_log_enable {
 	AVS_LOG_ENABLE = 1
 };
 
+enum avs_skl_log_priority {
+	AVS_SKL_LOG_CRITICAL = 1,
+	AVS_SKL_LOG_HIGH,
+	AVS_SKL_LOG_MEDIUM,
+	AVS_SKL_LOG_LOW,
+	AVS_SKL_LOG_VERBOSE,
+};
+
+struct skl_log_state {
+	u32 enable;
+	u32 min_priority;
+} __packed;
+
+struct skl_log_state_info {
+	u32 core_mask;
+	struct skl_log_state logs_core[];
+} __packed;
+
 int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size);
 
 struct avs_fw_version {
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index b2100dc630e4..68f06aa4e10f 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -48,6 +48,10 @@
 #define SKL_ADSP_HIPCIE_DONE		BIT(30)
 #define SKL_ADSP_HIPCT_BUSY		BIT(31)
 
+/* Intel HD Audio SRAM windows base addresses */
+#define SKL_ADSP_SRAM_BASE_OFFSET	0x8000
+#define SKL_ADSP_SRAM_WINDOW_SIZE	0x2000
+
 /* Constants used when accessing SRAM, space shared with firmware */
 #define AVS_FW_REG_BASE(adev)		((adev)->spec->sram_base_offset)
 #define AVS_FW_REG_STATUS(adev)		(AVS_FW_REG_BASE(adev) + 0x0)
diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c
new file mode 100644
index 000000000000..bda5ec7510fe
--- /dev/null
+++ b/sound/soc/intel/avs/skl.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/devcoredump.h>
+#include <linux/slab.h>
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "messages.h"
+
+static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+			   u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+{
+	struct skl_log_state_info *info;
+	u32 size, num_cores = adev->hw_cfg.dsp_cores;
+	int ret, i;
+
+	if (fls_long(resource_mask) > num_cores)
+		return -EINVAL;
+	size = struct_size(info, logs_core, num_cores);
+	info = kzalloc(size, GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->core_mask = resource_mask;
+	if (enable)
+		for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0)) {
+			info->logs_core[i].enable = enable;
+			info->logs_core[i].min_priority = *priorities++;
+		}
+	else
+		for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0))
+			info->logs_core[i].enable = enable;
+
+	ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
+	kfree(info);
+	if (ret)
+		return AVS_IPC_RET(ret);
+
+	return 0;
+}
+
+int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
+{
+	return core * avs_log_buffer_size(adev);
+}
+
+/* fw DbgLogWp registers */
+#define FW_REGS_DBG_LOG_WP(core) (0x30 + 0x4 * core)
+
+static int
+skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+	unsigned long flags;
+	void __iomem *buf;
+	u16 size, write, offset;
+
+	spin_lock_irqsave(&adev->dbg.trace_lock, flags);
+	if (!kfifo_initialized(&adev->dbg.trace_fifo)) {
+		spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+		return 0;
+	}
+
+	size = avs_log_buffer_size(adev) / 2;
+	write = readl(avs_sram_addr(adev, AVS_FW_REGS_WINDOW) + FW_REGS_DBG_LOG_WP(msg->log.core));
+	/* determine buffer half */
+	offset = (write < size) ? size : 0;
+
+	/* Address is guaranteed to exist in SRAM2. */
+	buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
+	__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf, size, &adev->dbg.fifo_lock);
+	wake_up(&adev->dbg.trace_waitq);
+	spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+
+	return 0;
+}
+
+static int skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+	u8 *dump;
+
+	dump = vzalloc(AVS_FW_REGS_SIZE);
+	if (!dump)
+		return -ENOMEM;
+
+	memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
+	dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE, GFP_KERNEL);
+
+	return 0;
+}
+
+static bool
+skl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
+{
+	/* unsupported on cAVS 1.5 hw */
+	return false;
+}
+
+static int skl_set_d0ix(struct avs_dev *adev, bool enable)
+{
+	/* unsupported on cAVS 1.5 hw */
+	return 0;
+}
+
+const struct avs_dsp_ops skl_dsp_ops = {
+	.power = avs_dsp_core_power,
+	.reset = avs_dsp_core_reset,
+	.stall = avs_dsp_core_stall,
+	.irq_handler = avs_dsp_irq_handler,
+	.irq_thread = avs_dsp_irq_thread,
+	.int_control = avs_dsp_interrupt_control,
+	.load_basefw = avs_cldma_load_basefw,
+	.load_lib = avs_cldma_load_library,
+	.transfer_mods = avs_cldma_transfer_modules,
+	.enable_logs = skl_enable_logs,
+	.log_buffer_offset = skl_log_buffer_offset,
+	.log_buffer_status = skl_log_buffer_status,
+	.coredump = skl_coredump,
+	.d0ix_toggle = skl_d0ix_toggle,
+	.set_d0ix = skl_set_d0ix,
+};
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v3 15/15] ASoC: Intel: avs: APL-based platforms support
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (13 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 14/15] ASoC: Intel: avs: SKL-based platforms support Cezary Rojewski
@ 2022-05-16 10:11 ` Cezary Rojewski
  2022-05-17 17:21 ` [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Mark Brown
  15 siblings, 0 replies; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-16 10:11 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

Define handlers specific to cAVS 1.5+ platforms, that is, APL and
similar platforms. These differ from SKL-alike ones in terms of AudioDSP
firmware generation and thus the '+' suffix. Introduciton of IMR,
removal of CLDMA, D0IX support and monolithic-ation of library/module
code are most impactful but are not the only changes brought with this
newer generation. Some generic and 1.5 operations are being re-used to
reduce code size.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/Makefile    |   2 +-
 sound/soc/intel/avs/apl.c       | 250 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/avs.h       |  13 ++
 sound/soc/intel/avs/core.c      |  18 +++
 sound/soc/intel/avs/loader.c    |   4 +
 sound/soc/intel/avs/messages.h  |   7 +
 sound/soc/intel/avs/registers.h |   2 +
 7 files changed, 295 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/apl.c

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 7d09385bc970..b6b93ae80304 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -3,7 +3,7 @@
 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
 		    topology.o path.o pcm.o board_selection.o
 snd-soc-avs-objs += cldma.o
-snd-soc-avs-objs += skl.o
+snd-soc-avs-objs += skl.o apl.o
 
 snd-soc-avs-objs += trace.o
 # tell define_trace.h where to find the trace header
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
new file mode 100644
index 000000000000..b8e2b23c9f64
--- /dev/null
+++ b/sound/soc/intel/avs/apl.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/devcoredump.h>
+#include <linux/slab.h>
+#include "avs.h"
+#include "messages.h"
+#include "path.h"
+#include "topology.h"
+
+static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+			   u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+{
+	struct apl_log_state_info *info;
+	u32 size, num_cores = adev->hw_cfg.dsp_cores;
+	int ret, i;
+
+	if (fls_long(resource_mask) > num_cores)
+		return -EINVAL;
+	size = struct_size(info, logs_core, num_cores);
+	info = kzalloc(size, GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->aging_timer_period = aging_period;
+	info->fifo_full_timer_period = fifo_full_period;
+	info->core_mask = resource_mask;
+	if (enable)
+		for_each_set_bit(i, &resource_mask, num_cores) {
+			info->logs_core[i].enable = enable;
+			info->logs_core[i].min_priority = *priorities++;
+		}
+	else
+		for_each_set_bit(i, &resource_mask, num_cores)
+			info->logs_core[i].enable = enable;
+
+	ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
+	kfree(info);
+	if (ret)
+		return AVS_IPC_RET(ret);
+
+	return 0;
+}
+
+static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+	struct apl_log_buffer_layout layout;
+	unsigned long flags;
+	void __iomem *addr, *buf;
+
+	addr = avs_log_buffer_addr(adev, msg->log.core);
+	if (!addr)
+		return -ENXIO;
+
+	memcpy_fromio(&layout, addr, sizeof(layout));
+
+	spin_lock_irqsave(&adev->dbg.trace_lock, flags);
+	if (!kfifo_initialized(&adev->dbg.trace_fifo))
+		/* consume the logs regardless of consumer presence */
+		goto update_read_ptr;
+
+	buf = apl_log_payload_addr(addr);
+
+	if (layout.read_ptr > layout.write_ptr) {
+		__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
+				      apl_log_payload_size(adev) - layout.read_ptr,
+				      &adev->dbg.fifo_lock);
+		layout.read_ptr = 0;
+	}
+	__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
+			      layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
+
+	wake_up(&adev->dbg.trace_waitq);
+
+update_read_ptr:
+	spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+	writel(layout.write_ptr, addr);
+	return 0;
+}
+
+static int apl_wait_log_entry(struct avs_dev *adev, u32 core, struct apl_log_buffer_layout *layout)
+{
+	unsigned long timeout;
+	void __iomem *addr;
+
+	addr = avs_log_buffer_addr(adev, core);
+	if (!addr)
+		return -ENXIO;
+
+	timeout = jiffies + msecs_to_jiffies(10);
+
+	do {
+		memcpy_fromio(layout, addr, sizeof(*layout));
+		if (layout->read_ptr != layout->write_ptr)
+			return 0;
+		usleep_range(500, 1000);
+	} while (!time_after(jiffies, timeout));
+
+	return -ETIMEDOUT;
+}
+
+/* reads log header and tests its type */
+#define apl_is_entry_stackdump(addr) ((readl(addr) >> 30) & 0x1)
+
+static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+	struct apl_log_buffer_layout layout;
+	void __iomem *addr, *buf;
+	size_t dump_size;
+	u16 offset = 0;
+	u8 *dump, *pos;
+
+	dump_size = AVS_FW_REGS_SIZE + msg->ext.coredump.stack_dump_size;
+	dump = vzalloc(dump_size);
+	if (!dump)
+		return -ENOMEM;
+
+	memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
+
+	if (!msg->ext.coredump.stack_dump_size)
+		goto exit;
+
+	/* Dump the registers even if an external error prevents gathering the stack. */
+	addr = avs_log_buffer_addr(adev, msg->ext.coredump.core_id);
+	if (!addr)
+		goto exit;
+
+	buf = apl_log_payload_addr(addr);
+	memcpy_fromio(&layout, addr, sizeof(layout));
+	if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
+		/*
+		 * DSP awaits the remaining logs to be
+		 * gathered before dumping stack
+		 */
+		msg->log.core = msg->ext.coredump.core_id;
+		avs_dsp_op(adev, log_buffer_status, msg);
+	}
+
+	pos = dump + AVS_FW_REGS_SIZE;
+	/* gather the stack */
+	do {
+		u32 count;
+
+		if (apl_wait_log_entry(adev, msg->ext.coredump.core_id, &layout))
+			break;
+
+		if (layout.read_ptr > layout.write_ptr) {
+			count = apl_log_payload_size(adev) - layout.read_ptr;
+			memcpy_fromio(pos + offset, buf + layout.read_ptr, count);
+			layout.read_ptr = 0;
+			offset += count;
+		}
+		count = layout.write_ptr - layout.read_ptr;
+		memcpy_fromio(pos + offset, buf + layout.read_ptr, count);
+		offset += count;
+
+		/* update read pointer */
+		writel(layout.write_ptr, addr);
+	} while (offset < msg->ext.coredump.stack_dump_size);
+
+exit:
+	dev_coredumpv(adev->dev, dump, dump_size, GFP_KERNEL);
+
+	return 0;
+}
+
+static bool apl_lp_streaming(struct avs_dev *adev)
+{
+	struct avs_path *path;
+
+	/* Any gateway without buffer allocated in LP area disqualifies D0IX. */
+	list_for_each_entry(path, &adev->path_list, node) {
+		struct avs_path_pipeline *ppl;
+
+		list_for_each_entry(ppl, &path->ppl_list, node) {
+			struct avs_path_module *mod;
+
+			list_for_each_entry(mod, &ppl->mod_list, node) {
+				struct avs_tplg_modcfg_ext *cfg;
+
+				cfg = mod->template->cfg_ext;
+
+				/* only copiers have gateway attributes */
+				if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
+					continue;
+				/* non-gateway copiers do not prevent PG */
+				if (cfg->copier.dma_type == INVALID_OBJECT_ID)
+					continue;
+
+				if (!mod->gtw_attrs.lp_buffer_alloc)
+					return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+static bool apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
+{
+	/* wake in all cases */
+	if (wake)
+		return true;
+
+	/*
+	 * If no pipelines are running, allow for d0ix schedule.
+	 * If all gateways have lp=1, allow for d0ix schedule.
+	 * If any gateway with lp=0 is allocated, abort scheduling d0ix.
+	 *
+	 * Note: for cAVS 1.5+ and 1.8, D0IX is LP-firmware transition,
+	 * not the power-gating mechanism known from cAVS 2.0.
+	 */
+	return apl_lp_streaming(adev);
+}
+
+static int apl_set_d0ix(struct avs_dev *adev, bool enable)
+{
+	bool streaming = false;
+	int ret;
+
+	if (enable)
+		/* Either idle or all gateways with lp=1. */
+		streaming = !list_empty(&adev->path_list);
+
+	ret = avs_ipc_set_d0ix(adev, enable, streaming);
+	return AVS_IPC_RET(ret);
+}
+
+const struct avs_dsp_ops apl_dsp_ops = {
+	.power = avs_dsp_core_power,
+	.reset = avs_dsp_core_reset,
+	.stall = avs_dsp_core_stall,
+	.irq_handler = avs_dsp_irq_handler,
+	.irq_thread = avs_dsp_irq_thread,
+	.int_control = avs_dsp_interrupt_control,
+	.load_basefw = avs_hda_load_basefw,
+	.load_lib = avs_hda_load_library,
+	.transfer_mods = avs_hda_transfer_modules,
+	.enable_logs = apl_enable_logs,
+	.log_buffer_offset = skl_log_buffer_offset,
+	.log_buffer_status = apl_log_buffer_status,
+	.coredump = apl_coredump,
+	.d0ix_toggle = apl_d0ix_toggle,
+	.set_d0ix = apl_set_d0ix,
+};
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 237e4422dcad..92e37722d280 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -57,6 +57,7 @@ struct avs_dsp_ops {
 	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
 
 extern const struct avs_dsp_ops skl_dsp_ops;
+extern const struct avs_dsp_ops apl_dsp_ops;
 
 #define AVS_PLATATTR_CLDMA		BIT_ULL(0)
 #define AVS_PLATATTR_IMR		BIT_ULL(1)
@@ -333,4 +334,16 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src,
 			 (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
 })
 
+struct apl_log_buffer_layout {
+	u32 read_ptr;
+	u32 write_ptr;
+	u8 buffer[];
+} __packed;
+
+#define apl_log_payload_size(adev) \
+	(avs_log_buffer_size(adev) - sizeof(struct apl_log_buffer_layout))
+
+#define apl_log_payload_addr(addr) \
+	(addr + sizeof(struct apl_log_buffer_layout))
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 7e78a9a9d166..3a0997c3af2b 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -650,9 +650,27 @@ static const struct avs_spec skl_desc = {
 	.rom_status = SKL_ADSP_SRAM_BASE_OFFSET,
 };
 
+static const struct avs_spec apl_desc = {
+	.name = "apl",
+	.min_fw_version = {
+		.major = 9,
+		.minor = 22,
+		.hotfix = 1,
+		.build = 4323,
+	},
+	.dsp_ops = &apl_dsp_ops,
+	.core_init_mask = 3,
+	.attributes = AVS_PLATATTR_IMR,
+	.sram_base_offset = APL_ADSP_SRAM_BASE_OFFSET,
+	.sram_window_size = APL_ADSP_SRAM_WINDOW_SIZE,
+	.rom_status = APL_ADSP_SRAM_BASE_OFFSET,
+};
+
 static const struct pci_device_id avs_ids[] = {
 	{ PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
 	{ PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
+	{ PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
+	{ PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, avs_ids);
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 8aa658c52325..542fd44aa501 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -37,6 +37,8 @@
 #define AVS_EXT_MANIFEST_MAGIC		0x31454124
 #define SKL_MANIFEST_MAGIC		0x00000006
 #define SKL_ADSPFW_OFFSET		0x284
+#define APL_MANIFEST_MAGIC		0x44504324
+#define APL_ADSPFW_OFFSET		0x2000
 
 /* Occasionally, engineering (release candidate) firmware is provided for testing. */
 static bool debug_ignore_fw_version;
@@ -87,6 +89,8 @@ static int avs_fw_manifest_offset(struct firmware *fw)
 	switch (magic) {
 	case SKL_MANIFEST_MAGIC:
 		return SKL_ADSPFW_OFFSET;
+	case APL_MANIFEST_MAGIC:
+		return APL_ADSPFW_OFFSET;
 	default:
 		return -EINVAL;
 	}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 981ec024b152..c0f90dba9af8 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -365,6 +365,13 @@ struct skl_log_state_info {
 	struct skl_log_state logs_core[];
 } __packed;
 
+struct apl_log_state_info {
+	u32 aging_timer_period;
+	u32 fifo_full_timer_period;
+	u32 core_mask;
+	struct skl_log_state logs_core[];
+} __packed;
+
 int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size);
 
 struct avs_fw_version {
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 68f06aa4e10f..95be86148cf3 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -51,6 +51,8 @@
 /* Intel HD Audio SRAM windows base addresses */
 #define SKL_ADSP_SRAM_BASE_OFFSET	0x8000
 #define SKL_ADSP_SRAM_WINDOW_SIZE	0x2000
+#define APL_ADSP_SRAM_BASE_OFFSET	0x80000
+#define APL_ADSP_SRAM_WINDOW_SIZE	0x20000
 
 /* Constants used when accessing SRAM, space shared with firmware */
 #define AVS_FW_REG_BASE(adev)		((adev)->spec->sram_base_offset)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations
  2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
                   ` (14 preceding siblings ...)
  2022-05-16 10:11 ` [PATCH v3 15/15] ASoC: Intel: avs: APL-based " Cezary Rojewski
@ 2022-05-17 17:21 ` Mark Brown
  15 siblings, 0 replies; 32+ messages in thread
From: Mark Brown @ 2022-05-17 17:21 UTC (permalink / raw)
  To: cezary.rojewski, alsa-devel
  Cc: upstream, rad, pierre-louis.bossart, tiwai, hdegoede,
	amadeuszx.slawinski, cujomalainey, lma

On Mon, 16 May 2022 12:11:01 +0200, Cezary Rojewski wrote:
> Part three of main AVS driver series. This series was originally part of
> the initial series which was later divided [1] into smaller,
> easier-to-review chunks. Thus, many patches found here were already
> present on the list.
> 
> This series consists of code typical to many drivers - PCI driver
> operations, trace ability, PM operations - as well as PCM handlers for
> all standard audio interfaces, that is, HDA, I2S and DMIC are found
> here.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[01/15] ASoC: Intel: avs: Account for libraries when booting basefw
        commit: 81a299105d69344233e6aed8565522da9beec99e
[02/15] ASoC: Intel: avs: Generic soc component driver
        commit: f1b3b320bd6519b16e3480f74f2926d106e3bcba
[03/15] ASoC: Intel: avs: Generic PCM FE operations
        commit: 9114700b496c6ce16ad6fc0073f0502cd0f46991
[04/15] ASoC: Intel: avs: non-HDA PCM BE operations
        commit: b9062f9867f0e601c64e973e2eecda37ccac2ee8
[05/15] ASoC: Intel: avs: HDA PCM BE operations
        commit: d070002a20fc071c6f14c2fd8ff5ebeabead8d2a
[06/15] ASoC: Intel: avs: Coredump and recovery flow
        commit: 2f1f570cd730c81807ae143a83766068dd82d577
[07/15] ASoC: Intel: avs: Prepare for firmware tracing
        commit: 4b86115cb91a3d34ce7da87b734572ce6063babc
[08/15] ASoC: Intel: avs: D0ix power state support
        commit: 335c4cbd201d4b74942ff37e6c644d56b9247df3
[09/15] ASoC: Intel: avs: Event tracing
        commit: 69b23b3937a1a1019f3d34696897d89f2d987edf
[10/15] ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask
        commit: 25b552f192877bec5aea44a6b060a36f78de9675
[11/15] ASoC: Intel: avs: Machine board registration
        commit: beed983621fbdfd291e6e3a0cdc4d10517e60af8
[12/15] ASoC: Intel: avs: PCI driver implementation
        commit: 1affc44ea5dd554c103e0ce1e809f3aa5d942349
[13/15] ASoC: Intel: avs: Power management
        commit: cfbc100e6bbfd01a56bb83fe796318a02dc18ce4
[14/15] ASoC: Intel: avs: SKL-based platforms support
        commit: b3e29075b2346564f1bef7f8e19a1a7fcbcf7ed8
[15/15] ASoC: Intel: avs: APL-based platforms support
        commit: c8c960c109716d96cfd1de65396fb8021eed4202

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-16 10:11 ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
@ 2022-05-26 16:24   ` Guenter Roeck
  2022-05-26 16:31     ` Cezary Rojewski
  2022-05-26 17:44     ` Mark Brown
  0 siblings, 2 replies; 32+ messages in thread
From: Guenter Roeck @ 2022-05-26 16:24 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	broonie, amadeuszx.slawinski, cujomalainey, lma

On Mon, May 16, 2022 at 12:11:12PM +0200, Cezary Rojewski wrote:
> AVS driver operates with granular audio card division in mind.
> Super-card approach (e.g.: I2S, DMIC and HDA DAIs combined) is
> deprecated in favour of individual cards - one per each device. This
> provides necessary dynamism, especially for configurations with number
> of codecs present and makes it easier to survive auxiliary devices
> failures - one card failing to probe does not prevent others from
> succeeding.
> 
> All boards spawned by AVS are unregistered on ->remove(). This includes
> dummy codecs such as DMIC.
> 
> As all machine boards found in sound/soc/intel/boards are irreversibly
> tied to 'super-card' approach, new boards are going to be introduced.
> This temporarily increases number of boards available under /intel
> directory until skylake-driver becomes deprecated and removed.
> 
> Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
[ ... ]

> +
> +static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
> +{
> +	struct platform_device *board;
> +	int num_ssps;
> +	char *name;
> +	int ret;
> +
> +	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
> +	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
> +		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",

   sound/soc/intel/avs/board_selection.c: In function 'avs_register_i2s_board':
>> sound/soc/intel/avs/board_selection.c:328:36: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'int' [-Wformat=]
     328 |                 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
                                                                                                  ^^^

Reported by 0-day but still made it into mainline.

Guenter

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-26 16:24   ` Guenter Roeck
@ 2022-05-26 16:31     ` Cezary Rojewski
  2022-05-26 17:09       ` Guenter Roeck
  2022-05-26 17:44     ` Mark Brown
  1 sibling, 1 reply; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-26 16:31 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-05-26 6:24 PM, Guenter Roeck wrote:
> On Mon, May 16, 2022 at 12:11:12PM +0200, Cezary Rojewski wrote:
>> AVS driver operates with granular audio card division in mind.
>> Super-card approach (e.g.: I2S, DMIC and HDA DAIs combined) is
>> deprecated in favour of individual cards - one per each device. This
>> provides necessary dynamism, especially for configurations with number
>> of codecs present and makes it easier to survive auxiliary devices
>> failures - one card failing to probe does not prevent others from
>> succeeding.
>>
>> All boards spawned by AVS are unregistered on ->remove(). This includes
>> dummy codecs such as DMIC.
>>
>> As all machine boards found in sound/soc/intel/boards are irreversibly
>> tied to 'super-card' approach, new boards are going to be introduced.
>> This temporarily increases number of boards available under /intel
>> directory until skylake-driver becomes deprecated and removed.
>>
>> Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
>> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
>> ---


>> +
>> +static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
>> +{
>> +	struct platform_device *board;
>> +	int num_ssps;
>> +	char *name;
>> +	int ret;
>> +
>> +	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
>> +	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
>> +		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
> 
>     sound/soc/intel/avs/board_selection.c: In function 'avs_register_i2s_board':
>>> sound/soc/intel/avs/board_selection.c:328:36: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'int' [-Wformat=]
>       328 |                 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
>                                                                                                    ^^^
> 
> Reported by 0-day but still made it into mainline.


Hello,

Thanks for the report. This seems to be a false-positive and is being 
addressed by a separate patchset [1]. Perhaps the cover letter for the 
mentioned series could have looped 0-day.
If I'm wrong about this, feel free to correct me.


[1]: 
https://lore.kernel.org/lkml/20220525144844.1571705-1-amadeuszx.slawinski@linux.intel.com/


Regards,
Czarek

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-26 16:31     ` Cezary Rojewski
@ 2022-05-26 17:09       ` Guenter Roeck
  0 siblings, 0 replies; 32+ messages in thread
From: Guenter Roeck @ 2022-05-26 17:09 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	broonie, amadeuszx.slawinski, cujomalainey, lma

On 5/26/22 09:31, Cezary Rojewski wrote:
> On 2022-05-26 6:24 PM, Guenter Roeck wrote:
>> On Mon, May 16, 2022 at 12:11:12PM +0200, Cezary Rojewski wrote:
>>> AVS driver operates with granular audio card division in mind.
>>> Super-card approach (e.g.: I2S, DMIC and HDA DAIs combined) is
>>> deprecated in favour of individual cards - one per each device. This
>>> provides necessary dynamism, especially for configurations with number
>>> of codecs present and makes it easier to survive auxiliary devices
>>> failures - one card failing to probe does not prevent others from
>>> succeeding.
>>>
>>> All boards spawned by AVS are unregistered on ->remove(). This includes
>>> dummy codecs such as DMIC.
>>>
>>> As all machine boards found in sound/soc/intel/boards are irreversibly
>>> tied to 'super-card' approach, new boards are going to be introduced.
>>> This temporarily increases number of boards available under /intel
>>> directory until skylake-driver becomes deprecated and removed.
>>>
>>> Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
>>> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
>>> ---
> 
> 
>>> +
>>> +static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
>>> +{
>>> +    struct platform_device *board;
>>> +    int num_ssps;
>>> +    char *name;
>>> +    int ret;
>>> +
>>> +    num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
>>> +    if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
>>> +        dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
>>
>>     sound/soc/intel/avs/board_selection.c: In function 'avs_register_i2s_board':
>>>> sound/soc/intel/avs/board_selection.c:328:36: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'int' [-Wformat=]
>>       328 |                 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
>>                                                                                                    ^^^
>>
>> Reported by 0-day but still made it into mainline.
> 
> 
> Hello,
> 
> Thanks for the report. This seems to be a false-positive and is being addressed by a separate patchset [1]. Perhaps the cover letter for the mentioned series could have looped 0-day.

No, this is not a false positive. More like a false assumption.

> If I'm wrong about this, feel free to correct me.
> 
> 
> [1]: https://lore.kernel.org/lkml/20220525144844.1571705-1-amadeuszx.slawinski@linux.intel.com/
> 
This is incomplete. It does not address all definitions of __fls() for arc, and it
does not address the build failure for sparc64 (arch/sparc/include/asm/bitops_64.h).

Guenter

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-26 16:24   ` Guenter Roeck
  2022-05-26 16:31     ` Cezary Rojewski
@ 2022-05-26 17:44     ` Mark Brown
  2022-05-29  5:48       ` Uwe Kleine-König
  1 sibling, 1 reply; 32+ messages in thread
From: Mark Brown @ 2022-05-26 17:44 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Cezary Rojewski, upstream, alsa-devel, rad, tiwai,
	pierre-louis.bossart, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

[-- Attachment #1: Type: text/plain, Size: 956 bytes --]

On Thu, May 26, 2022 at 09:24:43AM -0700, Guenter Roeck wrote:
> On Mon, May 16, 2022 at 12:11:12PM +0200, Cezary Rojewski wrote:

> > +	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
> > +		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",

>    sound/soc/intel/avs/board_selection.c: In function 'avs_register_i2s_board':
> >> sound/soc/intel/avs/board_selection.c:328:36: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'int' [-Wformat=]
>      328 |                 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
>                                                                                                   ^^^
> Reported by 0-day but still made it into mainline.

FWIW given how hard the 0-day reports have become to read I'd not rely
on people paying attention to things that are clearly pure build
coverage based off a 0-day report alone.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-26 17:44     ` Mark Brown
@ 2022-05-29  5:48       ` Uwe Kleine-König
  2022-05-29  6:05         ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
                           ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Uwe Kleine-König @ 2022-05-29  5:48 UTC (permalink / raw)
  To: Mark Brown
  Cc: pierre-louis.bossart, Cezary Rojewski, upstream, rad, alsa-devel,
	tiwai, hdegoede, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 3255 bytes --]

Hello Mark,

On Thu, May 26, 2022 at 06:44:38PM +0100, Mark Brown wrote:
> On Thu, May 26, 2022 at 09:24:43AM -0700, Guenter Roeck wrote:
> > On Mon, May 16, 2022 at 12:11:12PM +0200, Cezary Rojewski wrote:
> 
> > > +	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
> > > +		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
> 
> >    sound/soc/intel/avs/board_selection.c: In function 'avs_register_i2s_board':
> > >> sound/soc/intel/avs/board_selection.c:328:36: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'int' [-Wformat=]
> >      328 |                 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
> >                                                                                                   ^^^
> > Reported by 0-day but still made it into mainline.
> 
> FWIW given how hard the 0-day reports have become to read I'd not rely
> on people paying attention to things that are clearly pure build
> coverage based off a 0-day report alone.

I'm unsure if I understand your sentiment correctly. Are you saying it
doesn't matter if a patch breaks the build on some arch using a
randconfig?

My position is: The commit under discussion (i.e. beed983621fb ("ASoC:
Intel: avs: Machine board registration")) breaks an allmodconfig build
on all platforms where __fls doesn't return a long int (i.e. arc, m68k,
and sparc). This actively hurts people who do build tests using
allmodconfig (or allyesconfig) for their patch series (e.g. me).

I agree that some reports by the 0-day bot are hard to parse. But still,
if there is a build problem someone should look into that. If you (with
your maintainer hat on) don't have the resource to do that, that's IMHO
fine. But I'd wish you'd push back on the patch submitter in that case
and don't apply the patch until the problem is resolved. If this is a
corner case randconfig issue, applying might be fine despite the build
error but breaking allmodconfig on 3 archs is bad.

The fix would be 

diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 80cb0164678a..f189f71b8e1e 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -325,8 +325,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
 
 	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
 	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
-		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
-			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
+		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%d\n",
+			num_ssps, mach->drv_name, fls(mach->mach_params.i2s_link_mask));
 		return -ENODEV;
 	}
 
which uses fls instead of __fls (as is done in the test triggering the
error). The former returns an int on all platforms.

Tell me if you don't want to squash this into beed983621fb and prefer a
formal patch.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc
  2022-05-29  5:48       ` Uwe Kleine-König
@ 2022-05-29  6:05         ` Uwe Kleine-König
  2022-05-29  6:21           ` Guenter Roeck
  2022-05-29 13:24         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
  2022-05-30 13:29         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Mark Brown
  2 siblings, 1 reply; 32+ messages in thread
From: Uwe Kleine-König @ 2022-05-29  6:05 UTC (permalink / raw)
  To: Mark Brown
  Cc: pierre-louis.bossart, Cezary Rojewski, upstream, rad, alsa-devel,
	tiwai, hdegoede, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 1973 bytes --]

On some platforms (i.e. arc, m68k and sparc) __fls returns an int (while
on most platforms it returns an unsigned long). This triggers a format
warning on these few platforms as the driver uses %ld to print a warning.

Replace it by fls (and %d) which returns an int everywhere and which is
already used in the if condition triggering the warning.

Fixes: beed983621fb ("ASoC: Intel: avs: Machine board registration")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
Hello again

On Sun, May 29, 2022 at 07:48:18AM +0200, Uwe Kleine-König wrote:
> Tell me if you don't want to squash this into beed983621fb and prefer a
> formal patch.

I just realized this isn't a problem in next only any more, but the
commit is already in Linus Torvald's tree. So I guess this isn't fixed
by a fixup of said commit and here comes a proper patch.

 sound/soc/intel/avs/board_selection.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 80cb0164678a..f189f71b8e1e 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -325,8 +325,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
 
 	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
 	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
-		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
-			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
+		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%d\n",
+			num_ssps, mach->drv_name, fls(mach->mach_params.i2s_link_mask));
 		return -ENODEV;
 	}
 

base-commit: beed983621fbdfd291e6e3a0cdc4d10517e60af8
-- 
2.36.1

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc
  2022-05-29  6:05         ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
@ 2022-05-29  6:21           ` Guenter Roeck
  0 siblings, 0 replies; 32+ messages in thread
From: Guenter Roeck @ 2022-05-29  6:21 UTC (permalink / raw)
  To: Uwe Kleine-König, Mark Brown
  Cc: Cezary Rojewski, upstream, alsa-devel, rad, pierre-louis.bossart,
	tiwai, hdegoede, amadeuszx.slawinski, cujomalainey, lma

On 5/28/22 23:05, Uwe Kleine-König wrote:
> On some platforms (i.e. arc, m68k and sparc) __fls returns an int (while
> on most platforms it returns an unsigned long). This triggers a format
> warning on these few platforms as the driver uses %ld to print a warning.
> 
> Replace it by fls (and %d) which returns an int everywhere and which is
> already used in the if condition triggering the warning.
> 
> Fixes: beed983621fb ("ASoC: Intel: avs: Machine board registration")
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

FWIW:

Reviewed-by: Guenter Roeck <linux@roeck-us.net>

> ---
> Hello again
> 
> On Sun, May 29, 2022 at 07:48:18AM +0200, Uwe Kleine-König wrote:
>> Tell me if you don't want to squash this into beed983621fb and prefer a
>> formal patch.
> 
> I just realized this isn't a problem in next only any more, but the
> commit is already in Linus Torvald's tree. So I guess this isn't fixed
> by a fixup of said commit and here comes a proper patch.
> 
>   sound/soc/intel/avs/board_selection.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
> index 80cb0164678a..f189f71b8e1e 100644
> --- a/sound/soc/intel/avs/board_selection.c
> +++ b/sound/soc/intel/avs/board_selection.c
> @@ -325,8 +325,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
>   
>   	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
>   	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
> -		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
> -			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
> +		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%d\n",
> +			num_ssps, mach->drv_name, fls(mach->mach_params.i2s_link_mask));
>   		return -ENODEV;
>   	}
>   
> 
> base-commit: beed983621fbdfd291e6e3a0cdc4d10517e60af8


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-29  5:48       ` Uwe Kleine-König
  2022-05-29  6:05         ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
@ 2022-05-29 13:24         ` Cezary Rojewski
  2022-05-29 13:50           ` Uwe Kleine-König
  2022-05-30 13:29         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Mark Brown
  2 siblings, 1 reply; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-29 13:24 UTC (permalink / raw)
  To: Uwe Kleine-König, Mark Brown
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	lma, amadeuszx.slawinski, cujomalainey, Guenter Roeck

On 2022-05-29 7:48 AM, Uwe Kleine-König wrote:
> Hello Mark,
> 
> On Thu, May 26, 2022 at 06:44:38PM +0100, Mark Brown wrote:

>> FWIW given how hard the 0-day reports have become to read I'd not rely
>> on people paying attention to things that are clearly pure build
>> coverage based off a 0-day report alone.
> 
> I'm unsure if I understand your sentiment correctly. Are you saying it
> doesn't matter if a patch breaks the build on some arch using a
> randconfig?
> 
> My position is: The commit under discussion (i.e. beed983621fb ("ASoC:
> Intel: avs: Machine board registration")) breaks an allmodconfig build
> on all platforms where __fls doesn't return a long int (i.e. arc, m68k,
> and sparc). This actively hurts people who do build tests using
> allmodconfig (or allyesconfig) for their patch series (e.g. me).
> 
> I agree that some reports by the 0-day bot are hard to parse. But still,
> if there is a build problem someone should look into that. If you (with
> your maintainer hat on) don't have the resource to do that, that's IMHO
> fine. But I'd wish you'd push back on the patch submitter in that case
> and don't apply the patch until the problem is resolved. If this is a
> corner case randconfig issue, applying might be fine despite the build
> error but breaking allmodconfig on 3 archs is bad.
> 
> The fix would be


Hello Uwe,

I don't believe anyone here wanted to break the build-configurations you 
did mention above. I also believe it's important to mention that below 
is not a fix but a W/A. Developer should be able to use __fls() if 
required. Value returned by fls() differs from one returned by __fls(), 
and using fls() in below context is misleading (hurts the debug-ability).

Yes, the faulty print should be devoid of __fls() until the function is 
fixed for all the archs. It's too late for that and I'm sorry for any 
inconvenience caused by the change.
To my knowledge the real fix has been provided on LKML by Amadeo [1] and 
is under review since Friday. I'd kindly appreciate helping fix the root 
cause of the problem. If there's anything missing in the series let us know.


[1]: 
https://lore.kernel.org/lkml/20220527115345.2588775-3-amadeuszx.slawinski@linux.intel.com/T/


Regards,
Czarek


> diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
> index 80cb0164678a..f189f71b8e1e 100644
> --- a/sound/soc/intel/avs/board_selection.c
> +++ b/sound/soc/intel/avs/board_selection.c
> @@ -325,8 +325,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
>   
>   	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
>   	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
> -		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
> -			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
> +		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%d\n",
> +			num_ssps, mach->drv_name, fls(mach->mach_params.i2s_link_mask));
>   		return -ENODEV;
>   	}
>   
> which uses fls instead of __fls (as is done in the test triggering the
> error). The former returns an int on all platforms.
> 
> Tell me if you don't want to squash this into beed983621fb and prefer a
> formal patch.
> 
> Best regards
> Uwe
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-29 13:24         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
@ 2022-05-29 13:50           ` Uwe Kleine-König
  2022-05-29 13:56             ` Cezary Rojewski
  0 siblings, 1 reply; 32+ messages in thread
From: Uwe Kleine-König @ 2022-05-29 13:50 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	Mark Brown, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 3517 bytes --]

On Sun, May 29, 2022 at 03:24:48PM +0200, Cezary Rojewski wrote:
> On 2022-05-29 7:48 AM, Uwe Kleine-König wrote:
> > Hello Mark,
> > 
> > On Thu, May 26, 2022 at 06:44:38PM +0100, Mark Brown wrote:
> 
> > > FWIW given how hard the 0-day reports have become to read I'd not rely
> > > on people paying attention to things that are clearly pure build
> > > coverage based off a 0-day report alone.
> > 
> > I'm unsure if I understand your sentiment correctly. Are you saying it
> > doesn't matter if a patch breaks the build on some arch using a
> > randconfig?
> > 
> > My position is: The commit under discussion (i.e. beed983621fb ("ASoC:
> > Intel: avs: Machine board registration")) breaks an allmodconfig build
> > on all platforms where __fls doesn't return a long int (i.e. arc, m68k,
> > and sparc). This actively hurts people who do build tests using
> > allmodconfig (or allyesconfig) for their patch series (e.g. me).
> > 
> > I agree that some reports by the 0-day bot are hard to parse. But still,
> > if there is a build problem someone should look into that. If you (with
> > your maintainer hat on) don't have the resource to do that, that's IMHO
> > fine. But I'd wish you'd push back on the patch submitter in that case
> > and don't apply the patch until the problem is resolved. If this is a
> > corner case randconfig issue, applying might be fine despite the build
> > error but breaking allmodconfig on 3 archs is bad.
> > 
> > The fix would be
> 
> 
> Hello Uwe,
> 
> I don't believe anyone here wanted to break the build-configurations you did
> mention above. I also believe it's important to mention that below is not a
> fix but a W/A. Developer should be able to use __fls() if required. Value
> returned by fls() differs from one returned by __fls(), and using fls() in
> below context is misleading (hurts the debug-ability).
> 
> Yes, the faulty print should be devoid of __fls() until the function is
> fixed for all the archs. It's too late for that and I'm sorry for any
> inconvenience caused by the change.
> To my knowledge the real fix has been provided on LKML by Amadeo [1] and is
> under review since Friday. I'd kindly appreciate helping fix the root cause
> of the problem. If there's anything missing in the series let us know.

Hmm, I doubt this (i.e. unify the return value of __fls) will be merged
during this cycle. I'd want that to cook a bit in next before it hits
mainline, there might be similar problems introduced by changing __fls
to the one under discussion here.

A more short-term fix would be:

diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -325,8 +325,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
  	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
  	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
 		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
-			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
+			num_ssps, mach->drv_name, (unsigned long)__fls(mach->mach_params.i2s_link_mask));
  		return -ENODEV;
  	}

i.e. explicitly cast the return value of __fls to unsigned long.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-29 13:50           ` Uwe Kleine-König
@ 2022-05-29 13:56             ` Cezary Rojewski
  2022-05-29 14:12               ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
  0 siblings, 1 reply; 32+ messages in thread
From: Cezary Rojewski @ 2022-05-29 13:56 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	Mark Brown, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

On 2022-05-29 3:50 PM, Uwe Kleine-König wrote:

> A more short-term fix would be:
> 
> diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
> --- a/sound/soc/intel/avs/board_selection.c
> +++ b/sound/soc/intel/avs/board_selection.c
> @@ -325,8 +325,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
>    	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
>    	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
>   		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
> -			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
> +			num_ssps, mach->drv_name, (unsigned long)__fls(mach->mach_params.i2s_link_mask));
>    		return -ENODEV;
>    	}
> 
> i.e. explicitly cast the return value of __fls to unsigned long.

This looks very good indeed. Will you be updating the patch you had sent 
earlier today or would you like me to send it instead?

If you choose the former, feel free to append:

Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>


Regards,
Czarek

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc
  2022-05-29 13:56             ` Cezary Rojewski
@ 2022-05-29 14:12               ` Uwe Kleine-König
  2022-05-30 13:29                 ` Mark Brown
  0 siblings, 1 reply; 32+ messages in thread
From: Uwe Kleine-König @ 2022-05-29 14:12 UTC (permalink / raw)
  To: Cezary Rojewski, Mark Brown, Guenter Roeck
  Cc: alsa-devel, upstream, rad, tiwai, pierre-louis.bossart, hdegoede,
	amadeuszx.slawinski, cujomalainey, lma

On some platforms (i.e. arc, m68k and sparc) __fls returns an int (while
on most platforms it returns an unsigned long). This triggers a format
warning on these few platforms as the driver uses %ld to print a warning.

So explicitly cast the return value to unsigned long to make the warning
go away (and so fix allmodconfig build on the affected architectures).

Fixes: beed983621fb ("ASoC: Intel: avs: Machine board registration")
Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 sound/soc/intel/avs/board_selection.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 80cb0164678a..87f9c18be238 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -326,7 +326,8 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach
 	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
 	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
 		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
-			num_ssps, mach->drv_name, __fls(mach->mach_params.i2s_link_mask));
+			num_ssps, mach->drv_name,
+			(unsigned long)__fls(mach->mach_params.i2s_link_mask));
 		return -ENODEV;
 	}
 

base-commit: beed983621fbdfd291e6e3a0cdc4d10517e60af8
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration
  2022-05-29  5:48       ` Uwe Kleine-König
  2022-05-29  6:05         ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
  2022-05-29 13:24         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
@ 2022-05-30 13:29         ` Mark Brown
  2 siblings, 0 replies; 32+ messages in thread
From: Mark Brown @ 2022-05-30 13:29 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: pierre-louis.bossart, Cezary Rojewski, upstream, rad, alsa-devel,
	tiwai, hdegoede, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 2656 bytes --]

On Sun, May 29, 2022 at 07:48:07AM +0200, Uwe Kleine-König wrote:
> On Thu, May 26, 2022 at 06:44:38PM +0100, Mark Brown wrote:

> > FWIW given how hard the 0-day reports have become to read I'd not rely
> > on people paying attention to things that are clearly pure build
> > coverage based off a 0-day report alone.

> I'm unsure if I understand your sentiment correctly. Are you saying it
> doesn't matter if a patch breaks the build on some arch using a
> randconfig?

It matters, but in practice something that is only reported by an
automated tool with a hard to read report against a a randconfig
on an obscure platform that you need to go find a toolchain for
is a lot more likely to get buried than something that doesn't
have those properties.  Similarly if a tool is sending a lot of
reports with those properties it's a lot easier for even reports
in more important issues from that tool to get dropped on the
floor.

> My position is: The commit under discussion (i.e. beed983621fb ("ASoC:
> Intel: avs: Machine board registration")) breaks an allmodconfig build
> on all platforms where __fls doesn't return a long int (i.e. arc, m68k,
> and sparc). This actively hurts people who do build tests using
> allmodconfig (or allyesconfig) for their patch series (e.g. me).

> I agree that some reports by the 0-day bot are hard to parse. But still,
> if there is a build problem someone should look into that. If you (with
> your maintainer hat on) don't have the resource to do that, that's IMHO
> fine. But I'd wish you'd push back on the patch submitter in that case
> and don't apply the patch until the problem is resolved. If this is a
> corner case randconfig issue, applying might be fine despite the build
> error but breaking allmodconfig on 3 archs is bad.

My general approach here is that I'm expecting the reports from 0
day to be enough so I don't explicitly push back, but I don't
generally apply anything that looks like it has a live issue.  In
this case it looks like what happened was that 0-day only
reported against v2 and not v3 so it wasn't apparent to me that
the report hadn't been addressed in the new version, there
weren't any reports against v3 that I can see.

The other thing here is that if something did get missed and ends
up getting applied it really helps to get an explicit report that
there's a problem in -next, clearly something got missed and it's
much easier to get something dropped just after it gets applied.
TBH I hadn't realised from the followup that this was an
all*config issue, my best guess was that it was a randconfig
thing thatg got missed.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc
  2022-05-29 14:12               ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
@ 2022-05-30 13:29                 ` Mark Brown
  2022-05-30 20:19                   ` Uwe Kleine-König
  0 siblings, 1 reply; 32+ messages in thread
From: Mark Brown @ 2022-05-30 13:29 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: pierre-louis.bossart, Cezary Rojewski, upstream, rad, alsa-devel,
	tiwai, hdegoede, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 587 bytes --]

On Sun, May 29, 2022 at 04:12:50PM +0200, Uwe Kleine-König wrote:
> On some platforms (i.e. arc, m68k and sparc) __fls returns an int (while
> on most platforms it returns an unsigned long). This triggers a format
> warning on these few platforms as the driver uses %ld to print a warning.

Please don't send new patches in reply to old patches or serieses, this
makes it harder for both people and tools to understand what is going
on - it can bury things in mailboxes and make it difficult to keep track
of what current patches are, both for the new patches and the old ones.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc
  2022-05-30 13:29                 ` Mark Brown
@ 2022-05-30 20:19                   ` Uwe Kleine-König
  2022-05-31 10:41                     ` Mark Brown
  0 siblings, 1 reply; 32+ messages in thread
From: Uwe Kleine-König @ 2022-05-30 20:19 UTC (permalink / raw)
  To: Mark Brown
  Cc: pierre-louis.bossart, Cezary Rojewski, upstream, rad, alsa-devel,
	tiwai, hdegoede, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 1250 bytes --]

Hello Mark,

On Mon, May 30, 2022 at 03:29:48PM +0200, Mark Brown wrote:
> On Sun, May 29, 2022 at 04:12:50PM +0200, Uwe Kleine-König wrote:
> > On some platforms (i.e. arc, m68k and sparc) __fls returns an int (while
> > on most platforms it returns an unsigned long). This triggers a format
> > warning on these few platforms as the driver uses %ld to print a warning.
> 
> Please don't send new patches in reply to old patches or serieses, this
> makes it harder for both people and tools to understand what is going
> on - it can bury things in mailboxes and make it difficult to keep track
> of what current patches are, both for the new patches and the old ones.

The motivation to do that is that the thread for a patch that broke
something is the canonical place to look if someone already reported (or
even fixed) the problem before.

That b4 seems to fail to extract the patch is indeed unfortunate. For a
MUA I'd expect that it sorts threads after the last received mail, so
that part is only a matter of a sane mail reader configuration.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc
  2022-05-30 20:19                   ` Uwe Kleine-König
@ 2022-05-31 10:41                     ` Mark Brown
  0 siblings, 0 replies; 32+ messages in thread
From: Mark Brown @ 2022-05-31 10:41 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: pierre-louis.bossart, Cezary Rojewski, upstream, rad, alsa-devel,
	tiwai, hdegoede, lma, amadeuszx.slawinski, cujomalainey,
	Guenter Roeck

[-- Attachment #1: Type: text/plain, Size: 1224 bytes --]

On Mon, May 30, 2022 at 10:19:46PM +0200, Uwe Kleine-König wrote:
> On Mon, May 30, 2022 at 03:29:48PM +0200, Mark Brown wrote:

> > Please don't send new patches in reply to old patches or serieses, this
> > makes it harder for both people and tools to understand what is going
> > on - it can bury things in mailboxes and make it difficult to keep track
> > of what current patches are, both for the new patches and the old ones.

> The motivation to do that is that the thread for a patch that broke
> something is the canonical place to look if someone already reported (or
> even fixed) the problem before.

Once something is applied and as time marches on that starts to
get less and less helpful, searches for Fixes: are probably
better there.

> That b4 seems to fail to extract the patch is indeed unfortunate. For a
> MUA I'd expect that it sorts threads after the last received mail, so
> that part is only a matter of a sane mail reader configuration.

The sorting really is a user workflow/preference thing - for
example I find it helpful to sort by age of the thread to
highlight new patches which might be simple to deal with before
older threads with complicated discussions in them.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2022-05-31 10:42 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-16 10:11 [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 01/15] ASoC: Intel: avs: Account for libraries when booting basefw Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 02/15] ASoC: Intel: avs: Generic soc component driver Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 03/15] ASoC: Intel: avs: Generic PCM FE operations Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 04/15] ASoC: Intel: avs: non-HDA PCM BE operations Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 05/15] ASoC: Intel: avs: HDA " Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 06/15] ASoC: Intel: avs: Coredump and recovery flow Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 07/15] ASoC: Intel: avs: Prepare for firmware tracing Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 08/15] ASoC: Intel: avs: D0ix power state support Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 09/15] ASoC: Intel: avs: Event tracing Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 10/15] ASoC: Intel: avs: Replace link_mask usage with i2s_link_mask Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
2022-05-26 16:24   ` Guenter Roeck
2022-05-26 16:31     ` Cezary Rojewski
2022-05-26 17:09       ` Guenter Roeck
2022-05-26 17:44     ` Mark Brown
2022-05-29  5:48       ` Uwe Kleine-König
2022-05-29  6:05         ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
2022-05-29  6:21           ` Guenter Roeck
2022-05-29 13:24         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Cezary Rojewski
2022-05-29 13:50           ` Uwe Kleine-König
2022-05-29 13:56             ` Cezary Rojewski
2022-05-29 14:12               ` [PATCH] ASoC: Intel: avs: Fix build error on arc, m68k and sparc Uwe Kleine-König
2022-05-30 13:29                 ` Mark Brown
2022-05-30 20:19                   ` Uwe Kleine-König
2022-05-31 10:41                     ` Mark Brown
2022-05-30 13:29         ` [PATCH v3 11/15] ASoC: Intel: avs: Machine board registration Mark Brown
2022-05-16 10:11 ` [PATCH v3 12/15] ASoC: Intel: avs: PCI driver implementation Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 13/15] ASoC: Intel: avs: Power management Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 14/15] ASoC: Intel: avs: SKL-based platforms support Cezary Rojewski
2022-05-16 10:11 ` [PATCH v3 15/15] ASoC: Intel: avs: APL-based " Cezary Rojewski
2022-05-17 17:21 ` [PATCH v3 00/15] ASoC: Intel: avs: Driver core and PCM operations Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.